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, |
| 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()->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 |
OLD | NEW |