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