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) | |
|
nasko
2012/11/15 17:48:10
Why not put these right before the function that u
awong
2012/11/16 00:36:04
Was keeping all constants grouped...
| |
| 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, | |
|
Charlie Reis
2012/11/15 18:28:21
Why so violent? :) Obliterate seems like an unus
awong
2012/11/16 00:36:04
I was avoiding "Delete" because there's so many De
| |
| 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 for (std::vector<FilePath>::const_iterator to_keep = paths_to_keep.begin(); | |
| 274 to_keep != paths_to_keep.end(); | |
| 275 ++to_keep) { | |
| 276 if (to_delete == *to_keep) { | |
| 277 // Do nothing because this path shouldn't be deleted. | |
| 278 } else if (to_delete.IsParent(*to_keep)) { | |
| 279 // |to_delete| contains a path to keep. Add to stack for further | |
| 280 // processing. | |
| 281 paths_to_consider->push_back(*to_keep); | |
| 282 } else { | |
| 283 // |to_delete| isn't protected. Just delete it. | |
| 284 file_util::Delete(to_delete, true); | |
| 285 } | |
| 286 } | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 // Synchronously attempts to delete |root|, preserving only entries in | |
| 291 // |paths_to_keep|. If there are no entries in |paths_to_keep| on disk, then it | |
| 292 // completely removes |root|. All paths must be absolute paths. | |
| 293 void BlockingObliteratePath(const FilePath& root, | |
| 294 const std::vector<FilePath>& paths_to_keep) { | |
| 295 // Reduce |active_paths| set to those under the root and actually on disk. | |
|
nasko
2012/11/15 17:48:10
What is |active_paths|?
awong
2012/11/16 00:36:04
Old name. Fixed.
| |
| 296 std::vector<FilePath> valid_paths_to_keep; | |
| 297 for (std::vector<FilePath>::const_iterator it = paths_to_keep.begin(); | |
| 298 it != paths_to_keep.end(); | |
| 299 ++it) { | |
| 300 if (root.IsParent(*it) && file_util::PathExists(*it)) { | |
|
nasko
2012/11/15 17:48:10
nit: no braces needed.
awong
2012/11/16 00:36:04
Done.
| |
| 301 valid_paths_to_keep.push_back(*it); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 // If none of the |paths_to_keep| are valid anymore then we just whack the | |
| 306 // root and be done with it. | |
| 307 if (valid_paths_to_keep.empty()) { | |
| 308 file_util::Delete(root, true); | |
| 309 return; | |
| 310 } | |
| 311 | |
| 312 // Otherwise, start at the root and delete everything that is not in | |
| 313 // |valid_paths_to_keep|. | |
| 314 std::vector<FilePath> paths_to_consider; | |
| 315 paths_to_consider.push_back(root); | |
| 316 while(!paths_to_consider.empty()) { | |
| 317 FilePath path = paths_to_consider.back(); | |
| 318 paths_to_consider.pop_back(); | |
| 319 ObliterateOneDirectory(path, valid_paths_to_keep, &paths_to_consider); | |
| 320 } | |
| 321 } | |
| 322 | |
| 241 } // namespace | 323 } // namespace |
| 242 | 324 |
| 243 // static | 325 // static |
| 244 FilePath StoragePartitionImplMap::GetStoragePartitionPath( | 326 FilePath StoragePartitionImplMap::GetStoragePartitionPath( |
| 245 const std::string& partition_domain, | 327 const std::string& partition_domain, |
| 246 const std::string& partition_name) { | 328 const std::string& partition_name) { |
| 247 if (partition_domain.empty()) | 329 if (partition_domain.empty()) |
| 248 return FilePath(); | 330 return FilePath(); |
| 249 | 331 |
| 250 CHECK(IsStringUTF8(partition_domain)); | 332 FilePath path = GetStoragePartitionDomainPath(partition_domain); |
| 251 | 333 |
| 252 FilePath path = FilePath(kStoragePartitionDirname).Append(kExtensionsDirname) | 334 // TODO(ajwong): Mangle in-memory into this somehow, either by putting |
| 253 .Append(FilePath::FromUTF8Unsafe(partition_domain)); | 335 // it into the partition_name, or by manually adding another path component |
| 254 | 336 // here. Otherwise, it's possible to have an in-memory StoragePartition and |
| 337 // a persistent one that return the same FilePath for GetPath(). | |
|
nasko
2012/11/15 17:48:10
Adding a path component might not work with the qu
awong
2012/11/16 00:36:04
The more I think about this, the more I think we s
| |
| 255 if (!partition_name.empty()) { | 338 if (!partition_name.empty()) { |
| 256 // For analysis of why we can ignore collisions, see the comment above | 339 // For analysis of why we can ignore collisions, see the comment above |
| 257 // kPartitionNameHashBytes. | 340 // kPartitionNameHashBytes. |
| 258 char buffer[kPartitionNameHashBytes]; | 341 char buffer[kPartitionNameHashBytes]; |
| 259 crypto::SHA256HashString(partition_name, &buffer[0], | 342 crypto::SHA256HashString(partition_name, &buffer[0], |
| 260 sizeof(buffer)); | 343 sizeof(buffer)); |
| 261 return path.AppendASCII(base::HexEncode(buffer, sizeof(buffer))); | 344 return path.AppendASCII(base::HexEncode(buffer, sizeof(buffer))); |
| 262 } | 345 } |
| 263 | 346 |
| 264 return path.Append(kDefaultPartitionDirname); | 347 return path.Append(kDefaultPartitionDirname); |
| 265 } | 348 } |
| 266 | 349 |
| 267 | |
| 268 StoragePartitionImplMap::StoragePartitionImplMap( | 350 StoragePartitionImplMap::StoragePartitionImplMap( |
| 269 BrowserContext* browser_context) | 351 BrowserContext* browser_context) |
| 270 : browser_context_(browser_context), | 352 : browser_context_(browser_context), |
| 271 resource_context_initialized_(false) { | 353 resource_context_initialized_(false) { |
| 272 } | 354 } |
| 273 | 355 |
| 274 StoragePartitionImplMap::~StoragePartitionImplMap() { | 356 StoragePartitionImplMap::~StoragePartitionImplMap() { |
| 275 STLDeleteContainerPairSecondPointers(partitions_.begin(), | 357 STLDeleteContainerPairSecondPointers(partitions_.begin(), |
| 276 partitions_.end()); | 358 partitions_.end()); |
| 277 } | 359 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 partition_domain.empty() ? | 397 partition_domain.empty() ? |
| 316 browser_context_->GetMediaRequestContext() : | 398 browser_context_->GetMediaRequestContext() : |
| 317 browser_context_->GetMediaRequestContextForStoragePartition( | 399 browser_context_->GetMediaRequestContextForStoragePartition( |
| 318 partition->GetPath(), in_memory)); | 400 partition->GetPath(), in_memory)); |
| 319 | 401 |
| 320 PostCreateInitialization(partition); | 402 PostCreateInitialization(partition); |
| 321 | 403 |
| 322 return partition; | 404 return partition; |
| 323 } | 405 } |
| 324 | 406 |
| 407 void StoragePartitionImplMap::AsyncObliterate(const GURL& site) { | |
| 408 // This method should avoid creating any StoragePartition (which would | |
| 409 // create more open file handles) so that it can delete as much of the | |
| 410 // data off disk as possible. | |
| 411 std::string partition_domain; | |
| 412 std::string partition_name; | |
| 413 bool in_memory = false; | |
| 414 GetContentClient()->browser()->GetStoragePartitionConfigForSite( | |
| 415 browser_context_, site, &partition_domain, | |
| 416 &partition_name, &in_memory); | |
| 417 | |
| 418 // The default partition is the whole profile. We can't obliterate that and | |
| 419 // should never even try. | |
| 420 CHECK(!partition_domain.empty()); | |
| 421 | |
| 422 // Find the active partitions for the domain. Because these cannot be removed | |
| 423 // from disk, start deletions in all of them. | |
| 424 std::vector<StoragePartitionImpl*> active_partitions; | |
| 425 std::vector<FilePath> paths_to_keep; | |
| 426 for (PartitionMap::const_iterator it = partitions_.begin(); | |
| 427 it != partitions_.end(); | |
| 428 ++it) { | |
| 429 const StoragePartitionConfig& config = it->first; | |
| 430 if (config.partition_domain == partition_domain) { | |
| 431 it->second->AsyncClearAllData(); | |
| 432 if (!config.in_memory) { | |
|
nasko
2012/11/15 17:48:10
nit: no braces needed.
awong
2012/11/16 00:36:04
Done.
| |
| 433 paths_to_keep.push_back(it->second->GetPath()); | |
| 434 } | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 // Start a best-effort delete of the on-disk storage excluding paths that are | |
| 439 // known to still be in use. This is to delete any previously created | |
| 440 // StoragePartition state that just happens to not been used during this run | |
| 441 // of the browser. | |
| 442 // | |
| 443 // TODO(ajwong): Schedule a final cleanup of the whole directory on the next | |
| 444 // browser start. | |
| 445 FilePath domain_root = browser_context_->GetPath().Append( | |
| 446 GetStoragePartitionDomainPath(partition_domain)); | |
| 447 base::WorkerPool::PostTask( | |
| 448 FROM_HERE, | |
| 449 base::Bind(&BlockingObliteratePath, domain_root, paths_to_keep), | |
| 450 true); | |
| 451 } | |
| 452 | |
| 325 void StoragePartitionImplMap::ForEach( | 453 void StoragePartitionImplMap::ForEach( |
| 326 const BrowserContext::StoragePartitionCallback& callback) { | 454 const BrowserContext::StoragePartitionCallback& callback) { |
| 327 for (PartitionMap::const_iterator it = partitions_.begin(); | 455 for (PartitionMap::const_iterator it = partitions_.begin(); |
| 328 it != partitions_.end(); | 456 it != partitions_.end(); |
| 329 ++it) { | 457 ++it) { |
| 330 callback.Run(it->second); | 458 callback.Run(it->second); |
| 331 } | 459 } |
| 332 } | 460 } |
| 333 | 461 |
| 334 void StoragePartitionImplMap::PostCreateInitialization( | 462 void StoragePartitionImplMap::PostCreateInitialization( |
| 335 StoragePartitionImpl* partition) { | 463 StoragePartitionImpl* partition) { |
| 464 // TODO(ajwong): I think we lost the in-memory portion here. | |
| 336 // Check first to avoid memory leak in unittests. | 465 // Check first to avoid memory leak in unittests. |
| 337 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { | 466 if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) { |
| 338 BrowserThread::PostTask( | 467 BrowserThread::PostTask( |
| 339 BrowserThread::IO, FROM_HERE, | 468 BrowserThread::IO, FROM_HERE, |
| 340 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, | 469 base::Bind(&ChromeAppCacheService::InitializeOnIOThread, |
| 341 partition->GetAppCacheService(), | 470 partition->GetAppCacheService(), |
| 342 browser_context_->IsOffTheRecord() ? FilePath() : | 471 browser_context_->IsOffTheRecord() ? FilePath() : |
| 343 partition->GetPath().Append(kAppCacheDirname), | 472 partition->GetPath().Append(kAppCacheDirname), |
| 344 browser_context_->GetResourceContext(), | 473 browser_context_->GetResourceContext(), |
| 345 make_scoped_refptr(partition->GetURLRequestContext()), | 474 make_scoped_refptr(partition->GetURLRequestContext()), |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 359 | 488 |
| 360 // We do not call InitializeURLRequestContext() for media contexts because, | 489 // We do not call InitializeURLRequestContext() for media contexts because, |
| 361 // other than the HTTP cache, the media contexts share the same backing | 490 // other than the HTTP cache, the media contexts share the same backing |
| 362 // objects as their associated "normal" request context. Thus, the previous | 491 // objects as their associated "normal" request context. Thus, the previous |
| 363 // call serves to initialize the media request context for this storage | 492 // call serves to initialize the media request context for this storage |
| 364 // partition as well. | 493 // partition as well. |
| 365 } | 494 } |
| 366 } | 495 } |
| 367 | 496 |
| 368 } // namespace content | 497 } // namespace content |
| OLD | NEW |