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 "content/common/quota_messages.h"
10 #include "content/public/browser/quota_permission_context.h"
11 #include "net/base/net_util.h"
13 #include "webkit/browser/quota/quota_manager.h"
15 using quota::QuotaClient
;
16 using quota::QuotaManager
;
17 using quota::QuotaStatusCode
;
18 using quota::StorageType
;
22 // Created one per request to carry the request's request_id around.
23 // Dispatches requests from renderer/worker to the QuotaManager and
24 // sends back the response to the renderer/worker.
25 class QuotaDispatcherHost::RequestDispatcher
{
27 RequestDispatcher(base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
29 : dispatcher_host_(dispatcher_host
),
30 render_process_id_(dispatcher_host
->process_id_
),
31 request_id_(request_id
) {
32 dispatcher_host_
->outstanding_requests_
.AddWithID(this, request_id_
);
34 virtual ~RequestDispatcher() {}
37 // Subclass must call this when it's done with the request.
40 dispatcher_host_
->outstanding_requests_
.Remove(request_id_
);
43 QuotaDispatcherHost
* dispatcher_host() const {
44 return dispatcher_host_
.get();
46 quota::QuotaManager
* quota_manager() const {
47 return dispatcher_host_
? dispatcher_host_
->quota_manager_
: NULL
;
49 QuotaPermissionContext
* permission_context() const {
50 return dispatcher_host_
?
51 dispatcher_host_
->permission_context_
.get() : NULL
;
53 int render_process_id() const { return render_process_id_
; }
54 int request_id() const { return request_id_
; }
57 base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host_
;
58 int render_process_id_
;
62 class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
63 : public RequestDispatcher
{
65 QueryUsageAndQuotaDispatcher(
66 base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
68 : RequestDispatcher(dispatcher_host
, request_id
),
69 weak_factory_(this) {}
70 virtual ~QueryUsageAndQuotaDispatcher() {}
72 void QueryStorageUsageAndQuota(const GURL
& origin
, StorageType type
) {
73 quota_manager()->GetUsageAndQuotaForWebApps(
75 base::Bind(&QueryUsageAndQuotaDispatcher::DidQueryStorageUsageAndQuota
,
76 weak_factory_
.GetWeakPtr()));
80 void DidQueryStorageUsageAndQuota(
81 QuotaStatusCode status
, int64 usage
, int64 quota
) {
82 if (!dispatcher_host())
84 if (status
!= quota::kQuotaStatusOk
) {
85 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status
));
87 dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
88 request_id(), usage
, quota
));
93 base::WeakPtrFactory
<QueryUsageAndQuotaDispatcher
> weak_factory_
;
96 class QuotaDispatcherHost::RequestQuotaDispatcher
97 : public RequestDispatcher
{
99 typedef RequestQuotaDispatcher self_type
;
101 RequestQuotaDispatcher(base::WeakPtr
<QuotaDispatcherHost
> dispatcher_host
,
105 int64 requested_quota
,
107 : RequestDispatcher(dispatcher_host
, request_id
),
109 host_(net::GetHostOrSpecFromURL(origin
)),
112 requested_quota_(requested_quota
),
113 render_view_id_(render_view_id
),
114 weak_factory_(this) {}
115 virtual ~RequestQuotaDispatcher() {}
118 DCHECK(dispatcher_host());
119 DCHECK(type_
== quota::kStorageTypeTemporary
||
120 type_
== quota::kStorageTypePersistent
||
121 type_
== quota::kStorageTypeSyncable
);
122 if (type_
== quota::kStorageTypePersistent
) {
123 quota_manager()->GetPersistentHostQuota(
125 base::Bind(&self_type::DidGetHostQuota
,
126 weak_factory_
.GetWeakPtr(), host_
, type_
));
128 quota_manager()->GetUsageAndQuotaForWebApps(
130 base::Bind(&self_type::DidGetTemporaryUsageAndQuota
,
131 weak_factory_
.GetWeakPtr()));
136 void DidGetHostQuota(const std::string
& host
,
138 QuotaStatusCode status
,
140 if (!dispatcher_host())
142 DCHECK_EQ(type_
, type
);
143 DCHECK_EQ(host_
, host
);
144 if (status
!= quota::kQuotaStatusOk
) {
145 DidFinish(status
, 0);
148 if (requested_quota_
< 0) {
149 DidFinish(quota::kQuotaErrorInvalidModification
, 0);
152 if (requested_quota_
<= quota
) {
153 // Seems like we can just let it go.
154 DidFinish(quota::kQuotaStatusOk
, requested_quota_
);
157 current_quota_
= quota
;
158 // Otherwise we need to consult with the permission context and
159 // possibly show an infobar.
160 DCHECK(permission_context());
161 permission_context()->RequestQuotaPermission(
162 origin_
, type_
, requested_quota_
, render_process_id(), render_view_id_
,
163 base::Bind(&self_type::DidGetPermissionResponse
,
164 weak_factory_
.GetWeakPtr()));
167 void DidGetTemporaryUsageAndQuota(QuotaStatusCode status
,
170 DidFinish(status
, std::min(requested_quota_
, quota
));
173 void DidGetPermissionResponse(
174 QuotaPermissionContext::QuotaPermissionResponse response
) {
175 if (!dispatcher_host())
177 if (response
!= QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW
) {
178 // User didn't allow the new quota. Just returning the current quota.
179 DidFinish(quota::kQuotaStatusOk
, current_quota_
);
182 // Now we're allowed to set the new quota.
183 quota_manager()->SetPersistentHostQuota(
184 host_
, requested_quota_
,
185 base::Bind(&self_type::DidSetHostQuota
, weak_factory_
.GetWeakPtr()));
188 void DidSetHostQuota(QuotaStatusCode status
, int64 new_quota
) {
189 DidFinish(status
, new_quota
);
192 void DidFinish(QuotaStatusCode status
, int64 granted_quota
) {
193 if (!dispatcher_host())
195 DCHECK(dispatcher_host());
196 if (status
!= quota::kQuotaStatusOk
) {
197 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status
));
199 dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
200 request_id(), granted_quota
));
206 const std::string host_
;
207 const StorageType type_
;
208 int64 current_quota_
;
209 const int64 requested_quota_
;
210 const int render_view_id_
;
211 base::WeakPtrFactory
<self_type
> weak_factory_
;
214 QuotaDispatcherHost::QuotaDispatcherHost(
216 QuotaManager
* quota_manager
,
217 QuotaPermissionContext
* permission_context
)
218 : process_id_(process_id
),
219 quota_manager_(quota_manager
),
220 permission_context_(permission_context
),
221 weak_factory_(this) {
224 bool QuotaDispatcherHost::OnMessageReceived(
225 const IPC::Message
& message
, bool* message_was_ok
) {
226 *message_was_ok
= true;
228 IPC_BEGIN_MESSAGE_MAP_EX(QuotaDispatcherHost
, message
, *message_was_ok
)
229 IPC_MESSAGE_HANDLER(QuotaHostMsg_QueryStorageUsageAndQuota
,
230 OnQueryStorageUsageAndQuota
)
231 IPC_MESSAGE_HANDLER(QuotaHostMsg_RequestStorageQuota
,
232 OnRequestStorageQuota
)
233 IPC_MESSAGE_UNHANDLED(handled
= false)
234 IPC_END_MESSAGE_MAP_EX()
238 QuotaDispatcherHost::~QuotaDispatcherHost() {}
240 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
244 QueryUsageAndQuotaDispatcher
* dispatcher
= new QueryUsageAndQuotaDispatcher(
245 weak_factory_
.GetWeakPtr(), request_id
);
246 dispatcher
->QueryStorageUsageAndQuota(origin
, type
);
249 void QuotaDispatcherHost::OnRequestStorageQuota(
254 int64 requested_size
) {
255 if (quota_manager_
->IsStorageUnlimited(origin
, type
)) {
256 // If the origin is marked 'unlimited' we always just return ok.
257 Send(new QuotaMsg_DidGrantStorageQuota(request_id
, requested_size
));
261 if (type
!= quota::kStorageTypeTemporary
&&
262 type
!= quota::kStorageTypePersistent
) {
263 // Unsupported storage types.
264 Send(new QuotaMsg_DidFail(request_id
, quota::kQuotaErrorNotSupported
));
268 RequestQuotaDispatcher
* dispatcher
= new RequestQuotaDispatcher(
269 weak_factory_
.GetWeakPtr(), request_id
, origin
, type
,
270 requested_size
, render_view_id
);
274 } // namespace content