diff options
author | jorlow@chromium.org <jorlow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-24 01:22:51 +0000 |
---|---|---|
committer | jorlow@chromium.org <jorlow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-24 01:22:51 +0000 |
commit | 2a10f681c582df15719956061b6742a55bccb46a (patch) | |
tree | 4e4ee689cafbecb9b211f437f478b7588f6c05c2 /chrome/renderer | |
parent | 4f9b2a7e42fc567073f4999a888b3140bec460bb (diff) | |
download | chromium_src-2a10f681c582df15719956061b6742a55bccb46a.zip chromium_src-2a10f681c582df15719956061b6742a55bccb46a.tar.gz chromium_src-2a10f681c582df15719956061b6742a55bccb46a.tar.bz2 |
The final CL for plumbing DOM Storage.
Add webKitClient plumbing for getting/creating storage namespaces. Add a chromium implementation for WebStorageArea and WebStorageNamespace which communicates via IPC with the dom_storage_dispatcher_host in the browser process. Flesh out the StorageAreaProxy and StorageNamespaceProxy to use the aforementioned implementations.
The WebStorageArea implementation includes decently aggressive caching optimizations. There's still a lot of work to do, though.
BUG=4360
TEST=none
Review URL: http://codereview.chromium.org/147248
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21495 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.cc | 17 | ||||
-rw-r--r-- | chrome/renderer/renderer_webkitclient_impl.h | 3 | ||||
-rw-r--r-- | chrome/renderer/renderer_webstoragearea_impl.cc | 171 | ||||
-rw-r--r-- | chrome/renderer/renderer_webstoragearea_impl.h | 76 | ||||
-rw-r--r-- | chrome/renderer/renderer_webstoragenamespace_impl.cc | 65 | ||||
-rw-r--r-- | chrome/renderer/renderer_webstoragenamespace_impl.h | 35 |
6 files changed, 367 insertions, 0 deletions
diff --git a/chrome/renderer/renderer_webkitclient_impl.cc b/chrome/renderer/renderer_webkitclient_impl.cc index 05e56fb..a863971 100644 --- a/chrome/renderer/renderer_webkitclient_impl.cc +++ b/chrome/renderer/renderer_webkitclient_impl.cc @@ -10,6 +10,7 @@ #include "chrome/plugin/npobject_util.h" #include "chrome/renderer/net/render_dns_master.h" #include "chrome/renderer/render_thread.h" +#include "chrome/renderer/renderer_webstoragenamespace_impl.h" #include "chrome/renderer/visitedlink_slave.h" #include "webkit/api/public/WebString.h" #include "webkit/api/public/WebURL.h" @@ -20,6 +21,8 @@ #include "chrome/renderer/renderer_sandbox_support_linux.h" #endif +using WebKit::WebStorageArea; +using WebKit::WebStorageNamespace; using WebKit::WebString; using WebKit::WebURL; @@ -100,6 +103,20 @@ void RendererWebKitClientImpl::suddenTerminationChanged(bool enabled) { thread->Send(new ViewHostMsg_SuddenTerminationChanged(enabled)); } +WebStorageNamespace* RendererWebKitClientImpl::createLocalStorageNamespace( + const WebString& path) { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) + return WebStorageNamespace::createLocalStorageNamespace(path); + // The browser process decides the path, so ignore that param. + return new RendererWebStorageNamespaceImpl(true); +} + +WebStorageNamespace* RendererWebKitClientImpl::createSessionStorageNamespace() { + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) + return WebStorageNamespace::createSessionStorageNamespace(); + return new RendererWebStorageNamespaceImpl(false); +} + //------------------------------------------------------------------------------ WebString RendererWebKitClientImpl::MimeRegistry::mimeTypeForExtension( diff --git a/chrome/renderer/renderer_webkitclient_impl.h b/chrome/renderer/renderer_webkitclient_impl.h index 3f4d5cf..0190027 100644 --- a/chrome/renderer/renderer_webkitclient_impl.h +++ b/chrome/renderer/renderer_webkitclient_impl.h @@ -36,6 +36,9 @@ class RendererWebKitClientImpl : public webkit_glue::WebKitClientImpl { virtual void prefetchHostName(const WebKit::WebString&); virtual WebKit::WebString defaultLocale(); virtual void suddenTerminationChanged(bool enabled); + virtual WebKit::WebStorageNamespace* createLocalStorageNamespace( + const WebKit::WebString& path); + virtual WebKit::WebStorageNamespace* createSessionStorageNamespace(); private: class MimeRegistry : public webkit_glue::SimpleWebMimeRegistryImpl { diff --git a/chrome/renderer/renderer_webstoragearea_impl.cc b/chrome/renderer/renderer_webstoragearea_impl.cc new file mode 100644 index 0000000..c438cdfe --- /dev/null +++ b/chrome/renderer/renderer_webstoragearea_impl.cc @@ -0,0 +1,171 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +#include "chrome/renderer/renderer_webstoragearea_impl.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "webkit/api/public/WebString.h" + +RendererWebStorageAreaImpl::RendererWebStorageAreaImpl( + int64 namespace_id, + const WebKit::WebString& origin) + : namespace_id_(namespace_id), + origin_(origin), + storage_area_id_(kUninitializedStorageAreaId), + lock_held_(false), + bytes_left_in_quota_(0) { +} + +RendererWebStorageAreaImpl::~RendererWebStorageAreaImpl() { +} + +void RendererWebStorageAreaImpl::lock(bool& invalidate_cache, + size_t& bytes_left_in_quota) { + EnsureInitializedAndLocked(); +} + +void RendererWebStorageAreaImpl::unlock() { + if (storage_area_id_ != kUninitializedStorageAreaId) { + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageUnlock(storage_area_id_)); + } + lock_held_ = false; +} + +unsigned RendererWebStorageAreaImpl::length() { + EnsureInitializedAndLocked(); + // Right now this is always sync. We could cache it, but I can't think of + // too many use cases where you'd repeatedly look up length() and not be + // doing so many key() lookups that the length() calls are the problem. + unsigned length; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageLength(storage_area_id_, &length)); + return length; +} + +WebKit::WebString RendererWebStorageAreaImpl::key(unsigned index, + bool& key_exception) { + EnsureInitializedAndLocked(); + // Right now this is always sync. We may want to optimize this by fetching + // chunks of keys rather than single keys (and flushing the cache on every + // mutation of the storage area) since this will most often be used to fetch + // all the keys at once. + string16 key; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageKey(storage_area_id_, index, + &key_exception, &key)); + return key; +} + +WebKit::WebString RendererWebStorageAreaImpl::getItem( + const WebKit::WebString& webkit_key) { + EnsureInitializedAndLocked(); + string16 key = webkit_key; + + // Return from our cache if possible. + CacheMap::const_iterator iterator = cached_items_.find(key); + if (iterator != cached_items_.end()) + return iterator->second; + if (cached_invalid_items_.find(key) != cached_invalid_items_.end()) + return WebKit::WebString(); // Return a "null" string. + + // The item is not in the cache, so we must do a sync IPC. Afterwards, + // add it to the cache. + string16 raw_value; + bool value_is_null; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageGetItem(storage_area_id_, key, + &raw_value, &value_is_null)); + WebKit::WebString value = value_is_null ? WebKit::WebString() + : WebKit::WebString(raw_value); + SetCache(key, value); + return value; +} + +void RendererWebStorageAreaImpl::setItem(const WebKit::WebString& key, + const WebKit::WebString& value, + bool& quota_exception) { + EnsureInitializedAndLocked(); + quota_exception = !UpdateQuota(key, value); + if (quota_exception) + return; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageSetItem(storage_area_id_, key, value)); + SetCache(key, value); +} + +void RendererWebStorageAreaImpl::removeItem(const WebKit::WebString& key) { + EnsureInitializedAndLocked(); + bool update_succeeded = UpdateQuota(key, WebKit::WebString()); + DCHECK(update_succeeded); + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageRemoveItem(storage_area_id_, key)); + SetCache(key, WebKit::WebString()); +} + +void RendererWebStorageAreaImpl::clear() { + EnsureInitializedAndLocked(); + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageClear(storage_area_id_, + &bytes_left_in_quota_)); + // A possible optimization is a flag that says our cache is 100% complete. + // This could be set here, and then future gets would never require IPC. + cached_items_.clear(); + cached_invalid_items_.clear(); +} + +void RendererWebStorageAreaImpl::EnsureInitializedAndLocked() { + if (storage_area_id_ == kUninitializedStorageAreaId) { + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageStorageAreaId(namespace_id_, origin_, + &storage_area_id_)); + } + + if (lock_held_) + return; + + bool invalidate_cache; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageLock(storage_area_id_, &invalidate_cache, + &bytes_left_in_quota_)); + lock_held_ = true; + if (invalidate_cache) { + cached_items_.clear(); + cached_invalid_items_.clear(); + } +} + +bool RendererWebStorageAreaImpl::UpdateQuota(const WebKit::WebString& key, + const WebKit::WebString& value) { + // TODO(jorlow): Remove once the bytes_left_in_quota values we're getting + // are accurate. + return true; + + size_t existing_bytes = getItem(key).length(); + size_t new_bytes = value.length(); + + if (existing_bytes < new_bytes) { + size_t delta = new_bytes - existing_bytes; + if (delta > bytes_left_in_quota_) + return false; + bytes_left_in_quota_ -= delta; + } else { + size_t delta = existing_bytes - new_bytes; + DCHECK(delta + bytes_left_in_quota_ >= bytes_left_in_quota_); + bytes_left_in_quota_ += delta; + } + return true; +} + +void RendererWebStorageAreaImpl::SetCache(const string16& key, + const WebKit::WebString& value) { + cached_items_.erase(key); + cached_invalid_items_.erase(key); + + if (!value.isNull()) + cached_items_[key] = value; + else + cached_invalid_items_.insert(key); +} diff --git a/chrome/renderer/renderer_webstoragearea_impl.h b/chrome/renderer/renderer_webstoragearea_impl.h new file mode 100644 index 0000000..0a313c2 --- /dev/null +++ b/chrome/renderer/renderer_webstoragearea_impl.h @@ -0,0 +1,76 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +#ifndef CHROME_RENDERER_RENDERER_WEBSTORAGEAREA_IMPL_H_ +#define CHROME_RENDERER_RENDERER_WEBSTORAGEAREA_IMPL_H_ + +#include "base/basictypes.h" +#include "base/hash_tables.h" +#include "base/string16.h" +#include "webkit/api/public/WebStorageArea.h" +#include "webkit/api/public/WebString.h" + +class RendererWebStorageAreaImpl : public WebKit::WebStorageArea { + public: + RendererWebStorageAreaImpl(int64 namespace_id, + const WebKit::WebString& origin); + virtual ~RendererWebStorageAreaImpl(); + + // See WebStorageArea.h for documentation on these functions. + virtual void lock(bool& invalidate_cache, size_t& bytes_left_in_quota); + virtual void unlock(); + virtual unsigned length(); + virtual WebKit::WebString key(unsigned index, bool& key_exception); + virtual WebKit::WebString getItem(const WebKit::WebString& key); + virtual void setItem(const WebKit::WebString& key, + const WebKit::WebString& value, + bool& quota_exception); + virtual void removeItem(const WebKit::WebString& key); + virtual void clear(); + + private: + // Calls lock if we haven't already done so, and also gets a storage_area_id + // if we haven't done so. Fetches quota and cache invalidation information + // while locking. Only call on the WebKit thread. + void EnsureInitializedAndLocked(); + + // Update our quota calculation. Returns true if we updated the quota. + // Returns false if we couldn't update because we would have exceeded the + // quota. If an item is not in our cache, it'll require a getItem IPC in + // order to determine the existing value's size. + bool UpdateQuota(const WebKit::WebString& key, + const WebKit::WebString& value); + + // Set a key/value pair in our cache. + void SetCache(const string16& key, const WebKit::WebString& value); + + // Used for initialization or storage_area_id_. + int64 namespace_id_; + string16 origin_; + + // The ID we use for all IPC. Initialized lazily. + int64 storage_area_id_; + + // storage_area_id_ should equal this iff its unitialized. + static const int64 kUninitializedStorageAreaId = -1; + + // Do we currently hold the lock on this storage area? + bool lock_held_; + + // We track how many bytes are left in the quota between lock and unlock + // calls. This allows us to avoid sync IPC on setItem. + size_t bytes_left_in_quota_; + + // A cache of key/value pairs. If the item exists, it's put in the + // cached_items_ map. If not, it's added to the cached_invalid_items_ set. + // The lock IPC call tells us when to invalidate these caches. + // TODO(jorlow): Instead of a map + a set, use NullableString16 once it's + // implemented: http://crbug.com/17343 + typedef base::hash_map<string16, string16> CacheMap; + typedef base::hash_set<string16> CacheSet; + CacheMap cached_items_; + CacheSet cached_invalid_items_; +}; + +#endif // CHROME_RENDERER_WEBSTORAGEAREA_IMPL_H_ diff --git a/chrome/renderer/renderer_webstoragenamespace_impl.cc b/chrome/renderer/renderer_webstoragenamespace_impl.cc new file mode 100644 index 0000000..453bbcf --- /dev/null +++ b/chrome/renderer/renderer_webstoragenamespace_impl.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +#include "chrome/renderer/renderer_webstoragenamespace_impl.h" + +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" +#include "chrome/renderer/renderer_webstoragearea_impl.h" + +RendererWebStorageNamespaceImpl::RendererWebStorageNamespaceImpl( + bool is_local_storage) + : is_local_storage_(is_local_storage), + namespace_id_(kUninitializedNamespaceId) { +} + +RendererWebStorageNamespaceImpl::RendererWebStorageNamespaceImpl( + bool is_local_storage, int64 namespace_id) + : is_local_storage_(is_local_storage), + namespace_id_(namespace_id) { + DCHECK(namespace_id_ != kUninitializedNamespaceId); +} + +RendererWebStorageNamespaceImpl::~RendererWebStorageNamespaceImpl() { + if (namespace_id_ != kUninitializedNamespaceId) + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageDerefNamespaceId(namespace_id_)); +} + +WebKit::WebStorageArea* RendererWebStorageNamespaceImpl::createStorageArea( + const WebKit::WebString& origin) { + // This could be done async in the background (started when this class is + // first instantiated) rather than lazily on first use, but it's unclear + // whether it's worth the complexity. + if (namespace_id_ == kUninitializedNamespaceId) { + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageNamespaceId(is_local_storage_, + &namespace_id_)); + DCHECK(namespace_id_ != kUninitializedNamespaceId); + } + // Ideally, we'd keep a hash map of origin to these objects. Unfortunately + // this doesn't seem practical because there's no good way to ref-count these + // objects, and it'd be unclear who owned them. So, instead, we'll pay a + // price for an allocaiton and IPC for each. + return new RendererWebStorageAreaImpl(namespace_id_, origin); +} + +WebKit::WebStorageNamespace* RendererWebStorageNamespaceImpl::copy() { + // If we haven't been used yet, we might as well start out fresh (and lazy). + if (namespace_id_ == kUninitializedNamespaceId) + return new RendererWebStorageNamespaceImpl(is_local_storage_); + + // This cannot easily be differed because we need a snapshot in time. + int64 new_namespace_id; + RenderThread::current()->Send( + new ViewHostMsg_DOMStorageCloneNamespaceId(namespace_id_, + &new_namespace_id)); + return new RendererWebStorageNamespaceImpl(is_local_storage_, + new_namespace_id); +} + +void RendererWebStorageNamespaceImpl::close() { + // This is called only on LocalStorage namespaces when WebKit thinks its + // shutting down. This has no impact on Chromium. +} diff --git a/chrome/renderer/renderer_webstoragenamespace_impl.h b/chrome/renderer/renderer_webstoragenamespace_impl.h new file mode 100644 index 0000000..7478a67 --- /dev/null +++ b/chrome/renderer/renderer_webstoragenamespace_impl.h @@ -0,0 +1,35 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this +// source code is governed by a BSD-style license that can be found in the +// LICENSE file. + +#ifndef CHROME_RENDERER_RENDERER_WEBSTORAGENAMESPACE_IMPL_H_ +#define CHROME_RENDERER_RENDERER_WEBSTORAGENAMESPACE_IMPL_H_ + +#include "base/basictypes.h" +#include "webkit/api/public/WebStorageNamespace.h" + +class RendererWebStorageNamespaceImpl : public WebKit::WebStorageNamespace { + public: + explicit RendererWebStorageNamespaceImpl(bool is_local_storage); + RendererWebStorageNamespaceImpl(bool is_local_storage, int64 namespace_id); + + // See WebStorageNamespace.h for documentation on these functions. + virtual ~RendererWebStorageNamespaceImpl(); + virtual WebKit::WebStorageArea* createStorageArea( + const WebKit::WebString& origin); + virtual WebKit::WebStorageNamespace* copy(); + virtual void close(); + + private: + // Are we local storage (as opposed to session storage). Used during lazy + // initialization of namespace_id_. + bool is_local_storage_; + + // Our namespace ID. Lazily initialized. + int64 namespace_id_; + + // namespace_id_ should equal this iff its unitialized. + static const int64 kUninitializedNamespaceId = -1; +}; + +#endif // CHROME_RENDERER_WEBSTORAGENAMESPACE_IMPL_H_ |