Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: content/browser/storage_partition_impl_map.cc

Issue 11362268: Implement the ability to obliterate a storage partition from disk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: source control is hard, let's go shopping! Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/browser/storage_partition_impl_map.h ('k') | content/public/browser/browser_context.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/storage_partition_impl_map.h" 5 #include "content/browser/storage_partition_impl_map.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback.h" 8 #include "base/callback.h"
9 #include "base/file_path.h" 9 #include "base/file_path.h"
10 #include "base/file_util.h"
10 #include "base/stl_util.h" 11 #include "base/stl_util.h"
11 #include "base/string_util.h" 12 #include "base/string_util.h"
12 #include "base/string_number_conversions.h" 13 #include "base/string_number_conversions.h"
14 #include "base/threading/worker_pool.h"
13 #include "content/browser/appcache/chrome_appcache_service.h" 15 #include "content/browser/appcache/chrome_appcache_service.h"
14 #include "content/browser/fileapi/browser_file_system_helper.h" 16 #include "content/browser/fileapi/browser_file_system_helper.h"
15 #include "content/browser/fileapi/chrome_blob_storage_context.h" 17 #include "content/browser/fileapi/chrome_blob_storage_context.h"
16 #include "content/browser/histogram_internals_request_job.h" 18 #include "content/browser/histogram_internals_request_job.h"
17 #include "content/browser/net/view_blob_internals_job_factory.h" 19 #include "content/browser/net/view_blob_internals_job_factory.h"
18 #include "content/browser/net/view_http_cache_job_factory.h" 20 #include "content/browser/net/view_http_cache_job_factory.h"
19 #include "content/browser/renderer_host/resource_request_info_impl.h" 21 #include "content/browser/renderer_host/resource_request_info_impl.h"
20 #include "content/browser/resource_context_impl.h" 22 #include "content/browser/resource_context_impl.h"
21 #include "content/browser/storage_partition_impl.h" 23 #include "content/browser/storage_partition_impl.h"
22 #include "content/browser/tcmalloc_internals_request_job.h" 24 #include "content/browser/tcmalloc_internals_request_job.h"
23 #include "content/public/browser/browser_context.h" 25 #include "content/public/browser/browser_context.h"
24 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/content_browser_client.h"
25 #include "content/public/browser/storage_partition.h" 28 #include "content/public/browser/storage_partition.h"
26 #include "content/public/common/content_constants.h" 29 #include "content/public/common/content_constants.h"
27 #include "content/public/common/url_constants.h" 30 #include "content/public/common/url_constants.h"
28 #include "crypto/sha2.h" 31 #include "crypto/sha2.h"
29 #include "net/url_request/url_request_context_getter.h" 32 #include "net/url_request/url_request_context_getter.h"
30 #include "net/url_request/url_request_context.h" 33 #include "net/url_request/url_request_context.h"
31 #include "webkit/appcache/view_appcache_internals_job.h" 34 #include "webkit/appcache/view_appcache_internals_job.h"
32 #include "webkit/blob/blob_data.h" 35 #include "webkit/blob/blob_data.h"
33 #include "webkit/blob/blob_url_request_job_factory.h" 36 #include "webkit/blob/blob_url_request_job_factory.h"
34 #include "webkit/fileapi/file_system_url_request_job_factory.h" 37 #include "webkit/fileapi/file_system_url_request_job_factory.h"
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 // 234 //
232 // For a 6-byte hash, H = 2^(6*8). n(10^-11, H) ~= 75 235 // For a 6-byte hash, H = 2^(6*8). n(10^-11, H) ~= 75
233 // 236 //
234 // An average partition domain is likely to have less than 10 unique 237 // An average partition domain is likely to have less than 10 unique
235 // partition names which is far lower than 75. 238 // partition names which is far lower than 75.
236 // 239 //
237 // Note, that for 4 9s of reliability, the limit is 237 partition names per 240 // Note, that for 4 9s of reliability, the limit is 237 partition names per
238 // partition domain. 241 // partition domain.
239 const int kPartitionNameHashBytes = 6; 242 const int kPartitionNameHashBytes = 6;
240 243
244 // Needed for selecting all files in ObliterateOneDirectory() below.
245 #if defined(OS_POSIX)
246 const int kAllFileTypes = file_util::FileEnumerator::FILES |
247 file_util::FileEnumerator::DIRECTORIES |
248 file_util::FileEnumerator::SHOW_SYM_LINKS;
249 #else
250 const int kAllFileTypes = file_util::FileEnumerator::FILES |
251 file_util::FileEnumerator::DIRECTORIES;
252 #endif
253
254 FilePath GetStoragePartitionDomainPath(
255 const std::string& partition_domain) {
256 CHECK(IsStringUTF8(partition_domain));
257
258 return FilePath(kStoragePartitionDirname).Append(kExtensionsDirname)
259 .Append(FilePath::FromUTF8Unsafe(partition_domain));
260 }
261
262 // Helper function for doing a depth-first deletion of the data on disk.
263 // Examines paths directly in |current_dir| (no recursion) and tries to
264 // delete from disk anything that is in, or isn't a parent of something in
265 // |paths_to_keep|. Paths that need further expansion are added to
266 // |paths_to_consider|.
267 void ObliterateOneDirectory(const FilePath& current_dir,
268 const std::vector<FilePath>& paths_to_keep,
269 std::vector<FilePath>* paths_to_consider) {
270 file_util::FileEnumerator enumerator(current_dir, false, kAllFileTypes);
271 for (FilePath to_delete = enumerator.Next(); !to_delete.empty();
272 to_delete = enumerator.Next()) {
273 // Enum tracking which of the 3 possible actions to take for |to_delete|.
274 enum { kSkip, kEnqueue, kDelete } action = kDelete;
275
276 for (std::vector<FilePath>::const_iterator to_keep = paths_to_keep.begin();
277 to_keep != paths_to_keep.end();
278 ++to_keep) {
279 if (to_delete == *to_keep) {
280 action = kSkip;
281 break;
282 } else if (to_delete.IsParent(*to_keep)) {
283 // |to_delete| contains a path to keep. Add to stack for further
284 // processing.
285 action = kEnqueue;
286 break;
287 }
288 }
289
290 switch (action) {
291 case kDelete:
292 file_util::Delete(to_delete, true);
293 break;
294
295 case kEnqueue:
296 paths_to_consider->push_back(to_delete);
297 break;
298
299 case kSkip:
300 break;
301 }
302 }
303 }
304
305 // Synchronously attempts to delete |root|, preserving only entries in
306 // |paths_to_keep|. If there are no entries in |paths_to_keep| on disk, then it
307 // completely removes |root|. All paths must be absolute paths.
308 void BlockingObliteratePath(const FilePath& root,
309 const std::vector<FilePath>& paths_to_keep) {
310 // Reduce |paths_to_keep| set to those under the root and actually on disk.
311 std::vector<FilePath> valid_paths_to_keep;
312 for (std::vector<FilePath>::const_iterator it = paths_to_keep.begin();
313 it != paths_to_keep.end();
314 ++it) {
315 if (root.IsParent(*it) && file_util::PathExists(*it))
316 valid_paths_to_keep.push_back(*it);
317 }
318
319 // If none of the |paths_to_keep| are valid anymore then we just whack the
320 // root and be done with it.
321 if (valid_paths_to_keep.empty()) {
322 file_util::Delete(root, true);
323 return;
324 }
325
326 // Otherwise, start at the root and delete everything that is not in
327 // |valid_paths_to_keep|.
328 std::vector<FilePath> paths_to_consider;
329 paths_to_consider.push_back(root);
330 while(!paths_to_consider.empty()) {
331 FilePath path = paths_to_consider.back();
332 paths_to_consider.pop_back();
333 ObliterateOneDirectory(path, valid_paths_to_keep, &paths_to_consider);
334 }
335 }
336
241 } // namespace 337 } // namespace
242 338
243 // static 339 // static
244 FilePath StoragePartitionImplMap::GetStoragePartitionPath( 340 FilePath StoragePartitionImplMap::GetStoragePartitionPath(
245 const std::string& partition_domain, 341 const std::string& partition_domain,
246 const std::string& partition_name) { 342 const std::string& partition_name) {
247 if (partition_domain.empty()) 343 if (partition_domain.empty())
248 return FilePath(); 344 return FilePath();
249 345
250 CHECK(IsStringUTF8(partition_domain)); 346 FilePath path = GetStoragePartitionDomainPath(partition_domain);
251 347
252 FilePath path = FilePath(kStoragePartitionDirname).Append(kExtensionsDirname) 348 // TODO(ajwong): Mangle in-memory into this somehow, either by putting
253 .Append(FilePath::FromUTF8Unsafe(partition_domain)); 349 // it into the partition_name, or by manually adding another path component
254 350 // here. Otherwise, it's possible to have an in-memory StoragePartition and
351 // a persistent one that return the same FilePath for GetPath().
255 if (!partition_name.empty()) { 352 if (!partition_name.empty()) {
256 // For analysis of why we can ignore collisions, see the comment above 353 // For analysis of why we can ignore collisions, see the comment above
257 // kPartitionNameHashBytes. 354 // kPartitionNameHashBytes.
258 char buffer[kPartitionNameHashBytes]; 355 char buffer[kPartitionNameHashBytes];
259 crypto::SHA256HashString(partition_name, &buffer[0], 356 crypto::SHA256HashString(partition_name, &buffer[0],
260 sizeof(buffer)); 357 sizeof(buffer));
261 return path.AppendASCII(base::HexEncode(buffer, sizeof(buffer))); 358 return path.AppendASCII(base::HexEncode(buffer, sizeof(buffer)));
262 } 359 }
263 360
264 return path.Append(kDefaultPartitionDirname); 361 return path.Append(kDefaultPartitionDirname);
265 } 362 }
266 363
267
268 StoragePartitionImplMap::StoragePartitionImplMap( 364 StoragePartitionImplMap::StoragePartitionImplMap(
269 BrowserContext* browser_context) 365 BrowserContext* browser_context)
270 : browser_context_(browser_context), 366 : browser_context_(browser_context),
271 resource_context_initialized_(false) { 367 resource_context_initialized_(false) {
272 } 368 }
273 369
274 StoragePartitionImplMap::~StoragePartitionImplMap() { 370 StoragePartitionImplMap::~StoragePartitionImplMap() {
275 STLDeleteContainerPairSecondPointers(partitions_.begin(), 371 STLDeleteContainerPairSecondPointers(partitions_.begin(),
276 partitions_.end()); 372 partitions_.end());
277 } 373 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 partition_domain.empty() ? 406 partition_domain.empty() ?
311 browser_context_->GetRequestContext() : 407 browser_context_->GetRequestContext() :
312 browser_context_->GetRequestContextForStoragePartition( 408 browser_context_->GetRequestContextForStoragePartition(
313 partition->GetPath(), in_memory)); 409 partition->GetPath(), in_memory));
314 partition->SetMediaURLRequestContext( 410 partition->SetMediaURLRequestContext(
315 partition_domain.empty() ? 411 partition_domain.empty() ?
316 browser_context_->GetMediaRequestContext() : 412 browser_context_->GetMediaRequestContext() :
317 browser_context_->GetMediaRequestContextForStoragePartition( 413 browser_context_->GetMediaRequestContextForStoragePartition(
318 partition->GetPath(), in_memory)); 414 partition->GetPath(), in_memory));
319 415
320 PostCreateInitialization(partition); 416 PostCreateInitialization(partition, in_memory);
321 417
322 return partition; 418 return partition;
323 } 419 }
324 420
421 void StoragePartitionImplMap::AsyncObliterate(const GURL& site) {
422 // This method should avoid creating any StoragePartition (which would
423 // create more open file handles) so that it can delete as much of the
424 // data off disk as possible.
425 std::string partition_domain;
426 std::string partition_name;
427 bool in_memory = false;
428 GetContentClient()->browser()->GetStoragePartitionConfigForSite(
429 browser_context_, site, false, &partition_domain,
430 &partition_name, &in_memory);
431
432 // The default partition is the whole profile. We can't obliterate that and
433 // should never even try.
434 CHECK(!partition_domain.empty()) << site;
435
436 // Find the active partitions for the domain. Because these partitions are
437 // active, it is not possible to just delete the directories that contain
438 // the backing data structures without causing the browser to crash. Instead,
439 // of deleteing the directory, we tell each storage context later to
440 // remove any data they have saved. This will leave the directory structure
441 // intact but it will only contain empty databases.
442 std::vector<StoragePartitionImpl*> active_partitions;
443 std::vector<FilePath> paths_to_keep;
444 for (PartitionMap::const_iterator it = partitions_.begin();
445 it != partitions_.end();
446 ++it) {
447 const StoragePartitionConfig& config = it->first;
448 if (config.partition_domain == partition_domain) {
449 it->second->AsyncClearAllData();
450 if (!config.in_memory) {
451 paths_to_keep.push_back(it->second->GetPath());
452 }
453 }
454 }
455
456 // Start a best-effort delete of the on-disk storage excluding paths that are
457 // known to still be in use. This is to delete any previously created
458 // StoragePartition state that just happens to not have been used during this
459 // run of the browser.
460 FilePath domain_root = browser_context_->GetPath().Append(
461 GetStoragePartitionDomainPath(partition_domain));
462 base::WorkerPool::PostTask(
463 FROM_HERE,
464 base::Bind(&BlockingObliteratePath, domain_root, paths_to_keep),
465 true);
466
467 // TODO(ajwong): Schedule a final AsyncObliterate of the whole directory on
468 // the next browser start. http://crbug.com/85127.
469 }
470
325 void StoragePartitionImplMap::ForEach( 471 void StoragePartitionImplMap::ForEach(
326 const BrowserContext::StoragePartitionCallback& callback) { 472 const BrowserContext::StoragePartitionCallback& callback) {
327 for (PartitionMap::const_iterator it = partitions_.begin(); 473 for (PartitionMap::const_iterator it = partitions_.begin();
328 it != partitions_.end(); 474 it != partitions_.end();
329 ++it) { 475 ++it) {
330 callback.Run(it->second); 476 callback.Run(it->second);
331 } 477 }
332 } 478 }
333 479
334 void StoragePartitionImplMap::PostCreateInitialization( 480 void StoragePartitionImplMap::PostCreateInitialization(
335 StoragePartitionImpl* partition) { 481 StoragePartitionImpl* partition,
482 bool in_memory) {
336 // Check first to avoid memory leak in unittests. 483 // Check first to avoid memory leak in unittests.
337 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { 484 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
338 BrowserThread::PostTask( 485 BrowserThread::PostTask(
339 BrowserThread::IO, FROM_HERE, 486 BrowserThread::IO, FROM_HERE,
340 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, 487 base::Bind(&ChromeAppCacheService::InitializeOnIOThread,
341 partition->GetAppCacheService(), 488 partition->GetAppCacheService(),
342 browser_context_->IsOffTheRecord() ? FilePath() : 489 in_memory ? FilePath() :
343 partition->GetPath().Append(kAppCacheDirname), 490 partition->GetPath().Append(kAppCacheDirname),
344 browser_context_->GetResourceContext(), 491 browser_context_->GetResourceContext(),
345 make_scoped_refptr(partition->GetURLRequestContext()), 492 make_scoped_refptr(partition->GetURLRequestContext()),
346 make_scoped_refptr( 493 make_scoped_refptr(
347 browser_context_->GetSpecialStoragePolicy()))); 494 browser_context_->GetSpecialStoragePolicy())));
348 495
349 // Add content's URLRequestContext's hooks. 496 // Add content's URLRequestContext's hooks.
350 BrowserThread::PostTask( 497 BrowserThread::PostTask(
351 BrowserThread::IO, FROM_HERE, 498 BrowserThread::IO, FROM_HERE,
352 base::Bind( 499 base::Bind(
353 &InitializeURLRequestContext, 500 &InitializeURLRequestContext,
354 make_scoped_refptr(partition->GetURLRequestContext()), 501 make_scoped_refptr(partition->GetURLRequestContext()),
355 make_scoped_refptr(partition->GetAppCacheService()), 502 make_scoped_refptr(partition->GetAppCacheService()),
356 make_scoped_refptr(partition->GetFileSystemContext()), 503 make_scoped_refptr(partition->GetFileSystemContext()),
357 make_scoped_refptr( 504 make_scoped_refptr(
358 ChromeBlobStorageContext::GetFor(browser_context_)))); 505 ChromeBlobStorageContext::GetFor(browser_context_))));
359 506
360 // We do not call InitializeURLRequestContext() for media contexts because, 507 // We do not call InitializeURLRequestContext() for media contexts because,
361 // other than the HTTP cache, the media contexts share the same backing 508 // other than the HTTP cache, the media contexts share the same backing
362 // objects as their associated "normal" request context. Thus, the previous 509 // objects as their associated "normal" request context. Thus, the previous
363 // call serves to initialize the media request context for this storage 510 // call serves to initialize the media request context for this storage
364 // partition as well. 511 // partition as well.
365 } 512 }
366 } 513 }
367 514
368 } // namespace content 515 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/storage_partition_impl_map.h ('k') | content/public/browser/browser_context.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698