summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-24 17:40:50 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-02-24 17:40:50 +0000
commit567812dd45d36e093554664bdbd4284a9670a8b3 (patch)
tree803b8da070eabfd2efa6a50b53f331c4255bbbc6 /content
parentabe19c107967234fce377db157b8b963f83ec529 (diff)
downloadchromium_src-567812dd45d36e093554664bdbd4284a9670a8b3.zip
chromium_src-567812dd45d36e093554664bdbd4284a9670a8b3.tar.gz
chromium_src-567812dd45d36e093554664bdbd4284a9670a8b3.tar.bz2
Move in_process_webkit dir from chrome\browser to content\browser.
Review URL: http://codereview.chromium.org/6580019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75902 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/in_process_webkit/browser_webkitclient_impl.cc175
-rw-r--r--content/browser/in_process_webkit/browser_webkitclient_impl.h64
-rw-r--r--content/browser/in_process_webkit/dom_storage_area.cc98
-rw-r--r--content/browser/in_process_webkit/dom_storage_area.h83
-rw-r--r--content/browser/in_process_webkit/dom_storage_browsertest.cc53
-rw-r--r--content/browser/in_process_webkit/dom_storage_context.cc289
-rw-r--r--content/browser/in_process_webkit/dom_storage_context.h157
-rw-r--r--content/browser/in_process_webkit/dom_storage_message_filter.cc232
-rw-r--r--content/browser/in_process_webkit/dom_storage_message_filter.h97
-rw-r--r--content/browser/in_process_webkit/dom_storage_message_filter_unittest.cc8
-rw-r--r--content/browser/in_process_webkit/dom_storage_namespace.cc112
-rw-r--r--content/browser/in_process_webkit/dom_storage_namespace.h85
-rw-r--r--content/browser/in_process_webkit/dom_storage_uitest.cc190
-rw-r--r--content/browser/in_process_webkit/indexed_db_browsertest.cc128
-rw-r--r--content/browser/in_process_webkit/indexed_db_callbacks.cc77
-rw-r--r--content/browser/in_process_webkit/indexed_db_callbacks.h153
-rw-r--r--content/browser/in_process_webkit/indexed_db_context.cc93
-rw-r--r--content/browser/in_process_webkit/indexed_db_context.h63
-rw-r--r--content/browser/in_process_webkit/indexed_db_dispatcher_host.cc1024
-rw-r--r--content/browser/in_process_webkit/indexed_db_dispatcher_host.h280
-rw-r--r--content/browser/in_process_webkit/indexed_db_key_utility_client.cc383
-rw-r--r--content/browser/in_process_webkit/indexed_db_key_utility_client.h55
-rw-r--r--content/browser/in_process_webkit/session_storage_namespace.cc31
-rw-r--r--content/browser/in_process_webkit/session_storage_namespace.h46
-rw-r--r--content/browser/in_process_webkit/webkit_context.cc84
-rw-r--r--content/browser/in_process_webkit/webkit_context.h86
-rw-r--r--content/browser/in_process_webkit/webkit_context_unittest.cc60
-rw-r--r--content/browser/in_process_webkit/webkit_thread.cc61
-rw-r--r--content/browser/in_process_webkit/webkit_thread.h47
-rw-r--r--content/browser/in_process_webkit/webkit_thread_unittest.cc22
-rw-r--r--content/browser/renderer_host/render_message_filter.h6
-rw-r--r--content/browser/renderer_host/render_view_host.cc8
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.cc10
-rw-r--r--content/browser/tab_contents/navigation_controller.cc4
-rw-r--r--content/browser/tab_contents/tab_contents.cc16
-rw-r--r--content/content_browser.gypi24
36 files changed, 4382 insertions, 22 deletions
diff --git a/content/browser/in_process_webkit/browser_webkitclient_impl.cc b/content/browser/in_process_webkit/browser_webkitclient_impl.cc
new file mode 100644
index 0000000..2d086680
--- /dev/null
+++ b/content/browser/in_process_webkit/browser_webkitclient_impl.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/browser_webkitclient_impl.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/serialized_script_value.h"
+#include "content/browser/in_process_webkit/dom_storage_message_filter.h"
+#include "content/browser/in_process_webkit/indexed_db_key_utility_client.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebData.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSerializedScriptValue.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
+#include "webkit/glue/webkit_glue.h"
+
+BrowserWebKitClientImpl::BrowserWebKitClientImpl() {
+ file_utilities_.set_sandbox_enabled(false);
+}
+
+BrowserWebKitClientImpl::~BrowserWebKitClientImpl() {
+}
+
+WebKit::WebClipboard* BrowserWebKitClientImpl::clipboard() {
+ NOTREACHED();
+ return NULL;
+}
+
+WebKit::WebMimeRegistry* BrowserWebKitClientImpl::mimeRegistry() {
+ NOTREACHED();
+ return NULL;
+}
+
+WebKit::WebFileUtilities* BrowserWebKitClientImpl::fileUtilities() {
+ return &file_utilities_;
+}
+
+WebKit::WebSandboxSupport* BrowserWebKitClientImpl::sandboxSupport() {
+ NOTREACHED();
+ return NULL;
+}
+
+bool BrowserWebKitClientImpl::sandboxEnabled() {
+ return false;
+}
+
+unsigned long long BrowserWebKitClientImpl::visitedLinkHash(
+ const char* canonical_url,
+ size_t length) {
+ NOTREACHED();
+ return 0;
+}
+
+bool BrowserWebKitClientImpl::isLinkVisited(unsigned long long link_hash) {
+ NOTREACHED();
+ return false;
+}
+
+WebKit::WebMessagePortChannel*
+BrowserWebKitClientImpl::createMessagePortChannel() {
+ NOTREACHED();
+ return NULL;
+}
+
+void BrowserWebKitClientImpl::setCookies(
+ const WebKit::WebURL& url,
+ const WebKit::WebURL& first_party_for_cookies,
+ const WebKit::WebString& value) {
+ NOTREACHED();
+}
+
+WebKit::WebString BrowserWebKitClientImpl::cookies(
+ const WebKit::WebURL& url,
+ const WebKit::WebURL& first_party_for_cookies) {
+ NOTREACHED();
+ return WebKit::WebString();
+}
+
+void BrowserWebKitClientImpl::prefetchHostName(const WebKit::WebString&) {
+ NOTREACHED();
+}
+
+WebKit::WebString BrowserWebKitClientImpl::defaultLocale() {
+ NOTREACHED();
+ return WebKit::WebString();
+}
+
+WebKit::WebThemeEngine* BrowserWebKitClientImpl::themeEngine() {
+ NOTREACHED();
+ return NULL;
+}
+
+WebKit::WebURLLoader* BrowserWebKitClientImpl::createURLLoader() {
+ NOTREACHED();
+ return NULL;
+}
+
+WebKit::WebSocketStreamHandle*
+ BrowserWebKitClientImpl::createSocketStreamHandle() {
+ NOTREACHED();
+ return NULL;
+}
+
+void BrowserWebKitClientImpl::getPluginList(bool refresh,
+ WebKit::WebPluginListBuilder* builder) {
+ NOTREACHED();
+}
+
+WebKit::WebData BrowserWebKitClientImpl::loadResource(const char* name) {
+ NOTREACHED();
+ return WebKit::WebData();
+}
+
+WebKit::WebStorageNamespace*
+BrowserWebKitClientImpl::createLocalStorageNamespace(
+ const WebKit::WebString& path, unsigned quota) {
+ // The "WebStorage" interface is used for renderer WebKit -> browser WebKit
+ // communication only. "WebStorageClient" will be used for browser WebKit ->
+ // renderer WebKit. So this will never be implemented.
+ NOTREACHED();
+ return 0;
+}
+
+void BrowserWebKitClientImpl::dispatchStorageEvent(
+ const WebKit::WebString& key, const WebKit::WebString& old_value,
+ const WebKit::WebString& new_value, const WebKit::WebString& origin,
+ const WebKit::WebURL& url, bool is_local_storage) {
+ // TODO(jorlow): Implement
+ if (!is_local_storage)
+ return;
+
+ DOMStorageMessageFilter::DispatchStorageEvent(key, old_value, new_value,
+ origin, url, is_local_storage);
+}
+
+WebKit::WebSharedWorkerRepository*
+BrowserWebKitClientImpl::sharedWorkerRepository() {
+ NOTREACHED();
+ return NULL;
+}
+
+int BrowserWebKitClientImpl::databaseDeleteFile(
+ const WebKit::WebString& vfs_file_name, bool sync_dir) {
+ const FilePath path = webkit_glue::WebStringToFilePath(vfs_file_name);
+ return file_util::Delete(path, false) ? 0 : 1;
+}
+
+void BrowserWebKitClientImpl::createIDBKeysFromSerializedValuesAndKeyPath(
+ const WebKit::WebVector<WebKit::WebSerializedScriptValue>& values,
+ const WebKit::WebString& keyPath,
+ WebKit::WebVector<WebKit::WebIDBKey>& keys) {
+
+ std::vector<SerializedScriptValue> std_values;
+ size_t size = values.size();
+ std_values.reserve(size);
+ for (size_t i = 0; i < size; ++i)
+ std_values.push_back(SerializedScriptValue(values[i]));
+
+ std::vector<IndexedDBKey> std_keys;
+ IndexedDBKeyUtilityClient::
+ CreateIDBKeysFromSerializedValuesAndKeyPath(std_values, keyPath,
+ &std_keys);
+
+ keys = std_keys;
+}
+
+WebKit::WebSerializedScriptValue
+BrowserWebKitClientImpl::injectIDBKeyIntoSerializedValue(
+ const WebKit::WebIDBKey& key, const WebKit::WebSerializedScriptValue& value,
+ const WebKit::WebString& keyPath) {
+ return IndexedDBKeyUtilityClient::InjectIDBKeyIntoSerializedValue(
+ IndexedDBKey(key), SerializedScriptValue(value), keyPath);
+}
diff --git a/content/browser/in_process_webkit/browser_webkitclient_impl.h b/content/browser/in_process_webkit/browser_webkitclient_impl.h
new file mode 100644
index 0000000..d18e06d
--- /dev/null
+++ b/content/browser/in_process_webkit/browser_webkitclient_impl.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
+#pragma once
+
+#include "webkit/glue/webfileutilities_impl.h"
+#include "webkit/glue/webkitclient_impl.h"
+
+class IndexedDBKeyUtilityClient;
+
+class BrowserWebKitClientImpl : public webkit_glue::WebKitClientImpl {
+ public:
+ BrowserWebKitClientImpl();
+ virtual ~BrowserWebKitClientImpl();
+
+ // WebKitClient methods:
+ virtual WebKit::WebClipboard* clipboard();
+ virtual WebKit::WebMimeRegistry* mimeRegistry();
+ virtual WebKit::WebFileUtilities* fileUtilities();
+ virtual WebKit::WebSandboxSupport* sandboxSupport();
+ virtual bool sandboxEnabled();
+ virtual unsigned long long visitedLinkHash(const char* canonicalURL,
+ size_t length);
+ virtual bool isLinkVisited(unsigned long long linkHash);
+ virtual WebKit::WebMessagePortChannel* createMessagePortChannel();
+ virtual void setCookies(const WebKit::WebURL& url,
+ const WebKit::WebURL& first_party_for_cookies,
+ const WebKit::WebString& value);
+ virtual WebKit::WebString cookies(
+ const WebKit::WebURL& url,
+ const WebKit::WebURL& first_party_for_cookies);
+ virtual void prefetchHostName(const WebKit::WebString&);
+ virtual WebKit::WebString defaultLocale();
+ virtual WebKit::WebThemeEngine* themeEngine();
+ virtual WebKit::WebURLLoader* createURLLoader();
+ virtual WebKit::WebSocketStreamHandle* createSocketStreamHandle();
+ virtual void getPluginList(bool refresh, WebKit::WebPluginListBuilder*);
+ virtual WebKit::WebData loadResource(const char* name);
+ virtual WebKit::WebStorageNamespace* createLocalStorageNamespace(
+ const WebKit::WebString& path, unsigned quota);
+ virtual void dispatchStorageEvent(const WebKit::WebString& key,
+ const WebKit::WebString& oldValue, const WebKit::WebString& newValue,
+ const WebKit::WebString& origin, const WebKit::WebURL& url,
+ bool isLocalStorage);
+ virtual WebKit::WebSharedWorkerRepository* sharedWorkerRepository();
+ virtual int databaseDeleteFile(const WebKit::WebString& vfs_file_name,
+ bool sync_dir);
+ virtual void createIDBKeysFromSerializedValuesAndKeyPath(
+ const WebKit::WebVector<WebKit::WebSerializedScriptValue>& values,
+ const WebKit::WebString& keyPath,
+ WebKit::WebVector<WebKit::WebIDBKey>& keys);
+ virtual WebKit::WebSerializedScriptValue injectIDBKeyIntoSerializedValue(
+ const WebKit::WebIDBKey& key,
+ const WebKit::WebSerializedScriptValue& value,
+ const WebKit::WebString& keyPath);
+
+ private:
+ webkit_glue::WebFileUtilitiesImpl file_utilities_;
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_BROWSER_WEBKITCLIENT_IMPL_H_
diff --git a/content/browser/in_process_webkit/dom_storage_area.cc b/content/browser/in_process_webkit/dom_storage_area.cc
new file mode 100644
index 0000000..1fc2aab
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_area.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/dom_storage_area.h"
+
+#include "base/task.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/common/render_messages.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/dom_storage_namespace.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageArea.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebSecurityOrigin;
+using WebKit::WebStorageArea;
+using WebKit::WebString;
+using WebKit::WebURL;
+
+DOMStorageArea::DOMStorageArea(
+ const string16& origin,
+ int64 id,
+ DOMStorageNamespace* owner,
+ HostContentSettingsMap* host_content_settings_map)
+ : origin_(origin),
+ origin_url_(origin),
+ id_(id),
+ owner_(owner),
+ host_content_settings_map_(host_content_settings_map) {
+ DCHECK(owner_);
+ DCHECK(host_content_settings_map_);
+}
+
+DOMStorageArea::~DOMStorageArea() {
+}
+
+unsigned DOMStorageArea::Length() {
+ CreateWebStorageAreaIfNecessary();
+ return storage_area_->length();
+}
+
+NullableString16 DOMStorageArea::Key(unsigned index) {
+ CreateWebStorageAreaIfNecessary();
+ return storage_area_->key(index);
+}
+
+NullableString16 DOMStorageArea::GetItem(const string16& key) {
+ CreateWebStorageAreaIfNecessary();
+ return storage_area_->getItem(key);
+}
+
+NullableString16 DOMStorageArea::SetItem(
+ const string16& key, const string16& value,
+ WebStorageArea::Result* result) {
+ if (!CheckContentSetting(key, value)) {
+ *result = WebStorageArea::ResultBlockedByPolicy;
+ return NullableString16(true); // Ignored if the content was blocked.
+ }
+
+ CreateWebStorageAreaIfNecessary();
+ WebString old_value;
+ storage_area_->setItem(key, value, WebURL(), *result, old_value);
+ return old_value;
+}
+
+NullableString16 DOMStorageArea::RemoveItem(const string16& key) {
+ CreateWebStorageAreaIfNecessary();
+ WebString old_value;
+ storage_area_->removeItem(key, WebURL(), old_value);
+ return old_value;
+}
+
+bool DOMStorageArea::Clear() {
+ CreateWebStorageAreaIfNecessary();
+ bool somethingCleared;
+ storage_area_->clear(WebURL(), somethingCleared);
+ return somethingCleared;
+}
+
+void DOMStorageArea::PurgeMemory() {
+ storage_area_.reset();
+}
+
+void DOMStorageArea::CreateWebStorageAreaIfNecessary() {
+ if (!storage_area_.get())
+ storage_area_.reset(owner_->CreateWebStorageArea(origin_));
+}
+
+bool DOMStorageArea::CheckContentSetting(
+ const string16& key, const string16& value) {
+ ContentSetting content_setting =
+ host_content_settings_map_->GetContentSetting(
+ origin_url_, CONTENT_SETTINGS_TYPE_COOKIES, "");
+ return (content_setting != CONTENT_SETTING_BLOCK);
+}
diff --git a/content/browser/in_process_webkit/dom_storage_area.h b/content/browser/in_process_webkit/dom_storage_area.h
new file mode 100644
index 0000000..e451f8b
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_area.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_AREA_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_AREA_H_
+#pragma once
+
+#include "base/hash_tables.h"
+#include "base/nullable_string16.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/common/dom_storage_common.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageArea.h"
+
+class DOMStorageNamespace;
+class HostContentSettingsMap;
+
+// Only use on the WebKit thread. DOMStorageNamespace manages our registration
+// with DOMStorageContext.
+class DOMStorageArea {
+ public:
+ DOMStorageArea(const string16& origin,
+ int64 id,
+ DOMStorageNamespace* owner,
+ HostContentSettingsMap* host_content_settings_map);
+ ~DOMStorageArea();
+
+ unsigned Length();
+ NullableString16 Key(unsigned index);
+ NullableString16 GetItem(const string16& key);
+ NullableString16 SetItem(
+ const string16& key, const string16& value,
+ WebKit::WebStorageArea::Result* result);
+ NullableString16 RemoveItem(const string16& key);
+ bool Clear();
+ void PurgeMemory();
+
+ int64 id() const { return id_; }
+
+ DOMStorageNamespace* owner() const { return owner_; }
+
+ private:
+ // Creates the underlying WebStorageArea on demand.
+ void CreateWebStorageAreaIfNecessary();
+
+ // Used to see if setItem has permission to do its thing.
+ bool CheckContentSetting(const string16& key, const string16& value);
+
+ // The origin this storage area represents.
+ string16 origin_;
+ GURL origin_url_;
+
+ // The storage area we wrap.
+ scoped_ptr<WebKit::WebStorageArea> storage_area_;
+
+ // Our storage area id. Unique to our parent WebKitContext.
+ int64 id_;
+
+ // The DOMStorageNamespace that owns us.
+ DOMStorageNamespace* owner_;
+
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageArea);
+};
+
+#if defined(COMPILER_GCC)
+namespace __gnu_cxx {
+
+template<>
+struct hash<DOMStorageArea*> {
+ std::size_t operator()(DOMStorageArea* const& p) const {
+ return reinterpret_cast<std::size_t>(p);
+ }
+};
+
+} // namespace __gnu_cxx
+#endif
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_AREA_H_
diff --git a/content/browser/in_process_webkit/dom_storage_browsertest.cc b/content/browser/in_process_webkit/dom_storage_browsertest.cc
new file mode 100644
index 0000000..6e081a9
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_browsertest.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 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 "base/file_path.h"
+#include "base/file_util.h"
+#include "base/scoped_temp_dir.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/testing_profile.h"
+#include "chrome/test/thread_test_helper.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+
+typedef InProcessBrowserTest DOMStorageBrowserTest;
+
+// In proc browser test is needed here because ClearLocalState indirectly calls
+// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
+IN_PROC_BROWSER_TEST_F(DOMStorageBrowserTest, ClearLocalState) {
+ // Create test files.
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath domstorage_dir = temp_dir.path().Append(
+ DOMStorageContext::kLocalStorageDirectory);
+ ASSERT_TRUE(file_util::CreateDirectory(domstorage_dir));
+
+ FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
+ file_name_1.append(DOMStorageContext::kLocalStorageExtension);
+ FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
+ file_name_2.append(DOMStorageContext::kLocalStorageExtension);
+ FilePath temp_file_path_1 = domstorage_dir.Append(file_name_1);
+ FilePath temp_file_path_2 = domstorage_dir.Append(file_name_2);
+
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));
+
+ // Create the scope which will ensure we run the destructor of the webkit
+ // context which should trigger the clean up.
+ {
+ TestingProfile profile;
+ WebKitContext *webkit_context = profile.GetWebKitContext();
+ webkit_context->dom_storage_context()->set_data_path(temp_dir.path());
+ webkit_context->set_clear_local_state_on_exit(true);
+ }
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::WEBKIT));
+ ASSERT_TRUE(helper->Run());
+
+ // Because we specified https for scheme to be skipped the second file
+ // should survive and the first go into vanity.
+ ASSERT_FALSE(file_util::PathExists(temp_file_path_1));
+ ASSERT_TRUE(file_util::PathExists(temp_file_path_2));
+}
diff --git a/content/browser/in_process_webkit/dom_storage_context.cc b/content/browser/in_process_webkit/dom_storage_context.cc
new file mode 100644
index 0000000..c39d75a
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_context.cc
@@ -0,0 +1,289 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/dom_storage_context.h"
+
+#include <algorithm>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "chrome/common/dom_storage_common.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/in_process_webkit/dom_storage_area.h"
+#include "content/browser/in_process_webkit/dom_storage_namespace.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebSecurityOrigin;
+
+namespace {
+
+void ClearLocalState(const FilePath& domstorage_path,
+ const char* url_scheme_to_be_skipped) {
+ file_util::FileEnumerator file_enumerator(
+ domstorage_path, false, file_util::FileEnumerator::FILES);
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() == DOMStorageContext::kLocalStorageExtension) {
+ WebSecurityOrigin web_security_origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathToWebString(file_path.BaseName()));
+ if (!EqualsASCII(web_security_origin.protocol(),
+ url_scheme_to_be_skipped)) {
+ file_util::Delete(file_path, false);
+ }
+ }
+ }
+}
+
+} // namespace
+
+const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] =
+ FILE_PATH_LITERAL("Local Storage");
+
+const FilePath::CharType DOMStorageContext::kLocalStorageExtension[] =
+ FILE_PATH_LITERAL(".localstorage");
+
+DOMStorageContext::DOMStorageContext(WebKitContext* webkit_context)
+ : last_storage_area_id_(0),
+ last_session_storage_namespace_id_on_ui_thread_(kLocalStorageNamespaceId),
+ last_session_storage_namespace_id_on_io_thread_(kLocalStorageNamespaceId),
+ clear_local_state_on_exit_(false) {
+ data_path_ = webkit_context->data_path();
+}
+
+DOMStorageContext::~DOMStorageContext() {
+ // This should not go away until all DOM Storage message filters have gone
+ // away. And they remove themselves from this list.
+ DCHECK(message_filter_set_.empty());
+
+ for (StorageNamespaceMap::iterator iter(storage_namespace_map_.begin());
+ iter != storage_namespace_map_.end(); ++iter) {
+ delete iter->second;
+ }
+
+ // Not being on the WEBKIT thread here means we are running in a unit test
+ // where no clean up is needed.
+ if (clear_local_state_on_exit_ &&
+ BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ ClearLocalState(data_path_.Append(kLocalStorageDirectory),
+ chrome::kExtensionScheme);
+ }
+}
+
+int64 DOMStorageContext::AllocateStorageAreaId() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ return ++last_storage_area_id_;
+}
+
+int64 DOMStorageContext::AllocateSessionStorageNamespaceId() {
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI))
+ return ++last_session_storage_namespace_id_on_ui_thread_;
+ return --last_session_storage_namespace_id_on_io_thread_;
+}
+
+int64 DOMStorageContext::CloneSessionStorage(int64 original_id) {
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ int64 clone_id = AllocateSessionStorageNamespaceId();
+ BrowserThread::PostTask(
+ BrowserThread::WEBKIT, FROM_HERE, NewRunnableFunction(
+ &DOMStorageContext::CompleteCloningSessionStorage,
+ this, original_id, clone_id));
+ return clone_id;
+}
+
+void DOMStorageContext::RegisterStorageArea(DOMStorageArea* storage_area) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ int64 id = storage_area->id();
+ DCHECK(!GetStorageArea(id));
+ storage_area_map_[id] = storage_area;
+}
+
+void DOMStorageContext::UnregisterStorageArea(DOMStorageArea* storage_area) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ int64 id = storage_area->id();
+ DCHECK(GetStorageArea(id));
+ storage_area_map_.erase(id);
+}
+
+DOMStorageArea* DOMStorageContext::GetStorageArea(int64 id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ StorageAreaMap::iterator iter = storage_area_map_.find(id);
+ if (iter == storage_area_map_.end())
+ return NULL;
+ return iter->second;
+}
+
+void DOMStorageContext::DeleteSessionStorageNamespace(int64 namespace_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ StorageNamespaceMap::iterator iter =
+ storage_namespace_map_.find(namespace_id);
+ if (iter == storage_namespace_map_.end())
+ return;
+ DCHECK(iter->second->dom_storage_type() == DOM_STORAGE_SESSION);
+ delete iter->second;
+ storage_namespace_map_.erase(iter);
+}
+
+DOMStorageNamespace* DOMStorageContext::GetStorageNamespace(
+ int64 id, bool allocation_allowed) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ StorageNamespaceMap::iterator iter = storage_namespace_map_.find(id);
+ if (iter != storage_namespace_map_.end())
+ return iter->second;
+ if (!allocation_allowed)
+ return NULL;
+ if (id == kLocalStorageNamespaceId)
+ return CreateLocalStorage();
+ return CreateSessionStorage(id);
+}
+
+void DOMStorageContext::RegisterMessageFilter(
+ DOMStorageMessageFilter* message_filter) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(message_filter_set_.find(message_filter) ==
+ message_filter_set_.end());
+ message_filter_set_.insert(message_filter);
+}
+
+void DOMStorageContext::UnregisterMessageFilter(
+ DOMStorageMessageFilter* message_filter) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(message_filter_set_.find(message_filter) !=
+ message_filter_set_.end());
+ message_filter_set_.erase(message_filter);
+}
+
+const DOMStorageContext::MessageFilterSet*
+DOMStorageContext::GetMessageFilterSet() const {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ return &message_filter_set_;
+}
+
+void DOMStorageContext::PurgeMemory() {
+ // It is only safe to purge the memory from the LocalStorage namespace,
+ // because it is backed by disk and can be reloaded later. If we purge a
+ // SessionStorage namespace, its data will be gone forever, because it isn't
+ // currently backed by disk.
+ DOMStorageNamespace* local_storage =
+ GetStorageNamespace(kLocalStorageNamespaceId, false);
+ if (local_storage)
+ local_storage->PurgeMemory();
+}
+
+void DOMStorageContext::DeleteDataModifiedSince(
+ const base::Time& cutoff,
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins) {
+ // Make sure that we don't delete a database that's currently being accessed
+ // by unloading all of the databases temporarily.
+ PurgeMemory();
+
+ file_util::FileEnumerator file_enumerator(
+ data_path_.Append(kLocalStorageDirectory), false,
+ file_util::FileEnumerator::FILES);
+ for (FilePath path = file_enumerator.Next(); !path.value().empty();
+ path = file_enumerator.Next()) {
+ WebSecurityOrigin web_security_origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathToWebString(path.BaseName()));
+ if (EqualsASCII(web_security_origin.protocol(), url_scheme_to_be_skipped))
+ continue;
+
+ std::vector<string16>::const_iterator find_iter =
+ std::find(protected_origins.begin(), protected_origins.end(),
+ web_security_origin.databaseIdentifier());
+ if (find_iter != protected_origins.end())
+ continue;
+
+ file_util::FileEnumerator::FindInfo find_info;
+ file_enumerator.GetFindInfo(&find_info);
+ if (file_util::HasFileBeenModifiedSince(find_info, cutoff))
+ file_util::Delete(path, false);
+ }
+}
+
+void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+
+ // Make sure that we don't delete a database that's currently being accessed
+ // by unloading all of the databases temporarily.
+ // TODO(bulach): both this method and DeleteDataModifiedSince could purge
+ // only the memory used by the specific file instead of all memory at once.
+ // See http://crbug.com/32000
+ PurgeMemory();
+ file_util::Delete(file_path, false);
+}
+
+void DOMStorageContext::DeleteLocalStorageForOrigin(const string16& origin_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DeleteLocalStorageFile(GetLocalStorageFilePath(origin_id));
+}
+
+void DOMStorageContext::DeleteAllLocalStorageFiles() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+
+ // Make sure that we don't delete a database that's currently being accessed
+ // by unloading all of the databases temporarily.
+ PurgeMemory();
+
+ file_util::FileEnumerator file_enumerator(
+ data_path_.Append(kLocalStorageDirectory), false,
+ file_util::FileEnumerator::FILES);
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() == kLocalStorageExtension)
+ file_util::Delete(file_path, false);
+ }
+}
+
+DOMStorageNamespace* DOMStorageContext::CreateLocalStorage() {
+ FilePath dir_path;
+ if (!data_path_.empty())
+ dir_path = data_path_.Append(kLocalStorageDirectory);
+ DOMStorageNamespace* new_namespace =
+ DOMStorageNamespace::CreateLocalStorageNamespace(this, dir_path);
+ RegisterStorageNamespace(new_namespace);
+ return new_namespace;
+}
+
+DOMStorageNamespace* DOMStorageContext::CreateSessionStorage(
+ int64 namespace_id) {
+ DOMStorageNamespace* new_namespace =
+ DOMStorageNamespace::CreateSessionStorageNamespace(this, namespace_id);
+ RegisterStorageNamespace(new_namespace);
+ return new_namespace;
+}
+
+void DOMStorageContext::RegisterStorageNamespace(
+ DOMStorageNamespace* storage_namespace) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ int64 id = storage_namespace->id();
+ DCHECK(!GetStorageNamespace(id, false));
+ storage_namespace_map_[id] = storage_namespace;
+}
+
+/* static */
+void DOMStorageContext::CompleteCloningSessionStorage(
+ DOMStorageContext* context, int64 existing_id, int64 clone_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageNamespace* existing_namespace =
+ context->GetStorageNamespace(existing_id, false);
+ // If nothing exists, then there's nothing to clone.
+ if (existing_namespace)
+ context->RegisterStorageNamespace(existing_namespace->Copy(clone_id));
+}
+
+FilePath DOMStorageContext::GetLocalStorageFilePath(
+ const string16& origin_id) const {
+ FilePath storageDir = data_path_.Append(
+ DOMStorageContext::kLocalStorageDirectory);
+ FilePath::StringType id =
+ webkit_glue::WebStringToFilePathString(origin_id);
+ return storageDir.Append(id.append(kLocalStorageExtension));
+}
diff --git a/content/browser/in_process_webkit/dom_storage_context.h b/content/browser/in_process_webkit/dom_storage_context.h
new file mode 100644
index 0000000..6810453
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_context.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
+#pragma once
+
+#include <map>
+#include <set>
+
+#include "base/file_path.h"
+#include "base/string16.h"
+#include "base/time.h"
+
+class DOMStorageArea;
+class DOMStorageMessageFilter;
+class DOMStorageNamespace;
+class WebKitContext;
+
+// This is owned by WebKitContext and is all the dom storage information that's
+// shared by all the DOMStorageMessageFilters that share the same profile. The
+// specifics of responsibilities are fairly well documented here and in
+// StorageNamespace and StorageArea. Everything is only to be accessed on the
+// WebKit thread unless noted otherwise.
+//
+// NOTE: Virtual methods facilitate mocking functions for testing.
+class DOMStorageContext {
+ public:
+ explicit DOMStorageContext(WebKitContext* webkit_context);
+ virtual ~DOMStorageContext();
+
+ // Invalid storage id. No storage session will ever report this value.
+ // Used in DOMStorageMessageFilter::OnStorageAreaId when coping with
+ // interactions with non-existent storage sessions.
+ static const int64 kInvalidStorageId = -1;
+
+ // Allocate a new storage area id. Only call on the WebKit thread.
+ int64 AllocateStorageAreaId();
+
+ // Allocate a new session storage id. Only call on the UI or IO thread.
+ int64 AllocateSessionStorageNamespaceId();
+
+ // Clones a session storage namespace and returns the cloned namespaces' id.
+ // Only call on the IO thread.
+ int64 CloneSessionStorage(int64 original_id);
+
+ // Various storage area methods. The storage area is owned by one of the
+ // namespaces that's owned by this class.
+ void RegisterStorageArea(DOMStorageArea* storage_area);
+ void UnregisterStorageArea(DOMStorageArea* storage_area);
+ DOMStorageArea* GetStorageArea(int64 id);
+
+ // Called on WebKit thread when a session storage namespace can be deleted.
+ void DeleteSessionStorageNamespace(int64 namespace_id);
+
+ // Get a namespace from an id. What's returned is owned by this class. If
+ // allocation_allowed is true, then this function will create the storage
+ // namespace if it hasn't been already.
+ DOMStorageNamespace* GetStorageNamespace(int64 id, bool allocation_allowed);
+
+ // Sometimes an event from one DOM storage message filter requires
+ // communication to all of them.
+ typedef std::set<DOMStorageMessageFilter*> MessageFilterSet;
+ void RegisterMessageFilter(DOMStorageMessageFilter* message_filter);
+ void UnregisterMessageFilter(DOMStorageMessageFilter* MessageFilter);
+ const MessageFilterSet* GetMessageFilterSet() const;
+
+ // Tells storage namespaces to purge any memory they do not need.
+ virtual void PurgeMemory();
+
+ // Delete any local storage files that have been touched since the cutoff
+ // date that's supplied.
+ void DeleteDataModifiedSince(const base::Time& cutoff,
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins);
+
+ // Deletes a single local storage file.
+ void DeleteLocalStorageFile(const FilePath& file_path);
+
+ // Deletes the local storage file for the given origin.
+ void DeleteLocalStorageForOrigin(const string16& origin_id);
+
+ // Deletes all local storage files.
+ void DeleteAllLocalStorageFiles();
+
+ // The local storage directory.
+ static const FilePath::CharType kLocalStorageDirectory[];
+
+ // The local storage file extension.
+ static const FilePath::CharType kLocalStorageExtension[];
+
+ // Get the file name of the local storage file for the given origin.
+ FilePath GetLocalStorageFilePath(const string16& origin_id) const;
+
+ void set_clear_local_state_on_exit_(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
+
+#ifdef UNIT_TEST
+ // For unit tests allow to override the |data_path_|.
+ void set_data_path(const FilePath& data_path) { data_path_ = data_path; }
+#endif
+
+ private:
+ // Get the local storage instance. The object is owned by this class.
+ DOMStorageNamespace* CreateLocalStorage();
+
+ // Get a new session storage namespace. The object is owned by this class.
+ DOMStorageNamespace* CreateSessionStorage(int64 namespace_id);
+
+ // Used internally to register storage namespaces we create.
+ void RegisterStorageNamespace(DOMStorageNamespace* storage_namespace);
+
+ // The WebKit thread half of CloneSessionStorage above. Static because
+ // DOMStorageContext isn't ref counted thus we can't use a runnable method.
+ // That said, we know this is safe because this class is destroyed on the
+ // WebKit thread, so there's no way it could be destroyed before this is run.
+ static void CompleteCloningSessionStorage(DOMStorageContext* context,
+ int64 existing_id, int64 clone_id);
+
+ // The last used storage_area_id and storage_namespace_id's. For the storage
+ // namespaces, IDs allocated on the UI thread are positive and count up while
+ // IDs allocated on the IO thread are negative and count down. This allows us
+ // to allocate unique IDs on both without any locking. All storage area ids
+ // are allocated on the WebKit thread.
+ int64 last_storage_area_id_;
+ int64 last_session_storage_namespace_id_on_ui_thread_;
+ int64 last_session_storage_namespace_id_on_io_thread_;
+
+ // True if the destructor should delete its files.
+ bool clear_local_state_on_exit_;
+
+ // Path where the profile data is stored.
+ // TODO(pastarmovj): Keep in mind that unlike indexed db data_path_ variable
+ // this one still has to point to the upper level dir because of the
+ // MigrateLocalStorageDirectory function. Once this function disappears we can
+ // make it point directly to the dom storage path.
+ FilePath data_path_;
+
+ // All the DOMStorageMessageFilters that are attached to us. ONLY USE ON THE
+ // IO THREAD!
+ MessageFilterSet message_filter_set_;
+
+ // Maps ids to StorageAreas. We do NOT own these objects. StorageNamespace
+ // (which does own them) will notify us when we should remove the entries.
+ typedef std::map<int64, DOMStorageArea*> StorageAreaMap;
+ StorageAreaMap storage_area_map_;
+
+ // Maps ids to StorageNamespaces. We own these objects.
+ typedef std::map<int64, DOMStorageNamespace*> StorageNamespaceMap;
+ StorageNamespaceMap storage_namespace_map_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContext);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_CONTEXT_H_
diff --git a/content/browser/in_process_webkit/dom_storage_message_filter.cc b/content/browser/in_process_webkit/dom_storage_message_filter.cc
new file mode 100644
index 0000000..3043dbb
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_message_filter.cc
@@ -0,0 +1,232 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/dom_storage_message_filter.h"
+
+#include "base/nullable_string16.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/common/dom_storage_messages.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/in_process_webkit/dom_storage_area.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/dom_storage_namespace.h"
+#include "content/browser/renderer_host/render_view_host_notification_task.h"
+#include "googleurl/src/gurl.h"
+
+using WebKit::WebStorageArea;
+
+DOMStorageMessageFilter* DOMStorageMessageFilter::storage_event_message_filter =
+ NULL;
+const GURL* DOMStorageMessageFilter::storage_event_url_ = NULL;
+
+DOMStorageMessageFilter::
+ScopedStorageEventContext::ScopedStorageEventContext(
+ DOMStorageMessageFilter* dispatcher_message_filter, const GURL* url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(!storage_event_message_filter);
+ DCHECK(!storage_event_url_);
+ storage_event_message_filter = dispatcher_message_filter;
+ storage_event_url_ = url;
+ DCHECK(storage_event_message_filter);
+ DCHECK(storage_event_url_);
+}
+
+DOMStorageMessageFilter::
+ScopedStorageEventContext::~ScopedStorageEventContext() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(storage_event_message_filter);
+ DCHECK(storage_event_url_);
+ storage_event_message_filter = NULL;
+ storage_event_url_ = NULL;
+}
+
+DOMStorageMessageFilter::DOMStorageMessageFilter(int process_id,
+ Profile* profile)
+ : webkit_context_(profile->GetWebKitContext()),
+ process_id_(process_id),
+ host_content_settings_map_(profile->GetHostContentSettingsMap()) {
+}
+
+DOMStorageMessageFilter::~DOMStorageMessageFilter() {
+ // This is not always true during testing.
+ if (peer_handle())
+ Context()->UnregisterMessageFilter(this);
+}
+
+void DOMStorageMessageFilter::OnChannelConnected(int32 peer_pid) {
+ BrowserMessageFilter::OnChannelConnected(peer_pid);
+
+ Context()->RegisterMessageFilter(this);
+}
+
+/* static */
+void DOMStorageMessageFilter::DispatchStorageEvent(const NullableString16& key,
+ const NullableString16& old_value, const NullableString16& new_value,
+ const string16& origin, const GURL& url, bool is_local_storage) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(is_local_storage); // Only LocalStorage is implemented right now.
+ DCHECK(storage_event_message_filter);
+ DOMStorageMsg_Event_Params params;
+ params.key = key;
+ params.old_value = old_value;
+ params.new_value = new_value;
+ params.origin = origin;
+ params.url = *storage_event_url_; // The url passed in is junk.
+ params.storage_type = is_local_storage ? DOM_STORAGE_LOCAL
+ : DOM_STORAGE_SESSION;
+ // The storage_event_message_filter is the DOMStorageMessageFilter that is up
+ // in the current call stack since it caused the storage event to fire.
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(storage_event_message_filter,
+ &DOMStorageMessageFilter::OnStorageEvent, params));
+}
+
+bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_StorageAreaId, OnStorageAreaId)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Length, OnLength)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Key, OnKey)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_GetItem, OnGetItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem)
+ IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void DOMStorageMessageFilter::OnDestruct() const {
+ BrowserThread::DeleteOnIOThread::Destruct(this);
+}
+
+void DOMStorageMessageFilter::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart)
+ *thread = BrowserThread::WEBKIT;
+}
+
+void DOMStorageMessageFilter::OnStorageAreaId(int64 namespace_id,
+ const string16& origin,
+ int64* storage_area_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+
+ DOMStorageNamespace* storage_namespace =
+ Context()->GetStorageNamespace(namespace_id, true);
+ if (!storage_namespace) {
+ *storage_area_id = DOMStorageContext::kInvalidStorageId;
+ return;
+ }
+ DOMStorageArea* storage_area = storage_namespace->GetStorageArea(
+ origin, host_content_settings_map_);
+ *storage_area_id = storage_area->id();
+}
+
+void DOMStorageMessageFilter::OnLength(int64 storage_area_id,
+ unsigned* length) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *length = 0;
+ } else {
+ *length = storage_area->Length();
+ }
+}
+
+void DOMStorageMessageFilter::OnKey(int64 storage_area_id, unsigned index,
+ NullableString16* key) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *key = NullableString16(true);
+ } else {
+ *key = storage_area->Key(index);
+ }
+}
+
+void DOMStorageMessageFilter::OnGetItem(int64 storage_area_id,
+ const string16& key,
+ NullableString16* value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *value = NullableString16(true);
+ } else {
+ *value = storage_area->GetItem(key);
+ }
+}
+
+void DOMStorageMessageFilter::OnSetItem(
+ int render_view_id, int64 storage_area_id, const string16& key,
+ const string16& value, const GURL& url,
+ WebKit::WebStorageArea::Result* result, NullableString16* old_value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *old_value = NullableString16(true);
+ *result = WebKit::WebStorageArea::ResultOK;
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *old_value = storage_area->SetItem(key, value, result);
+
+ // If content was blocked, tell the UI to display the blocked content icon.
+ if (render_view_id == MSG_ROUTING_CONTROL) {
+ DLOG(WARNING) << "setItem was not given a proper routing id";
+ } else {
+ CallRenderViewHostContentSettingsDelegate(
+ process_id_, render_view_id,
+ &RenderViewHostDelegate::ContentSettings::OnLocalStorageAccessed,
+ url, storage_area->owner()->dom_storage_type(),
+ *result == WebStorageArea::ResultBlockedByPolicy);
+ }
+}
+
+void DOMStorageMessageFilter::OnRemoveItem(
+ int64 storage_area_id, const string16& key, const GURL& url,
+ NullableString16* old_value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *old_value = NullableString16(true);
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *old_value = storage_area->RemoveItem(key);
+}
+
+void DOMStorageMessageFilter::OnClear(int64 storage_area_id, const GURL& url,
+ bool* something_cleared) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id);
+ if (!storage_area) {
+ *something_cleared = false;
+ return;
+ }
+
+ ScopedStorageEventContext scope(this, &url);
+ *something_cleared = storage_area->Clear();
+}
+
+void DOMStorageMessageFilter::OnStorageEvent(
+ const DOMStorageMsg_Event_Params& params) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const DOMStorageContext::MessageFilterSet* set =
+ Context()->GetMessageFilterSet();
+ DOMStorageContext::MessageFilterSet::const_iterator cur = set->begin();
+ while (cur != set->end()) {
+ // The renderer that generates the event handles it itself.
+ if (*cur != this)
+ (*cur)->Send(new DOMStorageMsg_Event(params));
+ ++cur;
+ }
+}
diff --git a/content/browser/in_process_webkit/dom_storage_message_filter.h b/content/browser/in_process_webkit/dom_storage_message_filter.h
new file mode 100644
index 0000000..0140eef
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_message_filter.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
+#pragma once
+
+#include "base/process.h"
+#include "base/ref_counted.h"
+#include "base/tracked.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/common/dom_storage_common.h"
+#include "content/browser/browser_message_filter.h"
+#include "content/browser/in_process_webkit/dom_storage_area.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "ipc/ipc_message.h"
+
+class DOMStorageContext;
+class GURL;
+class Profile;
+struct DOMStorageMsg_Event_Params;
+
+// This class handles the logistics of DOM Storage within the browser process.
+// It mostly ferries information between IPCs and the WebKit implementations,
+// but it also handles some special cases like when renderer processes die.
+class DOMStorageMessageFilter : public BrowserMessageFilter {
+ public:
+ // Only call the constructor from the UI thread.
+ DOMStorageMessageFilter(int process_id, Profile* profile);
+
+ // BrowserMessageFilter implementation
+ virtual void OnChannelConnected(int32 peer_pid);
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+ virtual void OnDestruct() const;
+
+ // Only call on the WebKit thread.
+ static void DispatchStorageEvent(const NullableString16& key,
+ const NullableString16& old_value, const NullableString16& new_value,
+ const string16& origin, const GURL& url, bool is_local_storage);
+
+ private:
+ friend class BrowserThread;
+ friend class DeleteTask<DOMStorageMessageFilter>;
+ ~DOMStorageMessageFilter();
+
+ // Message Handlers.
+ void OnStorageAreaId(int64 namespace_id, const string16& origin,
+ int64* storage_area_id);
+ void OnLength(int64 storage_area_id, unsigned* length);
+ void OnKey(int64 storage_area_id, unsigned index, NullableString16* key);
+ void OnGetItem(int64 storage_area_id, const string16& key,
+ NullableString16* value);
+ void OnSetItem(int render_view_id, int64 storage_area_id, const string16& key,
+ const string16& value, const GURL& url,
+ WebKit::WebStorageArea::Result* result,
+ NullableString16* old_value);
+ void OnRemoveItem(int64 storage_area_id, const string16& key,
+ const GURL& url, NullableString16* old_value);
+ void OnClear(int64 storage_area_id, const GURL& url, bool* something_cleared);
+
+ // Only call on the IO thread.
+ void OnStorageEvent(const DOMStorageMsg_Event_Params& params);
+
+ // A shortcut for accessing our context.
+ DOMStorageContext* Context() {
+ return webkit_context_->dom_storage_context();
+ }
+
+ // Use whenever there's a chance OnStorageEvent will be called.
+ class ScopedStorageEventContext {
+ public:
+ ScopedStorageEventContext(
+ DOMStorageMessageFilter* dispatcher_message_filter,
+ const GURL* url);
+ ~ScopedStorageEventContext();
+ };
+
+ // Only access on the WebKit thread! Used for storage events.
+ static DOMStorageMessageFilter* storage_event_message_filter;
+ static const GURL* storage_event_url_;
+
+ // Data shared between renderer processes with the same profile.
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ // Used to dispatch messages to the correct view host.
+ int process_id_;
+
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageMessageFilter);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_MESSAGE_FILTER_H_
diff --git a/content/browser/in_process_webkit/dom_storage_message_filter_unittest.cc b/content/browser/in_process_webkit/dom_storage_message_filter_unittest.cc
new file mode 100644
index 0000000..c56ee71
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_message_filter_unittest.cc
@@ -0,0 +1,8 @@
+// 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/browser/in_process_webkit/dom_storage_message_filter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TODO(jorlow): Write me
diff --git a/content/browser/in_process_webkit/dom_storage_namespace.cc b/content/browser/in_process_webkit/dom_storage_namespace.cc
new file mode 100644
index 0000000..6cfccf8c
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_namespace.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/dom_storage_namespace.h"
+
+#include "base/file_path.h"
+#include "content/browser/in_process_webkit/dom_storage_area.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/dom_storage_message_filter.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageArea.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageNamespace.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebStorageArea;
+using WebKit::WebStorageNamespace;
+using WebKit::WebString;
+
+/* static */
+DOMStorageNamespace* DOMStorageNamespace::CreateLocalStorageNamespace(
+ DOMStorageContext* dom_storage_context, const FilePath& data_dir_path) {
+ int64 id = kLocalStorageNamespaceId;
+ DCHECK(!dom_storage_context->GetStorageNamespace(id, false));
+ return new DOMStorageNamespace(dom_storage_context, id,
+ webkit_glue::FilePathToWebString(data_dir_path), DOM_STORAGE_LOCAL);
+}
+
+/* static */
+DOMStorageNamespace* DOMStorageNamespace::CreateSessionStorageNamespace(
+ DOMStorageContext* dom_storage_context, int64 id) {
+ DCHECK(!dom_storage_context->GetStorageNamespace(id, false));
+ return new DOMStorageNamespace(dom_storage_context, id, WebString(),
+ DOM_STORAGE_SESSION);
+}
+
+DOMStorageNamespace::DOMStorageNamespace(DOMStorageContext* dom_storage_context,
+ int64 id,
+ const WebString& data_dir_path,
+ DOMStorageType dom_storage_type)
+ : dom_storage_context_(dom_storage_context),
+ id_(id),
+ data_dir_path_(data_dir_path),
+ dom_storage_type_(dom_storage_type) {
+ DCHECK(dom_storage_context_);
+}
+
+DOMStorageNamespace::~DOMStorageNamespace() {
+ // TODO(jorlow): If the DOMStorageContext is being destructed, there's no need
+ // to do these calls. Maybe we should add a fast path?
+ for (OriginToStorageAreaMap::iterator iter(origin_to_storage_area_.begin());
+ iter != origin_to_storage_area_.end(); ++iter) {
+ dom_storage_context_->UnregisterStorageArea(iter->second);
+ delete iter->second;
+ }
+}
+
+DOMStorageArea* DOMStorageNamespace::GetStorageArea(
+ const string16& origin,
+ HostContentSettingsMap* host_content_settings_map) {
+ // We may have already created it for another dispatcher host.
+ OriginToStorageAreaMap::iterator iter = origin_to_storage_area_.find(origin);
+ if (iter != origin_to_storage_area_.end())
+ return iter->second;
+
+ // We need to create a new one.
+ int64 id = dom_storage_context_->AllocateStorageAreaId();
+ DCHECK(!dom_storage_context_->GetStorageArea(id));
+ DOMStorageArea* storage_area = new DOMStorageArea(origin, id, this,
+ host_content_settings_map);
+ origin_to_storage_area_[origin] = storage_area;
+ dom_storage_context_->RegisterStorageArea(storage_area);
+ return storage_area;
+}
+
+DOMStorageNamespace* DOMStorageNamespace::Copy(int64 id) {
+ DCHECK(dom_storage_type_ == DOM_STORAGE_SESSION);
+ DCHECK(!dom_storage_context_->GetStorageNamespace(id, false));
+ DOMStorageNamespace* new_storage_namespace = new DOMStorageNamespace(
+ dom_storage_context_, id, data_dir_path_, dom_storage_type_);
+ // If we haven't used the namespace yet, there's nothing to copy.
+ if (storage_namespace_.get())
+ new_storage_namespace->storage_namespace_.reset(storage_namespace_->copy());
+ return new_storage_namespace;
+}
+
+void DOMStorageNamespace::PurgeMemory() {
+ DCHECK(dom_storage_type_ == DOM_STORAGE_LOCAL);
+ for (OriginToStorageAreaMap::iterator iter(origin_to_storage_area_.begin());
+ iter != origin_to_storage_area_.end(); ++iter)
+ iter->second->PurgeMemory();
+ storage_namespace_.reset();
+}
+
+WebStorageArea* DOMStorageNamespace::CreateWebStorageArea(
+ const string16& origin) {
+ CreateWebStorageNamespaceIfNecessary();
+ return storage_namespace_->createStorageArea(origin);
+}
+
+void DOMStorageNamespace::CreateWebStorageNamespaceIfNecessary() {
+ if (storage_namespace_.get())
+ return;
+
+ if (dom_storage_type_ == DOM_STORAGE_LOCAL) {
+ storage_namespace_.reset(
+ WebStorageNamespace::createLocalStorageNamespace(data_dir_path_,
+ WebStorageNamespace::m_localStorageQuota));
+ } else {
+ storage_namespace_.reset(WebStorageNamespace::createSessionStorageNamespace(
+ WebStorageNamespace::m_sessionStorageQuota));
+ }
+}
diff --git a/content/browser/in_process_webkit/dom_storage_namespace.h b/content/browser/in_process_webkit/dom_storage_namespace.h
new file mode 100644
index 0000000..b05a317
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_namespace.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_NAMESPACE_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_NAMESPACE_H_
+#pragma once
+
+#include "base/hash_tables.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/common/dom_storage_common.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+
+class DOMStorageArea;
+class DOMStorageContext;
+class FilePath;
+class HostContentSettingsMap;
+
+namespace WebKit {
+class WebStorageArea;
+class WebStorageNamespace;
+}
+
+// Only to be used on the WebKit thread.
+class DOMStorageNamespace {
+ public:
+ static DOMStorageNamespace* CreateLocalStorageNamespace(
+ DOMStorageContext* dom_storage_context, const FilePath& data_dir_path);
+ static DOMStorageNamespace* CreateSessionStorageNamespace(
+ DOMStorageContext* dom_storage_context, int64 namespace_id);
+
+ ~DOMStorageNamespace();
+
+ DOMStorageArea* GetStorageArea(const string16& origin,
+ HostContentSettingsMap* map);
+ DOMStorageNamespace* Copy(int64 clone_namespace_id);
+
+ void PurgeMemory();
+
+ const DOMStorageContext* dom_storage_context() const {
+ return dom_storage_context_;
+ }
+ int64 id() const { return id_; }
+ const WebKit::WebString& data_dir_path() const { return data_dir_path_; }
+ DOMStorageType dom_storage_type() const { return dom_storage_type_; }
+
+ // Creates a WebStorageArea for the given origin. This should only be called
+ // by an owned DOMStorageArea.
+ WebKit::WebStorageArea* CreateWebStorageArea(const string16& origin);
+
+ private:
+ // Called by the static factory methods above.
+ DOMStorageNamespace(DOMStorageContext* dom_storage_context,
+ int64 id,
+ const WebKit::WebString& data_dir_path,
+ DOMStorageType storage_type);
+
+ // Creates the underlying WebStorageNamespace on demand.
+ void CreateWebStorageNamespaceIfNecessary();
+
+ // All the storage areas we own.
+ typedef base::hash_map<string16, DOMStorageArea*> OriginToStorageAreaMap;
+ OriginToStorageAreaMap origin_to_storage_area_;
+
+ // The DOMStorageContext that owns us.
+ DOMStorageContext* dom_storage_context_;
+
+ // The WebKit storage namespace we manage.
+ scoped_ptr<WebKit::WebStorageNamespace> storage_namespace_;
+
+ // Our id. Unique to our parent WebKitContext class.
+ int64 id_;
+
+ // The path used to create us, so we can recreate our WebStorageNamespace on
+ // demand.
+ WebKit::WebString data_dir_path_;
+
+ // SessionStorage vs. LocalStorage.
+ const DOMStorageType dom_storage_type_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageNamespace);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_DOM_STORAGE_NAMESPACE_H_
diff --git a/content/browser/in_process_webkit/dom_storage_uitest.cc b/content/browser/in_process_webkit/dom_storage_uitest.cc
new file mode 100644
index 0000000..ac82728
--- /dev/null
+++ b/content/browser/in_process_webkit/dom_storage_uitest.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2011 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 "base/file_path.h"
+#include "base/file_util.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/automation/tab_proxy.h"
+#include "chrome/test/ui/ui_layout_test.h"
+#include "chrome/test/ui_test_utils.h"
+#include "net/base/net_util.h"
+
+static const char* kRootFiles[] = {
+ "clear.html",
+// "complex-keys.html", // Output too big for a cookie. crbug.com/33472
+// "complex-values.html", // crbug.com/33472
+ "quota.html",
+ "remove-item.html",
+ "window-attributes-exist.html",
+ NULL
+};
+
+static const char* kEventsFiles[] = {
+// "basic-body-attribute.html", // crbug.com/33472
+// "basic.html", // crbug.com/33472
+// "basic-setattribute.html", // crbug.com/33472
+ "case-sensitive.html",
+ "documentURI.html",
+ NULL
+};
+
+static const char* kStorageFiles[] = {
+ "delete-removal.html",
+ "enumerate-storage.html",
+ "enumerate-with-length-and-key.html",
+ "index-get-and-set.html",
+ "simple-usage.html",
+ "string-conversion.html",
+// "window-open.html", // TODO(jorlow): Fix
+ NULL
+};
+
+class DOMStorageTest : public UILayoutTest {
+ protected:
+ DOMStorageTest()
+ : UILayoutTest(),
+ test_dir_(FilePath().
+ AppendASCII("storage").AppendASCII("domstorage")) {
+ }
+
+ virtual ~DOMStorageTest() { }
+
+ virtual void SetUp() {
+ launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking);
+ UILayoutTest::SetUp();
+ }
+
+ // We require fast/js/resources for most of the DOM Storage layout tests.
+ // Add those to the list to be copied.
+ void AddJSTestResources() {
+ // Add other paths our tests require.
+ FilePath js_dir = FilePath().
+ AppendASCII("fast").AppendASCII("js");
+ AddResourceForLayoutTest(js_dir, FilePath().AppendASCII("resources"));
+ }
+
+ // This is somewhat of a hack because we're running a real browser that
+ // actually persists the LocalStorage state vs. DRT and TestShell which don't.
+ // The correct fix is to fix the LayoutTests, but similar patches have been
+ // rejected in the past.
+ void ClearDOMStorage() {
+ scoped_refptr<TabProxy> tab(GetActiveTab());
+ ASSERT_TRUE(tab.get());
+
+ const FilePath dir(FILE_PATH_LITERAL("layout_tests"));
+ const FilePath file(FILE_PATH_LITERAL("clear_dom_storage.html"));
+ GURL url = ui_test_utils::GetTestUrl(dir, file);
+ ASSERT_TRUE(tab->SetCookie(url, ""));
+ ASSERT_TRUE(tab->NavigateToURL(url));
+
+ WaitUntilCookieNonEmpty(tab.get(), url, "cleared",
+ TestTimeouts::action_max_timeout_ms());
+ }
+
+ // Runs each test in an array of strings until it hits a NULL.
+ void RunTests(const char** files) {
+ while (*files) {
+ ClearDOMStorage();
+ RunLayoutTest(*files, kNoHttpPort);
+ ++files;
+ }
+ }
+
+ FilePath test_dir_;
+};
+
+
+TEST_F(DOMStorageTest, RootLayoutTests) {
+ InitializeForLayoutTest(test_dir_, FilePath(), kNoHttpPort);
+ AddJSTestResources();
+ AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("script-tests"));
+ RunTests(kRootFiles);
+}
+
+TEST_F(DOMStorageTest, EventLayoutTests) {
+ InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("events"),
+ kNoHttpPort);
+ AddJSTestResources();
+ AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
+ AppendASCII("resources"));
+ AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("events").
+ AppendASCII("script-tests"));
+ RunTests(kEventsFiles);
+}
+
+TEST_F(DOMStorageTest, LocalStorageLayoutTests) {
+ InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage"),
+ kNoHttpPort);
+ AddJSTestResources();
+ AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("localstorage").
+ AppendASCII("resources"));
+ RunTests(kStorageFiles);
+}
+
+TEST_F(DOMStorageTest, SessionStorageLayoutTests) {
+ InitializeForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage"),
+ kNoHttpPort);
+ AddJSTestResources();
+ AddResourceForLayoutTest(test_dir_, FilePath().AppendASCII("sessionstorage").
+ AppendASCII("resources"));
+ RunTests(kStorageFiles);
+}
+
+class DomStorageEmptyDatabaseTest : public UITest {
+ protected:
+ FilePath StorageDir() const {
+ FilePath storage_dir = user_data_dir();
+ storage_dir = storage_dir.AppendASCII("Default");
+ storage_dir = storage_dir.AppendASCII("Local Storage");
+ return storage_dir;
+ }
+
+ bool StorageDirIsEmpty() const {
+ FilePath storage_dir = StorageDir();
+ if (!file_util::DirectoryExists(storage_dir))
+ return true;
+ return file_util::IsDirectoryEmpty(storage_dir);
+ }
+
+ GURL TestUrl() const {
+ FilePath test_dir = test_data_directory_;
+ FilePath test_file = test_dir.AppendASCII("dom_storage_empty_db.html");
+ return net::FilePathToFileURL(test_file);
+ }
+};
+
+TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterClear) {
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
+
+ NavigateToURL(GURL("javascript:set()"));
+ NavigateToURL(GURL("javascript:clear()"));
+ QuitBrowser();
+ EXPECT_TRUE(StorageDirIsEmpty());
+}
+
+TEST_F(DomStorageEmptyDatabaseTest, EmptyDirAfterGet) {
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
+
+ NavigateToURL(GURL("javascript:get()"));
+ QuitBrowser();
+ EXPECT_TRUE(StorageDirIsEmpty());
+}
+
+TEST_F(DomStorageEmptyDatabaseTest, NonEmptyDirAfterSet) {
+ NavigateToURL(TestUrl());
+ ASSERT_TRUE(StorageDirIsEmpty());
+
+ NavigateToURL(GURL("javascript:set()"));
+ QuitBrowser();
+ EXPECT_FALSE(StorageDirIsEmpty());
+
+ LaunchBrowserAndServer();
+ NavigateToURL(TestUrl());
+ NavigateToURL(GURL("javascript:clear()"));
+ QuitBrowser();
+ EXPECT_TRUE(StorageDirIsEmpty());
+}
diff --git a/content/browser/in_process_webkit/indexed_db_browsertest.cc b/content/browser/in_process_webkit/indexed_db_browsertest.cc
new file mode 100644
index 0000000..35f60b2
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_browsertest.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2010 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 "base/command_line.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/ref_counted.h"
+#include "base/scoped_temp_dir.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/in_process_browser_test.h"
+#include "chrome/test/testing_profile.h"
+#include "chrome/test/thread_test_helper.h"
+#include "chrome/test/ui_test_utils.h"
+#include "content/browser/in_process_webkit/indexed_db_context.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "content/browser/tab_contents/tab_contents.h"
+
+// This browser test is aimed towards exercising the IndexedDB bindings and
+// the actual implementation that lives in the browser side (in_process_webkit).
+class IndexedDBBrowserTest : public InProcessBrowserTest {
+ public:
+ IndexedDBBrowserTest() {
+ EnableDOMAutomation();
+ }
+
+ GURL testUrl(const FilePath& file_path) {
+ const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
+ return ui_test_utils::GetTestUrl(kTestDir, file_path);
+ }
+
+ void SimpleTest(const GURL& test_url) {
+ // The test page will perform tests on IndexedDB, then navigate to either
+ // a #pass or #fail ref.
+ LOG(INFO) << "Navigating to URL and blocking.";
+ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
+ browser(), test_url, 2);
+ LOG(INFO) << "Navigation done.";
+ std::string result = browser()->GetSelectedTabContents()->GetURL().ref();
+ if (result != "pass") {
+ std::string js_result;
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(), L"",
+ L"window.domAutomationController.send(getLog())", &js_result));
+ FAIL() << "Failed: " << js_result;
+ }
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))));
+}
+
+// Flaky: http://crbug.com/70773
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_IndexTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
+}
+
+// Flaky: http://crbug.com/70773
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_KeyPathTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_path_test.html"))));
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_get_test.html"))));
+}
+
+// Flaky: http://crbug.com/70773
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_ObjectStoreTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("object_store_test.html"))));
+}
+
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
+}
+
+// Flaky: http://crbug.com/70773
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_TransactionTest) {
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
+}
+
+// Flaky: http://crbug.com/70773
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_DoesntHangTest) {
+ SimpleTest(testUrl(FilePath(
+ FILE_PATH_LITERAL("transaction_run_forever.html"))));
+ ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
+ SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
+}
+
+// In proc browser test is needed here because ClearLocalState indirectly calls
+// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
+IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
+ // Create test files.
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath indexeddb_dir = temp_dir.path().Append(
+ IndexedDBContext::kIndexedDBDirectory);
+ ASSERT_TRUE(file_util::CreateDirectory(indexeddb_dir));
+
+ FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
+ file_name_1.append(IndexedDBContext::kIndexedDBExtension);
+ FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
+ file_name_2.append(IndexedDBContext::kIndexedDBExtension);
+ FilePath temp_file_path_1 = indexeddb_dir.Append(file_name_1);
+ FilePath temp_file_path_2 = indexeddb_dir.Append(file_name_2);
+
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
+ ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));
+
+ // Create the scope which will ensure we run the destructor of the webkit
+ // context which should trigger the clean up.
+ {
+ TestingProfile profile;
+ WebKitContext *webkit_context = profile.GetWebKitContext();
+ webkit_context->indexed_db_context()->set_data_path(indexeddb_dir);
+ webkit_context->set_clear_local_state_on_exit(true);
+ }
+ // Make sure we wait until the destructor has run.
+ scoped_refptr<ThreadTestHelper> helper(
+ new ThreadTestHelper(BrowserThread::WEBKIT));
+ ASSERT_TRUE(helper->Run());
+
+ // Because we specified https for scheme to be skipped the second file
+ // should survive and the first go into vanity.
+ ASSERT_FALSE(file_util::PathExists(temp_file_path_1));
+ ASSERT_TRUE(file_util::PathExists(temp_file_path_2));
+}
diff --git a/content/browser/in_process_webkit/indexed_db_callbacks.cc b/content/browser/in_process_webkit/indexed_db_callbacks.cc
new file mode 100644
index 0000000..9c9679e
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_callbacks.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/indexed_db_callbacks.h"
+
+#include "chrome/common/indexed_db_messages.h"
+
+IndexedDBCallbacksBase::IndexedDBCallbacksBase(
+ IndexedDBDispatcherHost* dispatcher_host,
+ int32 response_id)
+ : dispatcher_host_(dispatcher_host),
+ response_id_(response_id) {
+}
+
+IndexedDBCallbacksBase::~IndexedDBCallbacksBase() {}
+
+IndexedDBTransactionCallbacks::IndexedDBTransactionCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host,
+ int transaction_id)
+ : dispatcher_host_(dispatcher_host),
+ transaction_id_(transaction_id) {
+}
+
+IndexedDBTransactionCallbacks::~IndexedDBTransactionCallbacks() {}
+
+void IndexedDBCallbacksBase::onError(const WebKit::WebIDBDatabaseError& error) {
+ dispatcher_host_->Send(new IndexedDBMsg_CallbacksError(
+ response_id_, error.code(), error.message()));
+}
+
+void IndexedDBCallbacksBase::onBlocked() {
+ dispatcher_host_->Send(new IndexedDBMsg_CallbacksBlocked(response_id_));
+}
+
+void IndexedDBTransactionCallbacks::onAbort() {
+ dispatcher_host_->Send(
+ new IndexedDBMsg_TransactionCallbacksAbort(transaction_id_));
+}
+
+void IndexedDBTransactionCallbacks::onComplete() {
+ dispatcher_host_->Send(
+ new IndexedDBMsg_TransactionCallbacksComplete(transaction_id_));
+}
+
+void IndexedDBTransactionCallbacks::onTimeout() {
+ dispatcher_host_->Send(
+ new IndexedDBMsg_TransactionCallbacksTimeout(transaction_id_));
+}
+
+void IndexedDBCallbacks<WebKit::WebIDBCursor>::onSuccess(
+ WebKit::WebIDBCursor* idb_object) {
+ int32 object_id = dispatcher_host()->Add(idb_object);
+ dispatcher_host()->Send(
+ new IndexedDBMsg_CallbacksSuccessIDBCursor(response_id(), object_id));
+}
+
+void IndexedDBCallbacks<WebKit::WebIDBCursor>::onSuccess(
+ const WebKit::WebSerializedScriptValue& value) {
+ dispatcher_host()->Send(
+ new IndexedDBMsg_CallbacksSuccessSerializedScriptValue(
+ response_id(), SerializedScriptValue(value)));
+}
+
+void IndexedDBCallbacks<WebKit::WebIDBKey>::onSuccess(
+ const WebKit::WebIDBKey& value) {
+ dispatcher_host()->Send(
+ new IndexedDBMsg_CallbacksSuccessIndexedDBKey(
+ response_id(), IndexedDBKey(value)));
+}
+
+void IndexedDBCallbacks<WebKit::WebSerializedScriptValue>::onSuccess(
+ const WebKit::WebSerializedScriptValue& value) {
+ dispatcher_host()->Send(
+ new IndexedDBMsg_CallbacksSuccessSerializedScriptValue(
+ response_id(), SerializedScriptValue(value)));
+}
diff --git a/content/browser/in_process_webkit/indexed_db_callbacks.h b/content/browser/in_process_webkit/indexed_db_callbacks.h
new file mode 100644
index 0000000..853573c
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_callbacks.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+#include "content/browser/in_process_webkit/indexed_db_dispatcher_host.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBCallbacks.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBCursor.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabaseError.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBTransaction.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBTransactionCallbacks.h"
+
+class IndexedDBMsg_CallbacksSuccessIDBDatabase;
+class IndexedDBMsg_CallbacksSuccessIDBIndex;
+class IndexedDBMsg_CallbacksSuccessIDBObjectStore;
+class IndexedDBMsg_CallbacksSuccessIDBTransaction;
+
+// Template magic to figure out what message to send to the renderer based on
+// which (overloaded) onSuccess method we expect to be called.
+template <class Type> struct WebIDBToMsgHelper { };
+template <> struct WebIDBToMsgHelper<WebKit::WebIDBDatabase> {
+ typedef IndexedDBMsg_CallbacksSuccessIDBDatabase MsgType;
+};
+template <> struct WebIDBToMsgHelper<WebKit::WebIDBIndex> {
+ typedef IndexedDBMsg_CallbacksSuccessIDBIndex MsgType;
+};
+template <> struct WebIDBToMsgHelper<WebKit::WebIDBObjectStore> {
+ typedef IndexedDBMsg_CallbacksSuccessIDBObjectStore MsgType;
+};
+template <> struct WebIDBToMsgHelper<WebKit::WebIDBTransaction> {
+ typedef IndexedDBMsg_CallbacksSuccessIDBTransaction MsgType;
+};
+
+// The code the following two classes share.
+class IndexedDBCallbacksBase : public WebKit::WebIDBCallbacks {
+ public:
+ IndexedDBCallbacksBase(IndexedDBDispatcherHost* dispatcher_host,
+ int32 response_id);
+
+ virtual ~IndexedDBCallbacksBase();
+
+ virtual void onError(const WebKit::WebIDBDatabaseError& error);
+ virtual void onBlocked();
+
+ protected:
+ IndexedDBDispatcherHost* dispatcher_host() const {
+ return dispatcher_host_.get();
+ }
+ int32 response_id() const { return response_id_; }
+
+ private:
+ scoped_refptr<IndexedDBDispatcherHost> dispatcher_host_;
+ int32 response_id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacksBase);
+};
+
+// A WebIDBCallbacks implementation that returns an object of WebObjectType.
+template <class WebObjectType>
+class IndexedDBCallbacks : public IndexedDBCallbacksBase {
+ public:
+ IndexedDBCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int32 response_id)
+ : IndexedDBCallbacksBase(dispatcher_host, response_id) { }
+
+ virtual void onSuccess(WebObjectType* idb_object) {
+ int32 object_id = dispatcher_host()->Add(idb_object);
+ dispatcher_host()->Send(
+ new typename WebIDBToMsgHelper<WebObjectType>::MsgType(response_id(),
+ object_id));
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
+};
+
+// WebIDBCursor uses onSuccess(WebIDBCursor*) to indicate it has data, and
+// onSuccess() without params to indicate it does not contain any data, i.e.,
+// there is no key within the key range, or it has reached the end.
+template <>
+class IndexedDBCallbacks<WebKit::WebIDBCursor>
+ : public IndexedDBCallbacksBase {
+ public:
+ IndexedDBCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int32 response_id)
+ : IndexedDBCallbacksBase(dispatcher_host, response_id) { }
+
+ virtual void onSuccess(WebKit::WebIDBCursor* idb_object);
+ virtual void onSuccess(const WebKit::WebSerializedScriptValue& value);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
+};
+
+// WebIDBKey is implemented in WebKit as opposed to being an interface Chromium
+// implements. Thus we pass a const ___& version and thus we need this
+// specialization.
+template <>
+class IndexedDBCallbacks<WebKit::WebIDBKey>
+ : public IndexedDBCallbacksBase {
+ public:
+ IndexedDBCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int32 response_id)
+ : IndexedDBCallbacksBase(dispatcher_host, response_id) { }
+
+ virtual void onSuccess(const WebKit::WebIDBKey& value);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
+};
+
+// WebSerializedScriptValue is implemented in WebKit as opposed to being an
+// interface Chromium implements. Thus we pass a const ___& version and thus
+// we need this specialization.
+template <>
+class IndexedDBCallbacks<WebKit::WebSerializedScriptValue>
+ : public IndexedDBCallbacksBase {
+ public:
+ IndexedDBCallbacks(
+ IndexedDBDispatcherHost* dispatcher_host, int32 response_id)
+ : IndexedDBCallbacksBase(dispatcher_host, response_id) { }
+
+ virtual void onSuccess(const WebKit::WebSerializedScriptValue& value);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBCallbacks);
+};
+
+class IndexedDBTransactionCallbacks
+ : public WebKit::WebIDBTransactionCallbacks {
+ public:
+ IndexedDBTransactionCallbacks(IndexedDBDispatcherHost* dispatcher_host,
+ int transaction_id);
+
+ virtual ~IndexedDBTransactionCallbacks();
+
+ virtual void onAbort();
+
+ virtual void onComplete();
+
+ virtual void onTimeout();
+
+ private:
+ scoped_refptr<IndexedDBDispatcherHost> dispatcher_host_;
+ int transaction_id_;
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CALLBACKS_H_
diff --git a/content/browser/in_process_webkit/indexed_db_context.cc b/content/browser/in_process_webkit/indexed_db_context.cc
new file mode 100644
index 0000000..0c590f7
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_context.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/indexed_db_context.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBFactory;
+using WebKit::WebSecurityOrigin;
+
+namespace {
+
+void ClearLocalState(const FilePath& indexeddb_path,
+ const char* url_scheme_to_be_skipped) {
+ file_util::FileEnumerator file_enumerator(
+ indexeddb_path, false, file_util::FileEnumerator::FILES);
+ // TODO(pastarmovj): We might need to consider exchanging this loop for
+ // something more efficient in the future.
+ for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
+ file_path = file_enumerator.Next()) {
+ if (file_path.Extension() != IndexedDBContext::kIndexedDBExtension)
+ continue;
+ WebSecurityOrigin origin =
+ WebSecurityOrigin::createFromDatabaseIdentifier(
+ webkit_glue::FilePathToWebString(file_path.BaseName()));
+ if (!EqualsASCII(origin.protocol(), url_scheme_to_be_skipped))
+ file_util::Delete(file_path, false);
+ }
+}
+
+} // namespace
+
+const FilePath::CharType IndexedDBContext::kIndexedDBDirectory[] =
+ FILE_PATH_LITERAL("IndexedDB");
+
+const FilePath::CharType IndexedDBContext::kIndexedDBExtension[] =
+ FILE_PATH_LITERAL(".indexeddb");
+
+IndexedDBContext::IndexedDBContext(WebKitContext* webkit_context)
+ : clear_local_state_on_exit_(false) {
+ data_path_ = webkit_context->data_path().Append(kIndexedDBDirectory);
+}
+
+IndexedDBContext::~IndexedDBContext() {
+ // Not being on the WEBKIT thread here means we are running in a unit test
+ // where no clean up is needed.
+ if (clear_local_state_on_exit_ &&
+ BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ ClearLocalState(data_path_, chrome::kExtensionScheme);
+ }
+}
+
+WebIDBFactory* IndexedDBContext::GetIDBFactory() {
+ if (!idb_factory_.get())
+ idb_factory_.reset(WebIDBFactory::create());
+ DCHECK(idb_factory_.get());
+ return idb_factory_.get();
+}
+
+FilePath IndexedDBContext::GetIndexedDBFilePath(
+ const string16& origin_id) const {
+ FilePath::StringType id = webkit_glue::WebStringToFilePathString(origin_id);
+ return data_path_.Append(id.append(kIndexedDBExtension));
+}
+
+void IndexedDBContext::DeleteIndexedDBFile(const FilePath& file_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ // TODO(pastarmovj): Close all database connections that use that file.
+ file_util::Delete(file_path, false);
+}
+
+void IndexedDBContext::DeleteIndexedDBForOrigin(const string16& origin_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ // TODO(pastarmovj): Remove this check once we are safe to delete any time.
+ FilePath idb_file = GetIndexedDBFilePath(origin_id);
+ DCHECK_EQ(idb_file.BaseName().value().substr(0, strlen("chrome-extension")),
+ FILE_PATH_LITERAL("chrome-extension"));
+ DeleteIndexedDBFile(GetIndexedDBFilePath(origin_id));
+}
diff --git a/content/browser/in_process_webkit/indexed_db_context.h b/content/browser/in_process_webkit/indexed_db_context.h
new file mode 100644
index 0000000..d7f8403
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_context.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/scoped_ptr.h"
+
+class FilePath;
+class WebKitContext;
+
+namespace WebKit {
+class WebIDBFactory;
+}
+
+class IndexedDBContext {
+ public:
+ explicit IndexedDBContext(WebKitContext* webkit_context);
+ ~IndexedDBContext();
+
+ WebKit::WebIDBFactory* GetIDBFactory();
+
+ // The indexed db directory.
+ static const FilePath::CharType kIndexedDBDirectory[];
+
+ // The indexed db file extension.
+ static const FilePath::CharType kIndexedDBExtension[];
+
+ // Get the file name of the indexed db file for the given origin.
+ FilePath GetIndexedDBFilePath(const string16& origin_id) const;
+
+ void set_clear_local_state_on_exit(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
+
+ // Deletes a single indexed db file.
+ void DeleteIndexedDBFile(const FilePath& file_path);
+
+ // Deletes all indexed db files for the given origin.
+ void DeleteIndexedDBForOrigin(const string16& origin_id);
+
+#ifdef UNIT_TEST
+ // For unit tests allow to override the |data_path_|.
+ void set_data_path(const FilePath& data_path) { data_path_ = data_path; }
+#endif
+
+ private:
+ scoped_ptr<WebKit::WebIDBFactory> idb_factory_;
+
+ // Path where the indexed db data is stored
+ FilePath data_path_;
+
+ // True if the destructor should delete its files.
+ bool clear_local_state_on_exit_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedDBContext);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_CONTEXT_H_
diff --git a/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc b/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc
new file mode 100644
index 0000000..5e8020e
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_dispatcher_host.cc
@@ -0,0 +1,1024 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/indexed_db_dispatcher_host.h"
+
+#include "base/command_line.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/content_settings/host_content_settings_map.h"
+#include "chrome/browser/metrics/user_metrics.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/renderer_host/browser_render_process_host.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/indexed_db_messages.h"
+#include "content/browser/in_process_webkit/indexed_db_callbacks.h"
+#include "content/browser/renderer_host/render_message_filter.h"
+#include "content/browser/renderer_host/render_view_host_notification_task.h"
+#include "chrome/common/result_codes.h"
+#include "googleurl/src/gurl.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebDOMStringList.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBCursor.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabase.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBDatabaseError.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBKeyRange.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBIndex.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBFactory.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBObjectStore.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebIDBTransaction.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebDOMStringList;
+using WebKit::WebExceptionCode;
+using WebKit::WebIDBCallbacks;
+using WebKit::WebIDBCursor;
+using WebKit::WebIDBDatabase;
+using WebKit::WebIDBDatabaseError;
+using WebKit::WebIDBIndex;
+using WebKit::WebIDBKey;
+using WebKit::WebIDBKeyRange;
+using WebKit::WebIDBObjectStore;
+using WebKit::WebIDBTransaction;
+using WebKit::WebSecurityOrigin;
+using WebKit::WebSerializedScriptValue;
+using WebKit::WebVector;
+
+namespace {
+
+// FIXME: Replace this magic constant once we have a more sophisticated quota
+// system.
+static const uint64 kDefaultQuota = 5 * 1024 * 1024;
+
+template <class T>
+void DeleteOnWebKitThread(T* obj) {
+ if (!BrowserThread::DeleteSoon(BrowserThread::WEBKIT, FROM_HERE, obj))
+ delete obj;
+}
+
+}
+
+IndexedDBDispatcherHost::IndexedDBDispatcherHost(int process_id,
+ Profile* profile)
+ : webkit_context_(profile->GetWebKitContext()),
+ host_content_settings_map_(profile->GetHostContentSettingsMap()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(database_dispatcher_host_(
+ new DatabaseDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(index_dispatcher_host_(
+ new IndexDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(object_store_dispatcher_host_(
+ new ObjectStoreDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(cursor_dispatcher_host_(
+ new CursorDispatcherHost(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(transaction_dispatcher_host_(
+ new TransactionDispatcherHost(this))),
+ process_id_(process_id) {
+ DCHECK(webkit_context_.get());
+}
+
+IndexedDBDispatcherHost::~IndexedDBDispatcherHost() {
+}
+
+void IndexedDBDispatcherHost::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, database_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, index_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE,
+ object_store_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, cursor_dispatcher_host_.release());
+ BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE,
+ transaction_dispatcher_host_.release());
+}
+
+void IndexedDBDispatcherHost::OverrideThreadForMessage(
+ const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (IPC_MESSAGE_CLASS(message) == IndexedDBMsgStart)
+ *thread = BrowserThread::WEBKIT;
+}
+
+bool IndexedDBDispatcherHost::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ if (IPC_MESSAGE_CLASS(message) != IndexedDBMsgStart)
+ return false;
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+
+ bool handled =
+ database_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ index_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ object_store_dispatcher_host_->OnMessageReceived(
+ message, message_was_ok) ||
+ cursor_dispatcher_host_->OnMessageReceived(message, message_was_ok) ||
+ transaction_dispatcher_host_->OnMessageReceived(message, message_was_ok);
+
+ if (!handled) {
+ handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryOpen, OnIDBFactoryOpen)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_FactoryDeleteDatabase,
+ OnIDBFactoryDeleteDatabase)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ }
+
+ return handled;
+}
+
+int32 IndexedDBDispatcherHost::Add(WebIDBCursor* idb_cursor) {
+ if (!cursor_dispatcher_host_.get()) {
+ delete idb_cursor;
+ return 0;
+ }
+ return cursor_dispatcher_host_->map_.Add(idb_cursor);
+}
+
+int32 IndexedDBDispatcherHost::Add(WebIDBDatabase* idb_database) {
+ if (!database_dispatcher_host_.get()) {
+ delete idb_database;
+ return 0;
+ }
+ return database_dispatcher_host_->map_.Add(idb_database);
+}
+
+int32 IndexedDBDispatcherHost::Add(WebIDBIndex* idb_index) {
+ if (!index_dispatcher_host_.get()) {
+ delete idb_index;
+ return 0;
+ }
+ if (!idb_index)
+ return 0;
+ return index_dispatcher_host_->map_.Add(idb_index);
+}
+
+int32 IndexedDBDispatcherHost::Add(WebIDBObjectStore* idb_object_store) {
+ if (!object_store_dispatcher_host_.get()) {
+ delete idb_object_store;
+ return 0;
+ }
+ if (!idb_object_store)
+ return 0;
+ return object_store_dispatcher_host_->map_.Add(idb_object_store);
+}
+
+int32 IndexedDBDispatcherHost::Add(WebIDBTransaction* idb_transaction) {
+ if (!transaction_dispatcher_host_.get()) {
+ delete idb_transaction;
+ return 0;
+ }
+ int32 id = transaction_dispatcher_host_->map_.Add(idb_transaction);
+ idb_transaction->setCallbacks(new IndexedDBTransactionCallbacks(this, id));
+ return id;
+}
+
+bool IndexedDBDispatcherHost::CheckContentSetting(const string16& origin,
+ const string16& description,
+ int routing_id,
+ int response_id) {
+ GURL host(string16(WebSecurityOrigin::createFromDatabaseIdentifier(
+ origin).toString()));
+
+ ContentSetting content_setting =
+ host_content_settings_map_->GetContentSetting(
+ host, CONTENT_SETTINGS_TYPE_COOKIES, "");
+
+ CallRenderViewHostContentSettingsDelegate(
+ process_id_, routing_id,
+ &RenderViewHostDelegate::ContentSettings::OnIndexedDBAccessed,
+ host, description, content_setting == CONTENT_SETTING_BLOCK);
+
+ if (content_setting == CONTENT_SETTING_BLOCK) {
+ // TODO(jorlow): Change this to the proper error code once we figure out
+ // one.
+ int error_code = 0; // Defined by the IndexedDB spec.
+ static string16 error_message = ASCIIToUTF16(
+ "The user denied permission to access the database.");
+ Send(new IndexedDBMsg_CallbacksError(response_id, error_code,
+ error_message));
+ return false;
+ }
+ return true;
+}
+
+void IndexedDBDispatcherHost::OnIDBFactoryOpen(
+ const IndexedDBHostMsg_FactoryOpen_Params& params) {
+ FilePath base_path = webkit_context_->data_path();
+ FilePath indexed_db_path;
+ if (!base_path.empty()) {
+ indexed_db_path = base_path.Append(
+ IndexedDBContext::kIndexedDBDirectory);
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ if (!CheckContentSetting(params.origin, params.name, params.routing_id,
+ params.response_id)) {
+ return;
+ }
+
+ DCHECK(kDefaultQuota == params.maximum_size);
+
+ uint64 quota = kDefaultQuota;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUnlimitedQuotaForIndexedDB)) {
+ quota = 1024 * 1024 * 1024; // 1GB. More or less "unlimited".
+ }
+
+ Context()->GetIDBFactory()->open(
+ params.name,
+ new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id),
+ WebSecurityOrigin::createFromDatabaseIdentifier(params.origin), NULL,
+ webkit_glue::FilePathToWebString(indexed_db_path), quota);
+}
+
+void IndexedDBDispatcherHost::OnIDBFactoryDeleteDatabase(
+ const IndexedDBHostMsg_FactoryDeleteDatabase_Params& params) {
+ FilePath base_path = webkit_context_->data_path();
+ FilePath indexed_db_path;
+ if (!base_path.empty()) {
+ indexed_db_path = base_path.Append(
+ IndexedDBContext::kIndexedDBDirectory);
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ if (!CheckContentSetting(params.origin, params.name, params.routing_id,
+ params.response_id)) {
+ return;
+ }
+
+ Context()->GetIDBFactory()->deleteDatabase(
+ params.name,
+ new IndexedDBCallbacks<WebIDBDatabase>(this, params.response_id),
+ WebSecurityOrigin::createFromDatabaseIdentifier(params.origin), NULL,
+ webkit_glue::FilePathToWebString(indexed_db_path));
+}
+
+//////////////////////////////////////////////////////////////////////
+// Helper templates.
+//
+
+template <typename ObjectType>
+ObjectType* IndexedDBDispatcherHost::GetOrTerminateProcess(
+ IDMap<ObjectType, IDMapOwnPointer>* map, int32 return_object_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ ObjectType* return_object = map->Lookup(return_object_id);
+ if (!return_object) {
+ UserMetrics::RecordAction(UserMetricsAction("BadMessageTerminate_IDBMF"));
+ BadMessageReceived();
+ }
+ return return_object;
+}
+
+template <typename ReplyType, typename MapObjectType, typename Method>
+void IndexedDBDispatcherHost::SyncGetter(
+ IDMap<MapObjectType, IDMapOwnPointer>* map, int32 object_id,
+ ReplyType* reply, Method method) {
+ MapObjectType* object = GetOrTerminateProcess(map, object_id);
+ if (!object)
+ return;
+
+ *reply = (object->*method)();
+}
+
+template <typename ObjectType>
+void IndexedDBDispatcherHost::DestroyObject(
+ IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id) {
+ GetOrTerminateProcess(map, object_id);
+ map->Remove(object_id);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::DatabaseDispatcherHost
+//
+
+IndexedDBDispatcherHost::DatabaseDispatcherHost::DatabaseDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+ map_.set_check_on_null_data(true);
+}
+
+IndexedDBDispatcherHost::DatabaseDispatcherHost::~DatabaseDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::DatabaseDispatcherHost,
+ message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseVersion, OnVersion)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseObjectStoreNames,
+ OnObjectStoreNames)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseCreateObjectStore,
+ OnCreateObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDeleteObjectStore,
+ OnDeleteObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetVersion, OnSetVersion)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseTransaction, OnTransaction)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseClose, OnClose)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::Send(
+ IPC::Message* message) {
+ parent_->Send(message);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnName(
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(&map_, object_id, name, &WebIDBDatabase::name);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnVersion(
+ int32 object_id, string16* version) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, version, &WebIDBDatabase::version);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnObjectStoreNames(
+ int32 idb_database_id, std::vector<string16>* object_stores) {
+ WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id);
+ if (!idb_database)
+ return;
+
+ WebDOMStringList web_object_stores = idb_database->objectStoreNames();
+ object_stores->reserve(web_object_stores.length());
+ for (unsigned i = 0; i < web_object_stores.length(); ++i)
+ object_stores->push_back(web_object_stores.item(i));
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnCreateObjectStore(
+ const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params,
+ int32* object_store_id, WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
+ &map_, params.idb_database_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_database || !idb_transaction)
+ return;
+
+ *ec = 0;
+ WebIDBObjectStore* object_store = idb_database->createObjectStore(
+ params.name, params.key_path, params.auto_increment,
+ *idb_transaction, *ec);
+ *object_store_id = *ec ? 0 : parent_->Add(object_store);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDeleteObjectStore(
+ int32 idb_database_id,
+ const string16& name,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_database || !idb_transaction)
+ return;
+
+ *ec = 0;
+ idb_database->deleteObjectStore(name, *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnSetVersion(
+ int32 idb_database_id,
+ int32 response_id,
+ const string16& version,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBDatabase* idb_database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id);
+ if (!idb_database)
+ return;
+
+ *ec = 0;
+ idb_database->setVersion(
+ version,
+ new IndexedDBCallbacks<WebIDBTransaction>(parent_, response_id),
+ *ec);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnTransaction(
+ int32 idb_database_id,
+ const std::vector<string16>& names,
+ int32 mode,
+ int32 timeout,
+ int32* idb_transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ WebIDBDatabase* database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id);
+ if (!database)
+ return;
+
+ WebDOMStringList object_stores;
+ for (std::vector<string16>::const_iterator it = names.begin();
+ it != names.end(); ++it) {
+ object_stores.append(*it);
+ }
+
+ *ec = 0;
+ WebIDBTransaction* transaction = database->transaction(
+ object_stores, mode, timeout, *ec);
+ DCHECK(!transaction != !*ec);
+ *idb_transaction_id = *ec ? 0 : parent_->Add(transaction);
+}
+
+void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnClose(
+ int32 idb_database_id) {
+ WebIDBDatabase* database = parent_->GetOrTerminateProcess(
+ &map_, idb_database_id);
+ database->close();
+}
+
+ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(&map_, object_id);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::IndexDispatcherHost
+//
+
+IndexedDBDispatcherHost::IndexDispatcherHost::IndexDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+ map_.set_check_on_null_data(true);
+}
+
+IndexedDBDispatcherHost::IndexDispatcherHost::~IndexDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::IndexDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::IndexDispatcherHost,
+ message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexStoreName, OnStoreName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexKeyPath, OnKeyPath)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexUnique, OnUnique)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenObjectCursor,
+ OnOpenObjectCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexOpenKeyCursor, OnOpenKeyCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetObject, OnGetObject)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexGetKey, OnGetKey)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_IndexDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::Send(
+ IPC::Message* message) {
+ parent_->Send(message);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnName(
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(&map_, object_id, name, &WebIDBIndex::name);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnStoreName(
+ int32 object_id, string16* store_name) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, store_name, &WebIDBIndex::storeName);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnKeyPath(
+ int32 object_id, NullableString16* key_path) {
+ parent_->SyncGetter<NullableString16>(
+ &map_, object_id, key_path, &WebIDBIndex::keyPath);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnUnique(
+ int32 object_id, bool* unique) {
+ parent_->SyncGetter<bool>(&map_, object_id, unique, &WebIDBIndex::unique);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenObjectCursor(
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, params.idb_index_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
+ idb_index->openObjectCursor(
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnOpenKeyCursor(
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, params.idb_index_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
+ idb_index->openKeyCursor(
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetObject(
+ int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, idb_index_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_index->getObject(key, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnGetKey(
+ int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBIndex* idb_index = parent_->GetOrTerminateProcess(
+ &map_, idb_index_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_transaction || !idb_index)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBKey>(parent_, response_id));
+ idb_index->getKey(key, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::IndexDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(&map_, object_id);
+}
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::ObjectStoreDispatcherHost
+//
+
+IndexedDBDispatcherHost::ObjectStoreDispatcherHost::ObjectStoreDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+ map_.set_check_on_null_data(true);
+}
+
+IndexedDBDispatcherHost::
+ObjectStoreDispatcherHost::~ObjectStoreDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::ObjectStoreDispatcherHost,
+ message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreName, OnName)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreKeyPath, OnKeyPath)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndexNames, OnIndexNames)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreGet, OnGet)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStorePut, OnPut)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDelete, OnDelete)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreClear, OnClear)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreCreateIndex, OnCreateIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreIndex, OnIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDeleteIndex, OnDeleteIndex)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreOpenCursor, OnOpenCursor)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_ObjectStoreDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::Send(
+ IPC::Message* message) {
+ parent_->Send(message);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnName(
+ int32 object_id, string16* name) {
+ parent_->SyncGetter<string16>(
+ &map_, object_id, name, &WebIDBObjectStore::name);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnKeyPath(
+ int32 object_id, NullableString16* keyPath) {
+ parent_->SyncGetter<NullableString16>(
+ &map_, object_id, keyPath, &WebIDBObjectStore::keyPath);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndexNames(
+ int32 idb_object_store_id, std::vector<string16>* index_names) {
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ if (!idb_object_store)
+ return;
+
+ WebDOMStringList web_index_names = idb_object_store->indexNames();
+ index_names->reserve(web_index_names.length());
+ for (unsigned i = 0; i < web_index_names.length(); ++i)
+ index_names->push_back(web_index_names.item(i));
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnGet(
+ int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_object_store->get(key, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnPut(
+ const IndexedDBHostMsg_ObjectStorePut_Params& params,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, params.idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBKey>(parent_, params.response_id));
+ idb_object_store->put(params.serialized_value, params.key, params.put_mode,
+ callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDelete(
+ int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_object_store->deleteFunction(
+ key, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnClear(
+ int idb_object_store_id,
+ int32 response_id,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id));
+ idb_object_store->clear(callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnCreateIndex(
+ const IndexedDBHostMsg_ObjectStoreCreateIndex_Params& params,
+ int32* index_id, WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, params.idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_object_store || !idb_transaction)
+ return;
+
+ *ec = 0;
+ WebIDBIndex* index = idb_object_store->createIndex(
+ params.name, params.key_path, params.unique, *idb_transaction, *ec);
+ *index_id = *ec ? 0 : parent_->Add(index);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnIndex(
+ int32 idb_object_store_id,
+ const string16& name,
+ int32* idb_index_id,
+ WebKit::WebExceptionCode* ec) {
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ if (!idb_object_store)
+ return;
+
+ *ec = 0;
+ WebIDBIndex* index = idb_object_store->index(name, *ec);
+ *idb_index_id = parent_->Add(index);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDeleteIndex(
+ int32 idb_object_store_id,
+ const string16& name,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &map_, idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, transaction_id);
+ if (!idb_object_store || !idb_transaction)
+ return;
+
+ *ec = 0;
+ idb_object_store->deleteIndex(name, *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnOpenCursor(
+ const IndexedDBHostMsg_ObjectStoreOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBObjectStore* idb_object_store = parent_->GetOrTerminateProcess(
+ &parent_->object_store_dispatcher_host_->map_,
+ params.idb_object_store_id);
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &parent_->transaction_dispatcher_host_->map_, params.transaction_id);
+ if (!idb_transaction || !idb_object_store)
+ return;
+
+ *ec = 0;
+ scoped_ptr<WebIDBCallbacks> callbacks(
+ new IndexedDBCallbacks<WebIDBCursor>(parent_, params.response_id));
+ idb_object_store->openCursor(
+ WebIDBKeyRange(params.lower_key, params.upper_key, params.lower_open,
+ params.upper_open),
+ params.direction, callbacks.release(), *idb_transaction, *ec);
+}
+
+void IndexedDBDispatcherHost::ObjectStoreDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(&map_, object_id);
+}
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::CursorDispatcherHost
+//
+
+IndexedDBDispatcherHost::CursorDispatcherHost::CursorDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+ map_.set_check_on_null_data(true);
+}
+
+IndexedDBDispatcherHost::CursorDispatcherHost::~CursorDispatcherHost() {
+}
+
+bool IndexedDBDispatcherHost::CursorDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::CursorDispatcherHost,
+ message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDirection, OnDirection)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorKey, OnKey)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorValue, OnValue)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorUpdate, OnUpdate)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorContinue, OnContinue)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDelete, OnDelete)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_CursorDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::Send(
+ IPC::Message* message) {
+ parent_->Send(message);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnDirection(
+ int32 object_id, int32* direction) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
+ if (!idb_cursor)
+ return;
+
+ *direction = idb_cursor->direction();
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnKey(
+ int32 object_id, IndexedDBKey* key) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
+ if (!idb_cursor)
+ return;
+
+ *key = IndexedDBKey(idb_cursor->key());
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnValue(
+ int32 object_id,
+ SerializedScriptValue* script_value,
+ IndexedDBKey* key) {
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, object_id);
+ if (!idb_cursor)
+ return;
+
+ WebSerializedScriptValue temp_script_value;
+ WebIDBKey temp_key;
+ idb_cursor->value(temp_script_value, temp_key);
+
+ *script_value = SerializedScriptValue(temp_script_value);
+ *key = IndexedDBKey(temp_key);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnUpdate(
+ int32 cursor_id,
+ int32 response_id,
+ const SerializedScriptValue& value,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
+ if (!idb_cursor)
+ return;
+
+ *ec = 0;
+ idb_cursor->update(
+ value, new IndexedDBCallbacks<WebIDBKey>(parent_, response_id), *ec);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnContinue(
+ int32 cursor_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
+ if (!idb_cursor)
+ return;
+
+ *ec = 0;
+ idb_cursor->continueFunction(
+ key, new IndexedDBCallbacks<WebIDBCursor>(parent_, response_id), *ec);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnDelete(
+ int32 cursor_id,
+ int32 response_id,
+ WebKit::WebExceptionCode* ec) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBCursor* idb_cursor = parent_->GetOrTerminateProcess(&map_, cursor_id);
+ if (!idb_cursor)
+ return;
+
+ *ec = 0;
+ // TODO(jorlow): This should be delete.
+ idb_cursor->remove(
+ new IndexedDBCallbacks<WebSerializedScriptValue>(parent_, response_id), *ec);
+}
+
+void IndexedDBDispatcherHost::CursorDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(&map_, object_id);
+}
+
+//////////////////////////////////////////////////////////////////////
+// IndexedDBDispatcherHost::TransactionDispatcherHost
+//
+
+IndexedDBDispatcherHost::TransactionDispatcherHost::TransactionDispatcherHost(
+ IndexedDBDispatcherHost* parent)
+ : parent_(parent) {
+ map_.set_check_on_null_data(true);
+}
+
+IndexedDBDispatcherHost::
+ TransactionDispatcherHost::~TransactionDispatcherHost() {
+ MapType::iterator it(&map_);
+ while (!it.IsAtEnd()) {
+ it.GetCurrentValue()->abort();
+ it.Advance();
+ }
+}
+
+bool IndexedDBDispatcherHost::TransactionDispatcherHost::OnMessageReceived(
+ const IPC::Message& message, bool* msg_is_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(IndexedDBDispatcherHost::TransactionDispatcherHost,
+ message, *msg_is_ok)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionAbort, OnAbort)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionMode, OnMode)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionObjectStore, OnObjectStore)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDidCompleteTaskEvents,
+ OnDidCompleteTaskEvents)
+ IPC_MESSAGE_HANDLER(IndexedDBHostMsg_TransactionDestroyed, OnDestroyed)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::Send(
+ IPC::Message* message) {
+ parent_->Send(message);
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnAbort(
+ int32 transaction_id) {
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id);
+ if (!idb_transaction)
+ return;
+
+ idb_transaction->abort();
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnMode(
+ int32 transaction_id,
+ int* mode) {
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id);
+ if (!idb_transaction)
+ return;
+
+ *mode = idb_transaction->mode();
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnObjectStore(
+ int32 transaction_id, const string16& name, int32* object_store_id,
+ WebKit::WebExceptionCode* ec) {
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id);
+ if (!idb_transaction)
+ return;
+
+ *ec = 0;
+ WebIDBObjectStore* object_store = idb_transaction->objectStore(name, *ec);
+ *object_store_id = object_store ? parent_->Add(object_store) : 0;
+}
+
+void IndexedDBDispatcherHost::
+ TransactionDispatcherHost::OnDidCompleteTaskEvents(int transaction_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ WebIDBTransaction* idb_transaction = parent_->GetOrTerminateProcess(
+ &map_, transaction_id);
+ if (!idb_transaction)
+ return;
+
+ idb_transaction->didCompleteTaskEvents();
+}
+
+void IndexedDBDispatcherHost::TransactionDispatcherHost::OnDestroyed(
+ int32 object_id) {
+ parent_->DestroyObject(&map_, object_id);
+}
diff --git a/content/browser/in_process_webkit/indexed_db_dispatcher_host.h b/content/browser/in_process_webkit/indexed_db_dispatcher_host.h
new file mode 100644
index 0000000..1823954
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_dispatcher_host.h
@@ -0,0 +1,280 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_DISPATCHER_HOST_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_DISPATCHER_HOST_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/id_map.h"
+#include "content/browser/browser_message_filter.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebExceptionCode.h"
+
+class HostContentSettingsMap;
+class IndexedDBKey;
+class NullableString16;
+class Profile;
+class SerializedScriptValue;
+struct IndexedDBHostMsg_DatabaseCreateObjectStore_Params;
+struct IndexedDBHostMsg_FactoryDeleteDatabase_Params;
+struct IndexedDBHostMsg_FactoryOpen_Params;
+struct IndexedDBHostMsg_IndexOpenCursor_Params;
+struct IndexedDBHostMsg_ObjectStoreCreateIndex_Params;
+struct IndexedDBHostMsg_ObjectStoreOpenCursor_Params;
+struct IndexedDBHostMsg_ObjectStorePut_Params;
+
+namespace WebKit {
+class WebIDBCursor;
+class WebIDBDatabase;
+class WebIDBIndex;
+class WebIDBObjectStore;
+class WebIDBTransaction;
+}
+
+// Handles all IndexedDB related messages from a particular renderer process.
+class IndexedDBDispatcherHost : public BrowserMessageFilter {
+ public:
+ // Only call the constructor from the UI thread.
+ IndexedDBDispatcherHost(int process_id, Profile* profile);
+
+ // BrowserMessageFilter implementation.
+ virtual void OnChannelClosing();
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread);
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok);
+
+ // A shortcut for accessing our context.
+ IndexedDBContext* Context() {
+ return webkit_context_->indexed_db_context();
+ }
+
+ // The various IndexedDBCallbacks children call these methods to add the
+ // results into the applicable map. See below for more details.
+ int32 Add(WebKit::WebIDBCursor* idb_cursor);
+ int32 Add(WebKit::WebIDBDatabase* idb_database);
+ int32 Add(WebKit::WebIDBIndex* idb_index);
+ int32 Add(WebKit::WebIDBObjectStore* idb_object_store);
+ int32 Add(WebKit::WebIDBTransaction* idb_transaction);
+
+ private:
+ ~IndexedDBDispatcherHost();
+
+ // True if the given |origin| can use databases according to the content
+ // settings.
+ bool CheckContentSetting(const string16& origin,
+ const string16& description,
+ int routing_id,
+ int response_id);
+
+ // Message processing. Most of the work is delegated to the dispatcher hosts
+ // below.
+ void OnIDBFactoryOpen(const IndexedDBHostMsg_FactoryOpen_Params& p);
+
+ void OnIDBFactoryDeleteDatabase(
+ const IndexedDBHostMsg_FactoryDeleteDatabase_Params& p);
+
+ // Helper templates.
+ template <class ReturnType>
+ ReturnType* GetOrTerminateProcess(
+ IDMap<ReturnType, IDMapOwnPointer>* map, int32 return_object_id);
+
+ template <typename ReplyType, typename WebObjectType, typename Method>
+ void SyncGetter(IDMap<WebObjectType, IDMapOwnPointer>* map, int32 object_id,
+ ReplyType* reply, Method method);
+
+ template <typename ObjectType>
+ void DestroyObject(IDMap<ObjectType, IDMapOwnPointer>* map, int32 object_id);
+
+ class DatabaseDispatcherHost {
+ public:
+ explicit DatabaseDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~DatabaseDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ void OnName(int32 idb_database_id, string16* name);
+ void OnVersion(int32 idb_database_id, string16* version);
+ void OnObjectStoreNames(int32 idb_database_id,
+ std::vector<string16>* object_stores);
+ void OnCreateObjectStore(
+ const IndexedDBHostMsg_DatabaseCreateObjectStore_Params& params,
+ int32* object_store_id, WebKit::WebExceptionCode* ec);
+ void OnDeleteObjectStore(int32 idb_database_id,
+ const string16& name,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnSetVersion(int32 idb_database_id,
+ int32 response_id,
+ const string16& version,
+ WebKit::WebExceptionCode* ec);
+ void OnTransaction(int32 idb_database_id,
+ const std::vector<string16>& names,
+ int32 mode, int32 timeout,
+ int32* idb_transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnClose(int32 idb_database_id);
+ void OnDestroyed(int32 idb_database_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBDatabase, IDMapOwnPointer> map_;
+ };
+
+ class IndexDispatcherHost {
+ public:
+ explicit IndexDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~IndexDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ void OnName(int32 idb_index_id, string16* name);
+ void OnStoreName(int32 idb_index_id, string16* store_name);
+ void OnKeyPath(int32 idb_index_id, NullableString16* key_path);
+ void OnUnique(int32 idb_index_id, bool* unique);
+ void OnOpenObjectCursor(
+ const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnOpenKeyCursor(const IndexedDBHostMsg_IndexOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnGetObject(int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnGetKey(int idb_index_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDestroyed(int32 idb_index_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBIndex, IDMapOwnPointer> map_;
+ };
+
+ class ObjectStoreDispatcherHost {
+ public:
+ explicit ObjectStoreDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~ObjectStoreDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ void OnName(int32 idb_object_store_id, string16* name);
+ void OnKeyPath(int32 idb_object_store_id, NullableString16* keyPath);
+ void OnIndexNames(int32 idb_object_store_id,
+ std::vector<string16>* index_names);
+ void OnGet(int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnPut(const IndexedDBHostMsg_ObjectStorePut_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnDelete(int idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnClear(int idb_object_store_id,
+ int32 response_id,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnCreateIndex(
+ const IndexedDBHostMsg_ObjectStoreCreateIndex_Params& params,
+ int32* index_id,
+ WebKit::WebExceptionCode* ec);
+ void OnIndex(int32 idb_object_store_id,
+ const string16& name,
+ int32* idb_index_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDeleteIndex(int32 idb_object_store_id,
+ const string16& name,
+ int32 transaction_id,
+ WebKit::WebExceptionCode* ec);
+ void OnOpenCursor(
+ const IndexedDBHostMsg_ObjectStoreOpenCursor_Params& params,
+ WebKit::WebExceptionCode* ec);
+ void OnDestroyed(int32 idb_object_store_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBObjectStore, IDMapOwnPointer> map_;
+ };
+
+ class CursorDispatcherHost {
+ public:
+ explicit CursorDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~CursorDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ void OnDirection(int32 idb_object_store_id, int32* direction);
+ void OnKey(int32 idb_object_store_id, IndexedDBKey* key);
+ void OnValue(int32 idb_object_store_id,
+ SerializedScriptValue* script_value,
+ IndexedDBKey* key);
+ void OnUpdate(int32 idb_object_store_id,
+ int32 response_id,
+ const SerializedScriptValue& value,
+ WebKit::WebExceptionCode* ec);
+ void OnContinue(int32 idb_object_store_id,
+ int32 response_id,
+ const IndexedDBKey& key,
+ WebKit::WebExceptionCode* ec);
+ void OnDelete(int32 idb_object_store_id,
+ int32 response_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDestroyed(int32 idb_cursor_id);
+
+ IndexedDBDispatcherHost* parent_;
+ IDMap<WebKit::WebIDBCursor, IDMapOwnPointer> map_;
+ };
+
+ class TransactionDispatcherHost {
+ public:
+ explicit TransactionDispatcherHost(IndexedDBDispatcherHost* parent);
+ ~TransactionDispatcherHost();
+
+ bool OnMessageReceived(const IPC::Message& message, bool *msg_is_ok);
+ void Send(IPC::Message* message);
+
+ // TODO: add the rest of the transaction methods.
+ void OnAbort(int32 transaction_id);
+ void OnMode(int32 transaction_id, int* mode);
+ void OnObjectStore(int32 transaction_id,
+ const string16& name,
+ int32* object_store_id,
+ WebKit::WebExceptionCode* ec);
+ void OnDidCompleteTaskEvents(int transaction_id);
+ void OnDestroyed(int32 idb_transaction_id);
+
+ IndexedDBDispatcherHost* parent_;
+ typedef IDMap<WebKit::WebIDBTransaction, IDMapOwnPointer> MapType;
+ MapType map_;
+ };
+
+ // Data shared between renderer processes with the same profile.
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ // Tells us whether the user wants to allow databases to be opened.
+ scoped_refptr<HostContentSettingsMap> host_content_settings_map_;
+
+ // Only access on WebKit thread.
+ scoped_ptr<DatabaseDispatcherHost> database_dispatcher_host_;
+ scoped_ptr<IndexDispatcherHost> index_dispatcher_host_;
+ scoped_ptr<ObjectStoreDispatcherHost> object_store_dispatcher_host_;
+ scoped_ptr<CursorDispatcherHost> cursor_dispatcher_host_;
+ scoped_ptr<TransactionDispatcherHost> transaction_dispatcher_host_;
+
+ // Used to dispatch messages to the correct view host.
+ int process_id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(IndexedDBDispatcherHost);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_DISPATCHER_HOST_H_
diff --git a/content/browser/in_process_webkit/indexed_db_key_utility_client.cc b/content/browser/in_process_webkit/indexed_db_key_utility_client.cc
new file mode 100644
index 0000000..a8f8e5b
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_key_utility_client.cc
@@ -0,0 +1,383 @@
+// 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 "content/browser/in_process_webkit/indexed_db_key_utility_client.h"
+
+#include "base/lazy_instance.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/utility_process_host.h"
+#include "chrome/common/indexed_db_key.h"
+#include "chrome/common/serialized_script_value.h"
+
+// This class is used to obtain IndexedDBKeys from SerializedScriptValues
+// given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox
+// (a V8 lock is required there). At this level, all methods are synchronous
+// as required by the caller. The public API is used on WEBKIT thread,
+// but internally it moves around to UI and IO as needed.
+class KeyUtilityClientImpl
+ : public base::RefCountedThreadSafe<KeyUtilityClientImpl> {
+ public:
+ KeyUtilityClientImpl();
+
+ // Starts the UtilityProcess. Must be called before any other method.
+ void StartUtilityProcess();
+
+ // Stops the UtilityProcess. No further keys can be created after this.
+ void Shutdown();
+
+ // Synchronously obtain the |keys| from |values| for the given |key_path|.
+ void CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys);
+
+ // Synchronously inject |key| into |value| using the given |key_path|,
+ // returning the new value.
+ SerializedScriptValue InjectIDBKeyIntoSerializedValue(
+ const IndexedDBKey& key,
+ const SerializedScriptValue& value,
+ const string16& key_path);
+
+ private:
+ class Client : public UtilityProcessHost::Client {
+ public:
+ explicit Client(KeyUtilityClientImpl* parent);
+
+ // UtilityProcessHost::Client
+ virtual void OnProcessCrashed(int exit_code);
+ virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
+ int id, const std::vector<IndexedDBKey>& keys);
+ virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
+ virtual void OnInjectIDBKeyFinished(const SerializedScriptValue& value);
+
+ private:
+ KeyUtilityClientImpl* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(Client);
+ };
+
+ friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>;
+ ~KeyUtilityClientImpl();
+
+ void GetRDHAndStartUtilityProcess();
+ void StartUtilityProcessInternal(ResourceDispatcherHost* rdh);
+ void EndUtilityProcessInternal();
+ void CallStartIDBKeyFromValueAndKeyPathFromIOThread(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path);
+ void CallStartInjectIDBKeyFromIOThread(
+ const IndexedDBKey& key,
+ const SerializedScriptValue& value,
+ const string16& key_path);
+
+ void SetKeys(const std::vector<IndexedDBKey>& keys);
+ void FinishCreatingKeys();
+ void SetValueAfterInjection(const SerializedScriptValue& value);
+ void FinishInjectingKey();
+
+ base::WaitableEvent waitable_event_;
+
+ // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e.,
+ // these members are only set / read when the other thread is blocked.
+ enum State {
+ STATE_UNINITIALIZED,
+ STATE_INITIALIZED,
+ STATE_CREATING_KEYS,
+ STATE_INJECTING_KEY,
+ STATE_SHUTDOWN,
+ };
+ State state_;
+ std::vector<IndexedDBKey> keys_;
+ SerializedScriptValue value_after_injection_;
+
+ // Used in the IO thread.
+ UtilityProcessHost* utility_process_host_;
+ scoped_refptr<Client> client_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl);
+};
+
+// IndexedDBKeyUtilityClient definitions.
+
+static base::LazyInstance<IndexedDBKeyUtilityClient> client_instance(
+ base::LINKER_INITIALIZED);
+
+IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
+ : is_shutdown_(false) {
+ // Note that creating the impl_ object is deferred until it is first needed,
+ // as this class can be constructed even though it never gets used.
+}
+
+IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() {
+ DCHECK(!impl_ || is_shutdown_);
+}
+
+// static
+void IndexedDBKeyUtilityClient::Shutdown() {
+ IndexedDBKeyUtilityClient* instance = client_instance.Pointer();
+ if (!instance->impl_)
+ return;
+
+ instance->is_shutdown_ = true;
+ instance->impl_->Shutdown();
+}
+
+// static
+void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys) {
+ IndexedDBKeyUtilityClient* instance = client_instance.Pointer();
+
+ if (instance->is_shutdown_) {
+ keys->clear();
+ return;
+ }
+
+ if (!instance->impl_) {
+ instance->impl_ = new KeyUtilityClientImpl();
+ instance->impl_->StartUtilityProcess();
+ }
+
+ instance->impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path,
+ keys);
+}
+
+// static
+SerializedScriptValue
+IndexedDBKeyUtilityClient::InjectIDBKeyIntoSerializedValue(
+ const IndexedDBKey& key, const SerializedScriptValue& value,
+ const string16& key_path) {
+ IndexedDBKeyUtilityClient* instance = client_instance.Pointer();
+
+ if (instance->is_shutdown_)
+ return SerializedScriptValue();
+
+ if (!instance->impl_) {
+ instance->impl_ = new KeyUtilityClientImpl();
+ instance->impl_->StartUtilityProcess();
+ }
+
+ return instance->impl_->InjectIDBKeyIntoSerializedValue(key, value, key_path);
+}
+
+
+
+// KeyUtilityClientImpl definitions.
+
+void KeyUtilityClientImpl::Shutdown() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ utility_process_host_->EndBatchMode();
+ utility_process_host_ = NULL;
+ client_ = NULL;
+ state_ = STATE_SHUTDOWN;
+}
+
+KeyUtilityClientImpl::KeyUtilityClientImpl()
+ : waitable_event_(false, false),
+ state_(STATE_UNINITIALIZED),
+ utility_process_host_(NULL) {
+}
+
+KeyUtilityClientImpl::~KeyUtilityClientImpl() {
+ DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN);
+ DCHECK(!utility_process_host_);
+ DCHECK(!client_.get());
+}
+
+void KeyUtilityClientImpl::StartUtilityProcess() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ DCHECK(state_ == STATE_UNINITIALIZED);
+
+ GetRDHAndStartUtilityProcess();
+ bool ret = waitable_event_.Wait();
+
+ DCHECK(ret && state_ == STATE_INITIALIZED);
+}
+
+void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ if (state_ == STATE_SHUTDOWN) {
+ keys->clear();
+ return;
+ }
+
+ DCHECK(state_ == STATE_INITIALIZED);
+
+ state_ = STATE_CREATING_KEYS;
+ CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path);
+ bool ret = waitable_event_.Wait();
+ DCHECK(ret && state_ == STATE_INITIALIZED);
+
+ *keys = keys_;
+}
+
+SerializedScriptValue KeyUtilityClientImpl::InjectIDBKeyIntoSerializedValue(
+ const IndexedDBKey& key,
+ const SerializedScriptValue& value,
+ const string16& key_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ if (state_ == STATE_SHUTDOWN)
+ return SerializedScriptValue();
+
+ DCHECK(state_ == STATE_INITIALIZED);
+
+ state_ = STATE_INJECTING_KEY;
+ CallStartInjectIDBKeyFromIOThread(key, value, key_path);
+
+ bool ret = waitable_event_.Wait();
+ DCHECK(ret && state_ == STATE_INITIALIZED);
+
+ return value_after_injection_;
+}
+
+
+void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() {
+ // In order to start the UtilityProcess, we need to grab
+ // a pointer to the ResourceDispatcherHost. This can only
+ // be done on the UI thread. See the comment at the top of
+ // browser_process.h
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess));
+ return;
+ }
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host());
+}
+
+void KeyUtilityClientImpl::StartUtilityProcessInternal(
+ ResourceDispatcherHost* rdh) {
+ DCHECK(rdh);
+ // The ResourceDispatcherHost can only be used on the IO thread.
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &KeyUtilityClientImpl::StartUtilityProcessInternal,
+ rdh));
+ return;
+ }
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(state_ == STATE_UNINITIALIZED);
+
+ client_ = new KeyUtilityClientImpl::Client(this);
+ utility_process_host_ = new UtilityProcessHost(
+ rdh, client_.get(), BrowserThread::IO);
+ utility_process_host_->StartBatchMode();
+ state_ = STATE_INITIALIZED;
+ waitable_event_.Signal();
+}
+
+void KeyUtilityClientImpl::EndUtilityProcessInternal() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &KeyUtilityClientImpl::EndUtilityProcessInternal));
+ return;
+ }
+
+ utility_process_host_->EndBatchMode();
+ utility_process_host_ = NULL;
+ client_ = NULL;
+ state_ = STATE_SHUTDOWN;
+ waitable_event_.Signal();
+}
+
+void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this,
+ &KeyUtilityClientImpl::
+ CallStartIDBKeyFromValueAndKeyPathFromIOThread,
+ values, key_path));
+ return;
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
+ 0, values, key_path);
+}
+
+void KeyUtilityClientImpl::CallStartInjectIDBKeyFromIOThread(
+ const IndexedDBKey& key,
+ const SerializedScriptValue& value,
+ const string16& key_path) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ NewRunnableMethod(this,
+ &KeyUtilityClientImpl::
+ CallStartInjectIDBKeyFromIOThread,
+ key, value, key_path));
+ return;
+ }
+
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ utility_process_host_->StartInjectIDBKey(key, value, key_path);
+}
+
+void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ keys_ = keys;
+}
+
+void KeyUtilityClientImpl::FinishCreatingKeys() {
+ DCHECK(state_ == STATE_CREATING_KEYS);
+ state_ = STATE_INITIALIZED;
+ waitable_event_.Signal();
+}
+
+void KeyUtilityClientImpl::SetValueAfterInjection(
+ const SerializedScriptValue& value) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ value_after_injection_ = value;
+}
+
+void KeyUtilityClientImpl::FinishInjectingKey() {
+ DCHECK(state_ == STATE_INJECTING_KEY);
+ state_ = STATE_INITIALIZED;
+ waitable_event_.Signal();
+}
+
+KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent)
+ : parent_(parent) {
+}
+
+void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) {
+ if (parent_->state_ == STATE_CREATING_KEYS)
+ parent_->FinishCreatingKeys();
+}
+
+void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
+ int id, const std::vector<IndexedDBKey>& keys) {
+ parent_->SetKeys(keys);
+ parent_->FinishCreatingKeys();
+}
+
+void KeyUtilityClientImpl::Client::OnInjectIDBKeyFinished(
+ const SerializedScriptValue& value) {
+ parent_->SetValueAfterInjection(value);
+ parent_->FinishInjectingKey();
+}
+
+void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed(
+ int id) {
+ parent_->FinishCreatingKeys();
+}
diff --git a/content/browser/in_process_webkit/indexed_db_key_utility_client.h b/content/browser/in_process_webkit/indexed_db_key_utility_client.h
new file mode 100644
index 0000000..ed141c9
--- /dev/null
+++ b/content/browser/in_process_webkit/indexed_db_key_utility_client.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_KEY_UTILITY_CLIENT_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_KEY_UTILITY_CLIENT_H_
+#pragma once
+
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "base/string16.h"
+
+class IndexedDBKey;
+class SerializedScriptValue;
+class KeyUtilityClientImpl;
+
+namespace base {
+template <typename T>
+struct DefaultLazyInstanceTraits;
+} // namespace base
+
+// Class for obtaining IndexedDBKeys from the SerializedScriptValues given
+// an IDBKeyPath. This class is a thin singleton wrapper around the
+// KeyUtilityClientImpl, which does the real work.
+class IndexedDBKeyUtilityClient {
+ public:
+ // Synchronously obtain the |keys| from |values| for the given |key_path|.
+ static void CreateIDBKeysFromSerializedValuesAndKeyPath(
+ const std::vector<SerializedScriptValue>& values,
+ const string16& key_path,
+ std::vector<IndexedDBKey>* keys);
+
+ // Synchronously inject |key| into |value| using |key_path|. Returns the new
+ // value.
+ static SerializedScriptValue InjectIDBKeyIntoSerializedValue(
+ const IndexedDBKey& key,
+ const SerializedScriptValue& value,
+ const string16& key_path);
+
+ // Shut down the underlying implementation. Must be called on the IO thread.
+ static void Shutdown();
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<IndexedDBKeyUtilityClient>;
+ IndexedDBKeyUtilityClient();
+ ~IndexedDBKeyUtilityClient();
+
+ bool is_shutdown_;
+
+ // The real client; laziliy instantiated.
+ scoped_refptr<KeyUtilityClientImpl> impl_;
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_INDEXED_DB_KEY_UTILITY_CLIENT_H_
diff --git a/content/browser/in_process_webkit/session_storage_namespace.cc b/content/browser/in_process_webkit/session_storage_namespace.cc
new file mode 100644
index 0000000..ddb42c5
--- /dev/null
+++ b/content/browser/in_process_webkit/session_storage_namespace.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/session_storage_namespace.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+
+SessionStorageNamespace::SessionStorageNamespace(Profile* profile)
+ : webkit_context_(profile->GetWebKitContext()),
+ id_(webkit_context_->dom_storage_context()
+ ->AllocateSessionStorageNamespaceId()) {
+}
+
+SessionStorageNamespace::SessionStorageNamespace(WebKitContext* webkit_context,
+ int64 id)
+ : webkit_context_(webkit_context),
+ id_(id) {
+}
+
+SessionStorageNamespace::~SessionStorageNamespace() {
+ webkit_context_->DeleteSessionStorageNamespace(id_);
+}
+
+SessionStorageNamespace* SessionStorageNamespace::Clone() {
+ return new SessionStorageNamespace(
+ webkit_context_,
+ webkit_context_->dom_storage_context()->CloneSessionStorage(id_));
+}
diff --git a/content/browser/in_process_webkit/session_storage_namespace.h b/content/browser/in_process_webkit/session_storage_namespace.h
new file mode 100644
index 0000000..d85baf7
--- /dev/null
+++ b/content/browser/in_process_webkit/session_storage_namespace.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_SESSION_STORAGE_NAMESPACE_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_SESSION_STORAGE_NAMESPACE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/ref_counted.h"
+
+class Profile;
+class WebKitContext;
+
+// This is a ref-counted class that represents a SessionStorageNamespace.
+// On destruction it ensures that the storage namespace is destroyed.
+// NOTE: That if we're shutting down, we don't strictly need to do this, but
+// it keeps valgrind happy.
+class SessionStorageNamespace
+ : public base::RefCountedThreadSafe<SessionStorageNamespace> {
+ public:
+ explicit SessionStorageNamespace(Profile* profile);
+
+ int64 id() const { return id_; }
+
+ // The session storage namespace parameter allows multiple render views and
+ // tab contentses to share the same session storage (part of the WebStorage
+ // spec) space. Passing in NULL simply allocates a new one which is often the
+ // correct thing to do (especially in tests.
+ SessionStorageNamespace* Clone();
+
+ private:
+ SessionStorageNamespace(WebKitContext* webkit_context, int64 id);
+
+ friend class base::RefCountedThreadSafe<SessionStorageNamespace>;
+ ~SessionStorageNamespace();
+
+ scoped_refptr<WebKitContext> webkit_context_;
+
+ // The session storage namespace id.
+ int64 id_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SessionStorageNamespace);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_SESSION_STORAGE_NAMESPACE_H_
diff --git a/content/browser/in_process_webkit/webkit_context.cc b/content/browser/in_process_webkit/webkit_context.cc
new file mode 100644
index 0000000..b19fdbf
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_context.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2010 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 "content/browser/in_process_webkit/webkit_context.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/browser/browser_thread.h"
+
+WebKitContext::WebKitContext(Profile* profile, bool clear_local_state_on_exit)
+ : data_path_(profile->IsOffTheRecord() ? FilePath() : profile->GetPath()),
+ is_incognito_(profile->IsOffTheRecord()),
+ clear_local_state_on_exit_(clear_local_state_on_exit),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ dom_storage_context_(new DOMStorageContext(this))),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ indexed_db_context_(new IndexedDBContext(this))) {
+}
+
+WebKitContext::~WebKitContext() {
+ // If the WebKit thread was ever spun up, delete the object there. The task
+ // will just get deleted if the WebKit thread isn't created (which only
+ // happens during testing).
+ dom_storage_context_->set_clear_local_state_on_exit_(
+ clear_local_state_on_exit_);
+ DOMStorageContext* dom_storage_context = dom_storage_context_.release();
+ if (!BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, dom_storage_context)) {
+ // The WebKit thread wasn't created, and the task got deleted without
+ // freeing the DOMStorageContext, so delete it manually.
+ delete dom_storage_context;
+ }
+
+ indexed_db_context_->set_clear_local_state_on_exit(
+ clear_local_state_on_exit_);
+ IndexedDBContext* indexed_db_context = indexed_db_context_.release();
+ if (!BrowserThread::DeleteSoon(
+ BrowserThread::WEBKIT, FROM_HERE, indexed_db_context)) {
+ delete indexed_db_context;
+ }
+}
+
+void WebKitContext::PurgeMemory() {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ BrowserThread::PostTask(
+ BrowserThread::WEBKIT, FROM_HERE,
+ NewRunnableMethod(this, &WebKitContext::PurgeMemory));
+ return;
+ }
+
+ dom_storage_context_->PurgeMemory();
+}
+
+void WebKitContext::DeleteDataModifiedSince(
+ const base::Time& cutoff,
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ BrowserThread::PostTask(
+ BrowserThread::WEBKIT, FROM_HERE,
+ NewRunnableMethod(this, &WebKitContext::DeleteDataModifiedSince,
+ cutoff, url_scheme_to_be_skipped, protected_origins));
+ return;
+ }
+
+ dom_storage_context_->DeleteDataModifiedSince(
+ cutoff, url_scheme_to_be_skipped, protected_origins);
+}
+
+
+void WebKitContext::DeleteSessionStorageNamespace(
+ int64 session_storage_namespace_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)) {
+ BrowserThread::PostTask(
+ BrowserThread::WEBKIT, FROM_HERE,
+ NewRunnableMethod(this, &WebKitContext::DeleteSessionStorageNamespace,
+ session_storage_namespace_id));
+ return;
+ }
+
+ dom_storage_context_->DeleteSessionStorageNamespace(
+ session_storage_namespace_id);
+}
diff --git a/content/browser/in_process_webkit/webkit_context.h b/content/browser/in_process_webkit/webkit_context.h
new file mode 100644
index 0000000..5f647ef
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_context.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CONTEXT_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CONTEXT_H_
+#pragma once
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/time.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/indexed_db_context.h"
+
+class Profile;
+
+// There's one WebKitContext per profile. Various DispatcherHost classes
+// have a pointer to the Context to store shared state. Unfortunately, this
+// class has become a bit of a dumping ground for calls made on the UI thread
+// that need to be proxied over to the WebKit thread.
+//
+// This class is created on the UI thread and accessed on the UI, IO, and WebKit
+// threads.
+class WebKitContext
+ : public base::RefCountedThreadSafe<WebKitContext> {
+ public:
+ explicit WebKitContext(Profile* profile, bool clear_local_state_on_exit);
+
+ const FilePath& data_path() const { return data_path_; }
+ bool is_incognito() const { return is_incognito_; }
+
+ DOMStorageContext* dom_storage_context() {
+ return dom_storage_context_.get();
+ }
+
+ IndexedDBContext* indexed_db_context() {
+ return indexed_db_context_.get();
+ }
+
+ void set_clear_local_state_on_exit(bool clear_local_state) {
+ clear_local_state_on_exit_ = clear_local_state;
+ }
+
+#ifdef UNIT_TEST
+ // For unit tests, allow specifying a DOMStorageContext directly so it can be
+ // mocked.
+ void set_dom_storage_context(DOMStorageContext* dom_storage_context) {
+ dom_storage_context_.reset(dom_storage_context);
+ }
+#endif
+
+ // Tells the DOMStorageContext to purge any memory it does not need.
+ void PurgeMemory();
+
+ // Tell all children (where applicable) to delete any objects that were
+ // last modified on or after the following time.
+ void DeleteDataModifiedSince(const base::Time& cutoff,
+ const char* url_scheme_to_be_skipped,
+ const std::vector<string16>& protected_origins);
+
+ // Delete the session storage namespace associated with this id. Can be
+ // called from any thread.
+ void DeleteSessionStorageNamespace(int64 session_storage_namespace_id);
+
+ private:
+ friend class base::RefCountedThreadSafe<WebKitContext>;
+ virtual ~WebKitContext();
+
+ // Copies of profile data that can be accessed on any thread.
+ const FilePath data_path_;
+ const bool is_incognito_;
+
+ // True if the destructors of context objects should delete their files.
+ bool clear_local_state_on_exit_;
+
+ scoped_ptr<DOMStorageContext> dom_storage_context_;
+
+ scoped_ptr<IndexedDBContext> indexed_db_context_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WebKitContext);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_CONTEXT_H_
diff --git a/content/browser/in_process_webkit/webkit_context_unittest.cc b/content/browser/in_process_webkit/webkit_context_unittest.cc
new file mode 100644
index 0000000..811a3d0
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_context_unittest.cc
@@ -0,0 +1,60 @@
+// 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/test/testing_profile.h"
+#include "content/browser/browser_thread.h"
+#include "content/browser/in_process_webkit/dom_storage_context.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class MockDOMStorageContext : public DOMStorageContext {
+ public:
+ explicit MockDOMStorageContext(WebKitContext* webkit_context)
+ : DOMStorageContext(webkit_context),
+ purge_count_(0) {
+ }
+
+ virtual void PurgeMemory() {
+ EXPECT_FALSE(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+ ++purge_count_;
+ }
+
+ int purge_count() const { return purge_count_; }
+
+ private:
+ int purge_count_;
+};
+
+TEST(WebKitContextTest, Basic) {
+ TestingProfile profile;
+
+ scoped_refptr<WebKitContext> context1(new WebKitContext(&profile, false));
+ EXPECT_TRUE(profile.GetPath() == context1->data_path());
+ EXPECT_TRUE(profile.IsOffTheRecord() == context1->is_incognito());
+
+ scoped_refptr<WebKitContext> context2(new WebKitContext(&profile, false));
+ EXPECT_TRUE(context1->data_path() == context2->data_path());
+ EXPECT_TRUE(context1->is_incognito() == context2->is_incognito());
+}
+
+TEST(WebKitContextTest, PurgeMemory) {
+ // Start up a WebKit thread for the WebKitContext to call the
+ // DOMStorageContext on.
+ BrowserThread webkit_thread(BrowserThread::WEBKIT);
+ webkit_thread.Start();
+
+ // Create the contexts.
+ TestingProfile profile;
+ scoped_refptr<WebKitContext> context(new WebKitContext(&profile, false));
+ MockDOMStorageContext* mock_context =
+ new MockDOMStorageContext(context.get());
+ context->set_dom_storage_context(mock_context); // Takes ownership.
+
+ // Ensure PurgeMemory() calls our mock object on the right thread.
+ EXPECT_EQ(0, mock_context->purge_count());
+ context->PurgeMemory();
+ webkit_thread.Stop(); // Blocks until all tasks are complete.
+ EXPECT_EQ(1, mock_context->purge_count());
+}
diff --git a/content/browser/in_process_webkit/webkit_thread.cc b/content/browser/in_process_webkit/webkit_thread.cc
new file mode 100644
index 0000000..5a70be3
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_thread.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 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 "content/browser/in_process_webkit/webkit_thread.h"
+
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/browser/in_process_webkit/browser_webkitclient_impl.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
+#include "webkit/glue/webkit_glue.h"
+
+WebKitThread::WebKitThread() {
+}
+
+// This happens on the UI thread after the IO thread has been shut down.
+WebKitThread::~WebKitThread() {
+ // We can't just check CurrentlyOn(BrowserThread::UI) because in unit tests,
+ // MessageLoop::Current is sometimes NULL and other times valid and there's
+ // no BrowserThread object. Can't check that CurrentlyOn is not IO since
+ // some unit tests set that BrowserThread for other checks.
+ DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
+}
+
+void WebKitThread::Initialize() {
+ DCHECK(!webkit_thread_.get());
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) {
+ // TODO(jorlow): We need a better story for single process mode.
+ return;
+ }
+
+ webkit_thread_.reset(new InternalWebKitThread);
+ bool started = webkit_thread_->Start();
+ DCHECK(started);
+}
+
+WebKitThread::InternalWebKitThread::InternalWebKitThread()
+ : BrowserThread(BrowserThread::WEBKIT) {
+}
+
+WebKitThread::InternalWebKitThread::~InternalWebKitThread() {
+ Stop();
+}
+
+void WebKitThread::InternalWebKitThread::Init() {
+ DCHECK(!webkit_client_.get());
+ webkit_client_.reset(new BrowserWebKitClientImpl);
+ WebKit::initialize(webkit_client_.get());
+ webkit_glue::EnableWebCoreLogChannels(
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kWebCoreLogChannels));
+
+ // If possible, post initialization tasks to this thread (rather than doing
+ // them now) so we don't block the UI thread any longer than we have to.
+}
+
+void WebKitThread::InternalWebKitThread::CleanUp() {
+ DCHECK(webkit_client_.get());
+ WebKit::shutdown();
+}
diff --git a/content/browser/in_process_webkit/webkit_thread.h b/content/browser/in_process_webkit/webkit_thread.h
new file mode 100644
index 0000000..a677379
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_thread.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 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 CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_THREAD_H_
+#define CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_THREAD_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "base/threading/thread.h"
+#include "content/browser/browser_thread.h"
+
+class BrowserWebKitClientImpl;
+
+// This creates a WebKit main thread on instantiation (if not in
+// --single-process mode) on construction and kills it on deletion.
+class WebKitThread {
+ public:
+ // Called from the UI thread.
+ WebKitThread();
+ ~WebKitThread();
+ void Initialize();
+
+ private:
+ // Must be private so that we can carefully control its lifetime.
+ class InternalWebKitThread : public BrowserThread {
+ public:
+ InternalWebKitThread();
+ virtual ~InternalWebKitThread();
+ // Does the actual initialization and shutdown of WebKit. Called at the
+ // beginning and end of the thread's lifetime.
+ virtual void Init();
+ virtual void CleanUp();
+
+ private:
+ // The WebKitClient implementation. Only access on WebKit thread.
+ scoped_ptr<BrowserWebKitClientImpl> webkit_client_;
+ };
+
+ // Pointer to the actual WebKitThread.
+ scoped_ptr<InternalWebKitThread> webkit_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebKitThread);
+};
+
+#endif // CONTENT_BROWSER_IN_PROCESS_WEBKIT_WEBKIT_THREAD_H_
diff --git a/content/browser/in_process_webkit/webkit_thread_unittest.cc b/content/browser/in_process_webkit/webkit_thread_unittest.cc
new file mode 100644
index 0000000..ea56026
--- /dev/null
+++ b/content/browser/in_process_webkit/webkit_thread_unittest.cc
@@ -0,0 +1,22 @@
+// 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 "content/browser/in_process_webkit/webkit_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(WebKitThreadTest, DISABLED_ExposedInBrowserThread) {
+ int* null = NULL; // Help the template system out.
+ EXPECT_FALSE(BrowserThread::DeleteSoon(BrowserThread::WEBKIT,
+ FROM_HERE, null));
+ {
+ WebKitThread thread;
+ EXPECT_FALSE(BrowserThread::DeleteSoon(BrowserThread::WEBKIT,
+ FROM_HERE, null));
+ thread.Initialize();
+ EXPECT_TRUE(BrowserThread::DeleteSoon(BrowserThread::WEBKIT,
+ FROM_HERE, null));
+ }
+ EXPECT_FALSE(BrowserThread::DeleteSoon(BrowserThread::WEBKIT,
+ FROM_HERE, null));
+}
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index b821466..b44a56c 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -19,11 +19,11 @@
#include "base/string16.h"
#include "base/task.h"
#include "build/build_config.h"
-#include "chrome/browser/browser_message_filter.h"
-#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/net/resolve_proxy_msg_helper.h"
-#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/common/content_settings.h"
+#include "content/browser/browser_message_filter.h"
+#include "content/browser/in_process_webkit/webkit_context.h"
+#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPopupType.h"
#include "ui/base/clipboard/clipboard.h"
diff --git a/content/browser/renderer_host/render_view_host.cc b/content/browser/renderer_host/render_view_host.cc
index 58d3768..505416e 100644
--- a/content/browser/renderer_host/render_view_host.cc
+++ b/content/browser/renderer_host/render_view_host.cc
@@ -15,16 +15,12 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
-#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/extensions/extension_message_service.h"
-#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/net/predictor_api.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/common/bindings_policy.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
@@ -40,10 +36,14 @@
#include "chrome/common/translate_errors.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/web_apps.h"
+#include "content/browser/child_process_security_policy.h"
+#include "content/browser/cross_site_request_manager.h"
+#include "content/browser/in_process_webkit/session_storage_namespace.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host.h"
#include "content/browser/renderer_host/render_widget_host_view.h"
+#include "content/browser/site_instance.h"
#include "net/base/net_util.h"
#include "printing/native_metafile.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc
index 47709e5..89440cb 100644
--- a/content/browser/renderer_host/resource_dispatcher_host.cc
+++ b/content/browser/renderer_host/resource_dispatcher_host.cc
@@ -17,10 +17,6 @@
#include "base/shared_memory.h"
#include "base/stl_util-inl.h"
#include "base/time.h"
-#include "chrome/browser/cert_store.h"
-#include "chrome/browser/child_process_security_policy.h"
-#include "chrome/browser/chrome_blob_storage_context.h"
-#include "chrome/browser/cross_site_request_manager.h"
#include "chrome/browser/download/download_file_manager.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_request_limiter.h"
@@ -28,7 +24,6 @@
#include "chrome/browser/download/save_file_manager.h"
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/browser/external_protocol_handler.h"
-#include "chrome/browser/in_process_webkit/webkit_thread.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/net/url_request_tracking.h"
#include "chrome/browser/plugin_service.h"
@@ -48,6 +43,11 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "content/browser/cert_store.h"
+#include "content/browser/child_process_security_policy.h"
+#include "content/browser/chrome_blob_storage_context.h"
+#include "content/browser/cross_site_request_manager.h"
+#include "content/browser/in_process_webkit/webkit_thread.h"
#include "content/browser/renderer_host/async_resource_handler.h"
#include "content/browser/renderer_host/buffered_resource_handler.h"
#include "content/browser/renderer_host/cross_site_resource_handler.h"
diff --git a/content/browser/tab_contents/navigation_controller.cc b/content/browser/tab_contents/navigation_controller.cc
index 2ac9aba..ba3ef2a 100644
--- a/content/browser/tab_contents/navigation_controller.cc
+++ b/content/browser/tab_contents/navigation_controller.cc
@@ -11,10 +11,8 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_about_handler.h"
#include "chrome/browser/browser_url_handler.h"
-#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/sessions/session_types.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/navigation_types.h"
@@ -22,6 +20,8 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "content/browser/in_process_webkit/session_storage_namespace.h"
+#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/navigation_entry.h"
#include "content/browser/tab_contents/tab_contents.h"
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index 50fcb39..344e1cb 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -19,7 +19,6 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/character_encoding.h"
-#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/content_settings/content_settings_details.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
@@ -39,9 +38,7 @@
#include "chrome/browser/history/history.h"
#include "chrome/browser/history/history_types.h"
#include "chrome/browser/history/top_sites.h"
-#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/hung_renderer_dialog.h"
-#include "chrome/browser/in_process_webkit/session_storage_namespace.h"
#include "chrome/browser/load_from_memory_cache_details.h"
#include "chrome/browser/load_notification_details.h"
#include "chrome/browser/metrics/metric_event_duration_details.h"
@@ -57,11 +54,6 @@
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/printing/print_view_manager.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/renderer_host/render_process_host.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#include "chrome/browser/renderer_host/resource_request_details.h"
-#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/safe_browsing/client_side_detection_host.h"
@@ -86,6 +78,14 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "chrome/common/url_constants.h"
+#include "content/browser/child_process_security_policy.h"
+#include "content/browser/host_zoom_map.h"
+#include "content/browser/in_process_webkit/session_storage_namespace.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/renderer_host/render_widget_host_view.h"
+#include "content/browser/renderer_host/resource_request_details.h"
+#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/infobar_delegate.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/navigation_entry.h"
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index d851e49..7d2f7c3 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -54,6 +54,30 @@
'browser/gpu_process_host.h',
'browser/host_zoom_map.cc',
'browser/host_zoom_map.h',
+ 'browser/in_process_webkit/browser_webkitclient_impl.cc',
+ 'browser/in_process_webkit/browser_webkitclient_impl.h',
+ 'browser/in_process_webkit/dom_storage_area.cc',
+ 'browser/in_process_webkit/dom_storage_area.h',
+ 'browser/in_process_webkit/dom_storage_context.cc',
+ 'browser/in_process_webkit/dom_storage_context.h',
+ 'browser/in_process_webkit/dom_storage_message_filter.cc',
+ 'browser/in_process_webkit/dom_storage_message_filter.h',
+ 'browser/in_process_webkit/dom_storage_namespace.cc',
+ 'browser/in_process_webkit/dom_storage_namespace.h',
+ 'browser/in_process_webkit/indexed_db_callbacks.cc',
+ 'browser/in_process_webkit/indexed_db_callbacks.h',
+ 'browser/in_process_webkit/indexed_db_context.cc',
+ 'browser/in_process_webkit/indexed_db_context.h',
+ 'browser/in_process_webkit/indexed_db_dispatcher_host.cc',
+ 'browser/in_process_webkit/indexed_db_dispatcher_host.h',
+ 'browser/in_process_webkit/indexed_db_key_utility_client.cc',
+ 'browser/in_process_webkit/indexed_db_key_utility_client.h',
+ 'browser/in_process_webkit/session_storage_namespace.cc',
+ 'browser/in_process_webkit/session_storage_namespace.h',
+ 'browser/in_process_webkit/webkit_context.cc',
+ 'browser/in_process_webkit/webkit_context.h',
+ 'browser/in_process_webkit/webkit_thread.cc',
+ 'browser/in_process_webkit/webkit_thread.h',
'browser/mime_registry_message_filter.cc',
'browser/mime_registry_message_filter.h',
'browser/modal_html_dialog_delegate.cc',