Home | History | Annotate | Download | only in browser
      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& storage_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 (storage_origin.is_empty()) {
     53     cookie_store->DeleteAllCreatedBetweenAsync(
     54         begin,
     55         end,
     56         base::Bind(&OnClearedCookies, callback));
     57   } else {
     58     cookie_store->DeleteAllCreatedBetweenForHostAsync(
     59         begin,
     60         end,
     61         storage_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& storage_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 (!storage_origin.is_empty()) {
    163     bool can_delete = origin_matcher.is_null() ||
    164                       origin_matcher.Run(storage_origin,
    165                                          special_storage_policy.get());
    166     if (can_delete)
    167       dom_storage_context->DeleteLocalStorage(storage_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& storage_origin,
    217                                  const base::Closure& callback)
    218       : remove_mask(remove_mask),
    219         quota_storage_remove_mask(quota_storage_remove_mask),
    220         storage_origin(storage_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 storage_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& storage_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& storage_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& storage_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           storage_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(context);
    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& storage_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(storage_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 (!storage_origin.is_empty() && origin->GetOrigin() != storage_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& storage_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   if (remove_mask & REMOVE_DATA_MASK_COOKIES) {
    661     // Handle the cookies.
    662     IncrementTaskCountOnUI();
    663     BrowserThread::PostTask(
    664         BrowserThread::IO, FROM_HERE,
    665         base::Bind(&ClearCookiesOnIOThread,
    666                    make_scoped_refptr(rq_context), begin, end, storage_origin,
    667                    decrement_callback));
    668   }
    669 
    670   if (remove_mask & REMOVE_DATA_MASK_INDEXEDDB ||
    671       remove_mask & REMOVE_DATA_MASK_WEBSQL ||
    672       remove_mask & REMOVE_DATA_MASK_APPCACHE ||
    673       remove_mask & REMOVE_DATA_MASK_FILE_SYSTEMS) {
    674     IncrementTaskCountOnUI();
    675     BrowserThread::PostTask(
    676         BrowserThread::IO, FROM_HERE,
    677         base::Bind(&DataDeletionHelper::ClearQuotaManagedDataOnIOThread,
    678                    base::Unretained(this),
    679                    make_scoped_refptr(quota_manager),
    680                    begin,
    681                    storage_origin,
    682                    make_scoped_refptr(special_storage_policy),
    683                    origin_matcher,
    684                    decrement_callback));
    685   }
    686 
    687   if (remove_mask & REMOVE_DATA_MASK_LOCAL_STORAGE) {
    688     IncrementTaskCountOnUI();
    689     ClearLocalStorageOnUIThread(
    690         make_scoped_refptr(dom_storage_context),
    691         make_scoped_refptr(special_storage_policy),
    692         origin_matcher,
    693         storage_origin, begin, end,
    694         decrement_callback);
    695 
    696     // ClearDataImpl cannot clear session storage data when a particular origin
    697     // is specified. Therefore we ignore clearing session storage in this case.
    698     // TODO(lazyboy): Fix.
    699     if (storage_origin.is_empty()) {
    700       IncrementTaskCountOnUI();
    701       ClearSessionStorageOnUIThread(
    702           make_scoped_refptr(dom_storage_context),
    703           make_scoped_refptr(special_storage_policy),
    704           origin_matcher,
    705           decrement_callback);
    706     }
    707   }
    708 
    709   if (remove_mask & REMOVE_DATA_MASK_SHADER_CACHE) {
    710     IncrementTaskCountOnUI();
    711     BrowserThread::PostTask(
    712         BrowserThread::IO, FROM_HERE,
    713         base::Bind(&ClearShaderCacheOnIOThread,
    714                    path, begin, end, decrement_callback));
    715   }
    716 
    717   if (remove_mask & REMOVE_DATA_MASK_WEBRTC_IDENTITY) {
    718     IncrementTaskCountOnUI();
    719     BrowserThread::PostTask(
    720         BrowserThread::IO,
    721         FROM_HERE,
    722         base::Bind(&WebRTCIdentityStore::DeleteBetween,
    723                    webrtc_identity_store,
    724                    begin,
    725                    end,
    726                    decrement_callback));
    727   }
    728 
    729   DecrementTaskCountOnUI();
    730 }
    731 
    732 
    733 void StoragePartitionImpl::ClearDataForOrigin(
    734     uint32 remove_mask,
    735     uint32 quota_storage_remove_mask,
    736     const GURL& storage_origin,
    737     net::URLRequestContextGetter* request_context_getter) {
    738   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    739   ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_origin,
    740                 OriginMatcherFunction(), request_context_getter,
    741                 base::Time(), base::Time::Max(), base::Bind(&base::DoNothing));
    742 }
    743 
    744 void StoragePartitionImpl::ClearData(
    745     uint32 remove_mask,
    746     uint32 quota_storage_remove_mask,
    747     const GURL& storage_origin,
    748     const OriginMatcherFunction& origin_matcher,
    749     const base::Time begin,
    750     const base::Time end,
    751     const base::Closure& callback) {
    752   ClearDataImpl(remove_mask, quota_storage_remove_mask, storage_origin,
    753                 origin_matcher, GetURLRequestContext(), begin, end, callback);
    754 }
    755 
    756 WebRTCIdentityStore* StoragePartitionImpl::GetWebRTCIdentityStore() {
    757   return webrtc_identity_store_.get();
    758 }
    759 
    760 void StoragePartitionImpl::OverrideQuotaManagerForTesting(
    761     quota::QuotaManager* quota_manager) {
    762   quota_manager_ = quota_manager;
    763 }
    764 
    765 void StoragePartitionImpl::OverrideSpecialStoragePolicyForTesting(
    766     quota::SpecialStoragePolicy* special_storage_policy) {
    767   special_storage_policy_ = special_storage_policy;
    768 }
    769 
    770 void StoragePartitionImpl::SetURLRequestContext(
    771     net::URLRequestContextGetter* url_request_context) {
    772   url_request_context_ = url_request_context;
    773 }
    774 
    775 void StoragePartitionImpl::SetMediaURLRequestContext(
    776     net::URLRequestContextGetter* media_url_request_context) {
    777   media_url_request_context_ = media_url_request_context;
    778 }
    779 
    780 }  // namespace content
    781