• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
NetErrorCodeToQuotaStatus(int code)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 
RunFront(content::AppCacheQuotaClient::RequestQueue * queue)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 
AppCacheQuotaClient(AppCacheServiceImpl * service)36 AppCacheQuotaClient::AppCacheQuotaClient(AppCacheServiceImpl* service)
37     : service_(service),
38       appcache_is_ready_(false),
39       quota_manager_is_destroyed_(false) {
40 }
41 
~AppCacheQuotaClient()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 
id() const48 QuotaClient::ID AppCacheQuotaClient::id() const {
49   return kAppcache;
50 }
51 
OnQuotaManagerDestroyed()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 
GetOriginUsage(const GURL & origin,storage::StorageType type,const GetUsageCallback & callback)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 
GetOriginsForType(storage::StorageType type,const GetOriginsCallback & callback)96 void AppCacheQuotaClient::GetOriginsForType(
97     storage::StorageType type,
98     const GetOriginsCallback& callback) {
99   GetOriginsHelper(type, std::string(), callback);
100 }
101 
GetOriginsForHost(storage::StorageType type,const std::string & host,const GetOriginsCallback & callback)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 
DeleteOriginData(const GURL & origin,storage::StorageType type,const DeletionCallback & callback)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 
DoesSupport(storage::StorageType type) const141 bool AppCacheQuotaClient::DoesSupport(storage::StorageType type) const {
142   return type == storage::kStorageTypeTemporary;
143 }
144 
DidDeleteAppCachesForOrigin(int rv)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 
GetOriginsHelper(storage::StorageType type,const std::string & opt_host,const GetOriginsCallback & callback)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 
ProcessPendingRequests()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 
DeletePendingRequests()202 void AppCacheQuotaClient::DeletePendingRequests() {
203   pending_batch_requests_.clear();
204   pending_serial_requests_.clear();
205 }
206 
GetUsageMap()207 const AppCacheStorage::UsageMap* AppCacheQuotaClient::GetUsageMap() {
208   DCHECK(service_);
209   return service_->storage()->usage_map();
210 }
211 
212 net::CancelableCompletionCallback*
GetServiceDeleteCallback()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 
NotifyAppCacheReady()225 void AppCacheQuotaClient::NotifyAppCacheReady() {
226   // Can reoccur during reinitialization.
227   if (!appcache_is_ready_) {
228     appcache_is_ready_ = true;
229     ProcessPendingRequests();
230   }
231 }
232 
NotifyAppCacheDestroyed()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