Index: chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc |
=================================================================== |
--- chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc (revision 21342) |
+++ chrome/browser/in_process_webkit/dom_storage_dispatcher_host.cc (working copy) |
@@ -4,34 +4,98 @@ |
#include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" |
+#include "base/stl_util-inl.h" |
+#include "base/string16.h" |
#include "chrome/browser/chrome_thread.h" |
#include "chrome/browser/in_process_webkit/webkit_context.h" |
#include "chrome/browser/in_process_webkit/webkit_thread.h" |
+#include "chrome/common/render_messages.h" |
+#include "webkit/api/public/WebKit.h" |
+#include "webkit/api/public/WebStorageArea.h" |
+#include "webkit/api/public/WebStorageNamespace.h" |
+#include "webkit/api/public/WebString.h" |
+using WebKit::WebStorageArea; |
+using WebKit::WebStorageNamespace; |
+ |
DOMStorageDispatcherHost::DOMStorageDispatcherHost( |
IPC::Message::Sender* message_sender, |
WebKitContext* webkit_context, |
WebKitThread* webkit_thread) |
: webkit_context_(webkit_context), |
webkit_thread_(webkit_thread), |
- message_sender_(message_sender) { |
+ message_sender_(message_sender), |
+ last_storage_area_id_(0), |
+ last_storage_namespace_id_(0), |
+ ever_used_(false), |
+ shutdown_(false) { |
DCHECK(webkit_context_.get()); |
DCHECK(webkit_thread_); |
DCHECK(message_sender_); |
} |
DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { |
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
- message_sender_ = NULL; |
+ DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ DCHECK(shutdown_); |
} |
-bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& msg) { |
- // TODO(jorlow): Implement DOM Storage's message handler...and the rest |
- // of DOM Storage. :-) |
- return false; |
+void DOMStorageDispatcherHost::Shutdown() { |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ message_sender_ = NULL; |
+ if (!ever_used_) { |
+ shutdown_ = true; |
+ return; |
+ } |
+ |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::Shutdown)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ DCHECK(ever_used_); |
+ DCHECK(!message_sender_); |
+ DCHECK(!shutdown_); |
+ |
+ STLDeleteContainerPairSecondPointers(storage_area_map_.begin(), |
+ storage_area_map_.end()); |
+ STLDeleteContainerPairSecondPointers(storage_namespace_map_.begin(), |
+ storage_namespace_map_.end()); |
+ shutdown_ = true; |
} |
+bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message, |
+ bool *msg_is_ok) { |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ DCHECK(!shutdown_); |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageNamespaceId, |
+ OnNamespaceId) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageCloneNamespaceId, |
+ OnCloneNamespaceId) |
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageDerefNamespaceId, |
+ OnDerefNamespaceId) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId, |
+ OnStorageAreaId) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLock, OnLock) |
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageUnlock, OnUnlock) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem) |
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageSetItem, OnSetItem) |
+ IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageRemoveItem, OnRemoveItem) |
+ IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ if (handled) |
+ ever_used_ = true; |
+ return handled; |
+} |
+ |
void DOMStorageDispatcherHost::Send(IPC::Message* message) { |
+ DCHECK(!shutdown_); |
if (!message_sender_) { |
delete message; |
return; |
@@ -42,11 +106,277 @@ |
return; |
} |
- // The IO thread can't dissapear while the WebKit thread is still running. |
+ // The IO thread can't go away while the WebKit thread is still running. |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
- MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO); |
- CancelableTask* task = NewRunnableMethod(this, |
- &DOMStorageDispatcherHost::Send, |
- message); |
- io_loop->PostTask(FROM_HERE, task); |
+ webkit_thread_->PostIOThreadTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::Send, message)); |
} |
+ |
+void DOMStorageDispatcherHost::OnNamespaceId(bool is_local_storage, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnNamespaceId, |
+ is_local_storage, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageNamespace* new_namespace; |
+ if (is_local_storage) { |
+ new_namespace = WebStorageNamespace::createLocalStorageNamespace( |
+ GetLocalStoragePath()); |
+ } else { |
+ new_namespace = WebStorageNamespace::createSessionStorageNamespace(); |
+ } |
+ int64 new_namespace_id = AddStorageNamespace(new_namespace); |
+ ViewHostMsg_DOMStorageNamespaceId::WriteReplyParams(reply_msg, |
+ new_namespace_id); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnCloneNamespaceId(int64 namespace_id, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnCloneNamespaceId, |
+ namespace_id, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageNamespace* existing_namespace = GetStorageNamespace(namespace_id); |
+ CHECK(existing_namespace); // TODO(jorlow): Do better than this. |
+ WebStorageNamespace* new_namespace = existing_namespace->copy(); |
+ int64 new_namespace_id = AddStorageNamespace(new_namespace); |
+ ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, |
+ new_namespace_id); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnDerefNamespaceId(int64 namespace_id) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnDerefNamespaceId, namespace_id)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ // TODO(jorlow): We need to track resources so we can free them. |
+} |
+ |
+void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id, |
+ const string16& origin, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnStorageAreaId, |
+ namespace_id, origin, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageNamespace* storage_namespace = GetStorageNamespace(namespace_id); |
+ CHECK(storage_namespace); // TODO(jorlow): Do better than this. |
+ WebStorageArea* storage_area = storage_namespace->createStorageArea(origin); |
+ int64 storage_area_id = AddStorageArea(storage_area); |
+ ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, |
+ storage_area_id); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnLock(int64 storage_area_id, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnLock, storage_area_id, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ bool invalidate_cache; |
+ size_t bytes_left_in_quota; |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ storage_area->lock(invalidate_cache, bytes_left_in_quota); |
+ ViewHostMsg_DOMStorageLock::WriteReplyParams(reply_msg, invalidate_cache, |
+ bytes_left_in_quota); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnUnlock(int64 storage_area_id) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnUnlock, storage_area_id)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ storage_area->unlock(); |
+} |
+ |
+void DOMStorageDispatcherHost::OnLength(int64 storage_area_id, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ unsigned length = storage_area->length(); |
+ ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnKey, storage_area_id, index, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ bool key_exception = false; |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ string16 key = storage_area->key(index, key_exception); |
+ ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key_exception, key); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id, |
+ const string16& key, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnGetItem, |
+ storage_area_id, key, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ WebKit::WebString value = storage_area->getItem(key); |
+ ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, (string16)value, |
+ value.isNull()); |
+ Send(reply_msg); |
+} |
+ |
+void DOMStorageDispatcherHost::OnSetItem(int64 storage_area_id, |
+ const string16& key, |
+ const string16& value) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ bool quota_exception = false; |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ storage_area->setItem(key, value, quota_exception); |
+ DCHECK(!quota_exception); // This is tracked by the renderer. |
+} |
+ |
+void DOMStorageDispatcherHost::OnRemoveItem(int64 storage_area_id, |
+ const string16& key) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ storage_area->removeItem(key); |
+} |
+ |
+void DOMStorageDispatcherHost::OnClear(int64 storage_area_id, |
+ IPC::Message* reply_msg) { |
+ DCHECK(!shutdown_); |
+ if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
+ MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
+ webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
+ &DOMStorageDispatcherHost::OnClear, storage_area_id, reply_msg)); |
+ return; |
+ } |
+ |
+ DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
+ // TODO(jorlow): Return the total quota for this domain. |
+ size_t bytes_left_in_quota = 0; |
+ WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
+ CHECK(storage_area); // TODO(jorlow): Do better than this. |
+ storage_area->clear(); |
+ ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg, |
+ bytes_left_in_quota); |
+ Send(reply_msg); |
+} |
+ |
+WebStorageArea* DOMStorageDispatcherHost::GetStorageArea(int64 id) { |
+ StorageAreaMap::iterator iterator = storage_area_map_.find(id); |
+ if (iterator == storage_area_map_.end()) |
+ return NULL; |
+ return iterator->second; |
+} |
+ |
+WebStorageNamespace* DOMStorageDispatcherHost::GetStorageNamespace(int64 id) { |
+ StorageNamespaceMap::iterator iterator = storage_namespace_map_.find(id); |
+ if (iterator == storage_namespace_map_.end()) |
+ return NULL; |
+ return iterator->second; |
+} |
+ |
+int64 DOMStorageDispatcherHost::AddStorageArea( |
+ WebStorageArea* new_storage_area) { |
+ // Create a new ID and insert it into our map. |
+ int64 new_storage_area_id = ++last_storage_area_id_; |
+ DCHECK(!GetStorageArea(new_storage_area_id)); |
+ storage_area_map_[new_storage_area_id] = new_storage_area; |
+ return new_storage_area_id; |
+} |
+ |
+int64 DOMStorageDispatcherHost::AddStorageNamespace( |
+ WebStorageNamespace* new_namespace) { |
+ // Create a new ID and insert it into our map. |
+ int64 new_namespace_id = ++last_storage_namespace_id_; |
+ DCHECK(!GetStorageNamespace(new_namespace_id)); |
+ storage_namespace_map_[new_namespace_id] = new_namespace; |
+ return new_namespace_id; |
+} |
+ |
+string16 DOMStorageDispatcherHost::GetLocalStoragePath() { |
+ // TODO(jorlow): Create a path based on the WebKitContext. |
+ string16 path; |
+ return path; |
+} |