OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/service_worker/service_worker_cache_storage_manager.h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/files/file_enumerator.h" | |
12 #include "base/files/file_util.h" | |
13 #include "base/id_map.h" | |
14 #include "base/sha1.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "content/browser/service_worker/service_worker_cache.pb.h" | |
18 #include "content/browser/service_worker/service_worker_cache_quota_client.h" | |
19 #include "content/browser/service_worker/service_worker_cache_storage.h" | |
20 #include "content/browser/service_worker/service_worker_context_core.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "net/base/net_util.h" | |
23 #include "storage/browser/quota/quota_manager_proxy.h" | |
24 #include "storage/common/database/database_identifier.h" | |
25 #include "storage/common/quota/quota_status_code.h" | |
26 #include "url/gurl.h" | |
27 | |
28 namespace content { | |
29 | |
30 namespace { | |
31 | |
32 bool DeleteDir(const base::FilePath& path) { | |
33 return base::DeleteFile(path, true /* recursive */); | |
34 } | |
35 | |
36 void DeleteOriginDidDeleteDir( | |
37 const storage::QuotaClient::DeletionCallback& callback, | |
38 bool rv) { | |
39 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
40 | |
41 callback.Run(rv ? storage::kQuotaStatusOk : storage::kQuotaErrorAbort); | |
42 } | |
43 | |
44 std::set<GURL> ListOriginsOnDisk(base::FilePath root_path_) { | |
45 std::set<GURL> origins; | |
46 base::FileEnumerator file_enum( | |
47 root_path_, false /* recursive */, base::FileEnumerator::DIRECTORIES); | |
48 | |
49 base::FilePath path; | |
50 while (!(path = file_enum.Next()).empty()) { | |
51 std::string protobuf; | |
52 base::ReadFileToString( | |
53 path.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName), &protobuf); | |
54 | |
55 ServiceWorkerCacheStorageIndex index; | |
56 if (index.ParseFromString(protobuf)) { | |
57 if (index.has_origin()) | |
58 origins.insert(GURL(index.origin())); | |
59 } | |
60 } | |
61 | |
62 return origins; | |
63 } | |
64 | |
65 void GetOriginsForHostDidListOrigins( | |
66 const std::string& host, | |
67 const storage::QuotaClient::GetOriginsCallback& callback, | |
68 const std::set<GURL>& origins) { | |
69 std::set<GURL> out_origins; | |
70 for (const GURL& origin : origins) { | |
71 if (host == net::GetHostOrSpecFromURL(origin)) | |
72 out_origins.insert(origin); | |
73 } | |
74 callback.Run(out_origins); | |
75 } | |
76 | |
77 } // namespace | |
78 | |
79 // static | |
80 scoped_ptr<ServiceWorkerCacheStorageManager> | |
81 ServiceWorkerCacheStorageManager::Create( | |
82 const base::FilePath& path, | |
83 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner, | |
84 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy) { | |
85 base::FilePath root_path = path; | |
86 if (!path.empty()) { | |
87 root_path = path.Append(ServiceWorkerContextCore::kServiceWorkerDirectory) | |
88 .AppendASCII("CacheStorage"); | |
89 } | |
90 | |
91 return make_scoped_ptr(new ServiceWorkerCacheStorageManager( | |
92 root_path, cache_task_runner, quota_manager_proxy)); | |
93 } | |
94 | |
95 // static | |
96 scoped_ptr<ServiceWorkerCacheStorageManager> | |
97 ServiceWorkerCacheStorageManager::Create( | |
98 ServiceWorkerCacheStorageManager* old_manager) { | |
99 scoped_ptr<ServiceWorkerCacheStorageManager> manager( | |
100 new ServiceWorkerCacheStorageManager( | |
101 old_manager->root_path(), | |
102 old_manager->cache_task_runner(), | |
103 old_manager->quota_manager_proxy_.get())); | |
104 // These values may be NULL, in which case this will be called again later by | |
105 // the dispatcher host per usual. | |
106 manager->SetBlobParametersForCache(old_manager->url_request_context(), | |
107 old_manager->blob_storage_context()); | |
108 return manager.Pass(); | |
109 } | |
110 | |
111 ServiceWorkerCacheStorageManager::~ServiceWorkerCacheStorageManager() { | |
112 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
113 for (ServiceWorkerCacheStorageMap::iterator it = cache_storage_map_.begin(); | |
114 it != cache_storage_map_.end(); | |
115 ++it) { | |
116 delete it->second; | |
117 } | |
118 } | |
119 | |
120 void ServiceWorkerCacheStorageManager::OpenCache( | |
121 const GURL& origin, | |
122 const std::string& cache_name, | |
123 const ServiceWorkerCacheStorage::CacheAndErrorCallback& callback) { | |
124 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
125 | |
126 ServiceWorkerCacheStorage* cache_storage = | |
127 FindOrCreateServiceWorkerCacheManager(origin); | |
128 | |
129 cache_storage->OpenCache(cache_name, callback); | |
130 } | |
131 | |
132 void ServiceWorkerCacheStorageManager::HasCache( | |
133 const GURL& origin, | |
134 const std::string& cache_name, | |
135 const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback) { | |
136 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
137 | |
138 ServiceWorkerCacheStorage* cache_storage = | |
139 FindOrCreateServiceWorkerCacheManager(origin); | |
140 cache_storage->HasCache(cache_name, callback); | |
141 } | |
142 | |
143 void ServiceWorkerCacheStorageManager::DeleteCache( | |
144 const GURL& origin, | |
145 const std::string& cache_name, | |
146 const ServiceWorkerCacheStorage::BoolAndErrorCallback& callback) { | |
147 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
148 | |
149 ServiceWorkerCacheStorage* cache_storage = | |
150 FindOrCreateServiceWorkerCacheManager(origin); | |
151 cache_storage->DeleteCache(cache_name, callback); | |
152 } | |
153 | |
154 void ServiceWorkerCacheStorageManager::EnumerateCaches( | |
155 const GURL& origin, | |
156 const ServiceWorkerCacheStorage::StringsAndErrorCallback& callback) { | |
157 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
158 | |
159 ServiceWorkerCacheStorage* cache_storage = | |
160 FindOrCreateServiceWorkerCacheManager(origin); | |
161 | |
162 cache_storage->EnumerateCaches(callback); | |
163 } | |
164 | |
165 void ServiceWorkerCacheStorageManager::MatchCache( | |
166 const GURL& origin, | |
167 const std::string& cache_name, | |
168 scoped_ptr<ServiceWorkerFetchRequest> request, | |
169 const ServiceWorkerCache::ResponseCallback& callback) { | |
170 ServiceWorkerCacheStorage* cache_storage = | |
171 FindOrCreateServiceWorkerCacheManager(origin); | |
172 | |
173 cache_storage->MatchCache(cache_name, request.Pass(), callback); | |
174 } | |
175 | |
176 void ServiceWorkerCacheStorageManager::MatchAllCaches( | |
177 const GURL& origin, | |
178 scoped_ptr<ServiceWorkerFetchRequest> request, | |
179 const ServiceWorkerCache::ResponseCallback& callback) { | |
180 ServiceWorkerCacheStorage* cache_storage = | |
181 FindOrCreateServiceWorkerCacheManager(origin); | |
182 | |
183 cache_storage->MatchAllCaches(request.Pass(), callback); | |
184 } | |
185 | |
186 void ServiceWorkerCacheStorageManager::SetBlobParametersForCache( | |
187 net::URLRequestContext* request_context, | |
188 base::WeakPtr<storage::BlobStorageContext> blob_storage_context) { | |
189 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
190 DCHECK(cache_storage_map_.empty()); | |
191 DCHECK(!request_context_ || request_context_ == request_context); | |
192 DCHECK(!blob_context_ || blob_context_.get() == blob_storage_context.get()); | |
193 request_context_ = request_context; | |
194 blob_context_ = blob_storage_context; | |
195 } | |
196 | |
197 void ServiceWorkerCacheStorageManager::GetOriginUsage( | |
198 const GURL& origin_url, | |
199 const storage::QuotaClient::GetUsageCallback& callback) { | |
200 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
201 | |
202 if (IsMemoryBacked()) { | |
203 int64 sum = 0; | |
204 for (const auto& key_value : cache_storage_map_) | |
205 sum += key_value.second->MemoryBackedSize(); | |
206 callback.Run(sum); | |
207 return; | |
208 } | |
209 | |
210 MigrateOrigin(origin_url); | |
211 PostTaskAndReplyWithResult( | |
212 cache_task_runner_.get(), | |
213 FROM_HERE, | |
214 base::Bind(base::ComputeDirectorySize, | |
215 ConstructOriginPath(root_path_, origin_url)), | |
216 base::Bind(callback)); | |
217 } | |
218 | |
219 void ServiceWorkerCacheStorageManager::GetOrigins( | |
220 const storage::QuotaClient::GetOriginsCallback& callback) { | |
221 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
222 | |
223 if (IsMemoryBacked()) { | |
224 std::set<GURL> origins; | |
225 for (const auto& key_value : cache_storage_map_) | |
226 origins.insert(key_value.first); | |
227 | |
228 callback.Run(origins); | |
229 return; | |
230 } | |
231 | |
232 PostTaskAndReplyWithResult(cache_task_runner_.get(), | |
233 FROM_HERE, | |
234 base::Bind(&ListOriginsOnDisk, root_path_), | |
235 base::Bind(callback)); | |
236 } | |
237 | |
238 void ServiceWorkerCacheStorageManager::GetOriginsForHost( | |
239 const std::string& host, | |
240 const storage::QuotaClient::GetOriginsCallback& callback) { | |
241 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
242 | |
243 if (IsMemoryBacked()) { | |
244 std::set<GURL> origins; | |
245 for (const auto& key_value : cache_storage_map_) { | |
246 if (host == net::GetHostOrSpecFromURL(key_value.first)) | |
247 origins.insert(key_value.first); | |
248 } | |
249 callback.Run(origins); | |
250 return; | |
251 } | |
252 | |
253 PostTaskAndReplyWithResult( | |
254 cache_task_runner_.get(), | |
255 FROM_HERE, | |
256 base::Bind(&ListOriginsOnDisk, root_path_), | |
257 base::Bind(&GetOriginsForHostDidListOrigins, host, callback)); | |
258 } | |
259 | |
260 void ServiceWorkerCacheStorageManager::DeleteOriginData( | |
261 const GURL& origin, | |
262 const storage::QuotaClient::DeletionCallback& callback) { | |
263 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
264 | |
265 ServiceWorkerCacheStorage* cache_storage = | |
266 FindOrCreateServiceWorkerCacheManager(origin); | |
267 cache_storage_map_.erase(origin); | |
268 cache_storage->CloseAllCaches( | |
269 base::Bind(&ServiceWorkerCacheStorageManager::DeleteOriginDidClose, | |
270 origin, callback, base::Passed(make_scoped_ptr(cache_storage)), | |
271 weak_ptr_factory_.GetWeakPtr())); | |
272 } | |
273 | |
274 // static | |
275 void ServiceWorkerCacheStorageManager::DeleteOriginDidClose( | |
276 const GURL& origin, | |
277 const storage::QuotaClient::DeletionCallback& callback, | |
278 scoped_ptr<ServiceWorkerCacheStorage> cache_storage, | |
279 base::WeakPtr<ServiceWorkerCacheStorageManager> cache_manager) { | |
280 // TODO(jkarlin): Deleting the storage leaves any unfinished operations | |
281 // hanging, resulting in unresolved promises. Fix this by guaranteeing that | |
282 // callbacks are called in ServiceWorkerStorage. | |
283 cache_storage.reset(); | |
284 | |
285 if (!cache_manager) { | |
286 callback.Run(storage::kQuotaErrorAbort); | |
287 return; | |
288 } | |
289 | |
290 if (cache_manager->IsMemoryBacked()) { | |
291 callback.Run(storage::kQuotaStatusOk); | |
292 return; | |
293 } | |
294 | |
295 cache_manager->MigrateOrigin(origin); | |
296 PostTaskAndReplyWithResult( | |
297 cache_manager->cache_task_runner_.get(), FROM_HERE, | |
298 base::Bind(&DeleteDir, | |
299 ConstructOriginPath(cache_manager->root_path_, origin)), | |
300 base::Bind(&DeleteOriginDidDeleteDir, callback)); | |
301 } | |
302 | |
303 ServiceWorkerCacheStorageManager::ServiceWorkerCacheStorageManager( | |
304 const base::FilePath& path, | |
305 const scoped_refptr<base::SequencedTaskRunner>& cache_task_runner, | |
306 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy) | |
307 : root_path_(path), | |
308 cache_task_runner_(cache_task_runner), | |
309 quota_manager_proxy_(quota_manager_proxy), | |
310 request_context_(NULL), | |
311 weak_ptr_factory_(this) { | |
312 if (quota_manager_proxy_.get()) { | |
313 quota_manager_proxy_->RegisterClient( | |
314 new ServiceWorkerCacheQuotaClient(weak_ptr_factory_.GetWeakPtr())); | |
315 } | |
316 } | |
317 | |
318 ServiceWorkerCacheStorage* | |
319 ServiceWorkerCacheStorageManager::FindOrCreateServiceWorkerCacheManager( | |
320 const GURL& origin) { | |
321 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
322 DCHECK(request_context_); | |
323 ServiceWorkerCacheStorageMap::const_iterator it = | |
324 cache_storage_map_.find(origin); | |
325 if (it == cache_storage_map_.end()) { | |
326 MigrateOrigin(origin); | |
327 ServiceWorkerCacheStorage* cache_storage = | |
328 new ServiceWorkerCacheStorage(ConstructOriginPath(root_path_, origin), | |
329 IsMemoryBacked(), | |
330 cache_task_runner_.get(), | |
331 request_context_, | |
332 quota_manager_proxy_, | |
333 blob_context_, | |
334 origin); | |
335 // The map owns fetch_stores. | |
336 cache_storage_map_.insert(std::make_pair(origin, cache_storage)); | |
337 return cache_storage; | |
338 } | |
339 return it->second; | |
340 } | |
341 | |
342 // static | |
343 base::FilePath ServiceWorkerCacheStorageManager::ConstructLegacyOriginPath( | |
344 const base::FilePath& root_path, | |
345 const GURL& origin) { | |
346 const std::string origin_hash = base::SHA1HashString(origin.spec()); | |
347 const std::string origin_hash_hex = base::StringToLowerASCII( | |
348 base::HexEncode(origin_hash.c_str(), origin_hash.length())); | |
349 return root_path.AppendASCII(origin_hash_hex); | |
350 } | |
351 | |
352 // static | |
353 base::FilePath ServiceWorkerCacheStorageManager::ConstructOriginPath( | |
354 const base::FilePath& root_path, | |
355 const GURL& origin) { | |
356 const std::string identifier = storage::GetIdentifierFromOrigin(origin); | |
357 const std::string origin_hash = base::SHA1HashString(identifier); | |
358 const std::string origin_hash_hex = base::StringToLowerASCII( | |
359 base::HexEncode(origin_hash.c_str(), origin_hash.length())); | |
360 return root_path.AppendASCII(origin_hash_hex); | |
361 } | |
362 | |
363 // Migrate from old origin-based path to storage identifier-based path. | |
364 // TODO(jsbell); Remove after a few releases. | |
365 void ServiceWorkerCacheStorageManager::MigrateOrigin(const GURL& origin) { | |
366 if (IsMemoryBacked()) | |
367 return; | |
368 base::FilePath old_path = ConstructLegacyOriginPath(root_path_, origin); | |
369 base::FilePath new_path = ConstructOriginPath(root_path_, origin); | |
370 cache_task_runner_->PostTask( | |
371 FROM_HERE, base::Bind(&MigrateOriginOnTaskRunner, old_path, new_path)); | |
372 } | |
373 | |
374 // static | |
375 void ServiceWorkerCacheStorageManager::MigrateOriginOnTaskRunner( | |
376 const base::FilePath& old_path, | |
377 const base::FilePath& new_path) { | |
378 if (base::PathExists(old_path)) { | |
379 if (!base::PathExists(new_path)) | |
380 base::Move(old_path, new_path); | |
381 base::DeleteFile(old_path, /*recursive*/ true); | |
382 } | |
383 } | |
384 | |
385 } // namespace content | |
OLD | NEW |