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