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 |