1// Copyright (c) 2011 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/child/quota_dispatcher.h"
6
7#include "base/basictypes.h"
8#include "base/lazy_instance.h"
9#include "base/threading/thread_local.h"
10#include "content/child/child_thread.h"
11#include "content/child/quota_message_filter.h"
12#include "content/child/thread_safe_sender.h"
13#include "content/common/quota_messages.h"
14#include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
15#include "third_party/WebKit/public/platform/WebStorageQuotaType.h"
16#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
17#include "url/gurl.h"
18
19using blink::WebStorageQuotaCallbacks;
20using blink::WebStorageQuotaError;
21using blink::WebStorageQuotaType;
22using storage::QuotaStatusCode;
23using storage::StorageType;
24
25namespace content {
26
27static base::LazyInstance<base::ThreadLocalPointer<QuotaDispatcher> >::Leaky
28    g_quota_dispatcher_tls = LAZY_INSTANCE_INITIALIZER;
29
30namespace {
31
32// QuotaDispatcher::Callback implementation for WebStorageQuotaCallbacks.
33class WebStorageQuotaDispatcherCallback : public QuotaDispatcher::Callback {
34 public:
35  explicit WebStorageQuotaDispatcherCallback(
36      blink::WebStorageQuotaCallbacks callback)
37      : callbacks_(callback) {}
38  virtual ~WebStorageQuotaDispatcherCallback() {}
39
40  virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE {
41    callbacks_.didQueryStorageUsageAndQuota(usage, quota);
42  }
43  virtual void DidGrantStorageQuota(int64 usage, int64 granted_quota) OVERRIDE {
44    callbacks_.didGrantStorageQuota(usage, granted_quota);
45  }
46  virtual void DidFail(storage::QuotaStatusCode error) OVERRIDE {
47    callbacks_.didFail(static_cast<WebStorageQuotaError>(error));
48  }
49
50 private:
51  blink::WebStorageQuotaCallbacks callbacks_;
52
53  DISALLOW_COPY_AND_ASSIGN(WebStorageQuotaDispatcherCallback);
54};
55
56int CurrentWorkerId() {
57  return WorkerTaskRunner::Instance()->CurrentWorkerId();
58}
59
60}  // namespace
61
62QuotaDispatcher::QuotaDispatcher(ThreadSafeSender* thread_safe_sender,
63                                 QuotaMessageFilter* quota_message_filter)
64    : thread_safe_sender_(thread_safe_sender),
65      quota_message_filter_(quota_message_filter) {
66  g_quota_dispatcher_tls.Pointer()->Set(this);
67}
68
69QuotaDispatcher::~QuotaDispatcher() {
70  IDMap<Callback, IDMapOwnPointer>::iterator iter(&pending_quota_callbacks_);
71  while (!iter.IsAtEnd()) {
72    iter.GetCurrentValue()->DidFail(storage::kQuotaErrorAbort);
73    iter.Advance();
74  }
75
76  g_quota_dispatcher_tls.Pointer()->Set(NULL);
77}
78
79QuotaDispatcher* QuotaDispatcher::ThreadSpecificInstance(
80    ThreadSafeSender* thread_safe_sender,
81    QuotaMessageFilter* quota_message_filter) {
82  if (g_quota_dispatcher_tls.Pointer()->Get())
83    return g_quota_dispatcher_tls.Pointer()->Get();
84
85  QuotaDispatcher* dispatcher = new QuotaDispatcher(
86      thread_safe_sender, quota_message_filter);
87  if (WorkerTaskRunner::Instance()->CurrentWorkerId())
88    WorkerTaskRunner::Instance()->AddStopObserver(dispatcher);
89  return dispatcher;
90}
91
92void QuotaDispatcher::OnWorkerRunLoopStopped() {
93  delete this;
94}
95
96void QuotaDispatcher::OnMessageReceived(const IPC::Message& msg) {
97  bool handled = true;
98  IPC_BEGIN_MESSAGE_MAP(QuotaDispatcher, msg)
99    IPC_MESSAGE_HANDLER(QuotaMsg_DidGrantStorageQuota,
100                        DidGrantStorageQuota)
101    IPC_MESSAGE_HANDLER(QuotaMsg_DidQueryStorageUsageAndQuota,
102                        DidQueryStorageUsageAndQuota);
103    IPC_MESSAGE_HANDLER(QuotaMsg_DidFail, DidFail);
104    IPC_MESSAGE_UNHANDLED(handled = false)
105  IPC_END_MESSAGE_MAP()
106  DCHECK(handled) << "Unhandled message:" << msg.type();
107}
108
109void QuotaDispatcher::QueryStorageUsageAndQuota(
110    const GURL& origin_url,
111    StorageType type,
112    Callback* callback) {
113  DCHECK(callback);
114  int request_id = quota_message_filter_->GenerateRequestID(CurrentWorkerId());
115  pending_quota_callbacks_.AddWithID(callback, request_id);
116  thread_safe_sender_->Send(new QuotaHostMsg_QueryStorageUsageAndQuota(
117      request_id, origin_url, type));
118}
119
120void QuotaDispatcher::RequestStorageQuota(
121    int render_view_id,
122    const GURL& origin_url,
123    StorageType type,
124    uint64 requested_size,
125    Callback* callback) {
126  DCHECK(callback);
127  DCHECK(CurrentWorkerId() == 0);
128  int request_id = quota_message_filter_->GenerateRequestID(CurrentWorkerId());
129  pending_quota_callbacks_.AddWithID(callback, request_id);
130
131  StorageQuotaParams params;
132  params.render_view_id = render_view_id;
133  params.request_id = request_id;
134  params.origin_url = origin_url;
135  params.storage_type = type;
136  params.requested_size = requested_size;
137  params.user_gesture =
138      blink::WebUserGestureIndicator::isProcessingUserGesture();
139  thread_safe_sender_->Send(new QuotaHostMsg_RequestStorageQuota(params));
140}
141
142// static
143QuotaDispatcher::Callback*
144QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(
145    blink::WebStorageQuotaCallbacks callbacks) {
146  return new WebStorageQuotaDispatcherCallback(callbacks);
147}
148
149void QuotaDispatcher::DidGrantStorageQuota(
150    int request_id,
151    int64 current_usage,
152    int64 granted_quota) {
153  Callback* callback = pending_quota_callbacks_.Lookup(request_id);
154  DCHECK(callback);
155  callback->DidGrantStorageQuota(current_usage, granted_quota);
156  pending_quota_callbacks_.Remove(request_id);
157}
158
159void QuotaDispatcher::DidQueryStorageUsageAndQuota(
160    int request_id,
161    int64 current_usage,
162    int64 current_quota) {
163  Callback* callback = pending_quota_callbacks_.Lookup(request_id);
164  DCHECK(callback);
165  callback->DidQueryStorageUsageAndQuota(current_usage, current_quota);
166  pending_quota_callbacks_.Remove(request_id);
167}
168
169void QuotaDispatcher::DidFail(
170    int request_id,
171    QuotaStatusCode error) {
172  Callback* callback = pending_quota_callbacks_.Lookup(request_id);
173  DCHECK(callback);
174  callback->DidFail(error);
175  pending_quota_callbacks_.Remove(request_id);
176}
177
178COMPILE_ASSERT(int(blink::WebStorageQuotaTypeTemporary) ==
179                   int(storage::kStorageTypeTemporary),
180               mismatching_enums);
181COMPILE_ASSERT(int(blink::WebStorageQuotaTypePersistent) ==
182                   int(storage::kStorageTypePersistent),
183               mismatching_enums);
184
185COMPILE_ASSERT(int(blink::WebStorageQuotaErrorNotSupported) ==
186                   int(storage::kQuotaErrorNotSupported),
187               mismatching_enums);
188COMPILE_ASSERT(int(blink::WebStorageQuotaErrorAbort) ==
189                   int(storage::kQuotaErrorAbort),
190               mismatching_enums);
191
192}  // namespace content
193