diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 17:40:50 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-24 17:40:50 +0000 |
commit | 567812dd45d36e093554664bdbd4284a9670a8b3 (patch) | |
tree | 803b8da070eabfd2efa6a50b53f331c4255bbbc6 /content | |
parent | abe19c107967234fce377db157b8b963f83ec529 (diff) | |
download | chromium_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')
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', |