Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / service_worker / service_worker_cache_storage.cc
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/file_util.h"
10 #include "base/files/memory_mapped_file.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/sha1.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "content/browser/service_worker/service_worker_cache.h"
16 #include "content/browser/service_worker/service_worker_cache.pb.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/directory_lister.h"
19 #include "net/base/net_errors.h"
20 #include "webkit/browser/blob/blob_storage_context.h"
21
22 namespace content {
23
24 // Handles the loading and clean up of ServiceWorkerCache objects.
25 class ServiceWorkerCacheStorage::CacheLoader
26     : public base::RefCountedThreadSafe<
27           ServiceWorkerCacheStorage::CacheLoader> {
28  public:
29   typedef base::Callback<void(scoped_ptr<ServiceWorkerCache>)> CacheCallback;
30   typedef base::Callback<void(bool)> BoolCallback;
31   typedef base::Callback<void(scoped_ptr<std::vector<std::string> >)>
32       StringsCallback;
33
34   CacheLoader(
35       base::SequencedTaskRunner* cache_task_runner,
36       net::URLRequestContext* request_context,
37       base::WeakPtr<webkit_blob::BlobStorageContext> blob_context)
38       : cache_task_runner_(cache_task_runner),
39         request_context_(request_context),
40         blob_context_(blob_context) {}
41
42   // Loads the given cache_name, the cache is NULL if it fails. If the cache
43   // doesn't exist a new one is created.
44   virtual void LoadCache(const std::string& cache_name,
45                          const CacheCallback& callback) = 0;
46
47   // Deletes any pre-existing cache of the same name and then loads it.
48   virtual void CreateCache(const std::string& cache_name,
49                            const CacheCallback& callback) = 0;
50
51   // After the backend has been deleted, do any extra house keeping such as
52   // removing the cache's directory.
53   virtual void CleanUpDeletedCache(const std::string& key,
54                                    const BoolCallback& callback) = 0;
55
56   // Writes the cache names (and sizes) to disk if applicable.
57   virtual void WriteIndex(CacheMap* caches, const BoolCallback& callback) = 0;
58
59   // Loads the cache names from disk if applicable.
60   virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names,
61                          const StringsCallback& callback) = 0;
62
63  protected:
64   friend class base::RefCountedThreadSafe<
65       ServiceWorkerCacheStorage::CacheLoader>;
66
67   virtual ~CacheLoader() {};
68   virtual void LoadCacheImpl(const std::string&) {}
69
70   scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
71   net::URLRequestContext* request_context_;
72   base::WeakPtr<webkit_blob::BlobStorageContext> blob_context_;
73 };
74
75 class ServiceWorkerCacheStorage::MemoryLoader
76     : public ServiceWorkerCacheStorage::CacheLoader {
77  public:
78   MemoryLoader(
79       base::SequencedTaskRunner* cache_task_runner,
80       net::URLRequestContext* request_context,
81       base::WeakPtr<webkit_blob::BlobStorageContext> blob_context)
82       : CacheLoader(cache_task_runner, request_context, blob_context) {}
83   virtual void LoadCache(const std::string& cache_name,
84                          const CacheCallback& callback) OVERRIDE {
85     NOTREACHED();
86   }
87
88   virtual void CreateCache(const std::string& cache_name,
89                            const CacheCallback& callback) OVERRIDE {
90     scoped_ptr<ServiceWorkerCache> cache =
91         ServiceWorkerCache::CreateMemoryCache(
92             cache_name, request_context_, blob_context_);
93     callback.Run(cache.Pass());
94   }
95
96   virtual void CleanUpDeletedCache(const std::string& cache_name,
97                                    const BoolCallback& callback) OVERRIDE {
98     callback.Run(true);
99   }
100
101   virtual void WriteIndex(CacheMap* caches,
102                           const BoolCallback& callback) OVERRIDE {
103     callback.Run(false);
104   }
105
106   virtual void LoadIndex(scoped_ptr<std::vector<std::string> > cache_names,
107                          const StringsCallback& callback) OVERRIDE {
108     callback.Run(cache_names.Pass());
109   }
110
111  private:
112   virtual ~MemoryLoader() {}
113 };
114
115 class ServiceWorkerCacheStorage::SimpleCacheLoader
116     : public ServiceWorkerCacheStorage::CacheLoader {
117  public:
118   SimpleCacheLoader(const base::FilePath& origin_path,
119                     base::SequencedTaskRunner* cache_task_runner,
120                     net::URLRequestContext* request_context,
121                     base::WeakPtr<webkit_blob::BlobStorageContext> blob_context)
122       : CacheLoader(cache_task_runner, request_context, blob_context),
123         origin_path_(origin_path) {}
124
125   virtual void LoadCache(const std::string& cache_name,
126                          const CacheCallback& callback) OVERRIDE {
127     DCHECK_CURRENTLY_ON(BrowserThread::IO);
128
129     // 1. Create the cache's directory if necessary. (LoadCreateDirectoryInPool)
130     // 2. Create the cache object. (LoadDidCreateDirectory)
131
132     cache_task_runner_->PostTask(
133         FROM_HERE,
134         base::Bind(&SimpleCacheLoader::LoadCreateDirectoryInPool,
135                    this,
136                    CreatePersistentCachePath(origin_path_, cache_name),
137                    cache_name,
138                    callback,
139                    base::MessageLoopProxy::current()));
140   }
141
142   void LoadCreateDirectoryInPool(
143       const base::FilePath& path,
144       const std::string& cache_name,
145       const CacheCallback& callback,
146       const scoped_refptr<base::MessageLoopProxy>& original_loop) {
147     DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
148
149     bool rv = base::CreateDirectory(path);
150     original_loop->PostTask(
151         FROM_HERE,
152         base::Bind(&SimpleCacheLoader::LoadDidCreateDirectory,
153                    this,
154                    cache_name,
155                    callback,
156                    rv));
157   }
158
159   void LoadDidCreateDirectory(const std::string& cache_name,
160                               const CacheCallback& callback,
161                               bool dir_rv) {
162     DCHECK_CURRENTLY_ON(BrowserThread::IO);
163
164     if (!dir_rv) {
165       callback.Run(scoped_ptr<ServiceWorkerCache>());
166       return;
167     }
168
169     scoped_ptr<ServiceWorkerCache> cache =
170         ServiceWorkerCache::CreatePersistentCache(
171             CreatePersistentCachePath(origin_path_, cache_name),
172             cache_name,
173             request_context_,
174             blob_context_);
175     callback.Run(cache.Pass());
176   }
177
178   virtual void CreateCache(const std::string& cache_name,
179                            const CacheCallback& callback) OVERRIDE {
180     DCHECK_CURRENTLY_ON(BrowserThread::IO);
181
182     // 1. Delete the cache's directory if it exists.
183     // (CreateCacheDeleteFilesInPool)
184     // 2. Load the cache. (LoadCreateDirectoryInPool)
185
186     base::FilePath cache_path =
187         CreatePersistentCachePath(origin_path_, cache_name);
188
189     cache_task_runner_->PostTask(
190         FROM_HERE,
191         base::Bind(&SimpleCacheLoader::CreateCacheDeleteFilesInPool,
192                    this,
193                    cache_path,
194                    cache_name,
195                    callback,
196                    base::MessageLoopProxy::current()));
197   }
198
199   void CreateCacheDeleteFilesInPool(
200       const base::FilePath& cache_path,
201       const std::string& cache_name,
202       const CacheCallback& callback,
203       const scoped_refptr<base::MessageLoopProxy>& original_loop) {
204     DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
205
206     base::FilePath path(cache_path);
207     if (base::PathExists(path))
208       base::DeleteFile(path, /* recursive */ true);
209
210     // Jump straight into LoadCache on the same thread.
211     cache_task_runner_->PostTask(
212         FROM_HERE,
213         base::Bind(&SimpleCacheLoader::LoadCreateDirectoryInPool,
214                    this,
215                    cache_path,
216                    cache_name,
217                    callback,
218                    original_loop));
219   }
220
221   virtual void CleanUpDeletedCache(const std::string& cache_name,
222                                    const BoolCallback& callback) OVERRIDE {
223     DCHECK_CURRENTLY_ON(BrowserThread::IO);
224
225     // 1. Delete the cache's directory. (CleanUpDeleteCacheDirInPool)
226
227     base::FilePath cache_path =
228         CreatePersistentCachePath(origin_path_, cache_name);
229     cache_task_runner_->PostTask(
230         FROM_HERE,
231         base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool,
232                    this,
233                    cache_path,
234                    callback,
235                    base::MessageLoopProxy::current()));
236   }
237
238   void CleanUpDeleteCacheDirInPool(
239       const base::FilePath& cache_path,
240       const BoolCallback& callback,
241       const scoped_refptr<base::MessageLoopProxy>& original_loop) {
242     DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
243
244     bool rv = base::DeleteFile(cache_path, true);
245     original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
246   }
247
248   virtual void WriteIndex(CacheMap* caches,
249                           const BoolCallback& callback) OVERRIDE {
250     DCHECK_CURRENTLY_ON(BrowserThread::IO);
251
252     // 1. Create the index file as a string. (WriteIndex)
253     // 2. Write the file to disk. (WriteIndexWriteToFileInPool)
254
255     ServiceWorkerCacheStorageIndex index;
256
257     for (CacheMap::const_iterator iter(caches); !iter.IsAtEnd();
258          iter.Advance()) {
259       const ServiceWorkerCache* cache = iter.GetCurrentValue();
260       ServiceWorkerCacheStorageIndex::Cache* index_cache = index.add_cache();
261       index_cache->set_name(cache->name());
262       index_cache->set_size(0);  // TODO(jkarlin): Make this real.
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 = origin_path_.AppendASCII("index.txt");
271
272     cache_task_runner_->PostTask(
273         FROM_HERE,
274         base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
275                    this,
276                    tmp_path,
277                    index_path,
278                    serialized,
279                    caches,
280                    callback,
281                    base::MessageLoopProxy::current()));
282   }
283
284   void WriteIndexWriteToFileInPool(
285       const base::FilePath& tmp_path,
286       const base::FilePath& index_path,
287       const std::string& data,
288       CacheMap* caches,
289       const BoolCallback& callback,
290       const scoped_refptr<base::MessageLoopProxy>& original_loop) {
291     DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
292
293     int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
294     if (bytes_written != implicit_cast<int>(data.size())) {
295       base::DeleteFile(tmp_path, /* recursive */ false);
296       original_loop->PostTask(FROM_HERE, base::Bind(callback, false));
297     }
298
299     // Atomically rename the temporary index file to become the real one.
300     bool rv = base::ReplaceFile(tmp_path, index_path, NULL);
301     original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
302   }
303
304   virtual void LoadIndex(scoped_ptr<std::vector<std::string> > names,
305                          const StringsCallback& callback) OVERRIDE {
306     DCHECK_CURRENTLY_ON(BrowserThread::IO);
307
308     // 1. Read the file from disk. (LoadIndexReadFileInPool)
309     // 2. Parse file and return the names of the caches (LoadIndexDidReadFile)
310
311     base::FilePath index_path = origin_path_.AppendASCII("index.txt");
312
313     cache_task_runner_->PostTask(
314         FROM_HERE,
315         base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool,
316                    this,
317                    index_path,
318                    base::Passed(names.Pass()),
319                    callback,
320                    base::MessageLoopProxy::current()));
321   }
322
323   void LoadIndexReadFileInPool(
324       const base::FilePath& index_path,
325       scoped_ptr<std::vector<std::string> > names,
326       const StringsCallback& callback,
327       const scoped_refptr<base::MessageLoopProxy>& original_loop) {
328     DCHECK(cache_task_runner_->RunsTasksOnCurrentThread());
329
330     std::string body;
331     base::ReadFileToString(index_path, &body);
332
333     original_loop->PostTask(FROM_HERE,
334                             base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile,
335                                        this,
336                                        base::Passed(names.Pass()),
337                                        callback,
338                                        body));
339   }
340
341   void LoadIndexDidReadFile(scoped_ptr<std::vector<std::string> > names,
342                             const StringsCallback& callback,
343                             const std::string& serialized) {
344     DCHECK_CURRENTLY_ON(BrowserThread::IO);
345
346     ServiceWorkerCacheStorageIndex index;
347     index.ParseFromString(serialized);
348
349     for (int i = 0, max = index.cache_size(); i < max; ++i) {
350       const ServiceWorkerCacheStorageIndex::Cache& cache = index.cache(i);
351       names->push_back(cache.name());
352     }
353
354     // TODO(jkarlin): Delete caches that are in the directory and not returned
355     // in LoadIndex.
356     callback.Run(names.Pass());
357   }
358
359  private:
360   virtual ~SimpleCacheLoader() {}
361
362   std::string HexedHash(const std::string& value) {
363     std::string value_hash = base::SHA1HashString(value);
364     std::string valued_hexed_hash = base::StringToLowerASCII(
365         base::HexEncode(value_hash.c_str(), value_hash.length()));
366     return valued_hexed_hash;
367   }
368
369   base::FilePath CreatePersistentCachePath(const base::FilePath& origin_path,
370                                            const std::string& cache_name) {
371     return origin_path.AppendASCII(HexedHash(cache_name));
372   }
373
374   const base::FilePath origin_path_;
375 };
376
377 ServiceWorkerCacheStorage::ServiceWorkerCacheStorage(
378     const base::FilePath& path,
379     bool memory_only,
380     base::SequencedTaskRunner* cache_task_runner,
381     net::URLRequestContext* request_context,
382     base::WeakPtr<webkit_blob::BlobStorageContext> blob_context)
383     : initialized_(false),
384       origin_path_(path),
385       cache_task_runner_(cache_task_runner),
386       weak_factory_(this) {
387   if (memory_only)
388     cache_loader_ =
389         new MemoryLoader(cache_task_runner_, request_context, blob_context);
390   else
391     cache_loader_ = new SimpleCacheLoader(
392         origin_path_, cache_task_runner_, request_context, blob_context);
393 }
394
395 ServiceWorkerCacheStorage::~ServiceWorkerCacheStorage() {
396 }
397
398 void ServiceWorkerCacheStorage::CreateCache(
399     const std::string& cache_name,
400     const CacheAndErrorCallback& callback) {
401   if (!initialized_) {
402     LazyInit(base::Bind(&ServiceWorkerCacheStorage::CreateCache,
403                         weak_factory_.GetWeakPtr(),
404                         cache_name,
405                         callback));
406     return;
407   }
408
409   if (cache_name.empty()) {
410     callback.Run(0, CACHE_STORAGE_ERROR_EMPTY_KEY);
411     return;
412   }
413
414   if (GetLoadedCache(cache_name)) {
415     callback.Run(0, CACHE_STORAGE_ERROR_EXISTS);
416     return;
417   }
418
419   cache_loader_->CreateCache(
420       cache_name,
421       base::Bind(&ServiceWorkerCacheStorage::CreateCacheDidCreateCache,
422                  weak_factory_.GetWeakPtr(),
423                  cache_name,
424                  callback));
425 }
426
427 void ServiceWorkerCacheStorage::GetCache(
428     const std::string& cache_name,
429     const CacheAndErrorCallback& callback) {
430   DCHECK_CURRENTLY_ON(BrowserThread::IO);
431
432   if (!initialized_) {
433     LazyInit(base::Bind(&ServiceWorkerCacheStorage::GetCache,
434                         weak_factory_.GetWeakPtr(),
435                         cache_name,
436                         callback));
437     return;
438   }
439
440   if (cache_name.empty()) {
441     callback.Run(0, CACHE_STORAGE_ERROR_EMPTY_KEY);
442     return;
443   }
444
445   ServiceWorkerCache* cache = GetLoadedCache(cache_name);
446   if (!cache) {
447     callback.Run(0, CACHE_STORAGE_ERROR_NOT_FOUND);
448     return;
449   }
450
451   cache->CreateBackend(base::Bind(&ServiceWorkerCacheStorage::DidCreateBackend,
452                                   weak_factory_.GetWeakPtr(),
453                                   cache->AsWeakPtr(),
454                                   callback));
455 }
456
457 void ServiceWorkerCacheStorage::HasCache(const std::string& cache_name,
458                                          const BoolAndErrorCallback& callback) {
459   DCHECK_CURRENTLY_ON(BrowserThread::IO);
460
461   if (!initialized_) {
462     LazyInit(base::Bind(&ServiceWorkerCacheStorage::HasCache,
463                         weak_factory_.GetWeakPtr(),
464                         cache_name,
465                         callback));
466     return;
467   }
468
469   if (cache_name.empty()) {
470     callback.Run(false, CACHE_STORAGE_ERROR_EMPTY_KEY);
471     return;
472   }
473
474   bool has_cache = GetLoadedCache(cache_name) != NULL;
475
476   callback.Run(has_cache, CACHE_STORAGE_ERROR_NO_ERROR);
477 }
478
479 void ServiceWorkerCacheStorage::DeleteCache(
480     const std::string& cache_name,
481     const BoolAndErrorCallback& callback) {
482   DCHECK_CURRENTLY_ON(BrowserThread::IO);
483
484   if (!initialized_) {
485     LazyInit(base::Bind(&ServiceWorkerCacheStorage::DeleteCache,
486                         weak_factory_.GetWeakPtr(),
487                         cache_name,
488                         callback));
489     return;
490   }
491
492   if (cache_name.empty()) {
493     callback.Run(false, CACHE_STORAGE_ERROR_EMPTY_KEY);
494     return;
495   }
496
497   ServiceWorkerCache* cache = GetLoadedCache(cache_name);
498   if (!cache) {
499     callback.Run(false, CACHE_STORAGE_ERROR_NOT_FOUND);
500     return;
501   }
502
503   name_map_.erase(cache_name);
504   cache_map_.Remove(cache->id());  // deletes cache
505
506   // Update the Index
507   cache_loader_->WriteIndex(
508       &cache_map_,
509       base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex,
510                  weak_factory_.GetWeakPtr(),
511                  cache_name,
512                  callback));
513 }
514
515 void ServiceWorkerCacheStorage::EnumerateCaches(
516     const StringsAndErrorCallback& callback) {
517   DCHECK_CURRENTLY_ON(BrowserThread::IO);
518
519   if (!initialized_) {
520     LazyInit(base::Bind(&ServiceWorkerCacheStorage::EnumerateCaches,
521                         weak_factory_.GetWeakPtr(),
522                         callback));
523     return;
524   }
525
526   std::vector<std::string> names;
527   for (NameMap::const_iterator it = name_map_.begin(); it != name_map_.end();
528        ++it) {
529     names.push_back(it->first);
530   }
531
532   callback.Run(names, CACHE_STORAGE_ERROR_NO_ERROR);
533 }
534
535 void ServiceWorkerCacheStorage::DidCreateBackend(
536     base::WeakPtr<ServiceWorkerCache> cache,
537     const CacheAndErrorCallback& callback,
538     bool success) {
539   DCHECK_CURRENTLY_ON(BrowserThread::IO);
540
541   if (!success || !cache) {
542     // TODO(jkarlin): This should delete the directory and try again in case
543     // the cache is simply corrupt.
544     callback.Run(0, CACHE_STORAGE_ERROR_STORAGE);
545     return;
546   }
547   callback.Run(cache->id(), CACHE_STORAGE_ERROR_NO_ERROR);
548 }
549
550 // Init is run lazily so that it is called on the proper MessageLoop.
551 void ServiceWorkerCacheStorage::LazyInit(const base::Closure& callback) {
552   DCHECK_CURRENTLY_ON(BrowserThread::IO);
553   DCHECK(!initialized_);
554
555   init_callbacks_.push_back(callback);
556
557   // If this isn't the first call to LazyInit then return as the initialization
558   // has already started.
559   if (init_callbacks_.size() > 1u)
560     return;
561
562   // 1. Get the list of cache names (async call)
563   // 2. For each cache name, load the cache (async call)
564   // 3. Once each load is complete, update the map variables.
565   // 4. Call the list of waiting callbacks.
566
567   scoped_ptr<std::vector<std::string> > indexed_cache_names(
568       new std::vector<std::string>());
569
570   cache_loader_->LoadIndex(
571       indexed_cache_names.Pass(),
572       base::Bind(&ServiceWorkerCacheStorage::LazyInitDidLoadIndex,
573                  weak_factory_.GetWeakPtr(),
574                  callback));
575 }
576
577 void ServiceWorkerCacheStorage::LazyInitDidLoadIndex(
578     const base::Closure& callback,
579     scoped_ptr<std::vector<std::string> > indexed_cache_names) {
580   DCHECK_CURRENTLY_ON(BrowserThread::IO);
581
582   if (indexed_cache_names->empty()) {
583     LazyInitDone();
584     return;
585   }
586
587   std::vector<std::string>::const_iterator iter = indexed_cache_names->begin();
588   std::vector<std::string>::const_iterator iter_next = iter + 1;
589
590   cache_loader_->LoadCache(
591       *iter,
592       base::Bind(&ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName,
593                  weak_factory_.GetWeakPtr(),
594                  callback,
595                  base::Passed(indexed_cache_names.Pass()),
596                  iter_next));
597 }
598
599 void ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName(
600     const base::Closure& callback,
601     scoped_ptr<std::vector<std::string> > indexed_cache_names,
602     const std::vector<std::string>::const_iterator& iter,
603     scoped_ptr<ServiceWorkerCache> cache) {
604   DCHECK_CURRENTLY_ON(BrowserThread::IO);
605
606   if (cache)
607     AddCacheToMaps(cache.Pass());
608
609   if (iter == indexed_cache_names->end()) {
610     LazyInitDone();
611     return;
612   }
613
614   std::vector<std::string>::const_iterator iter_next = iter + 1;
615   cache_loader_->LoadCache(
616       *iter,
617       base::Bind(&ServiceWorkerCacheStorage::LazyInitIterateAndLoadCacheName,
618                  weak_factory_.GetWeakPtr(),
619                  callback,
620                  base::Passed(indexed_cache_names.Pass()),
621                  iter_next));
622 }
623
624 void ServiceWorkerCacheStorage::LazyInitDone() {
625   initialized_ = true;
626   for (std::vector<base::Closure>::iterator it = init_callbacks_.begin();
627        it != init_callbacks_.end();
628        ++it) {
629     it->Run();
630   }
631   init_callbacks_.clear();
632 }
633
634 void ServiceWorkerCacheStorage::AddCacheToMaps(
635     scoped_ptr<ServiceWorkerCache> cache) {
636   DCHECK_CURRENTLY_ON(BrowserThread::IO);
637
638   ServiceWorkerCache* cache_ptr = cache.release();
639   CacheID id = cache_map_.Add(cache_ptr);
640   name_map_.insert(std::make_pair(cache_ptr->name(), id));
641   cache_ptr->set_id(id);
642 }
643
644 void ServiceWorkerCacheStorage::CreateCacheDidCreateCache(
645     const std::string& cache_name,
646     const CacheAndErrorCallback& callback,
647     scoped_ptr<ServiceWorkerCache> cache) {
648   DCHECK_CURRENTLY_ON(BrowserThread::IO);
649
650   if (!cache) {
651     callback.Run(0, CACHE_STORAGE_ERROR_STORAGE);
652     return;
653   }
654
655   base::WeakPtr<ServiceWorkerCache> cache_ptr = cache->AsWeakPtr();
656
657   AddCacheToMaps(cache.Pass());
658
659   cache_loader_->WriteIndex(
660       &cache_map_,
661       base::Bind(
662           &ServiceWorkerCacheStorage::CreateCacheDidWriteIndex,
663           weak_factory_.GetWeakPtr(),
664           callback,
665           cache_ptr));  // cache is owned by this->CacheMap and won't be deleted
666 }
667
668 void ServiceWorkerCacheStorage::CreateCacheDidWriteIndex(
669     const CacheAndErrorCallback& callback,
670     base::WeakPtr<ServiceWorkerCache> cache,
671     bool success) {
672   DCHECK_CURRENTLY_ON(BrowserThread::IO);
673   if (!cache) {
674     callback.Run(false, CACHE_STORAGE_ERROR_STORAGE);
675     return;
676   }
677   cache->CreateBackend(base::Bind(&ServiceWorkerCacheStorage::DidCreateBackend,
678                                   weak_factory_.GetWeakPtr(),
679                                   cache,
680                                   callback));
681 }
682
683 void ServiceWorkerCacheStorage::DeleteCacheDidWriteIndex(
684     const std::string& cache_name,
685     const BoolAndErrorCallback& callback,
686     bool success) {
687   DCHECK_CURRENTLY_ON(BrowserThread::IO);
688
689   cache_loader_->CleanUpDeletedCache(
690       cache_name,
691       base::Bind(&ServiceWorkerCacheStorage::DeleteCacheDidCleanUp,
692                  weak_factory_.GetWeakPtr(),
693                  callback));
694 }
695
696 void ServiceWorkerCacheStorage::DeleteCacheDidCleanUp(
697     const BoolAndErrorCallback& callback,
698     bool success) {
699   DCHECK_CURRENTLY_ON(BrowserThread::IO);
700
701   callback.Run(true, CACHE_STORAGE_ERROR_NO_ERROR);
702 }
703
704 ServiceWorkerCache* ServiceWorkerCacheStorage::GetLoadedCache(
705     const std::string& cache_name) const {
706   DCHECK_CURRENTLY_ON(BrowserThread::IO);
707   DCHECK(initialized_);
708
709   NameMap::const_iterator it = name_map_.find(cache_name);
710   if (it == name_map_.end())
711     return NULL;
712
713   ServiceWorkerCache* cache = cache_map_.Lookup(it->second);
714   DCHECK(cache);
715   return cache;
716 }
717
718 }  // namespace content