diff options
-rw-r--r-- | chrome/browser/extensions/extension_data_deleter.cc | 50 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_data_deleter.h | 62 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 13 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.h | 3 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 79 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.h | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/user_script_listener_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_context.cc | 14 | ||||
-rw-r--r-- | chrome/browser/in_process_webkit/dom_storage_context.h | 7 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/test/testing_profile.cc | 29 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 5 | ||||
-rw-r--r-- | net/base/cookie_monster.cc | 79 | ||||
-rw-r--r-- | net/base/cookie_monster.h | 7 | ||||
-rw-r--r-- | webkit/database/database_tracker.cc | 60 | ||||
-rw-r--r-- | webkit/database/database_tracker.h | 10 |
16 files changed, 375 insertions, 52 deletions
diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc new file mode 100644 index 0000000..98cf433 --- /dev/null +++ b/chrome/browser/extensions/extension_data_deleter.cc @@ -0,0 +1,50 @@ +// 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 "chrome/browser/extensions/extension_data_deleter.h" + +#include "chrome/browser/profile.h" +#include "chrome/common/extensions/extension.h" +#include "net/base/cookie_monster.h" +#include "net/base/net_errors.h" +#include "webkit/database/database_util.h" + +ExtensionDataDeleter::ExtensionDataDeleter(Profile* profile, + const GURL& extension_url) { + DCHECK(profile); + webkit_context_ = profile->GetWebKitContext(); + database_tracker_ = profile->GetDatabaseTracker(); + extension_request_context_ = profile->GetRequestContextForExtensions(); + extension_url_ = extension_url; + origin_id_ = + webkit_database::DatabaseUtil::GetOriginIdentifier(extension_url_); +} + +void ExtensionDataDeleter::StartDeleting() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + net::CookieMonster* cookie_monster = + extension_request_context_->GetCookieStore()->GetCookieMonster(); + if (cookie_monster) + cookie_monster->DeleteAllForURL(extension_url_, true); + + ChromeThread::PostTask(ChromeThread::WEBKIT, FROM_HERE, + NewRunnableMethod(this, + &ExtensionDataDeleter::DeleteLocalStorageOnWebkitThread)); + + ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, + NewRunnableMethod(this, + &ExtensionDataDeleter::DeleteDatabaseOnFileThread)); +} + +void ExtensionDataDeleter::DeleteDatabaseOnFileThread() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); + int rv = database_tracker_->DeleteDataForOrigin(origin_id_, NULL); + DCHECK(rv == net::OK || rv == net::ERR_IO_PENDING); +} + +void ExtensionDataDeleter::DeleteLocalStorageOnWebkitThread() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + webkit_context_->dom_storage_context()->DeleteLocalStorageForOrigin( + origin_id_); +} diff --git a/chrome/browser/extensions/extension_data_deleter.h b/chrome/browser/extensions/extension_data_deleter.h new file mode 100644 index 0000000..a886833 --- /dev/null +++ b/chrome/browser/extensions/extension_data_deleter.h @@ -0,0 +1,62 @@ +// 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 CHROME_BROWSER_EXTENSIONS_EXTENSION_DATA_DELETER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_DATA_DELETER_H_ + +#include <string> + +#include "base/ref_counted.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/in_process_webkit/webkit_context.h" +#include "chrome/browser/net/url_request_context_getter.h" +#include "googleurl/src/gurl.h" +#include "webkit/database/database_tracker.h" + +class Extension; +class Profile; + +// A helper class that takes care of removing local storage, databases and +// cookies for a given extension. This is used by +// ExtensionsService::ClearExtensionData() upon uninstalling an extension. +class ExtensionDataDeleter + : public base::RefCountedThreadSafe<ExtensionDataDeleter, + ChromeThread::DeleteOnUIThread> { + public: + ExtensionDataDeleter(Profile* profile, const GURL& extension_url); + + // Start removing data. The extension should not be running when this is + // called. Cookies are deleted on the current thread, local storage and + // databases are deleted asynchronously on the webkit and file threads, + // respectively. This function must be called from the UI thread. + void StartDeleting(); + + private: + // Deletes the database for the extension. May only be called on the file + // thread. + void DeleteDatabaseOnFileThread(); + + // Deletes local storage for the extension. May only be called on the webkit + // thread. + void DeleteLocalStorageOnWebkitThread(); + + // The database context for deleting the database. + scoped_refptr<webkit_database::DatabaseTracker> database_tracker_; + + // Provides access to the extension request context. + scoped_refptr<URLRequestContextGetter> extension_request_context_; + + // The URL of the extension we're removing data for. + GURL extension_url_; + + // The security origin identifier for which we're deleting stuff. + string16 origin_id_; + + // Webkit context for accessing the DOM storage helper. + scoped_refptr<WebKitContext> webkit_context_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionDataDeleter); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_DATA_DELETER_H_ diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 4c3e039..28ba10c 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -19,6 +19,7 @@ #include "chrome/browser/extensions/extension_accessibility_api.h" #include "chrome/browser/extensions/extension_bookmarks_module.h" #include "chrome/browser/extensions/extension_browser_event_router.h" +#include "chrome/browser/extensions/extension_data_deleter.h" #include "chrome/browser/extensions/extension_dom_ui.h" #include "chrome/browser/extensions/extension_history_api.h" #include "chrome/browser/extensions/extension_host.h" @@ -41,6 +42,7 @@ #include "chrome/common/json_value_serializer.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" +#include "googleurl/src/gurl.h" #include "webkit/database/database_tracker.h" #include "webkit/database/database_util.h" @@ -268,6 +270,7 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id, // Callers should not send us nonexistant extensions. DCHECK(extension); + GURL extension_url(extension->url()); extension_prefs_->OnExtensionUninstalled(extension, external_uninstall); @@ -283,7 +286,17 @@ void ExtensionsService::UninstallExtension(const std::string& extension_id, ExtensionDOMUI::UnregisterChromeURLOverrides(profile_, extension->GetChromeURLOverrides()); + // TODO(mnissler, erikkay) Check whether we should really unload the extension + // first, so we we're sure it's not running while we clean up. UnloadExtension(extension_id); + + ClearExtensionData(extension_url); +} + +void ExtensionsService::ClearExtensionData(const GURL& extension_url) { + scoped_refptr<ExtensionDataDeleter> deleter( + new ExtensionDataDeleter(profile_, extension_url)); + deleter->StartDeleting(); } void ExtensionsService::EnableExtension(const std::string& extension_id) { diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 86737f0..413454c 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -293,6 +293,9 @@ class ExtensionsService friend class ChromeThread; friend class DeleteTask<ExtensionsService>; + // Clear all persistent data that may have been stored by the extension. + void ClearExtensionData(const GURL& extension_url); + // Look up an extension by ID, optionally including either or both of enabled // and disabled extensions. Extension* GetExtensionByIdInternal(const std::string& id, diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index a142ca4..ff9a2b6 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -39,6 +39,8 @@ #include "testing/platform_test.h" #include "webkit/database/database_tracker.h" #include "webkit/database/database_util.h" +#include "net/base/cookie_monster.h" +#include "net/base/cookie_options.h" namespace keys = extension_manifest_keys; @@ -221,14 +223,17 @@ class ExtensionTestingProfile : public TestingProfile { ExtensionsServiceTestBase::ExtensionsServiceTestBase() : loop_(MessageLoop::TYPE_IO), ui_thread_(ChromeThread::UI, &loop_), - file_thread_(ChromeThread::FILE, &loop_) { + webkit_thread_(ChromeThread::WEBKIT, &loop_), + file_thread_(ChromeThread::FILE, &loop_), + io_thread_(ChromeThread::IO, &loop_) { } ExtensionsServiceTestBase::~ExtensionsServiceTestBase() { - // Drop our reference to ExtensionsService now, so that it can be destroyed - // while ChromeThreads and MessageLoop are still around (they are used - // in the ExtensionsService destruction process). + // Drop our reference to ExtensionsService and TestingProfile, so that they + // can be destroyed while ChromeThreads and MessageLoop are still around (they + // are used in the destruction process). service_ = NULL; + profile_.reset(NULL); MessageLoop::current()->RunAllPending(); } @@ -1260,6 +1265,72 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) { EXPECT_FALSE(file_util::PathExists(extension_path)); } +// Verifies extension state is removed upon uninstall +TEST_F(ExtensionsServiceTest, ClearExtensionData) { + InitializeEmptyExtensionsService(); + + // Load a test extension. + FilePath path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); + path = path.AppendASCII("extensions"); + path = path.AppendASCII("good.crx"); + InstallExtension(path, true); + Extension* extension = service_->GetExtensionById(good_crx, false); + ASSERT_TRUE(extension); + GURL ext_url(extension->url()); + string16 origin_id = + webkit_database::DatabaseUtil::GetOriginIdentifier(ext_url); + + // Set a cookie for the extension. + net::CookieMonster* cookie_monster = profile_ + ->GetRequestContextForExtensions()->GetCookieStore()->GetCookieMonster(); + ASSERT_TRUE(cookie_monster); + net::CookieOptions options; + cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options); + net::CookieMonster::CookieList list = + cookie_monster->GetAllCookiesForURL(ext_url); + EXPECT_EQ(1U, list.size()); + + // Open a database. + webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker(); + string16 db_name = UTF8ToUTF16("db"); + string16 description = UTF8ToUTF16("db_description"); + int64 size; + int64 available; + db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size, + &available); + db_tracker->DatabaseClosed(origin_id, db_name); + std::vector<webkit_database::OriginInfo> origins; + db_tracker->GetAllOriginsInfo(&origins); + EXPECT_EQ(1U, origins.size()); + EXPECT_EQ(origin_id, origins[0].GetOrigin()); + + // Create local storage. We only simulate this by creating the backing file + // since webkit is not initialized. + DOMStorageContext* context = + profile_->GetWebKitContext()->dom_storage_context(); + FilePath lso_path = context->GetLocalStorageFilePath(origin_id); + EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName())); + EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0)); + EXPECT_TRUE(file_util::PathExists(lso_path)); + + // Uninstall the extension. + service_->UninstallExtension(good_crx, false); + loop_.RunAllPending(); + + // Check that the cookie is gone. + list = cookie_monster->GetAllCookiesForURL(ext_url); + EXPECT_EQ(0U, list.size()); + + // The database should have vanished as well. + origins.clear(); + db_tracker->GetAllOriginsInfo(&origins); + EXPECT_EQ(0U, origins.size()); + + // Check that the LSO file has been removed. + EXPECT_FALSE(file_util::PathExists(lso_path)); +} + // Tests loading single extensions (like --load-extension) TEST_F(ExtensionsServiceTest, LoadExtension) { InitializeEmptyExtensionsService(); diff --git a/chrome/browser/extensions/extensions_service_unittest.h b/chrome/browser/extensions/extensions_service_unittest.h index 1f24fed..fdb2ddd 100644 --- a/chrome/browser/extensions/extensions_service_unittest.h +++ b/chrome/browser/extensions/extensions_service_unittest.h @@ -44,7 +44,9 @@ class ExtensionsServiceTestBase : public testing::Test { size_t total_successes_; MessageLoop loop_; ChromeThread ui_thread_; + ChromeThread webkit_thread_; ChromeThread file_thread_; + ChromeThread io_thread_; }; #endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_UNITTEST_H_ diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc index cd9048c..ec13f9f 100644 --- a/chrome/browser/extensions/user_script_listener_unittest.cc +++ b/chrome/browser/extensions/user_script_listener_unittest.cc @@ -107,8 +107,7 @@ class UserScriptListenerTest : public ExtensionsServiceTestBase, public URLRequest::Interceptor { public: - UserScriptListenerTest() - : mock_io_thread_(ChromeThread::IO, MessageLoop::current()) { + UserScriptListenerTest() { URLRequest::RegisterRequestInterceptor(this); } @@ -171,8 +170,6 @@ class UserScriptListenerTest scoped_refptr<UserScriptListener> listener_; private: - ChromeThread mock_io_thread_; - ResourceQueue resource_queue_; }; diff --git a/chrome/browser/in_process_webkit/dom_storage_context.cc b/chrome/browser/in_process_webkit/dom_storage_context.cc index 279ecb5..bea4611 100644 --- a/chrome/browser/in_process_webkit/dom_storage_context.cc +++ b/chrome/browser/in_process_webkit/dom_storage_context.cc @@ -190,6 +190,11 @@ void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) { file_util::Delete(file_path, false); } +void DOMStorageContext::DeleteLocalStorageForOrigin(const string16& origin_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); + DeleteLocalStorageFile(GetLocalStorageFilePath(origin_id)); +} + void DOMStorageContext::DeleteAllLocalStorageFiles() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); @@ -264,3 +269,12 @@ void DOMStorageContext::ClearLocalState(const FilePath& profile_path, } } } + +FilePath DOMStorageContext::GetLocalStorageFilePath( + const string16& origin_id) const { + FilePath storageDir = webkit_context_->data_path().Append( + DOMStorageContext::kLocalStorageDirectory); + FilePath::StringType id = + webkit_glue::WebStringToFilePathString(origin_id); + return storageDir.Append(id.append(kLocalStorageExtension)); +} diff --git a/chrome/browser/in_process_webkit/dom_storage_context.h b/chrome/browser/in_process_webkit/dom_storage_context.h index 81276c2..2b9e1d1 100644 --- a/chrome/browser/in_process_webkit/dom_storage_context.h +++ b/chrome/browser/in_process_webkit/dom_storage_context.h @@ -9,6 +9,7 @@ #include <set> #include "base/file_path.h" +#include "base/string16.h" #include "base/time.h" class DOMStorageArea; @@ -70,6 +71,9 @@ class DOMStorageContext { // 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(); @@ -83,6 +87,9 @@ class DOMStorageContext { static void ClearLocalState(const FilePath& profile_path, const char* url_scheme_to_be_skipped); + // Get the file name of the local storage file for the given origin. + FilePath GetLocalStorageFilePath(const string16& origin_id) const; + private: // Get the local storage instance. The object is owned by this class. DOMStorageNamespace* CreateLocalStorage(); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 7f8f8d7..6284635 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -936,6 +936,8 @@ 'browser/extensions/extension_context_menu_model.h', 'browser/extensions/extension_creator.cc', 'browser/extensions/extension_creator.h', + 'browser/extensions/extension_data_deleter.cc', + 'browser/extensions/extension_data_deleter.h', 'browser/extensions/extension_disabled_infobar_delegate.cc', 'browser/extensions/extension_disabled_infobar_delegate.h', 'browser/extensions/extension_devtools_bridge.cc', diff --git a/chrome/test/testing_profile.cc b/chrome/test/testing_profile.cc index 8fb3a5b..b0be809 100644 --- a/chrome/test/testing_profile.cc +++ b/chrome/test/testing_profile.cc @@ -7,6 +7,7 @@ #include "build/build_config.h" #include "base/command_line.h" #include "base/string_util.h" +#include "chrome/common/url_constants.h" #include "chrome/browser/bookmarks/bookmark_model.h" #include "chrome/browser/dom_ui/ntp_resource_cache.h" #include "chrome/browser/history/history_backend.h" @@ -109,6 +110,28 @@ class TestURLRequestContextGetter : public URLRequestContextGetter { scoped_refptr<URLRequestContext> context_; }; +class TestExtensionURLRequestContext : public URLRequestContext { + public: + TestExtensionURLRequestContext() { + net::CookieMonster* cookie_monster = new net::CookieMonster(NULL, NULL); + const char* schemes[] = {chrome::kExtensionScheme}; + cookie_monster->SetCookieableSchemes(schemes, 1); + cookie_store_ = cookie_monster; + } +}; + +class TestExtensionURLRequestContextGetter : public URLRequestContextGetter { + public: + virtual URLRequestContext* GetURLRequestContext() { + if (!context_) + context_ = new TestExtensionURLRequestContext(); + return context_.get(); + } + + private: + scoped_refptr<URLRequestContext> context_; +}; + } // namespace TestingProfile::TestingProfile() @@ -277,6 +300,12 @@ void TestingProfile::CreateRequestContext() { request_context_ = new TestURLRequestContextGetter(); } +URLRequestContextGetter* TestingProfile::GetRequestContextForExtensions() { + if (!extensions_request_context_) + extensions_request_context_ = new TestExtensionURLRequestContextGetter(); + return extensions_request_context_.get(); +} + void TestingProfile::set_session_service(SessionService* session_service) { session_service_ = session_service; } diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 08e02b7..ce1603d 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -179,9 +179,7 @@ class TestingProfile : public Profile { void CreateRequestContext(); virtual URLRequestContextGetter* GetRequestContextForMedia() { return NULL; } - virtual URLRequestContextGetter* GetRequestContextForExtensions() { - return NULL; - } + virtual URLRequestContextGetter* GetRequestContextForExtensions(); virtual net::SSLConfigService* GetSSLConfigService() { return NULL; } virtual Blacklist* GetPrivacyBlacklist() { return NULL; } @@ -303,6 +301,7 @@ class TestingProfile : public Profile { // Internally, this is a TestURLRequestContextGetter that creates a dummy // request context. Currently, only the CookieMonster is hooked up. scoped_refptr<URLRequestContextGetter> request_context_; + scoped_refptr<URLRequestContextGetter> extensions_request_context_; // Do we have a history service? This defaults to the value of // history_service, but can be explicitly set. diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc index 5a1e492..f0cf00a 100644 --- a/net/base/cookie_monster.cc +++ b/net/base/cookie_monster.cc @@ -787,6 +787,20 @@ int CookieMonster::DeleteAllCreatedAfter(const Time& delete_begin, return DeleteAllCreatedBetween(delete_begin, Time(), sync_to_store); } +int CookieMonster::DeleteAllForURL(const GURL& url, + bool sync_to_store) { + AutoLock autolock(lock_); + InitIfNecessary(); + CookieList cookies = InternalGetAllCookiesForURL(url); + int num_deleted = 0; + for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) { + CookieMap::iterator curit = it; + ++it; + InternalDeleteCookie(curit, sync_to_store); + } + return num_deleted; +} + bool CookieMonster::DeleteCookie(const std::string& domain, const CanonicalCookie& cookie, bool sync_to_store) { @@ -916,37 +930,7 @@ CookieMonster::CookieList CookieMonster::GetAllCookies() { CookieMonster::CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) { AutoLock autolock(lock_); InitIfNecessary(); - - // Do not return removed cookies. - GarbageCollectExpired(Time::Now(), - CookieMapItPair(cookies_.begin(), cookies_.end()), - NULL); - - CookieList cookie_list; - if (!HasCookieableScheme(url)) - return cookie_list; - - bool secure = url.SchemeIsSecure(); - - // Query for the full host, For example: 'a.c.blah.com'. - std::string key(url.host()); - FindRawCookies(key, secure, url.path(), &cookie_list); - - // See if we can search for domain cookies, i.e. if the host has a TLD + 1. - const std::string domain(GetEffectiveDomain(url.scheme(), key)); - if (domain.empty()) - return cookie_list; - - // Use same logic as in FindCookiesForHostAndDomain. - DCHECK_LE(domain.length(), key.length()); - DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(), - domain)); - for (key = "." + key; key.length() > domain.length(); ) { - FindRawCookies(key, secure, url.path(), &cookie_list); - const size_t next_dot = key.find('.', 1); // Skip over leading dot. - key.erase(0, next_dot); - } - return cookie_list; + return InternalGetAllCookiesForURL(url); } void CookieMonster::FindCookiesForHostAndDomain( @@ -1035,6 +1019,39 @@ void CookieMonster::FindRawCookies(const std::string& key, } } +CookieMonster::CookieList CookieMonster::InternalGetAllCookiesForURL( + const GURL& url) { + // Do not return removed cookies. + GarbageCollectExpired(Time::Now(), + CookieMapItPair(cookies_.begin(), cookies_.end()), + NULL); + + CookieList cookie_list; + if (!HasCookieableScheme(url)) + return cookie_list; + + bool secure = url.SchemeIsSecure(); + + // Query for the full host, For example: 'a.c.blah.com'. + std::string key(url.host()); + FindRawCookies(key, secure, url.path(), &cookie_list); + + // See if we can search for domain cookies, i.e. if the host has a TLD + 1. + const std::string domain(GetEffectiveDomain(url.scheme(), key)); + if (domain.empty()) + return cookie_list; + + // Use same logic as in FindCookiesForHostAndDomain. + DCHECK_LE(domain.length(), key.length()); + DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(), + domain)); + for (key = "." + key; key.length() > domain.length(); ) { + FindRawCookies(key, secure, url.path(), &cookie_list); + const size_t next_dot = key.find('.', 1); // Skip over leading dot. + key.erase(0, next_dot); + } + return cookie_list; +} CookieMonster::ParsedCookie::ParsedCookie(const std::string& cookie_line) : is_valid_(false), diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h index ab82056..d421d6f 100644 --- a/net/base/cookie_monster.h +++ b/net/base/cookie_monster.h @@ -118,6 +118,9 @@ class CookieMonster : public CookieStore { // one passed into the function via |delete_after|. int DeleteAllCreatedAfter(const base::Time& delete_begin, bool sync_to_store); + // Delete all cookies that match the given URL. + int DeleteAllForURL(const GURL& url, bool sync_to_store); + // Delete one specific cookie. bool DeleteCookie(const std::string& domain, const CanonicalCookie& cookie, @@ -182,6 +185,10 @@ class CookieMonster : public CookieStore { const std::string& path, CookieList* list); + // Internal helper returning all cookies for a given URL. The caller is + // assumed to hold lock_ and having called InitIfNecessary(). + CookieList InternalGetAllCookiesForURL(const GURL& url); + // Delete any cookies that are equivalent to |ecc| (same path, key, etc). // If |skip_httponly| is true, httponly cookies will not be deleted. The // return value with be true if |skip_httponly| skipped an httponly cookie. diff --git a/webkit/database/database_tracker.cc b/webkit/database/database_tracker.cc index bc7dd47..ea1994e 100644 --- a/webkit/database/database_tracker.cc +++ b/webkit/database/database_tracker.cc @@ -420,6 +420,22 @@ void DatabaseTracker::ScheduleDatabaseForDeletion( origin_identifier, database_name)); } +void DatabaseTracker::ScheduleDatabasesForDeletion( + const DatabaseSet& databases, + net::CompletionCallback* callback) { + DCHECK(!callback || + deletion_callbacks_.find(callback) == deletion_callbacks_.end()); + DCHECK(!databases.empty()); + if (callback) + deletion_callbacks_[callback] = databases; + for (DatabaseSet::const_iterator ori = databases.begin(); + ori != databases.end(); ++ori) { + for (std::set<string16>::const_iterator db = ori->second.begin(); + db != ori->second.end(); ++db) + ScheduleDatabaseForDeletion(ori->first, *db); + } +} + int DatabaseTracker::DeleteDatabase(const string16& origin_identifier, const string16& database_name, net::CompletionCallback* callback) { @@ -477,18 +493,42 @@ int DatabaseTracker::DeleteDataModifiedSince( } } + if (rv != net::OK) + return rv; + if (!to_be_deleted.empty()) { - if (callback) - deletion_callbacks_[callback] = to_be_deleted; - for (DatabaseSet::iterator ori = to_be_deleted.begin(); - ori != to_be_deleted.end(); ++ori) { - for (std::set<string16>::iterator db = ori->second.begin(); - db != ori->second.end(); ++db) - ScheduleDatabaseForDeletion(ori->first, *db); - } - rv = net::ERR_IO_PENDING; + ScheduleDatabasesForDeletion(to_be_deleted, callback); + return net::ERR_IO_PENDING; + } + return net::OK; +} + +int DatabaseTracker::DeleteDataForOrigin(const string16& origin, + net::CompletionCallback* callback) { + if (!LazyInit()) + return net::ERR_FAILED; + + DCHECK(!callback || + deletion_callbacks_.find(callback) == deletion_callbacks_.end()); + DatabaseSet to_be_deleted; + + std::vector<DatabaseDetails> details; + if (!databases_table_->GetAllDatabaseDetailsForOrigin(origin, &details)) + return net::ERR_FAILED; + for (std::vector<DatabaseDetails>::const_iterator db = details.begin(); + db != details.end(); ++db) { + // Check if the database is opened by any renderer. + if (database_connections_.IsDatabaseOpened(origin, db->database_name)) + to_be_deleted[origin].insert(db->database_name); + else + DeleteClosedDatabase(origin, db->database_name); } - return rv; + + if (!to_be_deleted.empty()) { + ScheduleDatabasesForDeletion(to_be_deleted, callback); + return net::ERR_IO_PENDING; + } + return net::OK; } // static diff --git a/webkit/database/database_tracker.h b/webkit/database/database_tracker.h index 90c9ebc..d1d5a43 100644 --- a/webkit/database/database_tracker.h +++ b/webkit/database/database_tracker.h @@ -148,6 +148,12 @@ class DatabaseTracker int DeleteDataModifiedSince(const base::Time& cutoff, net::CompletionCallback* callback); + // Delete all databases that belong to the given origin. Returns net::OK on + // success, net::FAILED if not all databases could be deleted, and + // net::ERR_IO_PENDING and |callback| is invoked upon completion, if non-NULL. + int DeleteDataForOrigin(const string16& origin_identifier, + net::CompletionCallback* callback); + static void ClearLocalState(const FilePath& profile_path); private: @@ -201,6 +207,10 @@ class DatabaseTracker const string16& database_name); void ScheduleDatabaseForDeletion(const string16& origin_identifier, const string16& database_name); + // Schedule a set of open databases for deletion. If non-null, callback is + // invoked upon completion. + void ScheduleDatabasesForDeletion(const DatabaseSet& databases, + net::CompletionCallback* callback); bool initialized_; const FilePath db_dir_; |