1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/quota_dispatcher_host.h"
8 #include "base/memory/weak_ptr.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "content/common/quota_messages.h"
11 #include "content/public/browser/quota_permission_context.h"
12 #include "net/base/net_util.h"
13 #include "storage/browser/quota/quota_manager.h"
16 using storage::QuotaClient
;
17 using storage::QuotaManager
;
18 using storage::QuotaStatusCode
;
19 using storage::StorageType
;
23 // Created one per request to carry the request's request_id around.
24 // Dispatches requests from renderer/worker to the QuotaManager and
25 // sends back the response to the renderer/worker.
26 class QuotaDispatcherHost::RequestDispatcher
{
28 RequestDispatcher(base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
30 : dispatcher_host_(dispatcher_host
),
31 render_process_id_(dispatcher_host
->process_id_
),
32 request_id_(request_id
) {
33 dispatcher_host_
->outstanding_requests_
.AddWithID(this, request_id_
);
35 virtual ~RequestDispatcher() {}
38 // Subclass must call this when it's done with the request.
41 dispatcher_host_
->outstanding_requests_
.Remove(request_id_
);
44 QuotaDispatcherHost
* dispatcher_host() const {
45 return dispatcher_host_
.get();
47 storage::QuotaManager
* quota_manager() const {
48 return dispatcher_host_
? dispatcher_host_
->quota_manager_
: NULL
;
50 QuotaPermissionContext
* permission_context() const {
51 return dispatcher_host_
?
52 dispatcher_host_
->permission_context_
.get() : NULL
;
54 int render_process_id() const { return render_process_id_
; }
55 int request_id() const { return request_id_
; }
58 base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host_
;
59 int render_process_id_
;
63 class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
64 : public RequestDispatcher
{
66 QueryUsageAndQuotaDispatcher(
67 base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
69 : RequestDispatcher(dispatcher_host
, request_id
),
70 weak_factory_(this) {}
71 ~QueryUsageAndQuotaDispatcher() override
{}
73 void QueryStorageUsageAndQuota(const GURL
& origin
, StorageType type
) {
74 quota_manager()->GetUsageAndQuotaForWebApps(
76 base::Bind(&QueryUsageAndQuotaDispatcher::DidQueryStorageUsageAndQuota
,
77 weak_factory_
.GetWeakPtr()));
81 void DidQueryStorageUsageAndQuota(
82 QuotaStatusCode status
, int64 usage
, int64 quota
) {
83 if (!dispatcher_host())
85 if (status
!= storage::kQuotaStatusOk
) {
86 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status
));
88 dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
89 request_id(), usage
, quota
));
94 base::WeakPtrFactory
<QueryUsageAndQuotaDispatcher
> weak_factory_
;
97 class QuotaDispatcherHost::RequestQuotaDispatcher
98 : public RequestDispatcher
{
100 typedef RequestQuotaDispatcher self_type
;
102 RequestQuotaDispatcher(base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
103 const StorageQuotaParams
& params
)
104 : RequestDispatcher(dispatcher_host
, params
.request_id
),
109 weak_factory_(this) {
110 // Convert the requested size from uint64 to int64 since the quota backend
111 // requires int64 values.
112 // TODO(nhiroki): The backend should accept uint64 values.
113 requested_quota_
= base::saturated_cast
<int64
>(params_
.requested_size
);
115 ~RequestQuotaDispatcher() override
{}
118 DCHECK(dispatcher_host());
120 DCHECK(params_
.storage_type
== storage::kStorageTypeTemporary
||
121 params_
.storage_type
== storage::kStorageTypePersistent
||
122 params_
.storage_type
== storage::kStorageTypeSyncable
);
123 if (params_
.storage_type
== storage::kStorageTypePersistent
) {
124 quota_manager()->GetUsageAndQuotaForWebApps(
125 params_
.origin_url
, params_
.storage_type
,
126 base::Bind(&self_type::DidGetPersistentUsageAndQuota
,
127 weak_factory_
.GetWeakPtr()));
129 quota_manager()->GetUsageAndQuotaForWebApps(
130 params_
.origin_url
, params_
.storage_type
,
131 base::Bind(&self_type::DidGetTemporaryUsageAndQuota
,
132 weak_factory_
.GetWeakPtr()));
137 void DidGetPersistentUsageAndQuota(QuotaStatusCode status
,
140 if (!dispatcher_host())
142 if (status
!= storage::kQuotaStatusOk
) {
143 DidFinish(status
, 0, 0);
147 if (quota_manager()->IsStorageUnlimited(params_
.origin_url
,
148 params_
.storage_type
) ||
149 requested_quota_
<= quota
) {
150 // Seems like we can just let it go.
151 DidFinish(storage::kQuotaStatusOk
, usage
, params_
.requested_size
);
154 current_usage_
= usage
;
155 current_quota_
= quota
;
157 // Otherwise we need to consult with the permission context and
158 // possibly show a prompt.
159 DCHECK(permission_context());
160 permission_context()->RequestQuotaPermission(params_
, render_process_id(),
161 base::Bind(&self_type::DidGetPermissionResponse
,
162 weak_factory_
.GetWeakPtr()));
165 void DidGetTemporaryUsageAndQuota(QuotaStatusCode status
,
168 DidFinish(status
, usage
, std::min(requested_quota_
, quota
));
171 void DidGetPermissionResponse(
172 QuotaPermissionContext::QuotaPermissionResponse response
) {
173 if (!dispatcher_host())
175 if (response
!= QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW
) {
176 // User didn't allow the new quota. Just returning the current quota.
177 DidFinish(storage::kQuotaStatusOk
, current_usage_
, current_quota_
);
180 // Now we're allowed to set the new quota.
181 quota_manager()->SetPersistentHostQuota(
182 net::GetHostOrSpecFromURL(params_
.origin_url
), params_
.requested_size
,
183 base::Bind(&self_type::DidSetHostQuota
, weak_factory_
.GetWeakPtr()));
186 void DidSetHostQuota(QuotaStatusCode status
, int64 new_quota
) {
187 DidFinish(status
, current_usage_
, new_quota
);
190 void DidFinish(QuotaStatusCode status
,
192 int64 granted_quota
) {
193 if (!dispatcher_host())
195 DCHECK(dispatcher_host());
196 if (status
!= storage::kQuotaStatusOk
) {
197 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status
));
199 dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
200 request_id(), usage
, granted_quota
));
205 StorageQuotaParams params_
;
206 int64 current_usage_
;
207 int64 current_quota_
;
208 int64 requested_quota_
;
209 base::WeakPtrFactory
<self_type
> weak_factory_
;
212 QuotaDispatcherHost::QuotaDispatcherHost(
214 QuotaManager
* quota_manager
,
215 QuotaPermissionContext
* permission_context
)
216 : BrowserMessageFilter(QuotaMsgStart
),
217 process_id_(process_id
),
218 quota_manager_(quota_manager
),
219 permission_context_(permission_context
),
220 weak_factory_(this) {
223 bool QuotaDispatcherHost::OnMessageReceived(const IPC::Message
& message
) {
225 IPC_BEGIN_MESSAGE_MAP(QuotaDispatcherHost
, message
)
226 IPC_MESSAGE_HANDLER(QuotaHostMsg_QueryStorageUsageAndQuota
,
227 OnQueryStorageUsageAndQuota
)
228 IPC_MESSAGE_HANDLER(QuotaHostMsg_RequestStorageQuota
,
229 OnRequestStorageQuota
)
230 IPC_MESSAGE_UNHANDLED(handled
= false)
231 IPC_END_MESSAGE_MAP()
235 QuotaDispatcherHost::~QuotaDispatcherHost() {}
237 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
241 QueryUsageAndQuotaDispatcher
* dispatcher
= new QueryUsageAndQuotaDispatcher(
242 weak_factory_
.GetWeakPtr(), request_id
);
243 dispatcher
->QueryStorageUsageAndQuota(origin
, type
);
246 void QuotaDispatcherHost::OnRequestStorageQuota(
247 const StorageQuotaParams
& params
) {
248 if (params
.storage_type
!= storage::kStorageTypeTemporary
&&
249 params
.storage_type
!= storage::kStorageTypePersistent
) {
250 // Unsupported storage types.
251 Send(new QuotaMsg_DidFail(params
.request_id
,
252 storage::kQuotaErrorNotSupported
));
256 RequestQuotaDispatcher
* dispatcher
=
257 new RequestQuotaDispatcher(weak_factory_
.GetWeakPtr(),
262 } // namespace content