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_impl.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(AppCacheServiceImpl* 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 bool AppCacheQuotaClient::DoesSupport(quota::StorageType type) const {
    143   return type == quota::kStorageTypeTemporary;
    144 }
    145 
    146 void AppCacheQuotaClient::DidDeleteAppCachesForOrigin(int rv) {
    147   DCHECK(service_);
    148   if (quota_manager_is_destroyed_)
    149     return;
    150 
    151   // Finish the request by calling our callers callback.
    152   current_delete_request_callback_.Run(NetErrorCodeToQuotaStatus(rv));
    153   current_delete_request_callback_.Reset();
    154   if (pending_serial_requests_.empty())
    155     return;
    156 
    157   // Start the next in the queue.
    158   RunFront(&pending_serial_requests_);
    159 }
    160 
    161 void AppCacheQuotaClient::GetOriginsHelper(
    162     quota::StorageType type,
    163     const std::string& opt_host,
    164     const GetOriginsCallback& callback) {
    165   DCHECK(!callback.is_null());
    166   DCHECK(!quota_manager_is_destroyed_);
    167 
    168   if (!service_) {
    169     callback.Run(std::set<GURL>());
    170     return;
    171   }
    172 
    173   if (!appcache_is_ready_) {
    174     pending_batch_requests_.push_back(
    175         base::Bind(&AppCacheQuotaClient::GetOriginsHelper,
    176                    base::Unretained(this), type, opt_host, callback));
    177     return;
    178   }
    179 
    180   if (type != quota::kStorageTypeTemporary) {
    181     callback.Run(std::set<GURL>());
    182     return;
    183   }
    184 
    185   const AppCacheStorage::UsageMap* map = GetUsageMap();
    186   std::set<GURL> origins;
    187   for (AppCacheStorage::UsageMap::const_iterator iter = map->begin();
    188        iter != map->end(); ++iter) {
    189     if (opt_host.empty() || iter->first.host() == opt_host)
    190       origins.insert(iter->first);
    191   }
    192   callback.Run(origins);
    193 }
    194 
    195 void AppCacheQuotaClient::ProcessPendingRequests() {
    196   DCHECK(appcache_is_ready_);
    197   while (!pending_batch_requests_.empty())
    198     RunFront(&pending_batch_requests_);
    199 
    200   if (!pending_serial_requests_.empty())
    201     RunFront(&pending_serial_requests_);
    202 }
    203 
    204 void AppCacheQuotaClient::DeletePendingRequests() {
    205   pending_batch_requests_.clear();
    206   pending_serial_requests_.clear();
    207 }
    208 
    209 const AppCacheStorage::UsageMap* AppCacheQuotaClient::GetUsageMap() {
    210   DCHECK(service_);
    211   return service_->storage()->usage_map();
    212 }
    213 
    214 net::CancelableCompletionCallback*
    215 AppCacheQuotaClient::GetServiceDeleteCallback() {
    216   // Lazily created due to CancelableCompletionCallback's threading
    217   // restrictions, there is no way to detach from the thread created on.
    218   if (!service_delete_callback_) {
    219     service_delete_callback_.reset(
    220         new net::CancelableCompletionCallback(
    221             base::Bind(&AppCacheQuotaClient::DidDeleteAppCachesForOrigin,
    222                        base::Unretained(this))));
    223   }
    224   return service_delete_callback_.get();
    225 }
    226 
    227 void AppCacheQuotaClient::NotifyAppCacheReady() {
    228   // Can reoccur during reinitialization.
    229   if (!appcache_is_ready_) {
    230     appcache_is_ready_ = true;
    231     ProcessPendingRequests();
    232   }
    233 }
    234 
    235 void AppCacheQuotaClient::NotifyAppCacheDestroyed() {
    236   service_ = NULL;
    237   while (!pending_batch_requests_.empty())
    238     RunFront(&pending_batch_requests_);
    239 
    240   while (!pending_serial_requests_.empty())
    241     RunFront(&pending_serial_requests_);
    242 
    243   if (!current_delete_request_callback_.is_null()) {
    244     current_delete_request_callback_.Run(quota::kQuotaErrorAbort);
    245     current_delete_request_callback_.Reset();
    246     GetServiceDeleteCallback()->Cancel();
    247   }
    248 
    249   if (quota_manager_is_destroyed_)
    250     delete this;
    251 }
    252 
    253 }  // namespace appcache
    254