Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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, | |
|
Charlie Reis
2012/11/16 01:45:10
This all looks correct, though it is a ton of effo
awong
2012/11/16 02:56:10
The browser will eventually crash when one of the
| |
| 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 Loading... | |
| 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()->ParseNonDefaultStoragePartitionConfig( | |
| 429 site, &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 cannot be removed | |
| 437 // from disk, start deletions in all of them. | |
|
Charlie Reis
2012/11/16 01:45:10
Sorry, can you clarify "removed from disk" vs "del
awong
2012/11/16 02:56:10
Done.
Charlie Reis
2012/11/16 16:14:59
Much better, thanks!
| |
| 438 std::vector<StoragePartitionImpl*> active_partitions; | |
| 439 std::vector<FilePath> paths_to_keep; | |
| 440 for (PartitionMap::const_iterator it = partitions_.begin(); | |
| 441 it != partitions_.end(); | |
| 442 ++it) { | |
| 443 const StoragePartitionConfig& config = it->first; | |
| 444 if (config.partition_domain == partition_domain) { | |
| 445 it->second->AsyncClearAllData(); | |
| 446 if (!config.in_memory) { | |
| 447 paths_to_keep.push_back(it->second->GetPath()); | |
| 448 } | |
| 449 } | |
| 450 } | |
| 451 | |
| 452 // Start a best-effort delete of the on-disk storage excluding paths that are | |
| 453 // known to still be in use. This is to delete any previously created | |
| 454 // StoragePartition state that just happens to not been used during this run | |
|
Charlie Reis
2012/11/16 01:45:10
nit: not have been
awong
2012/11/16 02:56:10
Done.
| |
| 455 // of the browser. | |
| 456 FilePath domain_root = browser_context_->GetPath().Append( | |
| 457 GetStoragePartitionDomainPath(partition_domain)); | |
| 458 base::WorkerPool::PostTask( | |
| 459 FROM_HERE, | |
| 460 base::Bind(&BlockingObliteratePath, domain_root, paths_to_keep), | |
| 461 true); | |
| 462 | |
| 463 // TODO(ajwong): Schedule a final AsyncObliterate of the whole directory on | |
| 464 // the next browser start. http://crbug.com/85127. | |
| 465 } | |
| 466 | |
| 325 void StoragePartitionImplMap::ForEach( | 467 void StoragePartitionImplMap::ForEach( |
| 326 const BrowserContext::StoragePartitionCallback& callback) { | 468 const BrowserContext::StoragePartitionCallback& callback) { |
| 327 for (PartitionMap::const_iterator it = partitions_.begin(); | 469 for (PartitionMap::const_iterator it = partitions_.begin(); |
| 328 it != partitions_.end(); | 470 it != partitions_.end(); |
| 329 ++it) { | 471 ++it) { |
| 330 callback.Run(it->second); | 472 callback.Run(it->second); |
| 331 } | 473 } |
| 332 } | 474 } |
| 333 | 475 |
| 334 void StoragePartitionImplMap::PostCreateInitialization( | 476 void StoragePartitionImplMap::PostCreateInitialization( |
| 335 StoragePartitionImpl* partition) { | 477 StoragePartitionImpl* partition, |
| 478 bool in_memory) { | |
| 336 // Check first to avoid memory leak in unittests. | 479 // Check first to avoid memory leak in unittests. |
| 337 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { | 480 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
| 338 BrowserThread::PostTask( | 481 BrowserThread::PostTask( |
| 339 BrowserThread::IO, FROM_HERE, | 482 BrowserThread::IO, FROM_HERE, |
| 340 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, | 483 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, |
| 341 partition->GetAppCacheService(), | 484 partition->GetAppCacheService(), |
| 342 browser_context_->IsOffTheRecord() ? FilePath() : | 485 in_memory ? FilePath() : |
| 343 partition->GetPath().Append(kAppCacheDirname), | 486 partition->GetPath().Append(kAppCacheDirname), |
| 344 browser_context_->GetResourceContext(), | 487 browser_context_->GetResourceContext(), |
| 345 make_scoped_refptr(partition->GetURLRequestContext()), | 488 make_scoped_refptr(partition->GetURLRequestContext()), |
| 346 make_scoped_refptr( | 489 make_scoped_refptr( |
| 347 browser_context_->GetSpecialStoragePolicy()))); | 490 browser_context_->GetSpecialStoragePolicy()))); |
| 348 | 491 |
| 349 // Add content's URLRequestContext's hooks. | 492 // Add content's URLRequestContext's hooks. |
| 350 BrowserThread::PostTask( | 493 BrowserThread::PostTask( |
| 351 BrowserThread::IO, FROM_HERE, | 494 BrowserThread::IO, FROM_HERE, |
| 352 base::Bind( | 495 base::Bind( |
| 353 &InitializeURLRequestContext, | 496 &InitializeURLRequestContext, |
| 354 make_scoped_refptr(partition->GetURLRequestContext()), | 497 make_scoped_refptr(partition->GetURLRequestContext()), |
| 355 make_scoped_refptr(partition->GetAppCacheService()), | 498 make_scoped_refptr(partition->GetAppCacheService()), |
| 356 make_scoped_refptr(partition->GetFileSystemContext()), | 499 make_scoped_refptr(partition->GetFileSystemContext()), |
| 357 make_scoped_refptr( | 500 make_scoped_refptr( |
| 358 ChromeBlobStorageContext::GetFor(browser_context_)))); | 501 ChromeBlobStorageContext::GetFor(browser_context_)))); |
| 359 | 502 |
| 360 // We do not call InitializeURLRequestContext() for media contexts because, | 503 // We do not call InitializeURLRequestContext() for media contexts because, |
| 361 // other than the HTTP cache, the media contexts share the same backing | 504 // other than the HTTP cache, the media contexts share the same backing |
| 362 // objects as their associated "normal" request context. Thus, the previous | 505 // objects as their associated "normal" request context. Thus, the previous |
| 363 // call serves to initialize the media request context for this storage | 506 // call serves to initialize the media request context for this storage |
| 364 // partition as well. | 507 // partition as well. |
| 365 } | 508 } |
| 366 } | 509 } |
| 367 | 510 |
| 368 } // namespace content | 511 } // namespace content |
| OLD | NEW |