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