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