Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / quota_dispatcher_host.cc
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.
4
5 #include "content/browser/quota_dispatcher_host.h"
6
7 #include "base/bind.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"
14 #include "url/gurl.h"
15
16 using storage::QuotaClient;
17 using storage::QuotaManager;
18 using storage::QuotaStatusCode;
19 using storage::StorageType;
20
21 namespace content {
22
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 {
27  public:
28   RequestDispatcher(base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
29                     int request_id)
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_);
34   }
35   virtual ~RequestDispatcher() {}
36
37  protected:
38   // Subclass must call this when it's done with the request.
39   void Completed() {
40     if (dispatcher_host_)
41       dispatcher_host_->outstanding_requests_.Remove(request_id_);
42   }
43
44   QuotaDispatcherHost* dispatcher_host() const {
45     return dispatcher_host_.get();
46   }
47   storage::QuotaManager* quota_manager() const {
48     return dispatcher_host_ ? dispatcher_host_->quota_manager_ : NULL;
49   }
50   QuotaPermissionContext* permission_context() const {
51     return dispatcher_host_ ?
52         dispatcher_host_->permission_context_.get() : NULL;
53   }
54   int render_process_id() const { return render_process_id_; }
55   int request_id() const { return request_id_; }
56
57  private:
58   base::WeakPtr<QuotaDispatcherHost> dispatcher_host_;
59   int render_process_id_;
60   int request_id_;
61 };
62
63 class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
64     : public RequestDispatcher {
65  public:
66   QueryUsageAndQuotaDispatcher(
67       base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
68       int request_id)
69       : RequestDispatcher(dispatcher_host, request_id),
70         weak_factory_(this) {}
71   ~QueryUsageAndQuotaDispatcher() override {}
72
73   void QueryStorageUsageAndQuota(const GURL& origin, StorageType type) {
74     quota_manager()->GetUsageAndQuotaForWebApps(
75         origin, type,
76         base::Bind(&QueryUsageAndQuotaDispatcher::DidQueryStorageUsageAndQuota,
77                    weak_factory_.GetWeakPtr()));
78   }
79
80  private:
81   void DidQueryStorageUsageAndQuota(
82       QuotaStatusCode status, int64 usage, int64 quota) {
83     if (!dispatcher_host())
84       return;
85     if (status != storage::kQuotaStatusOk) {
86       dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
87     } else {
88       dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
89           request_id(), usage, quota));
90     }
91     Completed();
92   }
93
94   base::WeakPtrFactory<QueryUsageAndQuotaDispatcher> weak_factory_;
95 };
96
97 class QuotaDispatcherHost::RequestQuotaDispatcher
98     : public RequestDispatcher {
99  public:
100   typedef RequestQuotaDispatcher self_type;
101
102   RequestQuotaDispatcher(base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
103                          const StorageQuotaParams& params)
104       : RequestDispatcher(dispatcher_host, params.request_id),
105         params_(params),
106         current_usage_(0),
107         current_quota_(0),
108         requested_quota_(0),
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);
114   }
115   ~RequestQuotaDispatcher() override {}
116
117   void Start() {
118     DCHECK(dispatcher_host());
119
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()));
128     } else {
129       quota_manager()->GetUsageAndQuotaForWebApps(
130           params_.origin_url, params_.storage_type,
131           base::Bind(&self_type::DidGetTemporaryUsageAndQuota,
132                      weak_factory_.GetWeakPtr()));
133     }
134   }
135
136  private:
137   void DidGetPersistentUsageAndQuota(QuotaStatusCode status,
138                                      int64 usage,
139                                      int64 quota) {
140     if (!dispatcher_host())
141       return;
142     if (status != storage::kQuotaStatusOk) {
143       DidFinish(status, 0, 0);
144       return;
145     }
146
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);
152       return;
153     }
154     current_usage_ = usage;
155     current_quota_ = quota;
156
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()));
163   }
164
165   void DidGetTemporaryUsageAndQuota(QuotaStatusCode status,
166                                     int64 usage,
167                                     int64 quota) {
168     DidFinish(status, usage, std::min(requested_quota_, quota));
169   }
170
171   void DidGetPermissionResponse(
172       QuotaPermissionContext::QuotaPermissionResponse response) {
173     if (!dispatcher_host())
174       return;
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_);
178       return;
179     }
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()));
184   }
185
186   void DidSetHostQuota(QuotaStatusCode status, int64 new_quota) {
187     DidFinish(status, current_usage_, new_quota);
188   }
189
190   void DidFinish(QuotaStatusCode status,
191                  int64 usage,
192                  int64 granted_quota) {
193     if (!dispatcher_host())
194       return;
195     DCHECK(dispatcher_host());
196     if (status != storage::kQuotaStatusOk) {
197       dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
198     } else {
199       dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
200           request_id(), usage, granted_quota));
201     }
202     Completed();
203   }
204
205   StorageQuotaParams params_;
206   int64 current_usage_;
207   int64 current_quota_;
208   int64 requested_quota_;
209   base::WeakPtrFactory<self_type> weak_factory_;
210 };
211
212 QuotaDispatcherHost::QuotaDispatcherHost(
213     int process_id,
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) {
221 }
222
223 bool QuotaDispatcherHost::OnMessageReceived(const IPC::Message& message) {
224   bool handled = true;
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()
232   return handled;
233 }
234
235 QuotaDispatcherHost::~QuotaDispatcherHost() {}
236
237 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
238     int request_id,
239     const GURL& origin,
240     StorageType type) {
241   QueryUsageAndQuotaDispatcher* dispatcher = new QueryUsageAndQuotaDispatcher(
242       weak_factory_.GetWeakPtr(), request_id);
243   dispatcher->QueryStorageUsageAndQuota(origin, type);
244 }
245
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));
253     return;
254   }
255
256   RequestQuotaDispatcher* dispatcher =
257       new RequestQuotaDispatcher(weak_factory_.GetWeakPtr(),
258                                  params);
259   dispatcher->Start();
260 }
261
262 }  // namespace content