summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcreis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-17 12:20:10 +0000
committercreis@chromium.org <creis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-17 12:20:10 +0000
commit14acc6453fa956c279b2b788e00f937e23d951b3 (patch)
tree04df34881382e794d7218af42a62aa43df57e5e2
parent3df6cdbbdec79e947aeadfbb360c755b7790a637 (diff)
downloadchromium_src-14acc6453fa956c279b2b788e00f937e23d951b3.zip
chromium_src-14acc6453fa956c279b2b788e00f937e23d951b3.tar.gz
chromium_src-14acc6453fa956c279b2b788e00f937e23d951b3.tar.bz2
Implement the ability to obliterate a storage partition from disk.
On the uninstall of an extension with isolated storage, we want to delete all the data for the extension from disk as soon as possible. Because we cannot know when various objects with state on disk (eg., FileSystemContext) have all been deleted, we do a best-effort delete for any directory that we know isn't being used. The way this gets projected into the content modulue is that each extension defines one partition_domain. If an extension has a <webview> tag, it will also have multiple StoragePartitions, each with a different partition_name. If it doesn't have a <webview> tag, the partition_name is considered empty which yields the default partition. The default partition, and all webview partitions are peers inside the partition_domain's root directory. This CL introduces a function that allows us to delete partiton domain. Special care is taken to not accidentally instantiate a StoragePartition for the domain if none current exists. This is necessary to allow us to actually delete the whole partition domain directory. (Patch by ajwong@chromium.org) BUG=85127 Review URL: https://chromiumcodereview.appspot.com/11280030 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@168405 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chrome_content_browser_client.cc59
-rw-r--r--chrome/browser/chrome_content_browser_client.h1
-rw-r--r--chrome/browser/extensions/data_deleter.cc12
-rw-r--r--content/browser/browser_context.cc29
-rw-r--r--content/browser/storage_partition_impl.cc120
-rw-r--r--content/browser/storage_partition_impl.h1
-rw-r--r--content/browser/storage_partition_impl_map.cc163
-rw-r--r--content/browser/storage_partition_impl_map.h7
-rw-r--r--content/public/browser/browser_context.h3
-rw-r--r--content/public/browser/content_browser_client.cc1
-rw-r--r--content/public/browser/content_browser_client.h18
-rw-r--r--content/public/browser/storage_partition.h4
12 files changed, 337 insertions, 81 deletions
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 450a7ab..cd5048a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -501,9 +501,16 @@ bool ChromeContentBrowserClient::IsValidStoragePartitionId(
void ChromeContentBrowserClient::GetStoragePartitionConfigForSite(
content::BrowserContext* browser_context,
const GURL& site,
+ bool can_be_default,
std::string* partition_domain,
std::string* partition_name,
bool* in_memory) {
+ // Default to the browser-wide storage partition and override based on |site|
+ // below.
+ partition_domain->clear();
+ partition_name->clear();
+ *in_memory = false;
+
// For the webview tag, we create special guest processes, which host the
// tag content separately from the main application that embeds the tag.
// A webview tag can specify both the partition name and whether the storage
@@ -523,30 +530,44 @@ void ChromeContentBrowserClient::GetStoragePartitionConfigForSite(
// URL was created, so it needs to be decoded.
*partition_name = net::UnescapeURLComponent(site.query(),
net::UnescapeRule::NORMAL);
- return;
- }
+ } else if (site.SchemeIs(extensions::kExtensionScheme)) {
+ // If |can_be_default| is false, the caller is stating that the |site|
+ // should be parsed as if it had isolated storage. In particular it is
+ // important to NOT check ExtensionService for the is_storage_isolated()
+ // attribute because this code path is run during Extension uninstall
+ // to do cleanup after the Extension has already been unloaded from the
+ // ExtensionService.
+ bool is_isolated = !can_be_default;
+ if (can_be_default) {
+ const Extension* extension = NULL;
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+ ExtensionService* extension_service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ if (extension_service) {
+ extension = extension_service->extensions()->
+ GetExtensionOrAppByURL(ExtensionURLInfo(site));
+ if (extension && extension->is_storage_isolated()) {
+ is_isolated = true;
+ }
+ }
+ }
- const Extension* extension = NULL;
- Profile* profile = Profile::FromBrowserContext(browser_context);
- ExtensionService* extension_service =
- extensions::ExtensionSystem::Get(profile)->extension_service();
- if (extension_service) {
- extension = extension_service->extensions()->
- GetExtensionOrAppByURL(ExtensionURLInfo(site));
- if (extension && extension->is_storage_isolated()) {
- // Extensions which have storage isolation enabled (e.g., apps), use
- // the extension id as the |partition_domain|.
- *partition_domain = extension->id();
- partition_name->clear();
+ if (is_isolated) {
+ CHECK(site.has_host());
+ // For extensions with isolated storage, the the host of the |site| is
+ // the |partition_domain|. The |in_memory| and |partition_name| are only
+ // used in guest schemes so they are cleared here.
+ *partition_domain = site.host();
*in_memory = false;
- return;
+ partition_name->clear();
}
}
- // All other cases use the default, browser-wide, storage partition.
- partition_domain->clear();
- partition_name->clear();
- *in_memory = false;
+ // Assert that if |can_be_default| is false, the code above must have found a
+ // non-default partition. If this fails, the caller has a serious logic
+ // error about which StoragePartition they expect to be in and it is not
+ // safe to continue.
+ CHECK(can_be_default || !partition_domain->empty());
}
content::WebContentsViewDelegate*
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 78b741c..0b9e438 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -52,6 +52,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
virtual void GetStoragePartitionConfigForSite(
content::BrowserContext* browser_context,
const GURL& site,
+ bool can_be_default,
std::string* partition_domain,
std::string* partition_name,
bool* in_memory) OVERRIDE;
diff --git a/chrome/browser/extensions/data_deleter.cc b/chrome/browser/extensions/data_deleter.cc
index b4eac2b..fe84639 100644
--- a/chrome/browser/extensions/data_deleter.cc
+++ b/chrome/browser/extensions/data_deleter.cc
@@ -24,16 +24,16 @@ void DataDeleter::StartDeleting(Profile* profile,
const std::string& extension_id,
const GURL& storage_origin,
bool is_storage_isolated) {
- // TODO(ajwong): If |is_storage_isolated|, we should just blowaway the
- // whole directory that the associated StoragePartition is located at. To do
- // this, we need to ensure that all contexts referencing that directory have
- // closed their file handles, otherwise Windows will complain.
- //
- // http://www.crbug.com/85127
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile);
const GURL& site = Extension::GetBaseURLFromExtensionId(extension_id);
+
+ if (is_storage_isolated) {
+ BrowserContext::AsyncObliterateStoragePartition(profile, site);
+ return;
+ }
+
content::StoragePartition* partition =
BrowserContext::GetStoragePartitionForSite(profile, site);
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index d8bc87e..79355bc 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -37,11 +37,8 @@ namespace {
const char* kDownloadManagerKeyName = "download_manager";
const char* kStorageParitionMapKeyName = "content_storage_partition_map";
-StoragePartition* GetStoragePartitionFromConfig(
- BrowserContext* browser_context,
- const std::string& partition_domain,
- const std::string& partition_name,
- bool in_memory) {
+StoragePartitionImplMap* GetStoragePartitionMap(
+ BrowserContext* browser_context) {
StoragePartitionImplMap* partition_map =
static_cast<StoragePartitionImplMap*>(
browser_context->GetUserData(kStorageParitionMapKeyName));
@@ -49,6 +46,16 @@ StoragePartition* GetStoragePartitionFromConfig(
partition_map = new StoragePartitionImplMap(browser_context);
browser_context->SetUserData(kStorageParitionMapKeyName, partition_map);
}
+ return partition_map;
+}
+
+StoragePartition* GetStoragePartitionFromConfig(
+ BrowserContext* browser_context,
+ const std::string& partition_domain,
+ const std::string& partition_name,
+ bool in_memory) {
+ StoragePartitionImplMap* partition_map =
+ GetStoragePartitionMap(browser_context);
if (browser_context->IsOffTheRecord())
in_memory = true;
@@ -84,6 +91,13 @@ void PurgeMemoryOnIOThread(appcache::AppCacheService* appcache_service) {
} // namespace
+// static
+void BrowserContext::AsyncObliterateStoragePartition(
+ BrowserContext* browser_context,
+ const GURL& site) {
+ GetStoragePartitionMap(browser_context)->AsyncObliterate(site);
+}
+
DownloadManager* BrowserContext::GetDownloadManager(
BrowserContext* context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -116,7 +130,7 @@ StoragePartition* BrowserContext::GetStoragePartition(
// this conditional and require that |site_instance| is non-NULL.
if (site_instance) {
GetContentClient()->browser()->GetStoragePartitionConfigForSite(
- browser_context, site_instance->GetSiteURL(),
+ browser_context, site_instance->GetSiteURL(), true,
&partition_domain, &partition_name, &in_memory);
}
@@ -132,7 +146,8 @@ StoragePartition* BrowserContext::GetStoragePartitionForSite(
bool in_memory;
GetContentClient()->browser()->GetStoragePartitionConfigForSite(
- browser_context, site, &partition_domain, &partition_name, &in_memory);
+ browser_context, site, true, &partition_domain, &partition_name,
+ &in_memory);
return GetStoragePartitionFromConfig(
browser_context, partition_domain, partition_name, in_memory);
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index da17ff1..a3eafab 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -8,6 +8,7 @@
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/indexed_db_context.h"
#include "net/base/completion_callback.h"
#include "net/base/net_errors.h"
@@ -15,17 +16,38 @@
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_context.h"
#include "webkit/database/database_tracker.h"
-#include "webkit/database/database_util.h"
+#include "webkit/dom_storage/dom_storage_types.h"
#include "webkit/quota/quota_manager.h"
namespace content {
namespace {
-void ClearDataOnIOThread(
+void DoNothingStatusCallback(quota::QuotaStatusCode status) {
+ // Do nothing.
+}
+
+void ClearQuotaManagedOriginsOnIOThread(
+ const scoped_refptr<quota::QuotaManager>& quota_manager,
+ const std::set<GURL>& origins,
+ quota::StorageType type) {
+ // The QuotaManager manages all storage other than cookies, LocalStorage,
+ // and SessionStorage. This loop wipes out most HTML5 storage for the given
+ // origins.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ std::set<GURL>::const_iterator origin;
+ for (std::set<GURL>::const_iterator origin = origins.begin();
+ origin != origins.end(); ++origin) {
+ quota_manager->DeleteOriginData(*origin, type,
+ quota::QuotaClient::kAllClientsMask,
+ base::Bind(&DoNothingStatusCallback));
+ }
+}
+
+void ClearOriginOnIOThread(
const GURL& storage_origin,
const scoped_refptr<net::URLRequestContextGetter>& request_context,
- const scoped_refptr<ChromeAppCacheService>& appcache_service) {
+ const scoped_refptr<quota::QuotaManager>& quota_manager) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Handle the cookies.
@@ -36,26 +58,54 @@ void ClearDataOnIOThread(
cookie_monster->DeleteAllForHostAsync(
storage_origin, net::CookieMonster::DeleteCallback());
- // Clear out appcache.
- appcache_service->DeleteAppCachesForOrigin(storage_origin,
- net::CompletionCallback());
+ // Handle all HTML5 storage other than DOMStorageContext.
+ std::set<GURL> origins;
+ origins.insert(storage_origin);
+ ClearQuotaManagedOriginsOnIOThread(quota_manager, origins,
+ quota::kStorageTypePersistent);
+ ClearQuotaManagedOriginsOnIOThread(quota_manager, origins,
+ quota::kStorageTypeTemporary);
}
-void ClearDataOnFileThread(
- const GURL& storage_origin,
- string16 origin_id,
- const scoped_refptr<webkit_database::DatabaseTracker> &database_tracker,
- const scoped_refptr<fileapi::FileSystemContext>& file_system_context) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+void ClearAllDataOnIOThread(
+ const scoped_refptr<net::URLRequestContextGetter>& request_context,
+ const scoped_refptr<quota::QuotaManager>& quota_manager) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- // Clear out the HTML5 filesystem.
- file_system_context->DeleteDataForOriginOnFileThread(storage_origin);
+ // Handle the cookies.
+ net::CookieMonster* cookie_monster =
+ request_context->GetURLRequestContext()->cookie_store()->
+ GetCookieMonster();
+ if (cookie_monster)
+ cookie_monster->DeleteAllAsync(net::CookieMonster::DeleteCallback());
+
+ // Handle all HTML5 storage other than DOMStorageContext.
+ quota_manager->GetOriginsModifiedSince(
+ quota::kStorageTypePersistent, base::Time(),
+ base::Bind(&ClearQuotaManagedOriginsOnIOThread, quota_manager));
+ quota_manager->GetOriginsModifiedSince(
+ quota::kStorageTypeTemporary, base::Time(),
+ base::Bind(&ClearQuotaManagedOriginsOnIOThread, quota_manager));
+}
- // Clear out the database tracker. We just let this run until completion
- // without notification.
- int rv = database_tracker->DeleteDataForOrigin(
- origin_id, net::CompletionCallback());
- DCHECK(rv == net::OK || rv == net::ERR_IO_PENDING);
+void OnLocalStorageUsageInfo(
+ const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+ const std::vector<dom_storage::LocalStorageUsageInfo>& infos) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ for (size_t i = 0; i < infos.size(); ++i) {
+ dom_storage_context->DeleteLocalStorage(infos[i].origin);
+ }
+}
+
+void OnSessionStorageUsageInfo(
+ const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+ const std::vector<dom_storage::SessionStorageUsageInfo>& infos) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ for (size_t i = 0; i < infos.size(); ++i) {
+ dom_storage_context->DeleteSessionStorage(infos[i]);
+ }
}
} // namespace
@@ -192,28 +242,28 @@ void StoragePartitionImpl::AsyncClearDataForOrigin(
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::Bind(&ClearDataOnIOThread,
+ base::Bind(&ClearOriginOnIOThread,
storage_origin,
make_scoped_refptr(request_context_getter),
- appcache_service_));
-
- string16 origin_id =
- webkit_database::DatabaseUtil::GetOriginIdentifier(storage_origin);
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&ClearDataOnFileThread,
- storage_origin,
- origin_id,
- database_tracker_,
- filesystem_context_));
+ quota_manager_));
GetDOMStorageContext()->DeleteLocalStorage(storage_origin);
+}
+void StoragePartitionImpl::AsyncClearAllData() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // We ignore the media request context because it shares the same cookie store
+ // as the main request context.
BrowserThread::PostTask(
- BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
- base::Bind(
- &IndexedDBContext::DeleteForOrigin,
- indexed_db_context_,
- storage_origin));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ClearAllDataOnIOThread, url_request_context_,
+ quota_manager_));
+
+ dom_storage_context_->GetLocalStorageUsage(
+ base::Bind(&OnLocalStorageUsageInfo, dom_storage_context_));
+ dom_storage_context_->GetSessionStorageUsage(
+ base::Bind(&OnSessionStorageUsageInfo, dom_storage_context_));
}
void StoragePartitionImpl::SetURLRequestContext(
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index fe0c292..46daacd 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -32,6 +32,7 @@ class StoragePartitionImpl : public StoragePartition {
virtual void AsyncClearDataForOrigin(
const GURL& storage_origin,
net::URLRequestContextGetter* request_context_getter) OVERRIDE;
+ virtual void AsyncClearAllData() OVERRIDE;
private:
friend class StoragePartitionImplMap;
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index eb7ae78..01c0593 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -7,9 +7,11 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/file_path.h"
+#include "base/file_util.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
+#include "base/threading/worker_pool.h"
#include "content/browser/appcache/chrome_appcache_service.h"
#include "content/browser/fileapi/browser_file_system_helper.h"
#include "content/browser/fileapi/chrome_blob_storage_context.h"
@@ -22,6 +24,7 @@
#include "content/browser/tcmalloc_internals_request_job.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/url_constants.h"
@@ -238,6 +241,99 @@ const FilePath::CharType kDefaultPartitionDirname[] =
// partition domain.
const int kPartitionNameHashBytes = 6;
+// Needed for selecting all files in ObliterateOneDirectory() below.
+#if defined(OS_POSIX)
+const int kAllFileTypes = file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES |
+ file_util::FileEnumerator::SHOW_SYM_LINKS;
+#else
+const int kAllFileTypes = file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES;
+#endif
+
+FilePath GetStoragePartitionDomainPath(
+ const std::string& partition_domain) {
+ CHECK(IsStringUTF8(partition_domain));
+
+ return FilePath(kStoragePartitionDirname).Append(kExtensionsDirname)
+ .Append(FilePath::FromUTF8Unsafe(partition_domain));
+}
+
+// Helper function for doing a depth-first deletion of the data on disk.
+// Examines paths directly in |current_dir| (no recursion) and tries to
+// delete from disk anything that is in, or isn't a parent of something in
+// |paths_to_keep|. Paths that need further expansion are added to
+// |paths_to_consider|.
+void ObliterateOneDirectory(const FilePath& current_dir,
+ const std::vector<FilePath>& paths_to_keep,
+ std::vector<FilePath>* paths_to_consider) {
+ file_util::FileEnumerator enumerator(current_dir, false, kAllFileTypes);
+ for (FilePath to_delete = enumerator.Next(); !to_delete.empty();
+ to_delete = enumerator.Next()) {
+ // Enum tracking which of the 3 possible actions to take for |to_delete|.
+ enum { kSkip, kEnqueue, kDelete } action = kDelete;
+
+ for (std::vector<FilePath>::const_iterator to_keep = paths_to_keep.begin();
+ to_keep != paths_to_keep.end();
+ ++to_keep) {
+ if (to_delete == *to_keep) {
+ action = kSkip;
+ break;
+ } else if (to_delete.IsParent(*to_keep)) {
+ // |to_delete| contains a path to keep. Add to stack for further
+ // processing.
+ action = kEnqueue;
+ break;
+ }
+ }
+
+ switch (action) {
+ case kDelete:
+ file_util::Delete(to_delete, true);
+ break;
+
+ case kEnqueue:
+ paths_to_consider->push_back(to_delete);
+ break;
+
+ case kSkip:
+ break;
+ }
+ }
+}
+
+// Synchronously attempts to delete |root|, preserving only entries in
+// |paths_to_keep|. If there are no entries in |paths_to_keep| on disk, then it
+// completely removes |root|. All paths must be absolute paths.
+void BlockingObliteratePath(const FilePath& root,
+ const std::vector<FilePath>& paths_to_keep) {
+ // Reduce |paths_to_keep| set to those under the root and actually on disk.
+ std::vector<FilePath> valid_paths_to_keep;
+ for (std::vector<FilePath>::const_iterator it = paths_to_keep.begin();
+ it != paths_to_keep.end();
+ ++it) {
+ if (root.IsParent(*it) && file_util::PathExists(*it))
+ valid_paths_to_keep.push_back(*it);
+ }
+
+ // If none of the |paths_to_keep| are valid anymore then we just whack the
+ // root and be done with it.
+ if (valid_paths_to_keep.empty()) {
+ file_util::Delete(root, true);
+ return;
+ }
+
+ // Otherwise, start at the root and delete everything that is not in
+ // |valid_paths_to_keep|.
+ std::vector<FilePath> paths_to_consider;
+ paths_to_consider.push_back(root);
+ while(!paths_to_consider.empty()) {
+ FilePath path = paths_to_consider.back();
+ paths_to_consider.pop_back();
+ ObliterateOneDirectory(path, valid_paths_to_keep, &paths_to_consider);
+ }
+}
+
} // namespace
// static
@@ -247,11 +343,12 @@ FilePath StoragePartitionImplMap::GetStoragePartitionPath(
if (partition_domain.empty())
return FilePath();
- CHECK(IsStringUTF8(partition_domain));
-
- FilePath path = FilePath(kStoragePartitionDirname).Append(kExtensionsDirname)
- .Append(FilePath::FromUTF8Unsafe(partition_domain));
+ FilePath path = GetStoragePartitionDomainPath(partition_domain);
+ // TODO(ajwong): Mangle in-memory into this somehow, either by putting
+ // it into the partition_name, or by manually adding another path component
+ // here. Otherwise, it's possible to have an in-memory StoragePartition and
+ // a persistent one that return the same FilePath for GetPath().
if (!partition_name.empty()) {
// For analysis of why we can ignore collisions, see the comment above
// kPartitionNameHashBytes.
@@ -264,7 +361,6 @@ FilePath StoragePartitionImplMap::GetStoragePartitionPath(
return path.Append(kDefaultPartitionDirname);
}
-
StoragePartitionImplMap::StoragePartitionImplMap(
BrowserContext* browser_context)
: browser_context_(browser_context),
@@ -317,11 +413,61 @@ StoragePartitionImpl* StoragePartitionImplMap::Get(
browser_context_->GetMediaRequestContextForStoragePartition(
partition->GetPath(), in_memory));
- PostCreateInitialization(partition);
+ PostCreateInitialization(partition, in_memory);
return partition;
}
+void StoragePartitionImplMap::AsyncObliterate(const GURL& site) {
+ // This method should avoid creating any StoragePartition (which would
+ // create more open file handles) so that it can delete as much of the
+ // data off disk as possible.
+ std::string partition_domain;
+ std::string partition_name;
+ bool in_memory = false;
+ GetContentClient()->browser()->GetStoragePartitionConfigForSite(
+ browser_context_, site, false, &partition_domain,
+ &partition_name, &in_memory);
+
+ // The default partition is the whole profile. We can't obliterate that and
+ // should never even try.
+ CHECK(!partition_domain.empty()) << site;
+
+ // Find the active partitions for the domain. Because these partitions are
+ // active, it is not possible to just delete the directories that contain
+ // the backing data structures without causing the browser to crash. Instead,
+ // of deleteing the directory, we tell each storage context later to
+ // remove any data they have saved. This will leave the directory structure
+ // intact but it will only contain empty databases.
+ std::vector<StoragePartitionImpl*> active_partitions;
+ std::vector<FilePath> paths_to_keep;
+ for (PartitionMap::const_iterator it = partitions_.begin();
+ it != partitions_.end();
+ ++it) {
+ const StoragePartitionConfig& config = it->first;
+ if (config.partition_domain == partition_domain) {
+ it->second->AsyncClearAllData();
+ if (!config.in_memory) {
+ paths_to_keep.push_back(it->second->GetPath());
+ }
+ }
+ }
+
+ // Start a best-effort delete of the on-disk storage excluding paths that are
+ // known to still be in use. This is to delete any previously created
+ // StoragePartition state that just happens to not have been used during this
+ // run of the browser.
+ FilePath domain_root = browser_context_->GetPath().Append(
+ GetStoragePartitionDomainPath(partition_domain));
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(&BlockingObliteratePath, domain_root, paths_to_keep),
+ true);
+
+ // TODO(ajwong): Schedule a final AsyncObliterate of the whole directory on
+ // the next browser start. http://crbug.com/85127.
+}
+
void StoragePartitionImplMap::ForEach(
const BrowserContext::StoragePartitionCallback& callback) {
for (PartitionMap::const_iterator it = partitions_.begin();
@@ -332,14 +478,15 @@ void StoragePartitionImplMap::ForEach(
}
void StoragePartitionImplMap::PostCreateInitialization(
- StoragePartitionImpl* partition) {
+ StoragePartitionImpl* partition,
+ bool in_memory) {
// Check first to avoid memory leak in unittests.
if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&ChromeAppCacheService::InitializeOnIOThread,
partition->GetAppCacheService(),
- browser_context_->IsOffTheRecord() ? FilePath() :
+ in_memory ? FilePath() :
partition->GetPath().Append(kAppCacheDirname),
browser_context_->GetResourceContext(),
make_scoped_refptr(partition->GetURLRequestContext()),
diff --git a/content/browser/storage_partition_impl_map.h b/content/browser/storage_partition_impl_map.h
index 9da35c3..5c25e02 100644
--- a/content/browser/storage_partition_impl_map.h
+++ b/content/browser/storage_partition_impl_map.h
@@ -32,6 +32,10 @@ class StoragePartitionImplMap : public base::SupportsUserData::Data {
const std::string& partition_name,
bool in_memory);
+ // Starts an asynchronous best-effort attempt to delete all on-disk storage
+ // related to |site|, avoiding any directories that are known to be in use.
+ void AsyncObliterate(const GURL& site);
+
void ForEach(const BrowserContext::StoragePartitionCallback& callback);
private:
@@ -93,7 +97,8 @@ class StoragePartitionImplMap : public base::SupportsUserData::Data {
// TODO(ajwong): Is there a way to make it so that Get()'s implementation
// doesn't need to be aware of this ordering? Revisit when refactoring
// ResourceContext and AppCache to respect storage partitions.
- void PostCreateInitialization(StoragePartitionImpl* partition);
+ void PostCreateInitialization(StoragePartitionImpl* partition,
+ bool in_memory);
BrowserContext* browser_context_; // Not Owned.
PartitionMap partitions_;
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index addc4d7..ff4446f 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -50,6 +50,9 @@ class CONTENT_EXPORT BrowserContext : public base::SupportsUserData {
static void ForEachStoragePartition(
BrowserContext* browser_context,
const StoragePartitionCallback& callback);
+ static void AsyncObliterateStoragePartition(
+ BrowserContext* browser_context,
+ const GURL& site);
// DON'T USE THIS. GetDefaultStoragePartition() is going away.
// Use GetStoragePartition() instead. Ask ajwong@ if you have problems.
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 65374cf..05ddc93 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -177,6 +177,7 @@ bool ContentBrowserClient::IsValidStoragePartitionId(
void ContentBrowserClient::GetStoragePartitionConfigForSite(
BrowserContext* browser_context,
const GURL& site,
+ bool can_be_default,
std::string* partition_domain,
std::string* partition_name,
bool* in_memory) {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 228e4ee..7368ebb 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -278,14 +278,22 @@ class CONTENT_EXPORT ContentBrowserClient {
// Allows the embedder to provide a storage parititon configuration for a
// site. A storage partition configuration includes a domain of the embedder's
// choice, an optional name within that domain, and whether the partition is
- // in-memory only. The |partition_domain| is [a-z]* UTF-8 string, specifying
- // the domain in which partitions live (similar to namespace). Within a
- // domain, partitions can be uniquely identified by the combination of
- // |partition_name| and |in_memory| values. When a partition is not to be
- // persisted, the |in_memory| value must be set to true.
+ // in-memory only.
+ //
+ // If |can_be_default| is false, the caller is telling the embedder that the
+ // |site| is known to not be in the default partition. This is useful in
+ // some shutdown situations where the bookkeeping logic that maps sites to
+ // their partition configuration are no longer valid.
+ //
+ // The |partition_domain| is [a-z]* UTF-8 string, specifying the domain in
+ // which partitions live (similar to namespace). Within a domain, partitions
+ // can be uniquely identified by the combination of |partition_name| and
+ // |in_memory| values. When a partition is not to be persisted, the
+ // |in_memory| value must be set to true.
virtual void GetStoragePartitionConfigForSite(
content::BrowserContext* browser_context,
const GURL& site,
+ bool can_be_default,
std::string* partition_domain,
std::string* partition_name,
bool* in_memory);
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h
index a06a311..2a905d9 100644
--- a/content/public/browser/storage_partition.h
+++ b/content/public/browser/storage_partition.h
@@ -68,6 +68,10 @@ class StoragePartition {
const GURL& storage_origin,
net::URLRequestContextGetter* request_context_getter) = 0;
+ // Similar to AsyncClearDataForOrigin(), but deletes all data out of the
+ // StoragePartition rather than just the data related to this origin.
+ virtual void AsyncClearAllData() = 0;
+
protected:
virtual ~StoragePartition() {}
};