Upstream version 5.34.104.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 "url/gurl.h"
14 #include "webkit/browser/quota/quota_manager.h"
15
16 using quota::QuotaClient;
17 using quota::QuotaManager;
18 using quota::QuotaStatusCode;
19 using quota::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   quota::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   virtual ~QueryUsageAndQuotaDispatcher() {}
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 != quota::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                          int request_id,
104                          const GURL& origin,
105                          StorageType type,
106                          uint64 requested_quota,
107                          int render_view_id)
108       : RequestDispatcher(dispatcher_host, request_id),
109         origin_(origin),
110         type_(type),
111         current_usage_(0),
112         current_quota_(0),
113         requested_quota_(0),
114         render_view_id_(render_view_id),
115         weak_factory_(this) {
116     // Convert the requested size from uint64 to int64 since the quota backend
117     // requires int64 values.
118     // TODO(nhiroki): The backend should accept uint64 values.
119     requested_quota_ = base::saturated_cast<int64>(requested_quota);
120   }
121   virtual ~RequestQuotaDispatcher() {}
122
123   void Start() {
124     DCHECK(dispatcher_host());
125
126     DCHECK(type_ == quota::kStorageTypeTemporary ||
127            type_ == quota::kStorageTypePersistent ||
128            type_ == quota::kStorageTypeSyncable);
129     if (type_ == quota::kStorageTypePersistent) {
130       quota_manager()->GetUsageAndQuotaForWebApps(
131           origin_, type_,
132           base::Bind(&self_type::DidGetPersistentUsageAndQuota,
133                      weak_factory_.GetWeakPtr()));
134     } else {
135       quota_manager()->GetUsageAndQuotaForWebApps(
136           origin_, type_,
137           base::Bind(&self_type::DidGetTemporaryUsageAndQuota,
138                      weak_factory_.GetWeakPtr()));
139     }
140   }
141
142  private:
143   void DidGetPersistentUsageAndQuota(QuotaStatusCode status,
144                                      int64 usage,
145                                      int64 quota) {
146     if (!dispatcher_host())
147       return;
148     if (status != quota::kQuotaStatusOk) {
149       DidFinish(status, 0, 0);
150       return;
151     }
152
153     if (quota_manager()->IsStorageUnlimited(origin_, type_) ||
154         requested_quota_ <= quota) {
155       // Seems like we can just let it go.
156       DidFinish(quota::kQuotaStatusOk, usage, requested_quota_);
157       return;
158     }
159     current_usage_ = usage;
160     current_quota_ = quota;
161
162     // Otherwise we need to consult with the permission context and
163     // possibly show an infobar.
164     DCHECK(permission_context());
165     permission_context()->RequestQuotaPermission(
166         origin_, type_, requested_quota_, render_process_id(), render_view_id_,
167         base::Bind(&self_type::DidGetPermissionResponse,
168                    weak_factory_.GetWeakPtr()));
169   }
170
171   void DidGetTemporaryUsageAndQuota(QuotaStatusCode status,
172                                     int64 usage,
173                                     int64 quota) {
174     DidFinish(status, usage, std::min(requested_quota_, quota));
175   }
176
177   void DidGetPermissionResponse(
178       QuotaPermissionContext::QuotaPermissionResponse response) {
179     if (!dispatcher_host())
180       return;
181     if (response != QuotaPermissionContext::QUOTA_PERMISSION_RESPONSE_ALLOW) {
182       // User didn't allow the new quota.  Just returning the current quota.
183       DidFinish(quota::kQuotaStatusOk, current_usage_, current_quota_);
184       return;
185     }
186     // Now we're allowed to set the new quota.
187     quota_manager()->SetPersistentHostQuota(
188         net::GetHostOrSpecFromURL(origin_), requested_quota_,
189         base::Bind(&self_type::DidSetHostQuota, weak_factory_.GetWeakPtr()));
190   }
191
192   void DidSetHostQuota(QuotaStatusCode status, int64 new_quota) {
193     DidFinish(status, current_usage_, new_quota);
194   }
195
196   void DidFinish(QuotaStatusCode status,
197                  int64 usage,
198                  int64 granted_quota) {
199     if (!dispatcher_host())
200       return;
201     DCHECK(dispatcher_host());
202     if (status != quota::kQuotaStatusOk) {
203       dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
204     } else {
205       dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
206           request_id(), usage, granted_quota));
207     }
208     Completed();
209   }
210
211   const GURL origin_;
212   const StorageType type_;
213   int64 current_usage_;
214   int64 current_quota_;
215   int64 requested_quota_;
216   const int render_view_id_;
217   base::WeakPtrFactory<self_type> weak_factory_;
218 };
219
220 QuotaDispatcherHost::QuotaDispatcherHost(
221     int process_id,
222     QuotaManager* quota_manager,
223     QuotaPermissionContext* permission_context)
224     : process_id_(process_id),
225       quota_manager_(quota_manager),
226       permission_context_(permission_context),
227       weak_factory_(this) {
228 }
229
230 bool QuotaDispatcherHost::OnMessageReceived(
231     const IPC::Message& message, bool* message_was_ok) {
232   *message_was_ok = true;
233   bool handled = true;
234   IPC_BEGIN_MESSAGE_MAP_EX(QuotaDispatcherHost, message, *message_was_ok)
235     IPC_MESSAGE_HANDLER(QuotaHostMsg_QueryStorageUsageAndQuota,
236                         OnQueryStorageUsageAndQuota)
237     IPC_MESSAGE_HANDLER(QuotaHostMsg_RequestStorageQuota,
238                         OnRequestStorageQuota)
239     IPC_MESSAGE_UNHANDLED(handled = false)
240   IPC_END_MESSAGE_MAP_EX()
241   return handled;
242 }
243
244 QuotaDispatcherHost::~QuotaDispatcherHost() {}
245
246 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
247     int request_id,
248     const GURL& origin,
249     StorageType type) {
250   QueryUsageAndQuotaDispatcher* dispatcher = new QueryUsageAndQuotaDispatcher(
251       weak_factory_.GetWeakPtr(), request_id);
252   dispatcher->QueryStorageUsageAndQuota(origin, type);
253 }
254
255 void QuotaDispatcherHost::OnRequestStorageQuota(
256     int render_view_id,
257     int request_id,
258     const GURL& origin,
259     StorageType type,
260     uint64 requested_size) {
261   if (type != quota::kStorageTypeTemporary &&
262       type != quota::kStorageTypePersistent) {
263     // Unsupported storage types.
264     Send(new QuotaMsg_DidFail(request_id, quota::kQuotaErrorNotSupported));
265     return;
266   }
267
268   RequestQuotaDispatcher* dispatcher = new RequestQuotaDispatcher(
269       weak_factory_.GetWeakPtr(), request_id, origin, type,
270       requested_size, render_view_id);
271   dispatcher->Start();
272 }
273
274 }  // namespace content