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 3 // found in the LICENSE file. 4 5 #include "content/browser/storage_partition_impl.h" 6 7 #include "base/sequenced_task_runner.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "content/browser/browser_main_loop.h" 10 #include "content/browser/fileapi/browser_file_system_helper.h" 11 #include "content/browser/gpu/shader_disk_cache.h" 12 #include "content/common/dom_storage/dom_storage_types.h" 13 #include "content/public/browser/browser_context.h" 14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/dom_storage_context.h" 16 #include "content/public/browser/indexed_db_context.h" 17 #include "content/public/browser/local_storage_usage_info.h" 18 #include "content/public/browser/session_storage_usage_info.h" 19 #include "net/base/completion_callback.h" 20 #include "net/base/net_errors.h" 21 #include "net/cookies/cookie_monster.h" 22 #include "net/url_request/url_request_context.h" 23 #include "net/url_request/url_request_context_getter.h" 24 #include "webkit/browser/database/database_tracker.h" 25 #include "webkit/browser/quota/quota_manager.h" 26 27 namespace content { 28 29 namespace { 30 31 void OnClearedCookies(const base::Closure& callback, int num_deleted) { 32 // The final callback needs to happen from UI thread. 33 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 34 BrowserThread::PostTask( 35 BrowserThread::UI, FROM_HERE, 36 base::Bind(&OnClearedCookies, callback, num_deleted)); 37 return; 38 } 39 40 callback.Run(); 41 } 42 43 void ClearCookiesOnIOThread( 44 const scoped_refptr<net::URLRequestContextGetter>& rq_context, 45 const base::Time begin, 46 const base::Time end, 47 const GURL& remove_origin, 48 const base::Closure& callback) { 49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 50 net::CookieStore* cookie_store = rq_context-> 51 GetURLRequestContext()->cookie_store(); 52 if (remove_origin.is_empty()) { 53 cookie_store->GetCookieMonster()->DeleteAllCreatedBetweenAsync( 54 begin, 55 end, 56 base::Bind(&OnClearedCookies, callback)); 57 } else { 58 cookie_store->GetCookieMonster()->DeleteAllCreatedBetweenForHostAsync( 59 begin, 60 end, 61 remove_origin, base::Bind(&OnClearedCookies, callback)); 62 } 63 } 64 65 void CheckQuotaManagedDataDeletionStatus(size_t* deletion_task_count, 66 const base::Closure& callback) { 67 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 68 if (*deletion_task_count == 0) { 69 delete deletion_task_count; 70 callback.Run(); 71 } 72 } 73 74 void OnQuotaManagedOriginDeleted(const GURL& origin, 75 quota::StorageType type, 76 size_t* deletion_task_count, 77 const base::Closure& callback, 78 quota::QuotaStatusCode status) { 79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 80 DCHECK_GT(*deletion_task_count, 0u); 81 if (status != quota::kQuotaStatusOk) { 82 DLOG(ERROR) << "Couldn't remove data of type " << type << " for origin " 83 << origin << ". Status: " << status; 84 } 85 86 (*deletion_task_count)--; 87 CheckQuotaManagedDataDeletionStatus(deletion_task_count, callback); 88 } 89 90 void ClearedShaderCache(const base::Closure& callback) { 91 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 92 BrowserThread::PostTask( 93 BrowserThread::UI, FROM_HERE, 94 base::Bind(&ClearedShaderCache, callback)); 95 return; 96 } 97 callback.Run(); 98 } 99 100 void ClearShaderCacheOnIOThread(const base::FilePath& path, 101 const base::Time begin, 102 const base::Time end, 103 const base::Closure& callback) { 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 105 ShaderCacheFactory::GetInstance()->ClearByPath( 106 path, begin, end, base::Bind(&ClearedShaderCache, callback)); 107 } 108 109 void OnLocalStorageUsageInfo( 110 const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context, 111 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 112 const StoragePartition::OriginMatcherFunction& origin_matcher, 113 const base::Time delete_begin, 114 const base::Time delete_end, 115 const base::Closure& callback, 116 const std::vector<LocalStorageUsageInfo>& infos) { 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 118 119 for (size_t i = 0; i < infos.size(); ++i) { 120 if (!origin_matcher.is_null() && 121 !origin_matcher.Run(infos[i].origin, special_storage_policy.get())) { 122 continue; 123 } 124 125 if (infos[i].last_modified >= delete_begin && 126 infos[i].last_modified <= delete_end) { 127 dom_storage_context->DeleteLocalStorage(infos[i].origin); 128 } 129 } 130 callback.Run(); 131 } 132 133 void OnSessionStorageUsageInfo( 134 const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context, 135 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 136 const StoragePartition::OriginMatcherFunction& origin_matcher, 137 const base::Closure& callback, 138 const std::vector<SessionStorageUsageInfo>& infos) { 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 140 141 for (size_t i = 0; i < infos.size(); ++i) { 142 if (!origin_matcher.is_null() && 143 !origin_matcher.Run(infos[i].origin, special_storage_policy.get())) { 144 continue; 145 } 146 dom_storage_context->DeleteSessionStorage(infos[i]); 147 } 148 149 callback.Run(); 150 } 151 152 void ClearLocalStorageOnUIThread( 153 const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context, 154 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 155 const StoragePartition::OriginMatcherFunction& origin_matcher, 156 const GURL& remove_origin, 157 const base::Time begin, 158 const base::Time end, 159 const base::Closure& callback) { 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 161 162 if (!remove_origin.is_empty()) { 163 bool can_delete = origin_matcher.is_null() || 164 origin_matcher.Run(remove_origin, 165 special_storage_policy.get()); 166 if (can_delete) 167 dom_storage_context->DeleteLocalStorage(remove_origin); 168 169 callback.Run(); 170 return; 171 } 172 173 dom_storage_context->GetLocalStorageUsage( 174 base::Bind(&OnLocalStorageUsageInfo, 175 dom_storage_context, special_storage_policy, origin_matcher, 176 begin, end, callback)); 177 } 178 179 void ClearSessionStorageOnUIThread( 180 const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context, 181 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 182 const StoragePartition::OriginMatcherFunction& origin_matcher, 183 const base::Closure& callback) { 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 185 186 dom_storage_context->GetSessionStorageUsage( 187 base::Bind(&OnSessionStorageUsageInfo, dom_storage_context, 188 special_storage_policy, origin_matcher, 189 callback)); 190 } 191 192 } // namespace 193 194 // Static. 195 int StoragePartitionImpl::GenerateQuotaClientMask(uint32 remove_mask) { 196 int quota_client_mask = 0; 197 198 if (remove_mask & StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS) 199 quota_client_mask |= quota::QuotaClient::kFileSystem; 200 if (remove_mask & StoragePartition::REMOVE_DATA_MASK_WEBSQL) 201 quota_client_mask |= quota::QuotaClient::kDatabase; 202 if (remove_mask & StoragePartition::REMOVE_DATA_MASK_APPCACHE) 203 quota_client_mask |= quota::QuotaClient::kAppcache; 204 if (remove_mask & StoragePartition::REMOVE_DATA_MASK_INDEXEDDB) 205 quota_client_mask |= quota::QuotaClient::kIndexedDatabase; 206 207 return quota_client_mask; 208 } 209 210 // Helper for deleting quota managed data from a partition. 211 // 212 // Most of the operations in this class are done on IO thread. 213 struct StoragePartitionImpl::QuotaManagedDataDeletionHelper { 214 QuotaManagedDataDeletionHelper(uint32 remove_mask, 215 uint32 quota_storage_remove_mask, 216 const GURL& remove_origin, 217 const base::Closure& callback) 218 : remove_mask(remove_mask), 219 quota_storage_remove_mask(quota_storage_remove_mask), 220 remove_origin(remove_origin), 221 callback(callback), 222 task_count(0) { 223 } 224 225 void IncrementTaskCountOnIO(); 226 void DecrementTaskCountOnIO(); 227 228 void ClearDataOnIOThread( 229 const scoped_refptr<quota::QuotaManager>& quota_manager, 230 const base::Time begin, 231 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 232 const StoragePartition::OriginMatcherFunction& origin_matcher); 233 234 void ClearOriginsOnIOThread( 235 quota::QuotaManager* quota_manager, 236 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 237 const StoragePartition::OriginMatcherFunction& origin_matcher, 238 const base::Closure& callback, 239 const std::set<GURL>& origins, 240 quota::StorageType quota_storage_type); 241 242 // All of these data are accessed on IO thread. 243 uint32 remove_mask; 244 uint32 quota_storage_remove_mask; 245 GURL remove_origin; 246 const base::Closure callback; 247 int task_count; 248 }; 249 250 // Helper for deleting all sorts of data from a partition, keeps track of 251 // deletion status. 252 // 253 // StoragePartitionImpl creates an instance of this class to keep track of 254 // data deletion progress. Deletion requires deleting multiple bits of data 255 // (e.g. cookies, local storage, session storage etc.) and hopping between UI 256 // and IO thread. An instance of this class is created in the beginning of 257 // deletion process (StoragePartitionImpl::ClearDataImpl) and the instance is 258 // forwarded and updated on each (sub) deletion's callback. The instance is 259 // finally destroyed when deletion completes (and |callback| is invoked). 260 struct StoragePartitionImpl::DataDeletionHelper { 261 DataDeletionHelper(uint32 remove_mask, 262 uint32 quota_storage_remove_mask, 263 const base::Closure& callback) 264 : remove_mask(remove_mask), 265 quota_storage_remove_mask(quota_storage_remove_mask), 266 callback(callback), 267 task_count(0) { 268 } 269 270 void IncrementTaskCountOnUI(); 271 void DecrementTaskCountOnUI(); 272 273 void ClearDataOnUIThread(const GURL* remove_origin, 274 const OriginMatcherFunction& origin_matcher, 275 const base::FilePath& path, 276 net::URLRequestContextGetter* rq_context, 277 DOMStorageContextWrapper* dom_storage_context, 278 quota::QuotaManager* quota_manager, 279 quota::SpecialStoragePolicy* special_storage_policy, 280 WebRTCIdentityStore* webrtc_identity_store, 281 const base::Time begin, 282 const base::Time end); 283 284 void ClearQuotaManagedDataOnIOThread( 285 const scoped_refptr<quota::QuotaManager>& quota_manager, 286 const base::Time begin, 287 const GURL& remove_origin, 288 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 289 const StoragePartition::OriginMatcherFunction& origin_matcher, 290 const base::Closure& callback); 291 292 uint32 remove_mask; 293 uint32 quota_storage_remove_mask; 294 295 // Accessed on UI thread. 296 const base::Closure callback; 297 // Accessed on UI thread. 298 int task_count; 299 }; 300 301 void StoragePartitionImpl::DataDeletionHelper::ClearQuotaManagedDataOnIOThread( 302 const scoped_refptr<quota::QuotaManager>& quota_manager, 303 const base::Time begin, 304 const GURL& remove_origin, 305 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 306 const StoragePartition::OriginMatcherFunction& origin_matcher, 307 const base::Closure& callback) { 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 309 310 StoragePartitionImpl::QuotaManagedDataDeletionHelper* helper = 311 new StoragePartitionImpl::QuotaManagedDataDeletionHelper( 312 remove_mask, 313 quota_storage_remove_mask, 314 remove_origin, 315 callback); 316 helper->ClearDataOnIOThread(quota_manager, begin, special_storage_policy, 317 origin_matcher); 318 } 319 320 StoragePartitionImpl::StoragePartitionImpl( 321 const base::FilePath& partition_path, 322 quota::QuotaManager* quota_manager, 323 ChromeAppCacheService* appcache_service, 324 fileapi::FileSystemContext* filesystem_context, 325 webkit_database::DatabaseTracker* database_tracker, 326 DOMStorageContextWrapper* dom_storage_context, 327 IndexedDBContextImpl* indexed_db_context, 328 ServiceWorkerContextWrapper* service_worker_context, 329 WebRTCIdentityStore* webrtc_identity_store, 330 quota::SpecialStoragePolicy* special_storage_policy) 331 : partition_path_(partition_path), 332 quota_manager_(quota_manager), 333 appcache_service_(appcache_service), 334 filesystem_context_(filesystem_context), 335 database_tracker_(database_tracker), 336 dom_storage_context_(dom_storage_context), 337 indexed_db_context_(indexed_db_context), 338 service_worker_context_(service_worker_context), 339 webrtc_identity_store_(webrtc_identity_store), 340 special_storage_policy_(special_storage_policy) {} 341 342 StoragePartitionImpl::~StoragePartitionImpl() { 343 // These message loop checks are just to avoid leaks in unittests. 344 if (GetDatabaseTracker() && 345 BrowserThread::IsMessageLoopValid(BrowserThread::FILE)) { 346 BrowserThread::PostTask( 347 BrowserThread::FILE, FROM_HERE, 348 base::Bind(&webkit_database::DatabaseTracker::Shutdown, 349 GetDatabaseTracker())); 350 } 351 352 if (GetFileSystemContext()) 353 GetFileSystemContext()->Shutdown(); 354 355 if (GetDOMStorageContext()) 356 GetDOMStorageContext()->Shutdown(); 357 358 if (GetServiceWorkerContext()) 359 GetServiceWorkerContext()->Shutdown(); 360 } 361 362 // TODO(ajwong): Break the direct dependency on |context|. We only 363 // need 3 pieces of info from it. 364 StoragePartitionImpl* StoragePartitionImpl::Create( 365 BrowserContext* context, 366 bool in_memory, 367 const base::FilePath& partition_path) { 368 // Ensure that these methods are called on the UI thread, except for 369 // unittests where a UI thread might not have been created. 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 371 !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); 372 373 // All of the clients have to be created and registered with the 374 // QuotaManager prior to the QuotaManger being used. We do them 375 // all together here prior to handing out a reference to anything 376 // that utilizes the QuotaManager. 377 scoped_refptr<quota::QuotaManager> quota_manager = new quota::QuotaManager( 378 in_memory, 379 partition_path, 380 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO).get(), 381 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(), 382 context->GetSpecialStoragePolicy()); 383 384 // Each consumer is responsible for registering its QuotaClient during 385 // its construction. 386 scoped_refptr<fileapi::FileSystemContext> filesystem_context = 387 CreateFileSystemContext(context, 388 partition_path, in_memory, 389 quota_manager->proxy()); 390 391 scoped_refptr<webkit_database::DatabaseTracker> database_tracker = 392 new webkit_database::DatabaseTracker( 393 partition_path, 394 in_memory, 395 context->GetSpecialStoragePolicy(), 396 quota_manager->proxy(), 397 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) 398 .get()); 399 400 base::FilePath path = in_memory ? base::FilePath() : partition_path; 401 scoped_refptr<DOMStorageContextWrapper> dom_storage_context = 402 new DOMStorageContextWrapper(path, context->GetSpecialStoragePolicy()); 403 404 // BrowserMainLoop may not be initialized in unit tests. Tests will 405 // need to inject their own task runner into the IndexedDBContext. 406 base::SequencedTaskRunner* idb_task_runner = 407 BrowserThread::CurrentlyOn(BrowserThread::UI) && 408 BrowserMainLoop::GetInstance() 409 ? BrowserMainLoop::GetInstance()->indexed_db_thread() 410 ->message_loop_proxy().get() 411 : NULL; 412 scoped_refptr<IndexedDBContextImpl> indexed_db_context = 413 new IndexedDBContextImpl(path, 414 context->GetSpecialStoragePolicy(), 415 quota_manager->proxy(), 416 idb_task_runner); 417 418 scoped_refptr<ServiceWorkerContextWrapper> service_worker_context = 419 new ServiceWorkerContextWrapper(); 420 service_worker_context->Init(path, quota_manager->proxy()); 421 422 scoped_refptr<ChromeAppCacheService> appcache_service = 423 new ChromeAppCacheService(quota_manager->proxy()); 424 425 scoped_refptr<WebRTCIdentityStore> webrtc_identity_store( 426 new WebRTCIdentityStore(path, context->GetSpecialStoragePolicy())); 427 428 scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy( 429 context->GetSpecialStoragePolicy()); 430 431 return new StoragePartitionImpl(partition_path, 432 quota_manager.get(), 433 appcache_service.get(), 434 filesystem_context.get(), 435 database_tracker.get(), 436 dom_storage_context.get(), 437 indexed_db_context.get(), 438 service_worker_context.get(), 439 webrtc_identity_store.get(), 440 special_storage_policy.get()); 441 } 442 443 base::FilePath StoragePartitionImpl::GetPath() { 444 return partition_path_; 445 } 446 447 net::URLRequestContextGetter* StoragePartitionImpl::GetURLRequestContext() { 448 return url_request_context_.get(); 449 } 450 451 net::URLRequestContextGetter* 452 StoragePartitionImpl::GetMediaURLRequestContext() { 453 return media_url_request_context_.get(); 454 } 455 456 quota::QuotaManager* StoragePartitionImpl::GetQuotaManager() { 457 return quota_manager_.get(); 458 } 459 460 ChromeAppCacheService* StoragePartitionImpl::GetAppCacheService() { 461 return appcache_service_.get(); 462 } 463 464 fileapi::FileSystemContext* StoragePartitionImpl::GetFileSystemContext() { 465 return filesystem_context_.get(); 466 } 467 468 webkit_database::DatabaseTracker* StoragePartitionImpl::GetDatabaseTracker() { 469 return database_tracker_.get(); 470 } 471 472 DOMStorageContextWrapper* StoragePartitionImpl::GetDOMStorageContext() { 473 return dom_storage_context_.get(); 474 } 475 476 IndexedDBContextImpl* StoragePartitionImpl::GetIndexedDBContext() { 477 return indexed_db_context_.get(); 478 } 479 480 ServiceWorkerContextWrapper* StoragePartitionImpl::GetServiceWorkerContext() { 481 return service_worker_context_.get(); 482 } 483 484 void StoragePartitionImpl::ClearDataImpl( 485 uint32 remove_mask, 486 uint32 quota_storage_remove_mask, 487 const GURL* remove_origin, 488 const OriginMatcherFunction& origin_matcher, 489 net::URLRequestContextGetter* rq_context, 490 const base::Time begin, 491 const base::Time end, 492 const base::Closure& callback) { 493 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 494 DataDeletionHelper* helper = new DataDeletionHelper(remove_mask, 495 quota_storage_remove_mask, 496 callback); 497 // |helper| deletes itself when done in 498 // DataDeletionHelper::DecrementTaskCountOnUI(). 499 helper->ClearDataOnUIThread(remove_origin, origin_matcher, GetPath(), 500 rq_context, dom_storage_context_, quota_manager_, 501 special_storage_policy_.get(), 502 webrtc_identity_store_, begin, end); 503 } 504 505 void StoragePartitionImpl:: 506 QuotaManagedDataDeletionHelper::IncrementTaskCountOnIO() { 507 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 508 ++task_count; 509 } 510 511 void StoragePartitionImpl:: 512 QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO() { 513 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 514 DCHECK_GT(task_count, 0); 515 --task_count; 516 if (task_count) 517 return; 518 519 callback.Run(); 520 delete this; 521 } 522 523 void StoragePartitionImpl::QuotaManagedDataDeletionHelper::ClearDataOnIOThread( 524 const scoped_refptr<quota::QuotaManager>& quota_manager, 525 const base::Time begin, 526 const scoped_refptr<quota::SpecialStoragePolicy>& special_storage_policy, 527 const StoragePartition::OriginMatcherFunction& origin_matcher) { 528 IncrementTaskCountOnIO(); 529 base::Closure decrement_callback = base::Bind( 530 &QuotaManagedDataDeletionHelper::DecrementTaskCountOnIO, 531 base::Unretained(this)); 532 533 if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_PERSISTENT) { 534 IncrementTaskCountOnIO(); 535 // Ask the QuotaManager for all origins with persistent quota modified 536 // within the user-specified timeframe, and deal with the resulting set in 537 // ClearQuotaManagedOriginsOnIOThread(). 538 quota_manager->GetOriginsModifiedSince( 539 quota::kStorageTypePersistent, begin, 540 base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread, 541 base::Unretained(this), 542 quota_manager, 543 special_storage_policy, 544 origin_matcher, 545 decrement_callback)); 546 } 547 548 // Do the same for temporary quota. 549 if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_TEMPORARY) { 550 IncrementTaskCountOnIO(); 551 quota_manager->GetOriginsModifiedSince( 552 quota::kStorageTypeTemporary, begin, 553 base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread, 554 base::Unretained(this), 555 quota_manager, 556 special_storage_policy, 557 origin_matcher, 558 decrement_callback)); 559 } 560 561 // Do the same for syncable quota. 562 if (quota_storage_remove_mask & QUOTA_MANAGED_STORAGE_MASK_SYNCABLE) { 563 IncrementTaskCountOnIO(); 564 quota_manager->GetOriginsModifiedSince( 565 quota::kStorageTypeSyncable, begin, 566 base::Bind(&QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread, 567 base::Unretained(this), 568 quota_manager, 569 special_storage_policy, 570 origin_matcher, 571 decrement_callback)); 572 } 573 574 DecrementTaskCountOnIO(); 575 } 576 577 void StoragePartitionImpl:: 578 QuotaManagedDataDeletionHelper::ClearOriginsOnIOThread( 579 quota::QuotaManager* quota_manager, 580 const scoped_refptr<quota::SpecialStoragePolicy>& 581 special_storage_policy, 582 const StoragePartition::OriginMatcherFunction& origin_matcher, 583 const base::Closure& callback, 584 const std::set<GURL>& origins, 585 quota::StorageType quota_storage_type) { 586 // The QuotaManager manages all storage other than cookies, LocalStorage, 587 // and SessionStorage. This loop wipes out most HTML5 storage for the given 588 // origins. 589 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 590 if (!origins.size()) { 591 callback.Run(); 592 return; 593 } 594 595 size_t* deletion_task_count = new size_t(0u); 596 (*deletion_task_count)++; 597 for (std::set<GURL>::const_iterator origin = origins.begin(); 598 origin != origins.end(); ++origin) { 599 // TODO(mkwst): Clean this up, it's slow. http://crbug.com/130746 600 if (!remove_origin.is_empty() && origin->GetOrigin() != remove_origin) 601 continue; 602 603 if (!origin_matcher.is_null() && 604 !origin_matcher.Run(*origin, special_storage_policy.get())) { 605 continue; 606 } 607 608 (*deletion_task_count)++; 609 quota_manager->DeleteOriginData( 610 *origin, quota_storage_type, 611 StoragePartitionImpl::GenerateQuotaClientMask(remove_mask), 612 base::Bind(&OnQuotaManagedOriginDeleted, 613 origin->GetOrigin(), quota_storage_type, 614 deletion_task_count, callback)); 615 } 616 (*deletion_task_count)--; 617 618 CheckQuotaManagedDataDeletionStatus(deletion_task_count, callback); 619 } 620 621 void StoragePartitionImpl::DataDeletionHelper::IncrementTaskCountOnUI() { 622 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 623 ++task_count; 624 } 625 626 void StoragePartitionImpl::DataDeletionHelper::DecrementTaskCountOnUI() { 627 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 628 BrowserThread::PostTask( 629 BrowserThread::UI, FROM_HERE, 630 base::Bind(&DataDeletionHelper::DecrementTaskCountOnUI, 631 base::Unretained(this))); 632 return; 633 } 634 DCHECK_GT(task_count, 0); 635 --task_count; 636 if (!task_count) { 637 callback.Run(); 638 delete this; 639 } 640 } 641 642 void StoragePartitionImpl::DataDeletionHelper::ClearDataOnUIThread( 643 const GURL* remove_origin, 644 const OriginMatcherFunction& origin_matcher, 645 const base::FilePath& path, 646 net::URLRequestContextGetter* rq_context, 647 DOMStorageContextWrapper* dom_storage_context, 648 quota::QuotaManager* quota_manager, 649 quota::SpecialStoragePolicy* special_storage_policy, 650 WebRTCIdentityStore* webrtc_identity_store, 651 const base::Time begin, 652 const base::Time end) { 653 DCHECK_NE(remove_mask, 0u); 654 DCHECK(!callback.is_null()); 655 656 IncrementTaskCountOnUI(); 657 base::Closure decrement_callback = base::Bind( 658 &DataDeletionHelper::DecrementTaskCountOnUI, base::Unretained(this)); 659 660 GURL origin = remove_origin ? *remove_origin : GURL(); 661 if (remove_mask & REMOVE_DATA_MASK_COOKIES) { 662 // Handle the cookies. 663 IncrementTaskCountOnUI(); 664 BrowserThread::PostTask( 665 BrowserThread::IO, FROM_HERE, 666 base::Bind(&ClearCookiesOnIOThread, 667 make_scoped_refptr(rq_context), begin, end, origin, 668 decrement_callback)); 669 } 670 671 if (remove_mask & REMOVE_DATA_MASK_INDEXEDDB || 672 remove_mask & REMOVE_DATA_MASK_WEBSQL || 673 remove_mask & REMOVE_DATA_MASK_APPCACHE || 674 remove_mask & REMOVE_DATA_MASK_FILE_SYSTEMS) { 675 IncrementTaskCountOnUI(); 676 BrowserThread::PostTask( 677 BrowserThread::IO, FROM_HERE, 678 base::Bind(&DataDeletionHelper::ClearQuotaManagedDataOnIOThread, 679 base::Unretained(this), 680 make_scoped_refptr(quota_manager), 681 begin, 682 origin, 683 make_scoped_refptr(special_storage_policy), 684 origin_matcher, 685 decrement_callback)); 686 } 687 688 if (remove_mask & REMOVE_DATA_MASK_LOCAL_STORAGE) { 689 IncrementTaskCountOnUI(); 690 ClearLocalStorageOnUIThread( 691 make_scoped_refptr(dom_storage_context), 692 make_scoped_refptr(special_storage_policy), 693 origin_matcher, 694 origin, begin, end, 695 decrement_callback); 696 697 // ClearDataImpl cannot clear session storage data when a particular origin 698 // is specified. Therefore we ignore clearing session storage in this case. 699 // TODO(lazyboy): Fix. 700 if (origin.is_empty()) { 701 IncrementTaskCountOnUI(); 702 ClearSessionStorageOnUIThread( 703 make_scoped_refptr(dom_storage_context), 704 make_scoped_refptr(special_storage_policy), 705 origin_matcher, 706 decrement_callback); 707 } 708 } 709 710 if (remove_mask & REMOVE_DATA_MASK_SHADER_CACHE) { 711 IncrementTaskCountOnUI(); 712 BrowserThread::PostTask( 713 BrowserThread::IO, FROM_HERE, 714 base::Bind(&ClearShaderCacheOnIOThread, 715 path, begin, end, decrement_callback)); 716 } 717 718 if (remove_mask & REMOVE_DATA_MASK_WEBRTC_IDENTITY) { 719 IncrementTaskCountOnUI(); 720 BrowserThread::PostTask( 721 BrowserThread::IO, 722 FROM_HERE, 723 base::Bind(&WebRTCIdentityStore::DeleteBetween, 724 webrtc_identity_store, 725 begin, 726 end, 727 decrement_callback)); 728 } 729 730 DecrementTaskCountOnUI(); 731 } 732 733 734 void StoragePartitionImpl::ClearDataForOrigin( 735 uint32 remove_mask, 736 uint32 quota_storage_remove_mask, 737 const GURL& storage_origin, 738 net::URLRequestContextGetter* request_context_getter) { 739 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 740 ClearDataImpl(remove_mask, quota_storage_remove_mask, &storage_origin, 741 OriginMatcherFunction(), request_context_getter, 742 base::Time(), base::Time::Max(), base::Bind(&base::DoNothing)); 743 } 744 745 void StoragePartitionImpl::ClearData( 746 uint32 remove_mask, 747 uint32 quota_storage_remove_mask, 748 const GURL* storage_origin, 749 const OriginMatcherFunction& origin_matcher, 750 const base::Time begin, 751 const base::Time end, 752 const base::Closure& callback) { 753 ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_origin, 754 origin_matcher, GetURLRequestContext(), begin, end, callback); 755 } 756 757 WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() { 758 return webrtc_identity_store_.get(); 759 } 760 761 void StoragePartitionImpl::OverrideQuotaManagerForTesting( 762 quota::QuotaManager* quota_manager) { 763 quota_manager_ = quota_manager; 764 } 765 766 void StoragePartitionImpl::OverrideSpecialStoragePolicyForTesting( 767 quota::SpecialStoragePolicy* special_storage_policy) { 768 special_storage_policy_ = special_storage_policy; 769 } 770 771 void StoragePartitionImpl::SetURLRequestContext( 772 net::URLRequestContextGetter* url_request_context) { 773 url_request_context_ = url_request_context; 774 } 775 776 void StoragePartitionImpl::SetMediaURLRequestContext( 777 net::URLRequestContextGetter* media_url_request_context) { 778 media_url_request_context_ = media_url_request_context; 779 } 780 781 } // namespace content 782