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.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/barrier_closure.h" | |
10 #include "base/files/file_util.h" | |
11 #include "base/files/memory_mapped_file.h" | |
12 #include "base/memory/ref_counted.h" | |
13 #include "base/metrics/histogram_macros.h" | |
14 #include "base/sha1.h" | |
15 #include "base/stl_util.h" | |
16 #include "base/strings/string_number_conversions.h" | |
17 #include "base/strings/string_util.h" | |
18 #include "content/browser/service_worker/service_worker_cache.h" | |
19 #include "content/browser/service_worker/service_worker_cache.pb.h" | |
20 #include "content/browser/service_worker/service_worker_cache_scheduler.h" | |
21 #include "content/public/browser/browser_thread.h" | |
22 #include "net/base/directory_lister.h" | |
23 #include "net/base/net_errors.h" | |
24 #include "storage/browser/blob/blob_storage_context.h" | |
25 #include "storage/browser/quota/quota_manager_proxy.h" | |
26 | |
27 namespace content { | |
28 | |
29 namespace { | |
30 | |
31 void CloseAllCachesDidCloseCache(const scoped_refptr<ServiceWorkerCache>& cache, | |
32 const base::Closure& barrier_closure) { | |
33 barrier_closure.Run(); | |
34 } | |
35 | |
36 } // namespace | |
37 | |
38 const char ServiceWorkerCacheStorage::kIndexFileName[] = "index.txt"; | |
39 | |
40 // Handles the loading and clean up of ServiceWorkerCache objects. The | |
41 // callback of every public method is guaranteed to be called. | |
42 class ServiceWorkerCacheStorage::CacheLoader { | |
43 public: | |
44 typedef base::Callback<void(const scoped_refptr<ServiceWorkerCache>&)> | |
45 CacheCallback; | |
46 typedef base::Callback<void(bool)> BoolCallback; | |
47 typedef base::Callback<void(scoped_ptr<std::vector<std::string> >)> | |
48 StringVectorCallback; | |
49 | |
50 CacheLoader( | |
51 base::SequencedTaskRunner* cache_task_runner, | |
52 net::URLRequestContext* request_context, | |
53 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | |
54 base::WeakPtr<storage::BlobStorageContext> blob_context, | |
55 const GURL& origin) | |
56 : cache_task_runner_(cache_task_runner), | |
57 request_context_(request_context), | |
58 quota_manager_proxy_(quota_manager_proxy), | |
59 blob_context_(blob_context), | |
60 origin_(origin) { | |
61 DCHECK(!origin_.is_empty()); | |
62 } | |
63 | |
64 virtual ~CacheLoader() {} | |
65 | |
66 // Creates a ServiceWorkerCache with the given name. It does not attempt to | |
67 // load the backend, that happens lazily when the cache is used. | |
68 virtual scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache( | |
69 const std::string& cache_name) = 0; | |
70 | |
71 // Deletes any pre-existing cache of the same name and then loads it. | |
72 virtual void CreateCache(const std::string& cache_name, | |
73 const CacheCallback& callback) = 0; | |
74 | |
75 // After the backend has been deleted, do any extra house keeping such as | |
76 // removing the cache's directory. | |
77 virtual void CleanUpDeletedCache(const std::string& key, | |
78 const BoolCallback& callback) = 0; | |
79 | |
80 // Writes the cache names (and sizes) to disk if applicable. | |
81 virtual void WriteIndex(const StringVector& cache_names, | |
82 const BoolCallback& callback) = 0; | |
83 | |
84 // Loads the cache names from disk if applicable. | |
85 virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names, | |
86 const StringVectorCallback& callback) = 0; | |
87 | |
88 protected: | |
89 scoped_refptr<base::SequencedTaskRunner> cache_task_runner_; | |
90 net::URLRequestContext* request_context_; | |
91 scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_; | |
92 base::WeakPtr<storage::BlobStorageContext> blob_context_; | |
93 GURL origin_; | |
94 }; | |
95 | |
96 // Creates memory-only ServiceWorkerCaches. Because these caches have no | |
97 // persistent storage it is not safe to free them from memory if they might be | |
98 // used again. Therefore this class holds a reference to each cache until the | |
99 // cache is deleted. | |
100 class ServiceWorkerCacheStorage::MemoryLoader | |
101 : public ServiceWorkerCacheStorage::CacheLoader { | |
102 public: | |
103 MemoryLoader( | |
104 base::SequencedTaskRunner* cache_task_runner, | |
105 net::URLRequestContext* request_context, | |
106 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | |
107 base::WeakPtr<storage::BlobStorageContext> blob_context, | |
108 const GURL& origin) | |
109 : CacheLoader(cache_task_runner, | |
110 request_context, | |
111 quota_manager_proxy, | |
112 blob_context, | |
113 origin) {} | |
114 | |
115 scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache( | |
116 const std::string& cache_name) override { | |
117 return ServiceWorkerCache::CreateMemoryCache( | |
118 origin_, request_context_, quota_manager_proxy_, blob_context_); | |
119 } | |
120 | |
121 void CreateCache(const std::string& cache_name, | |
122 const CacheCallback& callback) override { | |
123 scoped_refptr<ServiceWorkerCache> cache = | |
124 CreateServiceWorkerCache(cache_name); | |
125 cache_refs_.insert(std::make_pair(cache_name, cache)); | |
126 callback.Run(cache); | |
127 } | |
128 | |
129 void CleanUpDeletedCache(const std::string& cache_name, | |
130 const BoolCallback& callback) override { | |
131 CacheRefMap::iterator it = cache_refs_.find(cache_name); | |
132 DCHECK(it != cache_refs_.end()); | |
133 cache_refs_.erase(it); | |
134 callback.Run(true); | |
135 } | |
136 | |
137 void WriteIndex(const StringVector& cache_names, | |
138 const BoolCallback& callback) override { | |
139 callback.Run(false); | |
140 } | |
141 | |
142 void LoadIndex(scoped_ptr<std::vector<std::string>> cache_names, | |
143 const StringVectorCallback& callback) override { | |
144 callback.Run(cache_names.Pass()); | |
145 } | |
146 | |
147 private: | |
148 typedef std::map<std::string, scoped_refptr<ServiceWorkerCache> > CacheRefMap; | |
149 ~MemoryLoader() override {} | |
150 | |
151 // Keep a reference to each cache to ensure that it's not freed before the | |
152 // client calls ServiceWorkerCacheStorage::Delete or the CacheStorage is | |
153 // freed. | |
154 CacheRefMap cache_refs_; | |
155 }; | |
156 | |
157 class ServiceWorkerCacheStorage::SimpleCacheLoader | |
158 : public ServiceWorkerCacheStorage::CacheLoader { | |
159 public: | |
160 SimpleCacheLoader( | |
161 const base::FilePath& origin_path, | |
162 base::SequencedTaskRunner* cache_task_runner, | |
163 net::URLRequestContext* request_context, | |
164 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | |
165 base::WeakPtr<storage::BlobStorageContext> blob_context, | |
166 const GURL& origin) | |
167 : CacheLoader(cache_task_runner, | |
168 request_context, | |
169 quota_manager_proxy, | |
170 blob_context, | |
171 origin), | |
172 origin_path_(origin_path), | |
173 weak_ptr_factory_(this) {} | |
174 | |
175 scoped_refptr<ServiceWorkerCache> CreateServiceWorkerCache( | |
176 const std::string& cache_name) override { | |
177 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
178 | |
179 return ServiceWorkerCache::CreatePersistentCache( | |
180 origin_, | |
181 CreatePersistentCachePath(origin_path_, cache_name), | |
182 request_context_, | |
183 quota_manager_proxy_, | |
184 blob_context_); | |
185 } | |
186 | |
187 void CreateCache(const std::string& cache_name, | |
188 const CacheCallback& callback) override { | |
189 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
190 | |
191 // 1. Delete the cache's directory if it exists. | |
192 // (CreateCacheDeleteFilesInPool) | |
193 // 2. Load the cache. (LoadCreateDirectoryInPool) | |
194 | |
195 base::FilePath cache_path = | |
196 CreatePersistentCachePath(origin_path_, cache_name); | |
197 | |
198 PostTaskAndReplyWithResult( | |
199 cache_task_runner_.get(), | |
200 FROM_HERE, | |
201 base::Bind(&SimpleCacheLoader::CreateCachePrepDirInPool, cache_path), | |
202 base::Bind(&SimpleCacheLoader::CreateCachePreppedDir, | |
203 cache_name, | |
204 callback, | |
205 weak_ptr_factory_.GetWeakPtr())); | |
206 } | |
207 | |
208 static bool CreateCachePrepDirInPool(const base::FilePath& cache_path) { | |
209 if (base::PathExists(cache_path)) | |
210 base::DeleteFile(cache_path, /* recursive */ true); | |
211 return base::CreateDirectory(cache_path); | |
212 } | |
213 | |
214 static void CreateCachePreppedDir(const std::string& cache_name, | |
215 const CacheCallback& callback, | |
216 base::WeakPtr<SimpleCacheLoader> loader, | |
217 bool success) { | |
218 if (!success || !loader) { | |
219 callback.Run(scoped_refptr<ServiceWorkerCache>()); | |
220 return; | |
221 } | |
222 | |
223 callback.Run(loader->CreateServiceWorkerCache(cache_name)); | |
224 } | |
225 | |
226 void CleanUpDeletedCache(const std::string& cache_name, | |
227 const BoolCallback& callback) override { | |
228 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
229 | |
230 // 1. Delete the cache's directory. (CleanUpDeleteCacheDirInPool) | |
231 | |
232 base::FilePath cache_path = | |
233 CreatePersistentCachePath(origin_path_, cache_name); | |
234 cache_task_runner_->PostTask( | |
235 FROM_HERE, | |
236 base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool, | |
237 cache_path, | |
238 callback, | |
239 base::MessageLoopProxy::current())); | |
240 } | |
241 | |
242 static void CleanUpDeleteCacheDirInPool( | |
243 const base::FilePath& cache_path, | |
244 const BoolCallback& callback, | |
245 const scoped_refptr<base::MessageLoopProxy>& original_loop) { | |
246 bool rv = base::DeleteFile(cache_path, true); | |
247 original_loop->PostTask(FROM_HERE, base::Bind(callback, rv)); | |
248 } | |
249 | |
250 void WriteIndex(const StringVector& cache_names, | |
251 const BoolCallback& callback) override { | |
252 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
253 | |
254 // 1. Create the index file as a string. (WriteIndex) | |
255 // 2. Write the file to disk. (WriteIndexWriteToFileInPool) | |
256 | |
257 ServiceWorkerCacheStorageIndex index; | |
258 index.set_origin(origin_.spec()); | |
259 | |
260 for (size_t i = 0u, max = cache_names.size(); i < max; ++i) { | |
261 ServiceWorkerCacheStorageIndex::Cache* index_cache = index.add_cache(); | |
262 index_cache->set_name(cache_names[i]); | |
263 } | |
264 | |
265 std::string serialized; | |
266 bool success = index.SerializeToString(&serialized); | |
267 DCHECK(success); | |
268 | |
269 base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp"); | |
270 base::FilePath index_path = | |
271 origin_path_.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName); | |
272 | |
273 cache_task_runner_->PostTask( | |
274 FROM_HERE, | |
275 base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool, | |
276 tmp_path, | |
277 index_path, | |
278 serialized, | |
279 callback, | |
280 base::MessageLoopProxy::current())); | |
281 } | |
282 | |
283 static void WriteIndexWriteToFileInPool( | |
284 const base::FilePath& tmp_path, | |
285 const base::FilePath& index_path, | |
286 const std::string& data, | |
287 const BoolCallback& callback, | |
288 const scoped_refptr<base::MessageLoopProxy>& original_loop) { | |
289 int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size()); | |
290 if (bytes_written != implicit_cast<int>(data.size())) { | |
291 base::DeleteFile(tmp_path, /* recursive */ false); | |
292 original_loop->PostTask(FROM_HERE, base::Bind(callback, false)); | |
293 } | |
294 | |
295 // Atomically rename the temporary index file to become the real one. | |
296 bool rv = base::ReplaceFile(tmp_path, index_path, NULL); | |
297 original_loop->PostTask(FROM_HERE, base::Bind(callback, rv)); | |
298 } | |
299 | |
300 void LoadIndex(scoped_ptr<std::vector<std::string>> names, | |
301 const StringVectorCallback& callback) override { | |
302 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
303 | |
304 // 1. Read the file from disk. (LoadIndexReadFileInPool) | |
305 // 2. Parse file and return the names of the caches (LoadIndexDidReadFile) | |
306 | |
307 base::FilePath index_path = | |
308 origin_path_.AppendASCII(ServiceWorkerCacheStorage::kIndexFileName); | |
309 | |
310 cache_task_runner_->PostTask( | |
311 FROM_HERE, | |
312 base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool, | |
313 index_path, | |
314 base::Passed(names.Pass()), | |
315 callback, | |
316 base::MessageLoopProxy::current())); | |
317 } | |
318 | |
319 static void LoadIndexReadFileInPool( | |
320 const base::FilePath& index_path, | |
321 scoped_ptr<std::vector<std::string> > names, | |
322 const StringVectorCallback& callback, | |
323 const scoped_refptr<base::MessageLoopProxy>& original_loop) { | |
324 std::string body; | |
325 base::ReadFileToString(index_path, &body); | |
326 | |
327 original_loop->PostTask(FROM_HERE, | |
328 base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile, | |
329 base::Passed(names.Pass()), | |
330 callback, | |
331 body)); | |
332 } | |
333 | |
334 static void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string> > names, | |
335 const StringVectorCallback& callback, | |
336 const std::string& serialized) { | |
337 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
338 | |
339 ServiceWorkerCacheStorageIndex index; | |
340 if (index.ParseFromString(serialized)) { | |
341 for (int i = 0, max = index.cache_size(); i < max; ++i) { | |
342 const ServiceWorkerCacheStorageIndex::Cache& cache = index.cache(i); | |
343 names->push_back(cache.name()); | |
344 } | |
345 } | |
346 | |
347 // TODO(jkarlin): Delete caches that are in the directory and not returned | |
348 // in LoadIndex. | |
349 callback.Run(names.Pass()); | |
350 } | |
351 | |
352 private: | |
353 ~SimpleCacheLoader() override {} | |
354 | |
355 static std::string HexedHash(const std::string& value) { | |
356 std::string value_hash = base::SHA1HashString(value); | |
357 std::string valued_hexed_hash = base::StringToLowerASCII( | |
358 base::HexEncode(value_hash.c_str(), value_hash.length())); | |
359 return valued_hexed_hash; | |
360 } | |
361 | |
362 static base::FilePath CreatePersistentCachePath( | |
363 const base::FilePath& origin_path, | |
364 const std::string& cache_name) { | |
365 return origin_path.AppendASCII(HexedHash(cache_name)); | |
366 } | |
367 | |
368 const base::FilePath origin_path_; | |
369 | |
370 base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_; | |
371 }; | |
372 | |
373 ServiceWorkerCacheStorage::ServiceWorkerCacheStorage( | |
374 const base::FilePath& path, | |
375 bool memory_only, | |
376 base::SequencedTaskRunner* cache_task_runner, | |
377 net::URLRequestContext* request_context, | |
378 const scoped_refptr<storage::QuotaManagerProxy>& quota_manager_proxy, | |
379 base::WeakPtr<storage::BlobStorageContext> blob_context, | |
380 const GURL& origin) | |
381 : initialized_(false), | |
382 initializing_(false), | |
383 scheduler_(new ServiceWorkerCacheScheduler()), | |
384 origin_path_(path), | |
385 cache_task_runner_(cache_task_runner), | |
386 memory_only_(memory_only), | |
387 weak_factory_(this) { | |
388 if (memory_only) | |
389 cache_loader_.reset(new MemoryLoader(cache_task_runner_.get(), | |
390 request_context, | |
391 quota_manager_proxy, | |
392 blob_context, | |
393 origin)); | |
394 else | |
395 cache_loader_.reset(new SimpleCacheLoader(origin_path_, | |
396 cache_task_runner_.get(), | |
397 request_context, | |
398 quota_manager_proxy, | |
399 blob_context, | |
400 origin)); | |
401 } | |
402 | |
403 ServiceWorkerCacheStorage::~ServiceWorkerCacheStorage() { | |
404 } | |
405 | |
406 void ServiceWorkerCacheStorage::OpenCache( | |
407 const std::string& cache_name, | |
408 const CacheAndErrorCallback& callback) { | |
409 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
410 | |
411 if (!initialized_) | |
412 LazyInit(); | |
413 | |
414 CacheAndErrorCallback pending_callback = | |
415 base::Bind(&ServiceWorkerCacheStorage::PendingCacheAndErrorCallback, | |
416 weak_factory_.GetWeakPtr(), callback); | |
417 scheduler_->ScheduleOperation( | |
418 base::Bind(&ServiceWorkerCacheStorage::OpenCacheImpl, | |
419 weak_factory_.GetWeakPtr(), cache_name, pending_callback)); | |
420 } | |
421 | |
422 void ServiceWorkerCacheStorage::HasCache(const std::string& cache_name, | |
423 const BoolAndErrorCallback& callback) { | |
424 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
425 | |
426 if (!initialized_) | |
427 LazyInit(); | |
428 | |
429 BoolAndErrorCallback pending_callback = | |
430 base::Bind(&ServiceWorkerCacheStorage::PendingBoolAndErrorCallback, | |
431 weak_factory_.GetWeakPtr(), callback); | |
432 scheduler_->ScheduleOperation( | |
433 base::Bind(&ServiceWorkerCacheStorage::HasCacheImpl, | |
434 weak_factory_.GetWeakPtr(), cache_name, pending_callback)); | |
435 } | |
436 | |
437 void ServiceWorkerCacheStorage::DeleteCache( | |
438 const std::string& cache_name, | |
439 const BoolAndErrorCallback& callback) { | |
440 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
441 | |
442 if (!initialized_) | |
443 LazyInit(); | |
444 | |
445 BoolAndErrorCallback pending_callback = | |
446 base::Bind(&ServiceWorkerCacheStorage::PendingBoolAndErrorCallback, | |
447 weak_factory_.GetWeakPtr(), callback); | |
448 scheduler_->ScheduleOperation( | |
449 base::Bind(&ServiceWorkerCacheStorage::DeleteCacheImpl, | |
450 weak_factory_.GetWeakPtr(), cache_name, pending_callback)); | |
451 } | |
452 | |
453 void ServiceWorkerCacheStorage::EnumerateCaches( | |
454 const StringsAndErrorCallback& callback) { | |
455 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
456 | |
457 if (!initialized_) | |
458 LazyInit(); | |
459 | |
460 StringsAndErrorCallback pending_callback = | |
461 base::Bind(&ServiceWorkerCacheStorage::PendingStringsAndErrorCallback, | |
462 weak_factory_.GetWeakPtr(), callback); | |
463 scheduler_->ScheduleOperation( | |
464 base::Bind(&ServiceWorkerCacheStorage::EnumerateCachesImpl, | |
465 weak_factory_.GetWeakPtr(), pending_callback)); | |
466 } | |
467 | |
468 void ServiceWorkerCacheStorage::MatchCache( | |
469 const std::string& cache_name, | |
470 scoped_ptr<ServiceWorkerFetchRequest> request, | |
471 const ServiceWorkerCache::ResponseCallback& callback) { | |
472 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
473 | |
474 if (!initialized_) | |
475 LazyInit(); | |
476 | |
477 ServiceWorkerCache::ResponseCallback pending_callback = | |
478 base::Bind(&ServiceWorkerCacheStorage::PendingResponseCallback, | |
479 weak_factory_.GetWeakPtr(), callback); | |
480 scheduler_->ScheduleOperation(base::Bind( | |
481 &ServiceWorkerCacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(), | |
482 cache_name, base::Passed(request.Pass()), pending_callback)); | |
483 } | |
484 | |
485 void ServiceWorkerCacheStorage::MatchAllCaches( | |
486 scoped_ptr<ServiceWorkerFetchRequest> request, | |
487 const ServiceWorkerCache::ResponseCallback& callback) { | |
488 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
489 | |
490 if (!initialized_) | |
491 LazyInit(); | |
492 | |
493 ServiceWorkerCache::ResponseCallback pending_callback = | |
494 base::Bind(&ServiceWorkerCacheStorage::PendingResponseCallback, | |
495 weak_factory_.GetWeakPtr(), callback); | |
496 scheduler_->ScheduleOperation( | |
497 base::Bind(&ServiceWorkerCacheStorage::MatchAllCachesImpl, | |
498 weak_factory_.GetWeakPtr(), base::Passed(request.Pass()), | |
499 pending_callback)); | |
500 } | |
501 | |
502 void ServiceWorkerCacheStorage::CloseAllCaches(const base::Closure& callback) { | |
503 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
504 | |
505 if (!initialized_) { | |
506 callback.Run(); | |
507 return; | |
508 } | |
509 | |
510 base::Closure pending_callback = | |
511 base::Bind(&ServiceWorkerCacheStorage::PendingClosure, | |
512 weak_factory_.GetWeakPtr(), callback); | |
513 scheduler_->ScheduleOperation( | |
514 base::Bind(&ServiceWorkerCacheStorage::CloseAllCachesImpl, | |
515 weak_factory_.GetWeakPtr(), pending_callback)); | |
516 } | |
517 | |
518 int64 ServiceWorkerCacheStorage::MemoryBackedSize() const { | |
519 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
520 | |
521 if (!initialized_ || !memory_only_) | |
522 return 0; | |
523 | |
524 int64 sum = 0; | |
525 for (auto& key_value : cache_map_) { | |
526 if (key_value.second) | |
527 sum += key_value.second->MemoryBackedSize(); | |
528 } | |
529 return sum; | |
530 } | |
531 | |
532 void ServiceWorkerCacheStorage::StartAsyncOperationForTesting() { | |
533 scheduler_->ScheduleOperation(base::Bind(&base::DoNothing)); | |
534 } | |
535 | |
536 void ServiceWorkerCacheStorage::CompleteAsyncOperationForTesting() { | |
537 scheduler_->CompleteOperationAndRunNext(); | |
538 } | |
539 | |
540 // Init is run lazily so that it is called on the proper MessageLoop. | |
541 void ServiceWorkerCacheStorage::LazyInit() { | |
542 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
543 DCHECK(!initialized_); | |
544 | |
545 if (initializing_) | |
546 return; | |
547 | |
548 DCHECK(!scheduler_->ScheduledOperations()); | |
549 | |
550 initializing_ = true; | |
551 scheduler_->ScheduleOperation(base::Bind( | |
552 &ServiceWorkerCacheStorage::LazyInitImpl, weak_factory_.GetWeakPtr())); | |
553 } | |
554 | |
555 void ServiceWorkerCacheStorage::LazyInitImpl() { | |
556 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
557 DCHECK(!initialized_); | |
558 DCHECK(initializing_); | |
559 | |
560 // 1. Get the list of cache names (async call) | |
561 // 2. For each cache name, load the cache (async call) | |
562 // 3. Once each load is complete, update the map variables. | |
563 // 4. Call the list of waiting callbacks. | |
564 | |
565 scoped_ptr<std::vector<std::string> > indexed_cache_names( | |
566 new std::vector<std::string>()); | |
567 | |
568 cache_loader_->LoadIndex( | |
569 indexed_cache_names.Pass(), | |
570 base::Bind(&ServiceWorkerCacheStorage::LazyInitDidLoadIndex, | |
571 weak_factory_.GetWeakPtr())); | |
572 } | |
573 | |
574 void ServiceWorkerCacheStorage::LazyInitDidLoadIndex( | |
575 scoped_ptr<std::vector<std::string> > indexed_cache_names) { | |
576 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
577 | |
578 for (size_t i = 0u, max = indexed_cache_names->size(); i < max; ++i) { | |
579 cache_map_.insert(std::make_pair(indexed_cache_names->at(i), | |
580 base::WeakPtr<ServiceWorkerCache>())); | |
581 ordered_cache_names_.push_back(indexed_cache_names->at(i)); | |
582 } | |
583 | |
584 initializing_ = false; | |
585 initialized_ = true; | |
586 | |
587 scheduler_->CompleteOperationAndRunNext(); | |
588 } | |
589 | |
590 void ServiceWorkerCacheStorage::OpenCacheImpl( | |
591 const std::string& cache_name, | |
592 const CacheAndErrorCallback& callback) { | |
593 scoped_refptr<ServiceWorkerCache> cache = GetLoadedCache(cache_name); | |
594 if (cache.get()) { | |
595 callback.Run(cache, CACHE_STORAGE_ERROR_NO_ERROR); | |
596 return; | |
597 } | |
598 | |
599 cache_loader_->CreateCache( | |
600 cache_name, | |
601 base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidCreateCache, | |
602 weak_factory_.GetWeakPtr(), cache_name, callback)); | |
603 } | |
604 | |
605 void ServiceWorkerCacheStorage::CreateCacheDidCreateCache( | |
606 const std::string& cache_name, | |
607 const CacheAndErrorCallback& callback, | |
608 const scoped_refptr<ServiceWorkerCache>& cache) { | |
609 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
610 | |
611 if (!cache.get()) { | |
612 callback.Run(scoped_refptr<ServiceWorkerCache>(), | |
613 CACHE_STORAGE_ERROR_CLOSING); | |
614 return; | |
615 } | |
616 | |
617 UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult", | |
618 cache != nullptr); | |
619 | |
620 cache_map_.insert(std::make_pair(cache_name, cache->AsWeakPtr())); | |
621 ordered_cache_names_.push_back(cache_name); | |
622 | |
623 cache_loader_->WriteIndex( | |
624 ordered_cache_names_, | |
625 base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidWriteIndex, | |
626 weak_factory_.GetWeakPtr(), | |
627 callback, | |
628 cache)); | |
629 } | |
630 | |
631 void ServiceWorkerCacheStorage::CreateCacheDidWriteIndex( | |
632 const CacheAndErrorCallback& callback, | |
633 const scoped_refptr<ServiceWorkerCache>& cache, | |
634 bool success) { | |
635 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
636 DCHECK(cache.get()); | |
637 | |
638 // TODO(jkarlin): Handle !success. | |
639 | |
640 callback.Run(cache, CACHE_STORAGE_ERROR_NO_ERROR); | |
641 } | |
642 | |
643 void ServiceWorkerCacheStorage::HasCacheImpl( | |
644 const std::string& cache_name, | |
645 const BoolAndErrorCallback& callback) { | |
646 bool has_cache = cache_map_.find(cache_name) != cache_map_.end(); | |
647 | |
648 callback.Run(has_cache, CACHE_STORAGE_ERROR_NO_ERROR); | |
649 } | |
650 | |
651 void ServiceWorkerCacheStorage::DeleteCacheImpl( | |
652 const std::string& cache_name, | |
653 const BoolAndErrorCallback& callback) { | |
654 CacheMap::iterator it = cache_map_.find(cache_name); | |
655 if (it == cache_map_.end()) { | |
656 callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND); | |
657 return; | |
658 } | |
659 | |
660 base::WeakPtr<ServiceWorkerCache> cache = it->second; | |
661 cache_map_.erase(it); | |
662 | |
663 // Delete the name from ordered_cache_names_. | |
664 StringVector::iterator iter = std::find( | |
665 ordered_cache_names_.begin(), ordered_cache_names_.end(), cache_name); | |
666 DCHECK(iter != ordered_cache_names_.end()); | |
667 ordered_cache_names_.erase(iter); | |
668 | |
669 base::Closure closure = | |
670 base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidClose, | |
671 weak_factory_.GetWeakPtr(), cache_name, callback, | |
672 ordered_cache_names_, make_scoped_refptr(cache.get())); | |
673 | |
674 if (cache) { | |
675 cache->Close(closure); | |
676 return; | |
677 } | |
678 | |
679 closure.Run(); | |
680 } | |
681 | |
682 void ServiceWorkerCacheStorage::DeleteCacheDidClose( | |
683 const std::string& cache_name, | |
684 const BoolAndErrorCallback& callback, | |
685 const StringVector& ordered_cache_names, | |
686 const scoped_refptr<ServiceWorkerCache>& cache /* might be null */) { | |
687 cache_loader_->WriteIndex( | |
688 ordered_cache_names, | |
689 base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex, | |
690 weak_factory_.GetWeakPtr(), cache_name, callback)); | |
691 } | |
692 | |
693 void ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex( | |
694 const std::string& cache_name, | |
695 const BoolAndErrorCallback& callback, | |
696 bool success) { | |
697 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
698 | |
699 cache_loader_->CleanUpDeletedCache( | |
700 cache_name, | |
701 base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidCleanUp, | |
702 weak_factory_.GetWeakPtr(), | |
703 callback)); | |
704 } | |
705 | |
706 void ServiceWorkerCacheStorage::DeleteCacheDidCleanUp( | |
707 const BoolAndErrorCallback& callback, | |
708 bool success) { | |
709 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
710 | |
711 callback.Run(true, CACHE_STORAGE_ERROR_NO_ERROR); | |
712 } | |
713 | |
714 void ServiceWorkerCacheStorage::EnumerateCachesImpl( | |
715 const StringsAndErrorCallback& callback) { | |
716 callback.Run(ordered_cache_names_, CACHE_STORAGE_ERROR_NO_ERROR); | |
717 } | |
718 | |
719 void ServiceWorkerCacheStorage::MatchCacheImpl( | |
720 const std::string& cache_name, | |
721 scoped_ptr<ServiceWorkerFetchRequest> request, | |
722 const ServiceWorkerCache::ResponseCallback& callback) { | |
723 scoped_refptr<ServiceWorkerCache> cache = GetLoadedCache(cache_name); | |
724 | |
725 if (!cache.get()) { | |
726 callback.Run(ServiceWorkerCache::ERROR_TYPE_NOT_FOUND, | |
727 scoped_ptr<ServiceWorkerResponse>(), | |
728 scoped_ptr<storage::BlobDataHandle>()); | |
729 return; | |
730 } | |
731 | |
732 // Pass the cache along to the callback to keep the cache open until match is | |
733 // done. | |
734 cache->Match(request.Pass(), | |
735 base::Bind(&ServiceWorkerCacheStorage::MatchCacheDidMatch, | |
736 weak_factory_.GetWeakPtr(), cache, callback)); | |
737 } | |
738 | |
739 void ServiceWorkerCacheStorage::MatchCacheDidMatch( | |
740 const scoped_refptr<ServiceWorkerCache>& cache, | |
741 const ServiceWorkerCache::ResponseCallback& callback, | |
742 ServiceWorkerCache::ErrorType error, | |
743 scoped_ptr<ServiceWorkerResponse> response, | |
744 scoped_ptr<storage::BlobDataHandle> handle) { | |
745 callback.Run(error, response.Pass(), handle.Pass()); | |
746 } | |
747 | |
748 void ServiceWorkerCacheStorage::MatchAllCachesImpl( | |
749 scoped_ptr<ServiceWorkerFetchRequest> request, | |
750 const ServiceWorkerCache::ResponseCallback& callback) { | |
751 scoped_ptr<ServiceWorkerCache::ResponseCallback> callback_copy( | |
752 new ServiceWorkerCache::ResponseCallback(callback)); | |
753 | |
754 ServiceWorkerCache::ResponseCallback* callback_ptr = callback_copy.get(); | |
755 base::Closure barrier_closure = base::BarrierClosure( | |
756 ordered_cache_names_.size(), | |
757 base::Bind(&ServiceWorkerCacheStorage::MatchAllCachesDidMatchAll, | |
758 weak_factory_.GetWeakPtr(), | |
759 base::Passed(callback_copy.Pass()))); | |
760 | |
761 for (const std::string& cache_name : ordered_cache_names_) { | |
762 scoped_refptr<ServiceWorkerCache> cache = GetLoadedCache(cache_name); | |
763 DCHECK(cache.get()); | |
764 | |
765 cache->Match(make_scoped_ptr(new ServiceWorkerFetchRequest(*request)), | |
766 base::Bind(&ServiceWorkerCacheStorage::MatchAllCachesDidMatch, | |
767 weak_factory_.GetWeakPtr(), cache, barrier_closure, | |
768 callback_ptr)); | |
769 } | |
770 } | |
771 | |
772 void ServiceWorkerCacheStorage::MatchAllCachesDidMatch( | |
773 scoped_refptr<ServiceWorkerCache> cache, | |
774 const base::Closure& barrier_closure, | |
775 ServiceWorkerCache::ResponseCallback* callback, | |
776 ServiceWorkerCache::ErrorType error, | |
777 scoped_ptr<ServiceWorkerResponse> response, | |
778 scoped_ptr<storage::BlobDataHandle> handle) { | |
779 if (callback->is_null() || | |
780 error == ServiceWorkerCache::ERROR_TYPE_NOT_FOUND) { | |
781 barrier_closure.Run(); | |
782 return; | |
783 } | |
784 callback->Run(error, response.Pass(), handle.Pass()); | |
785 callback->Reset(); // Only call the callback once. | |
786 | |
787 barrier_closure.Run(); | |
788 } | |
789 | |
790 void ServiceWorkerCacheStorage::MatchAllCachesDidMatchAll( | |
791 scoped_ptr<ServiceWorkerCache::ResponseCallback> callback) { | |
792 if (!callback->is_null()) { | |
793 callback->Run(ServiceWorkerCache::ERROR_TYPE_NOT_FOUND, | |
794 scoped_ptr<ServiceWorkerResponse>(), | |
795 scoped_ptr<storage::BlobDataHandle>()); | |
796 } | |
797 } | |
798 | |
799 scoped_refptr<ServiceWorkerCache> ServiceWorkerCacheStorage::GetLoadedCache( | |
800 const std::string& cache_name) { | |
801 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
802 DCHECK(initialized_); | |
803 | |
804 CacheMap::iterator map_iter = cache_map_.find(cache_name); | |
805 if (map_iter == cache_map_.end()) | |
806 return scoped_refptr<ServiceWorkerCache>(); | |
807 | |
808 base::WeakPtr<ServiceWorkerCache> cache = map_iter->second; | |
809 | |
810 if (!cache) { | |
811 scoped_refptr<ServiceWorkerCache> new_cache = | |
812 cache_loader_->CreateServiceWorkerCache(cache_name); | |
813 map_iter->second = new_cache->AsWeakPtr(); | |
814 return new_cache; | |
815 } | |
816 | |
817 return make_scoped_refptr(cache.get()); | |
818 } | |
819 | |
820 void ServiceWorkerCacheStorage::CloseAllCachesImpl( | |
821 const base::Closure& callback) { | |
822 int live_cache_count = 0; | |
823 for (const auto& key_value : cache_map_) { | |
824 if (key_value.second) | |
825 live_cache_count += 1; | |
826 } | |
827 | |
828 if (live_cache_count == 0) { | |
829 callback.Run(); | |
830 return; | |
831 } | |
832 | |
833 // The closure might modify this object so delay calling it until after | |
834 // iterating through cache_map_ by adding one to the barrier. | |
835 base::Closure barrier_closure = | |
836 base::BarrierClosure(live_cache_count + 1, base::Bind(callback)); | |
837 | |
838 for (auto& key_value : cache_map_) { | |
839 if (key_value.second) { | |
840 key_value.second->Close(base::Bind( | |
841 CloseAllCachesDidCloseCache, | |
842 make_scoped_refptr(key_value.second.get()), barrier_closure)); | |
843 } | |
844 } | |
845 | |
846 barrier_closure.Run(); | |
847 } | |
848 | |
849 void ServiceWorkerCacheStorage::PendingClosure(const base::Closure& callback) { | |
850 base::WeakPtr<ServiceWorkerCacheStorage> cache_storage = | |
851 weak_factory_.GetWeakPtr(); | |
852 | |
853 callback.Run(); | |
854 if (cache_storage) | |
855 scheduler_->CompleteOperationAndRunNext(); | |
856 } | |
857 | |
858 void ServiceWorkerCacheStorage::PendingBoolAndErrorCallback( | |
859 const BoolAndErrorCallback& callback, | |
860 bool found, | |
861 CacheStorageError error) { | |
862 base::WeakPtr<ServiceWorkerCacheStorage> cache_storage = | |
863 weak_factory_.GetWeakPtr(); | |
864 | |
865 callback.Run(found, error); | |
866 if (cache_storage) | |
867 scheduler_->CompleteOperationAndRunNext(); | |
868 } | |
869 | |
870 void ServiceWorkerCacheStorage::PendingCacheAndErrorCallback( | |
871 const CacheAndErrorCallback& callback, | |
872 const scoped_refptr<ServiceWorkerCache>& cache, | |
873 CacheStorageError error) { | |
874 base::WeakPtr<ServiceWorkerCacheStorage> cache_storage = | |
875 weak_factory_.GetWeakPtr(); | |
876 | |
877 callback.Run(cache, error); | |
878 if (cache_storage) | |
879 scheduler_->CompleteOperationAndRunNext(); | |
880 } | |
881 | |
882 void ServiceWorkerCacheStorage::PendingStringsAndErrorCallback( | |
883 const StringsAndErrorCallback& callback, | |
884 const StringVector& strings, | |
885 CacheStorageError error) { | |
886 base::WeakPtr<ServiceWorkerCacheStorage> cache_storage = | |
887 weak_factory_.GetWeakPtr(); | |
888 | |
889 callback.Run(strings, error); | |
890 if (cache_storage) | |
891 scheduler_->CompleteOperationAndRunNext(); | |
892 } | |
893 | |
894 void ServiceWorkerCacheStorage::PendingResponseCallback( | |
895 const ServiceWorkerCache::ResponseCallback& callback, | |
896 ServiceWorkerCache::ErrorType error, | |
897 scoped_ptr<ServiceWorkerResponse> response, | |
898 scoped_ptr<storage::BlobDataHandle> blob_data_handle) { | |
899 base::WeakPtr<ServiceWorkerCacheStorage> cache_storage = | |
900 weak_factory_.GetWeakPtr(); | |
901 | |
902 callback.Run(error, response.Pass(), blob_data_handle.Pass()); | |
903 if (cache_storage) | |
904 scheduler_->CompleteOperationAndRunNext(); | |
905 } | |
906 | |
907 } // namespace content | |
OLD | NEW |