Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / renderer_host / quota_dispatcher_host.cc
blob4bc387577cef96ed6d9b8a3bfd86639ba6494ca8
1 // Copyright (c) 2012 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/renderer_host/quota_dispatcher_host.h"
7 #include "base/bind.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 "googleurl/src/gurl.h"
12 #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;
20 namespace content {
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 {
26 public:
27 RequestDispatcher(QuotaDispatcherHost* dispatcher_host,
28 int request_id)
29 : dispatcher_host_(dispatcher_host),
30 request_id_(request_id) {
31 dispatcher_host_->outstanding_requests_.AddWithID(this, request_id_);
33 virtual ~RequestDispatcher() {}
35 protected:
36 // Subclass must call this when it's done with the request.
37 void Completed() {
38 dispatcher_host_->outstanding_requests_.Remove(request_id_);
41 QuotaDispatcherHost* dispatcher_host() const { return dispatcher_host_; }
42 quota::QuotaManager* quota_manager() const {
43 return dispatcher_host_->quota_manager_;
45 QuotaPermissionContext* permission_context() const {
46 return dispatcher_host_->permission_context_.get();
48 int render_process_id() const { return dispatcher_host_->process_id_; }
49 int request_id() const { return request_id_; }
51 private:
52 QuotaDispatcherHost* dispatcher_host_;
53 int request_id_;
56 class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
57 : public RequestDispatcher {
58 public:
59 QueryUsageAndQuotaDispatcher(
60 QuotaDispatcherHost* dispatcher_host,
61 int request_id)
62 : RequestDispatcher(dispatcher_host, request_id),
63 weak_factory_(this) {}
64 virtual ~QueryUsageAndQuotaDispatcher() {}
66 void QueryStorageUsageAndQuota(const GURL& origin, StorageType type) {
67 quota_manager()->GetUsageAndQuotaForWebApps(
68 origin, type,
69 base::Bind(&QueryUsageAndQuotaDispatcher::DidQueryStorageUsageAndQuota,
70 weak_factory_.GetWeakPtr()));
73 private:
74 void DidQueryStorageUsageAndQuota(
75 QuotaStatusCode status, int64 usage, int64 quota) {
76 DCHECK(dispatcher_host());
77 if (status != quota::kQuotaStatusOk) {
78 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
79 } else {
80 dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
81 request_id(), usage, quota));
83 Completed();
86 base::WeakPtrFactory<QueryUsageAndQuotaDispatcher> weak_factory_;
89 class QuotaDispatcherHost::RequestQuotaDispatcher
90 : public RequestDispatcher {
91 public:
92 typedef RequestQuotaDispatcher self_type;
94 RequestQuotaDispatcher(QuotaDispatcherHost* dispatcher_host,
95 int request_id,
96 const GURL& origin,
97 StorageType type,
98 int64 requested_quota,
99 int render_view_id)
100 : RequestDispatcher(dispatcher_host, request_id),
101 origin_(origin),
102 host_(net::GetHostOrSpecFromURL(origin)),
103 type_(type),
104 current_quota_(0),
105 requested_quota_(requested_quota),
106 render_view_id_(render_view_id),
107 weak_factory_(this) {}
108 virtual ~RequestQuotaDispatcher() {}
110 void Start() {
111 DCHECK(type_ == quota::kStorageTypeTemporary ||
112 type_ == quota::kStorageTypePersistent ||
113 type_ == quota::kStorageTypeSyncable);
114 if (type_ == quota::kStorageTypePersistent) {
115 quota_manager()->GetPersistentHostQuota(
116 host_,
117 base::Bind(&self_type::DidGetHostQuota,
118 weak_factory_.GetWeakPtr(), host_, type_));
119 } else {
120 quota_manager()->GetUsageAndQuotaForWebApps(
121 origin_, type_,
122 base::Bind(&self_type::DidGetTemporaryUsageAndQuota,
123 weak_factory_.GetWeakPtr()));
127 private:
128 void DidGetHostQuota(const std::string& host,
129 StorageType type,
130 QuotaStatusCode status,
131 int64 quota) {
132 DCHECK_EQ(type_, type);
133 DCHECK_EQ(host_, host);
134 if (status != quota::kQuotaStatusOk) {
135 DidFinish(status, 0);
136 return;
138 if (requested_quota_ < 0) {
139 DidFinish(quota::kQuotaErrorInvalidModification, 0);
140 return;
142 if (requested_quota_ <= quota) {
143 // Seems like we can just let it go.
144 DidFinish(quota::kQuotaStatusOk, requested_quota_);
145 return;
147 current_quota_ = quota;
148 // Otherwise we need to consult with the permission context and
149 // possibly show an infobar.
150 DCHECK(permission_context());
151 permission_context()->RequestQuotaPermission(
152 origin_, type_, requested_quota_, render_process_id(), render_view_id_,
153 base::Bind(&self_type::DidGetPermissionResponse,
154 weak_factory_.GetWeakPtr()));
157 void DidGetTemporaryUsageAndQuota(QuotaStatusCode status,
158 int64 usage_unused,
159 int64 quota) {
160 DidFinish(status, std::min(requested_quota_, quota));
163 void DidGetPermissionResponse(
164 QuotaPermissionContext::QuotaPermissionResponse response) {
165 if (response != QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW) {
166 // User didn't allow the new quota. Just returning the current quota.
167 DidFinish(quota::kQuotaStatusOk, current_quota_);
168 return;
170 // Now we're allowed to set the new quota.
171 quota_manager()->SetPersistentHostQuota(
172 host_, requested_quota_,
173 base::Bind(&self_type::DidSetHostQuota, weak_factory_.GetWeakPtr()));
176 void DidSetHostQuota(QuotaStatusCode status, int64 new_quota) {
177 DidFinish(status, new_quota);
180 void DidFinish(QuotaStatusCode status, int64 granted_quota) {
181 DCHECK(dispatcher_host());
182 if (status != quota::kQuotaStatusOk) {
183 dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
184 } else {
185 dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
186 request_id(), granted_quota));
188 Completed();
191 const GURL origin_;
192 const std::string host_;
193 const StorageType type_;
194 int64 current_quota_;
195 const int64 requested_quota_;
196 const int render_view_id_;
197 base::WeakPtrFactory<self_type> weak_factory_;
200 QuotaDispatcherHost::QuotaDispatcherHost(
201 int process_id,
202 QuotaManager* quota_manager,
203 QuotaPermissionContext* permission_context)
204 : process_id_(process_id),
205 quota_manager_(quota_manager),
206 permission_context_(permission_context) {
209 bool QuotaDispatcherHost::OnMessageReceived(
210 const IPC::Message& message, bool* message_was_ok) {
211 *message_was_ok = true;
212 bool handled = true;
213 IPC_BEGIN_MESSAGE_MAP_EX(QuotaDispatcherHost, message, *message_was_ok)
214 IPC_MESSAGE_HANDLER(QuotaHostMsg_QueryStorageUsageAndQuota,
215 OnQueryStorageUsageAndQuota)
216 IPC_MESSAGE_HANDLER(QuotaHostMsg_RequestStorageQuota,
217 OnRequestStorageQuota)
218 IPC_MESSAGE_UNHANDLED(handled = false)
219 IPC_END_MESSAGE_MAP_EX()
220 return handled;
223 QuotaDispatcherHost::~QuotaDispatcherHost() {}
225 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
226 int request_id,
227 const GURL& origin,
228 StorageType type) {
229 QueryUsageAndQuotaDispatcher* dispatcher = new QueryUsageAndQuotaDispatcher(
230 this, request_id);
231 dispatcher->QueryStorageUsageAndQuota(origin, type);
234 void QuotaDispatcherHost::OnRequestStorageQuota(
235 int render_view_id,
236 int request_id,
237 const GURL& origin,
238 StorageType type,
239 int64 requested_size) {
240 if (quota_manager_->IsStorageUnlimited(origin, type)) {
241 // If the origin is marked 'unlimited' we always just return ok.
242 Send(new QuotaMsg_DidGrantStorageQuota(request_id, requested_size));
243 return;
246 if (type != quota::kStorageTypeTemporary &&
247 type != quota::kStorageTypePersistent) {
248 // Unsupported storage types.
249 Send(new QuotaMsg_DidFail(request_id, quota::kQuotaErrorNotSupported));
250 return;
253 RequestQuotaDispatcher* dispatcher = new RequestQuotaDispatcher(
254 this, request_id, origin, type, requested_size, render_view_id);
255 dispatcher->Start();
258 } // namespace content