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 |