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: 37 WebStorageQuotaDispatcherCallback(blink::WebStorageQuotaCallbacks* callback) 38 : callbacks_(callback) { 39 DCHECK(callbacks_); 40 } 41 virtual ~WebStorageQuotaDispatcherCallback() {} 42 virtual void DidQueryStorageUsageAndQuota(int64 usage, int64 quota) OVERRIDE { 43 callbacks_->didQueryStorageUsageAndQuota(usage, quota); 44 } 45 virtual void DidGrantStorageQuota(int64 granted_quota) OVERRIDE { 46 callbacks_->didGrantStorageQuota(granted_quota); 47 } 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 57 int CurrentWorkerId() { 58 return WorkerTaskRunner::Instance()->CurrentWorkerId(); 59 } 60 61 } // namespace 62 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 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 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 93 void QuotaDispatcher::OnWorkerRunLoopStopped() { 94 delete this; 95 } 96 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 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 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* 137 QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper( 138 blink::WebStorageQuotaCallbacks* callbacks) { 139 return new WebStorageQuotaDispatcherCallback(callbacks); 140 } 141 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 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 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