Home | History | Annotate | Download | only in appcache
      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 "webkit/browser/appcache/appcache_quota_client.h"
      6 
      7 #include <algorithm>
      8 #include <map>
      9 #include <set>
     10 
     11 #include "base/bind.h"
     12 #include "base/bind_helpers.h"
     13 #include "webkit/browser/appcache/appcache_service.h"
     14 
     15 using quota::QuotaClient;
     16 
     17 namespace {
     18 quota::QuotaStatusCode NetErrorCodeToQuotaStatus(int code) {
     19   if (code == net::OK)
     20     return quota::kQuotaStatusOk;
     21   else if (code == net::ERR_ABORTED)
     22     return quota::kQuotaErrorAbort;
     23   else
     24     return quota::kQuotaStatusUnknown;
     25 }
     26 
     27 void RunFront(appcache::AppCacheQuotaClient::RequestQueue* queue) {
     28   base::Closure request = queue->front();
     29   queue->pop_front();
     30   request.Run();
     31 }
     32 }  // namespace
     33 
     34 namespace appcache {
     35 
     36 AppCacheQuotaClient::AppCacheQuotaClient(AppCacheService* service)
     37     : service_(service),
     38       appcache_is_ready_(false),
     39       quota_manager_is_destroyed_(false) {
     40 }
     41 
     42 AppCacheQuotaClient::~AppCacheQuotaClient() {
     43   DCHECK(pending_batch_requests_.empty());
     44   DCHECK(pending_serial_requests_.empty());
     45   DCHECK(current_delete_request_callback_.is_null());
     46 }
     47 
     48 QuotaClient::ID AppCacheQuotaClient::id() const {
     49   return kAppcache;
     50 }
     51 
     52 void AppCacheQuotaClient::OnQuotaManagerDestroyed() {
     53   DeletePendingRequests();
     54   if (!current_delete_request_callback_.is_null()) {
     55     current_delete_request_callback_.Reset();
     56     GetServiceDeleteCallback()->Cancel();
     57   }
     58 
     59   quota_manager_is_destroyed_ = true;
     60   if (!service_)
     61     delete this;
     62 }
     63 
     64 void AppCacheQuotaClient::GetOriginUsage(
     65     const GURL& origin,
     66     quota::StorageType type,
     67     const GetUsageCallback& callback) {
     68   DCHECK(!callback.is_null());
     69   DCHECK(!quota_manager_is_destroyed_);
     70 
     71   if (!service_) {
     72     callback.Run(0);
     73     return;
     74   }
     75 
     76   if (!appcache_is_ready_) {
     77     pending_batch_requests_.push_back(
     78         base::Bind(&AppCacheQuotaClient::GetOriginUsage,
     79                    base::Unretained(this), origin, type, callback));
     80     return;
     81   }
     82 
     83   if (type != quota::kStorageTypeTemporary) {
     84     callback.Run(0);
     85     return;
     86   }
     87 
     88   const AppCacheStorage::UsageMap* map = GetUsageMap();
     89   AppCacheStorage::UsageMap::const_iterator found = map->find(origin);
     90   if (found == map->end()) {
     91     callback.Run(0);
     92     return;
     93   }
     94   callback.Run(found->second);
     95 }
     96 
     97 void AppCacheQuotaClient::GetOriginsForType(
     98     quota::StorageType type,
     99     const GetOriginsCallback& callback) {
    100   GetOriginsHelper(type, std::string(), callback);
    101 }
    102 
    103 void AppCacheQuotaClient::GetOriginsForHost(
    104     quota::StorageType type,
    105     const std::string& host,
    106     const GetOriginsCallback& callback) {
    107   DCHECK(!callback.is_null());
    108   if (host.empty()) {
    109     callback.Run(std::set<GURL>());
    110     return;
    111   }
    112   GetOriginsHelper(type, host, callback);
    113 }
    114 
    115 void AppCacheQuotaClient::DeleteOriginData(const GURL& origin,
    116                                            quota::StorageType type,
    117                                            const DeletionCallback& callback) {
    118   DCHECK(!quota_manager_is_destroyed_);
    119 
    120   if (!service_) {
    121     callback.Run(quota::kQuotaErrorAbort);
    122     return;
    123   }
    124 
    125   if (!appcache_is_ready_ || !current_delete_request_callback_.is_null()) {
    126     pending_serial_requests_.push_back(
    127         base::Bind(&AppCacheQuotaClient::DeleteOriginData,
    128                    base::Unretained(this), origin, type, callback));
    129     return;
    130   }
    131 
    132   current_delete_request_callback_ = callback;
    133   if (type != quota::kStorageTypeTemporary) {
    134     DidDeleteAppCachesForOrigin(net::OK);
    135     return;
    136   }
    137 
    138   service_->DeleteAppCachesForOrigin(
    139       origin, GetServiceDeleteCallback()->callback());
    140 }
    141 
    142 void AppCacheQuotaClient::DidDeleteAppCachesForOrigin(int rv) {
    143   DCHECK(service_);
    144   if (quota_manager_is_destroyed_)
    145     return;
    146 
    147   // Finish the request by calling our callers callback.
    148   current_delete_request_callback_.Run(NetErrorCodeToQuotaStatus(rv));
    149   current_delete_request_callback_.Reset();
    150   if (pending_serial_requests_.empty())
    151     return;
    152 
    153   // Start the next in the queue.
    154   RunFront(&pending_serial_requests_);
    155 }
    156 
    157 void AppCacheQuotaClient::GetOriginsHelper(
    158     quota::StorageType type,
    159     const std::string& opt_host,
    160     const GetOriginsCallback& callback) {
    161   DCHECK(!callback.is_null());
    162   DCHECK(!quota_manager_is_destroyed_);
    163 
    164   if (!service_) {
    165     callback.Run(std::set<GURL>());
    166     return;
    167   }
    168 
    169   if (!appcache_is_ready_) {
    170     pending_batch_requests_.push_back(
    171         base::Bind(&AppCacheQuotaClient::GetOriginsHelper,
    172                    base::Unretained(this), type, opt_host, callback));
    173     return;
    174   }
    175 
    176   if (type != quota::kStorageTypeTemporary) {
    177     callback.Run(std::set<GURL>());
    178     return;
    179   }
    180 
    181   const AppCacheStorage::UsageMap* map = GetUsageMap();
    182   std::set<GURL> origins;
    183   for (AppCacheStorage::UsageMap::const_iterator iter = map->begin();
    184        iter != map->end(); ++iter) {
    185     if (opt_host.empty() || iter->first.host() == opt_host)
    186       origins.insert(iter->first);
    187   }
    188   callback.Run(origins);
    189 }
    190 
    191 void AppCacheQuotaClient::ProcessPendingRequests() {
    192   DCHECK(appcache_is_ready_);
    193   while (!pending_batch_requests_.empty())
    194     RunFront(&pending_batch_requests_);
    195 
    196   if (!pending_serial_requests_.empty())
    197     RunFront(&pending_serial_requests_);
    198 }
    199 
    200 void AppCacheQuotaClient::DeletePendingRequests() {
    201   pending_batch_requests_.clear();
    202   pending_serial_requests_.clear();
    203 }
    204 
    205 const AppCacheStorage::UsageMap* AppCacheQuotaClient::GetUsageMap() {
    206   DCHECK(service_);
    207   return service_->storage()->usage_map();
    208 }
    209 
    210 net::CancelableCompletionCallback*
    211 AppCacheQuotaClient::GetServiceDeleteCallback() {
    212   // Lazily created due to CancelableCompletionCallback's threading
    213   // restrictions, there is no way to detach from the thread created on.
    214   if (!service_delete_callback_) {
    215     service_delete_callback_.reset(
    216         new net::CancelableCompletionCallback(
    217             base::Bind(&AppCacheQuotaClient::DidDeleteAppCachesForOrigin,
    218                        base::Unretained(this))));
    219   }
    220   return service_delete_callback_.get();
    221 }
    222 
    223 void AppCacheQuotaClient::NotifyAppCacheReady() {
    224   appcache_is_ready_ = true;
    225   ProcessPendingRequests();
    226 }
    227 
    228 void AppCacheQuotaClient::NotifyAppCacheDestroyed() {
    229   service_ = NULL;
    230   while (!pending_batch_requests_.empty())
    231     RunFront(&pending_batch_requests_);
    232 
    233   while (!pending_serial_requests_.empty())
    234     RunFront(&pending_serial_requests_);
    235 
    236   if (!current_delete_request_callback_.is_null()) {
    237     current_delete_request_callback_.Run(quota::kQuotaErrorAbort);
    238     current_delete_request_callback_.Reset();
    239     GetServiceDeleteCallback()->Cancel();
    240   }
    241 
    242   if (quota_manager_is_destroyed_)
    243     delete this;
    244 }
    245 
    246 }  // namespace appcache
    247