- add sources.
[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 "content/common/quota_messages.h"
10 #include "content/public/browser/quota_permission_context.h"
11 #include "net/base/net_util.h"
12 #include "url/gurl.h"
13 #include "webkit/browser/quota/quota_manager.h"
14
15 using quota::QuotaClient;
16 using quota::QuotaManager;
17 using quota::QuotaStatusCode;
18 using quota::StorageType;
19
20 namespace content {
21
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(base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
28                     int request_id)
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_);
33   }
34   virtual ~RequestDispatcher() {}
35
36  protected:
37   // Subclass must call this when it's done with the request.
38   void Completed() {
39     if (dispatcher_host_)
40       dispatcher_host_->outstanding_requests_.Remove(request_id_);
41   }
42
43   QuotaDispatcherHost* dispatcher_host() const {
44     return dispatcher_host_.get();
45   }
46   quota::QuotaManager* quota_manager() const {
47     return dispatcher_host_ ? dispatcher_host_->quota_manager_ : NULL;
48   }
49   QuotaPermissionContext* permission_context() const {
50     return dispatcher_host_ ?
51         dispatcher_host_->permission_context_.get() : NULL;
52   }
53   int render_process_id() const { return render_process_id_; }
54   int request_id() const { return request_id_; }
55
56  private:
57   base::WeakPtr<QuotaDispatcherHost> dispatcher_host_;
58   int render_process_id_;
59   int request_id_;
60 };
61
62 class QuotaDispatcherHost::QueryUsageAndQuotaDispatcher
63     : public RequestDispatcher {
64  public:
65   QueryUsageAndQuotaDispatcher(
66       base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
67       int request_id)
68       : RequestDispatcher(dispatcher_host, request_id),
69         weak_factory_(this) {}
70   virtual ~QueryUsageAndQuotaDispatcher() {}
71
72   void QueryStorageUsageAndQuota(const GURL& origin, StorageType type) {
73     quota_manager()->GetUsageAndQuotaForWebApps(
74         origin, type,
75         base::Bind(&QueryUsageAndQuotaDispatcher::DidQueryStorageUsageAndQuota,
76                    weak_factory_.GetWeakPtr()));
77   }
78
79  private:
80   void DidQueryStorageUsageAndQuota(
81       QuotaStatusCode status, int64 usage, int64 quota) {
82     if (!dispatcher_host())
83       return;
84     if (status != quota::kQuotaStatusOk) {
85       dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
86     } else {
87       dispatcher_host()->Send(new QuotaMsg_DidQueryStorageUsageAndQuota(
88           request_id(), usage, quota));
89     }
90     Completed();
91   }
92
93   base::WeakPtrFactory<QueryUsageAndQuotaDispatcher> weak_factory_;
94 };
95
96 class QuotaDispatcherHost::RequestQuotaDispatcher
97     : public RequestDispatcher {
98  public:
99   typedef RequestQuotaDispatcher self_type;
100
101   RequestQuotaDispatcher(base::WeakPtr<QuotaDispatcherHost> dispatcher_host,
102                          int request_id,
103                          const GURL& origin,
104                          StorageType type,
105                          int64 requested_quota,
106                          int render_view_id)
107       : RequestDispatcher(dispatcher_host, request_id),
108         origin_(origin),
109         host_(net::GetHostOrSpecFromURL(origin)),
110         type_(type),
111         current_quota_(0),
112         requested_quota_(requested_quota),
113         render_view_id_(render_view_id),
114         weak_factory_(this) {}
115   virtual ~RequestQuotaDispatcher() {}
116
117   void Start() {
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(
124           host_,
125           base::Bind(&self_type::DidGetHostQuota,
126                      weak_factory_.GetWeakPtr(), host_, type_));
127     } else {
128       quota_manager()->GetUsageAndQuotaForWebApps(
129           origin_, type_,
130           base::Bind(&self_type::DidGetTemporaryUsageAndQuota,
131                      weak_factory_.GetWeakPtr()));
132     }
133   }
134
135  private:
136   void DidGetHostQuota(const std::string& host,
137                        StorageType type,
138                        QuotaStatusCode status,
139                        int64 quota) {
140     if (!dispatcher_host())
141       return;
142     DCHECK_EQ(type_, type);
143     DCHECK_EQ(host_, host);
144     if (status != quota::kQuotaStatusOk) {
145       DidFinish(status, 0);
146       return;
147     }
148     if (requested_quota_ < 0) {
149       DidFinish(quota::kQuotaErrorInvalidModification, 0);
150       return;
151     }
152     if (requested_quota_ <= quota) {
153       // Seems like we can just let it go.
154       DidFinish(quota::kQuotaStatusOk, requested_quota_);
155       return;
156     }
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()));
165   }
166
167   void DidGetTemporaryUsageAndQuota(QuotaStatusCode status,
168                                     int64 usage_unused,
169                                     int64 quota) {
170     DidFinish(status, std::min(requested_quota_, quota));
171   }
172
173   void DidGetPermissionResponse(
174       QuotaPermissionContext::QuotaPermissionResponse response) {
175     if (!dispatcher_host())
176       return;
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_);
180       return;
181     }
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()));
186   }
187
188   void DidSetHostQuota(QuotaStatusCode status, int64 new_quota) {
189     DidFinish(status, new_quota);
190   }
191
192   void DidFinish(QuotaStatusCode status, int64 granted_quota) {
193     if (!dispatcher_host())
194       return;
195     DCHECK(dispatcher_host());
196     if (status != quota::kQuotaStatusOk) {
197       dispatcher_host()->Send(new QuotaMsg_DidFail(request_id(), status));
198     } else {
199       dispatcher_host()->Send(new QuotaMsg_DidGrantStorageQuota(
200           request_id(), granted_quota));
201     }
202     Completed();
203   }
204
205   const GURL origin_;
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_;
212 };
213
214 QuotaDispatcherHost::QuotaDispatcherHost(
215     int process_id,
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) {
222 }
223
224 bool QuotaDispatcherHost::OnMessageReceived(
225     const IPC::Message& message, bool* message_was_ok) {
226   *message_was_ok = true;
227   bool handled = 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()
235   return handled;
236 }
237
238 QuotaDispatcherHost::~QuotaDispatcherHost() {}
239
240 void QuotaDispatcherHost::OnQueryStorageUsageAndQuota(
241     int request_id,
242     const GURL& origin,
243     StorageType type) {
244   QueryUsageAndQuotaDispatcher* dispatcher = new QueryUsageAndQuotaDispatcher(
245       weak_factory_.GetWeakPtr(), request_id);
246   dispatcher->QueryStorageUsageAndQuota(origin, type);
247 }
248
249 void QuotaDispatcherHost::OnRequestStorageQuota(
250     int render_view_id,
251     int request_id,
252     const GURL& origin,
253     StorageType type,
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));
258     return;
259   }
260
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