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