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/cache_storage/legacy/legacy_cache_storage.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <set>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "base/barrier_closure.h"
16 #include "base/bind.h"
17 #include "base/bind_helpers.h"
18 #include "base/files/file_util.h"
19 #include "base/files/memory_mapped_file.h"
20 #include "base/guid.h"
21 #include "base/hash/sha1.h"
22 #include "base/location.h"
23 #include "base/memory/ptr_util.h"
24 #include "base/memory/ref_counted.h"
25 #include "base/memory/scoped_refptr.h"
26 #include "base/metrics/histogram_macros.h"
27 #include "base/numerics/safe_conversions.h"
28 #include "base/sequenced_task_runner.h"
29 #include "base/stl_util.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/strings/string_util.h"
32 #include "base/threading/sequenced_task_runner_handle.h"
33 #include "base/trace_event/trace_event.h"
34 #include "base/trace_event/traced_value.h"
35 #include "content/browser/cache_storage/cache_storage.pb.h"
36 #include "content/browser/cache_storage/cache_storage_cache.h"
37 #include "content/browser/cache_storage/cache_storage_cache_handle.h"
38 #include "content/browser/cache_storage/cache_storage_histogram_utils.h"
39 #include "content/browser/cache_storage/cache_storage_index.h"
40 #include "content/browser/cache_storage/cache_storage_quota_client.h"
41 #include "content/browser/cache_storage/cache_storage_scheduler.h"
42 #include "content/browser/cache_storage/cache_storage_trace_utils.h"
43 #include "content/browser/cache_storage/legacy/legacy_cache_storage_manager.h"
44 #include "content/common/background_fetch/background_fetch_types.h"
45 #include "crypto/symmetric_key.h"
46 #include "net/base/directory_lister.h"
47 #include "net/base/net_errors.h"
48 #include "storage/browser/blob/blob_storage_context.h"
49 #include "storage/browser/quota/padding_key.h"
50 #include "storage/browser/quota/quota_manager_proxy.h"
51 #include "third_party/blink/public/mojom/quota/quota_types.mojom.h"
52 
53 using blink::mojom::CacheStorageError;
54 using blink::mojom::StorageType;
55 using crypto::SymmetricKey;
56 
57 namespace content {
58 
59 namespace {
60 
HexedHash(const std::string & value)61 std::string HexedHash(const std::string& value) {
62   std::string value_hash = base::SHA1HashString(value);
63   std::string valued_hexed_hash = base::ToLowerASCII(
64       base::HexEncode(value_hash.c_str(), value_hash.length()));
65   return valued_hexed_hash;
66 }
67 
SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator,LegacyCacheStorage::SizeCallback callback)68 void SizeRetrievedFromAllCaches(std::unique_ptr<int64_t> accumulator,
69                                 LegacyCacheStorage::SizeCallback callback) {
70   base::SequencedTaskRunnerHandle::Get()->PostTask(
71       FROM_HERE, base::BindOnce(std::move(callback), *accumulator));
72 }
73 
74 }  // namespace
75 
76 const char LegacyCacheStorage::kIndexFileName[] = "index.txt";
77 
78 struct LegacyCacheStorage::CacheMatchResponse {
79   CacheMatchResponse() = default;
80   ~CacheMatchResponse() = default;
81 
82   CacheStorageError error;
83   blink::mojom::FetchAPIResponsePtr response;
84   std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
85 };
86 
87 // Handles the loading and clean up of CacheStorageCache objects.
88 class LegacyCacheStorage::CacheLoader {
89  public:
90   using CacheCallback =
91       base::OnceCallback<void(std::unique_ptr<LegacyCacheStorageCache>)>;
92   using BoolCallback = base::OnceCallback<void(bool)>;
93   using CacheStorageIndexLoadCallback =
94       base::OnceCallback<void(std::unique_ptr<CacheStorageIndex>)>;
95 
CacheLoader(base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)96   CacheLoader(base::SequencedTaskRunner* cache_task_runner,
97               scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
98               scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
99               scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
100               LegacyCacheStorage* cache_storage,
101               const url::Origin& origin,
102               CacheStorageOwner owner)
103       : cache_task_runner_(cache_task_runner),
104         scheduler_task_runner_(std::move(scheduler_task_runner)),
105         quota_manager_proxy_(std::move(quota_manager_proxy)),
106         blob_storage_context_(std::move(blob_storage_context)),
107         cache_storage_(cache_storage),
108         origin_(origin),
109         owner_(owner) {
110     DCHECK(!origin_.opaque());
111   }
112 
~CacheLoader()113   virtual ~CacheLoader() {}
114 
115   // Creates a CacheStorageCache with the given name. It does not attempt to
116   // load the backend, that happens lazily when the cache is used.
117   virtual std::unique_ptr<LegacyCacheStorageCache> CreateCache(
118       const std::string& cache_name,
119       int64_t cache_size,
120       int64_t cache_padding,
121       std::unique_ptr<SymmetricKey> cache_padding_key) = 0;
122 
123   // Deletes any pre-existing cache of the same name and then loads it.
124   virtual void PrepareNewCacheDestination(const std::string& cache_name,
125                                           CacheCallback callback) = 0;
126 
127   // After the backend has been deleted, do any extra house keeping such as
128   // removing the cache's directory.
129   virtual void CleanUpDeletedCache(CacheStorageCache* cache) = 0;
130 
131   // Writes the cache index to disk if applicable.
132   virtual void WriteIndex(const CacheStorageIndex& index,
133                           BoolCallback callback) = 0;
134 
135   // Loads the cache index from disk if applicable.
136   virtual void LoadIndex(CacheStorageIndexLoadCallback callback) = 0;
137 
138   // Called when CacheStorage has created a cache. Used to hold onto a handle to
139   // the cache if necessary.
NotifyCacheCreated(const std::string & cache_name,CacheStorageCacheHandle cache_handle)140   virtual void NotifyCacheCreated(const std::string& cache_name,
141                                   CacheStorageCacheHandle cache_handle) {}
142 
143   // Notification that the cache for |cache_handle| has been doomed. If the
144   // loader is holding a handle to the cache, it should drop it now.
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)145   virtual void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) {}
146 
147  protected:
148   const scoped_refptr<base::SequencedTaskRunner> cache_task_runner_;
149   const scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner_;
150 
151   // Owned by CacheStorage which owns this. This is guaranteed to outlive
152   // CacheLoader, but we store a reference to keep it alive for callbacks.
153   scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy_;
154 
155   scoped_refptr<BlobStorageContextWrapper> blob_storage_context_;
156 
157   // Raw pointer is safe because this object is owned by cache_storage_.
158   LegacyCacheStorage* cache_storage_;
159 
160   url::Origin origin_;
161   CacheStorageOwner owner_;
162 };
163 
164 // Creates memory-only ServiceWorkerCaches. Because these caches have no
165 // persistent storage it is not safe to free them from memory if they might be
166 // used again. Therefore this class holds a reference to each cache until the
167 // cache is doomed.
168 class LegacyCacheStorage::MemoryLoader
169     : public LegacyCacheStorage::CacheLoader {
170  public:
MemoryLoader(base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)171   MemoryLoader(base::SequencedTaskRunner* cache_task_runner,
172                scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
173                scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
174                scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
175                LegacyCacheStorage* cache_storage,
176                const url::Origin& origin,
177                CacheStorageOwner owner)
178       : CacheLoader(cache_task_runner,
179                     std::move(scheduler_task_runner),
180                     std::move(quota_manager_proxy),
181                     std::move(blob_storage_context),
182                     cache_storage,
183                     origin,
184                     owner) {}
185 
CreateCache(const std::string & cache_name,int64_t cache_size,int64_t cache_padding,std::unique_ptr<SymmetricKey> cache_padding_key)186   std::unique_ptr<LegacyCacheStorageCache> CreateCache(
187       const std::string& cache_name,
188       int64_t cache_size,
189       int64_t cache_padding,
190       std::unique_ptr<SymmetricKey> cache_padding_key) override {
191     return LegacyCacheStorageCache::CreateMemoryCache(
192         origin_, owner_, cache_name, cache_storage_, scheduler_task_runner_,
193         quota_manager_proxy_, blob_storage_context_,
194         storage::CopyDefaultPaddingKey());
195   }
196 
PrepareNewCacheDestination(const std::string & cache_name,CacheCallback callback)197   void PrepareNewCacheDestination(const std::string& cache_name,
198                                   CacheCallback callback) override {
199     std::unique_ptr<LegacyCacheStorageCache> cache =
200         CreateCache(cache_name, 0 /*cache_size*/, 0 /* cache_padding */,
201                     storage::CopyDefaultPaddingKey());
202     std::move(callback).Run(std::move(cache));
203   }
204 
CleanUpDeletedCache(CacheStorageCache * cache)205   void CleanUpDeletedCache(CacheStorageCache* cache) override {}
206 
WriteIndex(const CacheStorageIndex & index,BoolCallback callback)207   void WriteIndex(const CacheStorageIndex& index,
208                   BoolCallback callback) override {
209     std::move(callback).Run(true);
210   }
211 
LoadIndex(CacheStorageIndexLoadCallback callback)212   void LoadIndex(CacheStorageIndexLoadCallback callback) override {
213     std::move(callback).Run(std::make_unique<CacheStorageIndex>());
214   }
215 
NotifyCacheCreated(const std::string & cache_name,CacheStorageCacheHandle cache_handle)216   void NotifyCacheCreated(const std::string& cache_name,
217                           CacheStorageCacheHandle cache_handle) override {
218     DCHECK(!base::Contains(cache_handles_, cache_name));
219     cache_handles_.insert(std::make_pair(cache_name, std::move(cache_handle)));
220   }
221 
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)222   void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override {
223     auto* impl = LegacyCacheStorageCache::From(cache_handle);
224     DCHECK(base::Contains(cache_handles_, impl->cache_name()));
225     cache_handles_.erase(impl->cache_name());
226   }
227 
228  private:
229   typedef std::map<std::string, CacheStorageCacheHandle> CacheHandles;
~MemoryLoader()230   ~MemoryLoader() override {}
231 
232   // Keep a reference to each cache to ensure that it's not freed before the
233   // client calls LegacyCacheStorage::Delete or the CacheStorage is
234   // freed.
235   CacheHandles cache_handles_;
236 };
237 
238 class LegacyCacheStorage::SimpleCacheLoader
239     : public LegacyCacheStorage::CacheLoader {
240  public:
SimpleCacheLoader(const base::FilePath & origin_path,base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorage * cache_storage,const url::Origin & origin,CacheStorageOwner owner)241   SimpleCacheLoader(
242       const base::FilePath& origin_path,
243       base::SequencedTaskRunner* cache_task_runner,
244       scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
245       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
246       scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
247       LegacyCacheStorage* cache_storage,
248       const url::Origin& origin,
249       CacheStorageOwner owner)
250       : CacheLoader(cache_task_runner,
251                     std::move(scheduler_task_runner),
252                     std::move(quota_manager_proxy),
253                     std::move(blob_storage_context),
254                     cache_storage,
255                     origin,
256                     owner),
257         origin_path_(origin_path) {}
258 
CreateCache(const std::string & cache_name,int64_t cache_size,int64_t cache_padding,std::unique_ptr<SymmetricKey> cache_padding_key)259   std::unique_ptr<LegacyCacheStorageCache> CreateCache(
260       const std::string& cache_name,
261       int64_t cache_size,
262       int64_t cache_padding,
263       std::unique_ptr<SymmetricKey> cache_padding_key) override {
264     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
265     DCHECK(base::Contains(cache_name_to_cache_dir_, cache_name));
266 
267     std::string cache_dir = cache_name_to_cache_dir_[cache_name];
268     base::FilePath cache_path = origin_path_.AppendASCII(cache_dir);
269     return LegacyCacheStorageCache::CreatePersistentCache(
270         origin_, owner_, cache_name, cache_storage_, cache_path,
271         scheduler_task_runner_, quota_manager_proxy_, blob_storage_context_,
272         cache_size, cache_padding, std::move(cache_padding_key));
273   }
274 
PrepareNewCacheDestination(const std::string & cache_name,CacheCallback callback)275   void PrepareNewCacheDestination(const std::string& cache_name,
276                                   CacheCallback callback) override {
277     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
278 
279     PostTaskAndReplyWithResult(
280         cache_task_runner_.get(), FROM_HERE,
281         base::BindOnce(&SimpleCacheLoader::PrepareNewCacheDirectoryInPool,
282                        origin_path_),
283         base::BindOnce(&SimpleCacheLoader::PrepareNewCacheCreateCache,
284                        weak_ptr_factory_.GetWeakPtr(), cache_name,
285                        std::move(callback)));
286   }
287 
288   // Runs on the cache_task_runner_.
PrepareNewCacheDirectoryInPool(const base::FilePath & origin_path)289   static std::string PrepareNewCacheDirectoryInPool(
290       const base::FilePath& origin_path) {
291     std::string cache_dir;
292     base::FilePath cache_path;
293     do {
294       cache_dir = base::GenerateGUID();
295       cache_path = origin_path.AppendASCII(cache_dir);
296     } while (base::PathExists(cache_path));
297 
298     return base::CreateDirectory(cache_path) ? cache_dir : "";
299   }
300 
PrepareNewCacheCreateCache(const std::string & cache_name,CacheCallback callback,const std::string & cache_dir)301   void PrepareNewCacheCreateCache(const std::string& cache_name,
302                                   CacheCallback callback,
303                                   const std::string& cache_dir) {
304     if (cache_dir.empty()) {
305       std::move(callback).Run(nullptr);
306       return;
307     }
308 
309     cache_name_to_cache_dir_[cache_name] = cache_dir;
310     std::move(callback).Run(CreateCache(
311         cache_name, LegacyCacheStorage::kSizeUnknown,
312         LegacyCacheStorage::kSizeUnknown, storage::CopyDefaultPaddingKey()));
313   }
314 
CleanUpDeletedCache(CacheStorageCache * cache)315   void CleanUpDeletedCache(CacheStorageCache* cache) override {
316     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
317     DCHECK(base::Contains(doomed_cache_to_path_, cache));
318 
319     base::FilePath cache_path =
320         origin_path_.AppendASCII(doomed_cache_to_path_[cache]);
321     doomed_cache_to_path_.erase(cache);
322 
323     cache_task_runner_->PostTask(
324         FROM_HERE,
325         base::BindOnce(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool,
326                        cache_path));
327   }
328 
CleanUpDeleteCacheDirInPool(const base::FilePath & cache_path)329   static void CleanUpDeleteCacheDirInPool(const base::FilePath& cache_path) {
330     base::DeleteFileRecursively(cache_path);
331   }
332 
WriteIndex(const CacheStorageIndex & index,BoolCallback callback)333   void WriteIndex(const CacheStorageIndex& index,
334                   BoolCallback callback) override {
335     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
336 
337     // 1. Create the index file as a string. (WriteIndex)
338     // 2. Write the file to disk. (WriteIndexWriteToFileInPool)
339 
340     proto::CacheStorageIndex protobuf_index;
341     // GetURL().spec() is used here rather than Serialize() to ensure
342     // backwards compatibility with older data. The serializations are
343     // subtly different, e.g. Origin does not include a trailing "/".
344     // TODO(crbug.com/809329): Add a test for validating fields in the proto
345     protobuf_index.set_origin(origin_.GetURL().spec());
346 
347     for (const auto& cache_metadata : index.ordered_cache_metadata()) {
348       DCHECK(base::Contains(cache_name_to_cache_dir_, cache_metadata.name));
349 
350       proto::CacheStorageIndex::Cache* index_cache = protobuf_index.add_cache();
351       index_cache->set_name(cache_metadata.name);
352       index_cache->set_cache_dir(cache_name_to_cache_dir_[cache_metadata.name]);
353       if (cache_metadata.size == LegacyCacheStorage::kSizeUnknown)
354         index_cache->clear_size();
355       else
356         index_cache->set_size(cache_metadata.size);
357       index_cache->set_padding_key(cache_metadata.padding_key);
358       index_cache->set_padding(cache_metadata.padding);
359       index_cache->set_padding_version(
360           LegacyCacheStorageCache::GetResponsePaddingVersion());
361     }
362 
363     std::string serialized;
364     bool success = protobuf_index.SerializeToString(&serialized);
365     DCHECK(success);
366 
367     base::FilePath tmp_path = origin_path_.AppendASCII("index.txt.tmp");
368     base::FilePath index_path =
369         origin_path_.AppendASCII(LegacyCacheStorage::kIndexFileName);
370 
371     PostTaskAndReplyWithResult(
372         cache_task_runner_.get(), FROM_HERE,
373         base::BindOnce(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
374                        tmp_path, index_path, serialized, quota_manager_proxy_,
375                        origin_),
376         std::move(callback));
377   }
378 
WriteIndexWriteToFileInPool(const base::FilePath & tmp_path,const base::FilePath & index_path,const std::string & data,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,const url::Origin & origin)379   static bool WriteIndexWriteToFileInPool(
380       const base::FilePath& tmp_path,
381       const base::FilePath& index_path,
382       const std::string& data,
383       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
384       const url::Origin& origin) {
385     int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
386     if (bytes_written != base::checked_cast<int>(data.size())) {
387       base::DeleteFile(tmp_path, /* recursive */ false);
388       quota_manager_proxy->NotifyWriteFailed(origin);
389       return false;
390     }
391 
392     // Atomically rename the temporary index file to become the real one.
393     return base::ReplaceFile(tmp_path, index_path, nullptr);
394   }
395 
LoadIndex(CacheStorageIndexLoadCallback callback)396   void LoadIndex(CacheStorageIndexLoadCallback callback) override {
397     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
398 
399     PostTaskAndReplyWithResult(
400         cache_task_runner_.get(), FROM_HERE,
401         base::BindOnce(&SimpleCacheLoader::ReadAndMigrateIndexInPool,
402                        origin_path_, quota_manager_proxy_, origin_),
403         base::BindOnce(&SimpleCacheLoader::LoadIndexDidReadIndex,
404                        weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
405   }
406 
LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback,proto::CacheStorageIndex protobuf_index)407   void LoadIndexDidReadIndex(CacheStorageIndexLoadCallback callback,
408                              proto::CacheStorageIndex protobuf_index) {
409     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
410 
411     std::unique_ptr<std::set<std::string>> cache_dirs(
412         new std::set<std::string>);
413 
414     auto index = std::make_unique<CacheStorageIndex>();
415     for (int i = 0, max = protobuf_index.cache_size(); i < max; ++i) {
416       const proto::CacheStorageIndex::Cache& cache = protobuf_index.cache(i);
417       DCHECK(cache.has_cache_dir());
418       int64_t cache_size =
419           cache.has_size() ? cache.size() : LegacyCacheStorage::kSizeUnknown;
420       int64_t cache_padding;
421       if (cache.has_padding()) {
422         if (cache.has_padding_version() &&
423             cache.padding_version() ==
424                 LegacyCacheStorageCache::GetResponsePaddingVersion()) {
425           cache_padding = cache.padding();
426         } else {
427           // The padding algorithm version changed so set to unknown to force
428           // recalculation.
429           cache_padding = LegacyCacheStorage::kSizeUnknown;
430         }
431       } else {
432         cache_padding = LegacyCacheStorage::kSizeUnknown;
433       }
434 
435       std::string cache_padding_key =
436           cache.has_padding_key() ? cache.padding_key()
437                                   : storage::SerializeDefaultPaddingKey();
438 
439       index->Insert(CacheStorageIndex::CacheMetadata(
440           cache.name(), cache_size, cache_padding,
441           std::move(cache_padding_key)));
442       cache_name_to_cache_dir_[cache.name()] = cache.cache_dir();
443       cache_dirs->insert(cache.cache_dir());
444     }
445 
446     cache_task_runner_->PostTask(
447         FROM_HERE, base::BindOnce(&DeleteUnreferencedCachesInPool, origin_path_,
448                                   std::move(cache_dirs)));
449     std::move(callback).Run(std::move(index));
450   }
451 
NotifyCacheDoomed(CacheStorageCacheHandle cache_handle)452   void NotifyCacheDoomed(CacheStorageCacheHandle cache_handle) override {
453     auto* impl = LegacyCacheStorageCache::From(cache_handle);
454     DCHECK(base::Contains(cache_name_to_cache_dir_, impl->cache_name()));
455     auto iter = cache_name_to_cache_dir_.find(impl->cache_name());
456     doomed_cache_to_path_[cache_handle.value()] = iter->second;
457     cache_name_to_cache_dir_.erase(iter);
458   }
459 
460  private:
461   friend class MigratedLegacyCacheDirectoryNameTest;
~SimpleCacheLoader()462   ~SimpleCacheLoader() override {}
463 
464   // Iterates over the caches and deletes any directory not found in
465   // |cache_dirs|. Runs on cache_task_runner_
DeleteUnreferencedCachesInPool(const base::FilePath & cache_base_dir,std::unique_ptr<std::set<std::string>> cache_dirs)466   static void DeleteUnreferencedCachesInPool(
467       const base::FilePath& cache_base_dir,
468       std::unique_ptr<std::set<std::string>> cache_dirs) {
469     base::FileEnumerator file_enum(cache_base_dir, false /* recursive */,
470                                    base::FileEnumerator::DIRECTORIES);
471     std::vector<base::FilePath> dirs_to_delete;
472     {
473       base::FilePath cache_path;
474       while (!(cache_path = file_enum.Next()).empty()) {
475         if (!base::Contains(*cache_dirs, cache_path.BaseName().AsUTF8Unsafe()))
476           dirs_to_delete.push_back(cache_path);
477       }
478     }
479 
480     for (const base::FilePath& cache_path : dirs_to_delete)
481       base::DeleteFileRecursively(cache_path);
482   }
483 
484   // Runs on cache_task_runner_
ReadAndMigrateIndexInPool(const base::FilePath & origin_path,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,const url::Origin & origin)485   static proto::CacheStorageIndex ReadAndMigrateIndexInPool(
486       const base::FilePath& origin_path,
487       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
488       const url::Origin& origin) {
489     const base::FilePath index_path =
490         origin_path.AppendASCII(LegacyCacheStorage::kIndexFileName);
491 
492     proto::CacheStorageIndex index;
493     std::string body;
494     if (!base::ReadFileToString(index_path, &body) ||
495         !index.ParseFromString(body))
496       return proto::CacheStorageIndex();
497     body.clear();
498 
499     base::File::Info file_info;
500     base::Time index_last_modified;
501     if (GetFileInfo(index_path, &file_info))
502       index_last_modified = file_info.last_modified;
503     bool index_modified = false;
504 
505     // Look for caches that have no cache_dir. Give any such caches a directory
506     // with a random name and move them there. Then, rewrite the index file.
507     // Additionally invalidate the size of any index entries where the cache was
508     // modified after the index (making it out-of-date).
509     for (int i = 0, max = index.cache_size(); i < max; ++i) {
510       const proto::CacheStorageIndex::Cache& cache = index.cache(i);
511       if (cache.has_cache_dir()) {
512         if (cache.has_size()) {
513           base::FilePath cache_dir = origin_path.AppendASCII(cache.cache_dir());
514           if (!GetFileInfo(cache_dir, &file_info) ||
515               index_last_modified <= file_info.last_modified) {
516             // Index is older than this cache, so invalidate index entries that
517             // may change as a result of cache operations.
518             index.mutable_cache(i)->clear_size();
519           }
520         }
521       } else {
522         // Find a new home for the cache.
523         base::FilePath legacy_cache_path =
524             origin_path.AppendASCII(HexedHash(cache.name()));
525         std::string cache_dir;
526         base::FilePath cache_path;
527         do {
528           cache_dir = base::GenerateGUID();
529           cache_path = origin_path.AppendASCII(cache_dir);
530         } while (base::PathExists(cache_path));
531 
532         if (!base::Move(legacy_cache_path, cache_path)) {
533           // If the move fails then the cache is in a bad state. Return an empty
534           // index so that the CacheStorage can start fresh. The unreferenced
535           // caches will be discarded later in initialization.
536           return proto::CacheStorageIndex();
537         }
538 
539         index.mutable_cache(i)->set_cache_dir(cache_dir);
540         index.mutable_cache(i)->clear_size();
541         index_modified = true;
542       }
543     }
544 
545     if (index_modified) {
546       base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp");
547       if (!index.SerializeToString(&body) ||
548           !WriteIndexWriteToFileInPool(tmp_path, index_path, body,
549                                        std::move(quota_manager_proxy),
550                                        origin)) {
551         return proto::CacheStorageIndex();
552       }
553     }
554 
555     return index;
556   }
557 
558   const base::FilePath origin_path_;
559   std::map<std::string, std::string> cache_name_to_cache_dir_;
560   std::map<CacheStorageCache*, std::string> doomed_cache_to_path_;
561 
562   SEQUENCE_CHECKER(sequence_checker_);
563   base::WeakPtrFactory<SimpleCacheLoader> weak_ptr_factory_{this};
564 };
565 
LegacyCacheStorage(const base::FilePath & path,bool memory_only,base::SequencedTaskRunner * cache_task_runner,scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,scoped_refptr<BlobStorageContextWrapper> blob_storage_context,LegacyCacheStorageManager * cache_storage_manager,const url::Origin & origin,CacheStorageOwner owner)566 LegacyCacheStorage::LegacyCacheStorage(
567     const base::FilePath& path,
568     bool memory_only,
569     base::SequencedTaskRunner* cache_task_runner,
570     scoped_refptr<base::SequencedTaskRunner> scheduler_task_runner,
571     scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
572     scoped_refptr<BlobStorageContextWrapper> blob_storage_context,
573     LegacyCacheStorageManager* cache_storage_manager,
574     const url::Origin& origin,
575     CacheStorageOwner owner)
576     : CacheStorage(origin),
577       initialized_(false),
578       initializing_(false),
579       memory_only_(memory_only),
580       scheduler_(
581           new CacheStorageScheduler(CacheStorageSchedulerClient::kStorage,
582                                     scheduler_task_runner)),
583       origin_path_(path),
584       cache_task_runner_(cache_task_runner),
585       quota_manager_proxy_(quota_manager_proxy),
586       blob_storage_context_(std::move(blob_storage_context)),
587       owner_(owner),
588       cache_storage_manager_(cache_storage_manager) {
589   if (memory_only) {
590     cache_loader_.reset(new MemoryLoader(
591         cache_task_runner_.get(), std::move(scheduler_task_runner),
592         quota_manager_proxy, blob_storage_context_, this, origin, owner));
593     return;
594   }
595 
596   cache_loader_.reset(new SimpleCacheLoader(
597       origin_path_, cache_task_runner_.get(), std::move(scheduler_task_runner),
598       quota_manager_proxy, blob_storage_context_, this, origin, owner));
599 
600 #if defined(OS_ANDROID)
601   app_status_listener_ = base::android::ApplicationStatusListener::New(
602       base::BindRepeating(&LegacyCacheStorage::OnApplicationStateChange,
603                           weak_factory_.GetWeakPtr()));
604 #endif
605 }
606 
~LegacyCacheStorage()607 LegacyCacheStorage::~LegacyCacheStorage() {
608   FlushIndexIfDirty();
609 }
610 
CreateHandle()611 CacheStorageHandle LegacyCacheStorage::CreateHandle() {
612   return CacheStorageHandle(weak_factory_.GetWeakPtr());
613 }
614 
AddHandleRef()615 void LegacyCacheStorage::AddHandleRef() {
616   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
617   handle_ref_count_ += 1;
618 }
619 
DropHandleRef()620 void LegacyCacheStorage::DropHandleRef() {
621   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622   DCHECK_GT(handle_ref_count_, 0U);
623   handle_ref_count_ -= 1;
624   if (!handle_ref_count_ && cache_storage_manager_) {
625     ReleaseUnreferencedCaches();
626     cache_storage_manager_->CacheStorageUnreferenced(this, origin_, owner_);
627   }
628 }
629 
OpenCache(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback)630 void LegacyCacheStorage::OpenCache(const std::string& cache_name,
631                                    int64_t trace_id,
632                                    CacheAndErrorCallback callback) {
633   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
634 
635   if (!initialized_)
636     LazyInit();
637 
638   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
639 
640   // TODO: Hold a handle to this CacheStorage instance while executing
641   //       operations to better support use by internal code that may
642   //       start a single operation without explicitly maintaining a
643   //       handle.
644   auto id = scheduler_->CreateId();
645   scheduler_->ScheduleOperation(
646       id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kOpen,
647       CacheStorageSchedulerPriority::kNormal,
648       base::BindOnce(
649           &LegacyCacheStorage::OpenCacheImpl, weak_factory_.GetWeakPtr(),
650           cache_name, trace_id,
651           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
652 }
653 
HasCache(const std::string & cache_name,int64_t trace_id,BoolAndErrorCallback callback)654 void LegacyCacheStorage::HasCache(const std::string& cache_name,
655                                   int64_t trace_id,
656                                   BoolAndErrorCallback callback) {
657   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
658 
659   if (!initialized_)
660     LazyInit();
661 
662   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
663 
664   auto id = scheduler_->CreateId();
665   scheduler_->ScheduleOperation(
666       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kHas,
667       CacheStorageSchedulerPriority::kNormal,
668       base::BindOnce(
669           &LegacyCacheStorage::HasCacheImpl, weak_factory_.GetWeakPtr(),
670           cache_name, trace_id,
671           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
672 }
673 
DoomCache(const std::string & cache_name,int64_t trace_id,ErrorCallback callback)674 void LegacyCacheStorage::DoomCache(const std::string& cache_name,
675                                    int64_t trace_id,
676                                    ErrorCallback callback) {
677   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
678 
679   if (!initialized_)
680     LazyInit();
681 
682   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
683 
684   auto id = scheduler_->CreateId();
685   scheduler_->ScheduleOperation(
686       id, CacheStorageSchedulerMode::kExclusive,
687       CacheStorageSchedulerOp::kDelete, CacheStorageSchedulerPriority::kNormal,
688       base::BindOnce(
689           &LegacyCacheStorage::DoomCacheImpl, weak_factory_.GetWeakPtr(),
690           cache_name, trace_id,
691           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
692 }
693 
EnumerateCaches(int64_t trace_id,EnumerateCachesCallback callback)694 void LegacyCacheStorage::EnumerateCaches(int64_t trace_id,
695                                          EnumerateCachesCallback callback) {
696   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
697 
698   if (!initialized_)
699     LazyInit();
700 
701   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
702 
703   auto id = scheduler_->CreateId();
704   scheduler_->ScheduleOperation(
705       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys,
706       CacheStorageSchedulerPriority::kNormal,
707       base::BindOnce(
708           &LegacyCacheStorage::EnumerateCachesImpl, weak_factory_.GetWeakPtr(),
709           trace_id,
710           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
711 }
712 
MatchCache(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)713 void LegacyCacheStorage::MatchCache(
714     const std::string& cache_name,
715     blink::mojom::FetchAPIRequestPtr request,
716     blink::mojom::CacheQueryOptionsPtr match_options,
717     CacheStorageSchedulerPriority priority,
718     int64_t trace_id,
719     CacheStorageCache::ResponseCallback callback) {
720   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
721 
722   if (!initialized_)
723     LazyInit();
724 
725   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
726 
727   auto id = scheduler_->CreateId();
728   scheduler_->ScheduleOperation(
729       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch,
730       CacheStorageSchedulerPriority::kNormal,
731       base::BindOnce(
732           &LegacyCacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(),
733           cache_name, std::move(request), std::move(match_options), priority,
734           trace_id,
735           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
736 }
737 
MatchAllCaches(blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)738 void LegacyCacheStorage::MatchAllCaches(
739     blink::mojom::FetchAPIRequestPtr request,
740     blink::mojom::CacheQueryOptionsPtr match_options,
741     CacheStorageSchedulerPriority priority,
742     int64_t trace_id,
743     CacheStorageCache::ResponseCallback callback) {
744   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
745 
746   if (!initialized_)
747     LazyInit();
748 
749   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
750 
751   auto id = scheduler_->CreateId();
752   scheduler_->ScheduleOperation(
753       id, CacheStorageSchedulerMode::kShared,
754       CacheStorageSchedulerOp::kMatchAll,
755       CacheStorageSchedulerPriority::kNormal,
756       base::BindOnce(
757           &LegacyCacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(),
758           std::move(request), std::move(match_options), priority, trace_id,
759           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
760 }
761 
WriteToCache(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::FetchAPIResponsePtr response,int64_t trace_id,LegacyCacheStorage::ErrorCallback callback)762 void LegacyCacheStorage::WriteToCache(
763     const std::string& cache_name,
764     blink::mojom::FetchAPIRequestPtr request,
765     blink::mojom::FetchAPIResponsePtr response,
766     int64_t trace_id,
767     LegacyCacheStorage::ErrorCallback callback) {
768   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
769 
770   if (!initialized_)
771     LazyInit();
772 
773   quota_manager_proxy_->NotifyStorageAccessed(origin_, StorageType::kTemporary);
774 
775   // Note, this is a shared operation since it only reads CacheStorage data.
776   // The CacheStorageCache is responsible for making its put operation
777   // exclusive.
778   auto id = scheduler_->CreateId();
779   scheduler_->ScheduleOperation(
780       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kPut,
781       CacheStorageSchedulerPriority::kNormal,
782       base::BindOnce(
783           &LegacyCacheStorage::WriteToCacheImpl, weak_factory_.GetWeakPtr(),
784           cache_name, std::move(request), std::move(response), trace_id,
785           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
786 }
787 
GetSizeThenCloseAllCaches(SizeCallback callback)788 void LegacyCacheStorage::GetSizeThenCloseAllCaches(SizeCallback callback) {
789   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
790 
791   if (!initialized_)
792     LazyInit();
793 
794   // Note, this is a shared operation since it only reads CacheStorage data.
795   // The CacheStorageCache is responsible for making its close operation
796   // exclusive.
797   auto id = scheduler_->CreateId();
798   scheduler_->ScheduleOperation(
799       id, CacheStorageSchedulerMode::kShared,
800       CacheStorageSchedulerOp::kSizeThenClose,
801       CacheStorageSchedulerPriority::kNormal,
802       base::BindOnce(
803           &LegacyCacheStorage::GetSizeThenCloseAllCachesImpl,
804           weak_factory_.GetWeakPtr(),
805           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
806 }
807 
Size(LegacyCacheStorage::SizeCallback callback)808 void LegacyCacheStorage::Size(LegacyCacheStorage::SizeCallback callback) {
809   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
810 
811   if (!initialized_)
812     LazyInit();
813 
814   auto id = scheduler_->CreateId();
815   scheduler_->ScheduleOperation(
816       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize,
817       CacheStorageSchedulerPriority::kNormal,
818       base::BindOnce(
819           &LegacyCacheStorage::SizeImpl, weak_factory_.GetWeakPtr(),
820           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
821 }
822 
ResetManager()823 void LegacyCacheStorage::ResetManager() {
824   cache_storage_manager_ = nullptr;
825 }
826 
NotifyCacheContentChanged(const std::string & cache_name)827 void LegacyCacheStorage::NotifyCacheContentChanged(
828     const std::string& cache_name) {
829   if (cache_storage_manager_)
830     cache_storage_manager_->NotifyCacheContentChanged(origin_, cache_name);
831 }
832 
ScheduleWriteIndex()833 void LegacyCacheStorage::ScheduleWriteIndex() {
834   // These values are chosen to be equal or greater than the simple disk_cache
835   // index write delays.  We want the cache_storage index to be written last.
836   static const int64_t kWriteIndexDelayMilliseconds = 20050;
837   static const int64_t kWriteIndexBackgroundDelayMilliseconds = 150;
838   int64_t delay_ms = app_on_background_ ? kWriteIndexBackgroundDelayMilliseconds
839                                         : kWriteIndexDelayMilliseconds;
840   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
841   index_write_task_.Reset(base::BindOnce(&LegacyCacheStorage::WriteIndex,
842                                          weak_factory_.GetWeakPtr(),
843                                          base::DoNothing::Once<bool>()));
844   base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
845       FROM_HERE, index_write_task_.callback(),
846       base::TimeDelta::FromMilliseconds(delay_ms));
847 }
848 
WriteIndex(base::OnceCallback<void (bool)> callback)849 void LegacyCacheStorage::WriteIndex(base::OnceCallback<void(bool)> callback) {
850   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
851   auto id = scheduler_->CreateId();
852   scheduler_->ScheduleOperation(
853       id, CacheStorageSchedulerMode::kExclusive,
854       CacheStorageSchedulerOp::kWriteIndex,
855       CacheStorageSchedulerPriority::kNormal,
856       base::BindOnce(
857           &LegacyCacheStorage::WriteIndexImpl, weak_factory_.GetWeakPtr(),
858           scheduler_->WrapCallbackToRunNext(id, std::move(callback))));
859 }
860 
WriteIndexImpl(base::OnceCallback<void (bool)> callback)861 void LegacyCacheStorage::WriteIndexImpl(
862     base::OnceCallback<void(bool)> callback) {
863   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
864   DCHECK(scheduler_->IsRunningExclusiveOperation());
865   cache_loader_->WriteIndex(*cache_index_, std::move(callback));
866 }
867 
InitiateScheduledIndexWriteForTest(base::OnceCallback<void (bool)> callback)868 bool LegacyCacheStorage::InitiateScheduledIndexWriteForTest(
869     base::OnceCallback<void(bool)> callback) {
870   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
871   if (index_write_pending()) {
872     index_write_task_.Cancel();
873     WriteIndex(std::move(callback));
874     return true;
875   }
876   std::move(callback).Run(true /* success */);
877   return false;
878 }
879 
CacheSizeUpdated(const LegacyCacheStorageCache * cache)880 void LegacyCacheStorage::CacheSizeUpdated(
881     const LegacyCacheStorageCache* cache) {
882   // Should not be called for doomed caches.
883   DCHECK(!base::Contains(doomed_caches_,
884                          const_cast<LegacyCacheStorageCache*>(cache)));
885   DCHECK_NE(cache->cache_padding(), kSizeUnknown);
886   bool size_changed =
887       cache_index_->SetCacheSize(cache->cache_name(), cache->cache_size());
888   bool padding_changed = cache_index_->SetCachePadding(cache->cache_name(),
889                                                        cache->cache_padding());
890   if (size_changed || padding_changed)
891     ScheduleWriteIndex();
892 }
893 
ReleaseUnreferencedCaches()894 void LegacyCacheStorage::ReleaseUnreferencedCaches() {
895   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
896   for (auto& entry : cache_map_) {
897     if (entry.second && entry.second->IsUnreferenced())
898       entry.second.reset();
899   }
900 }
901 
CacheUnreferenced(LegacyCacheStorageCache * cache)902 void LegacyCacheStorage::CacheUnreferenced(LegacyCacheStorageCache* cache) {
903   DCHECK(cache);
904   DCHECK(cache->IsUnreferenced());
905   auto doomed_caches_it = doomed_caches_.find(cache);
906   if (doomed_caches_it != doomed_caches_.end()) {
907     // The last reference to a doomed cache is gone, perform clean up.
908     DeleteCacheFinalize(cache);
909     return;
910   }
911 
912   // Opportunistically keep warmed caches open when the CacheStorage is
913   // still actively referenced.  Repeatedly opening and closing simple
914   // disk_cache backends can be quite slow.  This is easy to trigger when
915   // a site uses caches.match() frequently because the a Cache object is
916   // never exposed to script to explicitly hold the backend open.
917   if (handle_ref_count_)
918     return;
919 
920   // The CacheStorage is not actively being referenced.  Close the cache
921   // immediately.
922   auto cache_map_it = cache_map_.find(cache->cache_name());
923   DCHECK(cache_map_it != cache_map_.end());
924 
925   cache_map_it->second.reset();
926 }
927 
StartAsyncOperationForTesting()928 CacheStorageSchedulerId LegacyCacheStorage::StartAsyncOperationForTesting() {
929   auto id = scheduler_->CreateId();
930   scheduler_->ScheduleOperation(
931       id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest,
932       CacheStorageSchedulerPriority::kNormal, base::DoNothing());
933   return id;
934 }
935 
CompleteAsyncOperationForTesting(CacheStorageSchedulerId id)936 void LegacyCacheStorage::CompleteAsyncOperationForTesting(
937     CacheStorageSchedulerId id) {
938   scheduler_->CompleteOperationAndRunNext(id);
939 }
940 
941 // Init is run lazily so that it is called on the proper MessageLoop.
LazyInit()942 void LegacyCacheStorage::LazyInit() {
943   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
944   DCHECK(!initialized_);
945 
946   if (initializing_)
947     return;
948 
949   DCHECK(!scheduler_->ScheduledOperations());
950 
951   initializing_ = true;
952   init_id_ = scheduler_->CreateId();
953   scheduler_->ScheduleOperation(
954       init_id_, CacheStorageSchedulerMode::kExclusive,
955       CacheStorageSchedulerOp::kInit, CacheStorageSchedulerPriority::kNormal,
956       base::BindOnce(&LegacyCacheStorage::LazyInitImpl,
957                      weak_factory_.GetWeakPtr()));
958 }
959 
LazyInitImpl()960 void LegacyCacheStorage::LazyInitImpl() {
961   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
962   DCHECK(!initialized_);
963   DCHECK(initializing_);
964 
965   // 1. Get the cache index (async call)
966   // 2. For each cache name, load the cache (async call)
967   // 3. Once each load is complete, update the map variables.
968   // 4. Call the list of waiting callbacks.
969 
970   DCHECK(scheduler_->IsRunningExclusiveOperation());
971   cache_loader_->LoadIndex(base::BindOnce(
972       &LegacyCacheStorage::LazyInitDidLoadIndex, weak_factory_.GetWeakPtr()));
973 }
974 
LazyInitDidLoadIndex(std::unique_ptr<CacheStorageIndex> index)975 void LegacyCacheStorage::LazyInitDidLoadIndex(
976     std::unique_ptr<CacheStorageIndex> index) {
977   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
978   DCHECK(cache_map_.empty());
979 
980   for (const auto& cache_metadata : index->ordered_cache_metadata()) {
981     cache_map_.insert(std::make_pair(cache_metadata.name, nullptr));
982   }
983 
984   DCHECK(!cache_index_);
985   cache_index_ = std::move(index);
986 
987   initializing_ = false;
988   initialized_ = true;
989 
990   scheduler_->CompleteOperationAndRunNext(init_id_);
991 }
992 
OpenCacheImpl(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback)993 void LegacyCacheStorage::OpenCacheImpl(const std::string& cache_name,
994                                        int64_t trace_id,
995                                        CacheAndErrorCallback callback) {
996   TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::OpenCacheImpl",
997                          TRACE_ID_GLOBAL(trace_id),
998                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
999                          "cache_name", cache_name);
1000   CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1001   if (cache_handle.value()) {
1002     std::move(callback).Run(std::move(cache_handle),
1003                             CacheStorageError::kSuccess);
1004     return;
1005   }
1006 
1007   DCHECK(scheduler_->IsRunningExclusiveOperation());
1008   cache_loader_->PrepareNewCacheDestination(
1009       cache_name, base::BindOnce(&LegacyCacheStorage::CreateCacheDidCreateCache,
1010                                  weak_factory_.GetWeakPtr(), cache_name,
1011                                  trace_id, std::move(callback)));
1012 }
1013 
CreateCacheDidCreateCache(const std::string & cache_name,int64_t trace_id,CacheAndErrorCallback callback,std::unique_ptr<LegacyCacheStorageCache> cache)1014 void LegacyCacheStorage::CreateCacheDidCreateCache(
1015     const std::string& cache_name,
1016     int64_t trace_id,
1017     CacheAndErrorCallback callback,
1018     std::unique_ptr<LegacyCacheStorageCache> cache) {
1019   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1020 
1021   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1022                          "LegacyCacheStorage::CreateCacheDidCreateCache",
1023                          TRACE_ID_GLOBAL(trace_id),
1024                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1025 
1026   UMA_HISTOGRAM_BOOLEAN("ServiceWorkerCache.CreateCacheStorageResult",
1027                         static_cast<bool>(cache));
1028 
1029   if (!cache) {
1030     std::move(callback).Run(
1031         CacheStorageCacheHandle(),
1032         MakeErrorStorage(ErrorStorageType::kDidCreateNullCache));
1033     return;
1034   }
1035 
1036   LegacyCacheStorageCache* cache_ptr = cache.get();
1037 
1038   cache_map_.insert(std::make_pair(cache_name, std::move(cache)));
1039   cache_index_->Insert(CacheStorageIndex::CacheMetadata(
1040       cache_name, cache_ptr->cache_size(), cache_ptr->cache_padding(),
1041       cache_ptr->cache_padding_key()->key()));
1042 
1043   CacheStorageCacheHandle handle = cache_ptr->CreateHandle();
1044   index_write_task_.Cancel();
1045   cache_loader_->WriteIndex(
1046       *cache_index_,
1047       base::BindOnce(&LegacyCacheStorage::CreateCacheDidWriteIndex,
1048                      weak_factory_.GetWeakPtr(), std::move(callback),
1049                      cache_ptr->CreateHandle(), trace_id));
1050 
1051   cache_loader_->NotifyCacheCreated(cache_name, std::move(handle));
1052   if (cache_storage_manager_)
1053     cache_storage_manager_->NotifyCacheListChanged(origin_);
1054 }
1055 
CreateCacheDidWriteIndex(CacheAndErrorCallback callback,CacheStorageCacheHandle cache_handle,int64_t trace_id,bool success)1056 void LegacyCacheStorage::CreateCacheDidWriteIndex(
1057     CacheAndErrorCallback callback,
1058     CacheStorageCacheHandle cache_handle,
1059     int64_t trace_id,
1060     bool success) {
1061   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1062   DCHECK(cache_handle.value());
1063 
1064   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1065                          "LegacyCacheStorage::CreateCacheDidWriteIndex",
1066                          TRACE_ID_GLOBAL(trace_id),
1067                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1068 
1069   // TODO(jkarlin): Handle !success.
1070 
1071   std::move(callback).Run(std::move(cache_handle), CacheStorageError::kSuccess);
1072 }
1073 
HasCacheImpl(const std::string & cache_name,int64_t trace_id,BoolAndErrorCallback callback)1074 void LegacyCacheStorage::HasCacheImpl(const std::string& cache_name,
1075                                       int64_t trace_id,
1076                                       BoolAndErrorCallback callback) {
1077   TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::HasCacheImpl",
1078                          TRACE_ID_GLOBAL(trace_id),
1079                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1080                          "cache_name", cache_name);
1081   bool has_cache = base::Contains(cache_map_, cache_name);
1082   std::move(callback).Run(has_cache, CacheStorageError::kSuccess);
1083 }
1084 
DoomCacheImpl(const std::string & cache_name,int64_t trace_id,ErrorCallback callback)1085 void LegacyCacheStorage::DoomCacheImpl(const std::string& cache_name,
1086                                        int64_t trace_id,
1087                                        ErrorCallback callback) {
1088   TRACE_EVENT_WITH_FLOW1("CacheStorage", "LegacyCacheStorage::DoomCacheImpl",
1089                          TRACE_ID_GLOBAL(trace_id),
1090                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1091                          "cache_name", cache_name);
1092   CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1093   if (!cache_handle.value()) {
1094     base::SequencedTaskRunnerHandle::Get()->PostTask(
1095         FROM_HERE,
1096         base::BindOnce(std::move(callback), CacheStorageError::kErrorNotFound));
1097     return;
1098   }
1099 
1100   DCHECK(scheduler_->IsRunningExclusiveOperation());
1101   LegacyCacheStorageCache::From(cache_handle)->SetObserver(nullptr);
1102   cache_index_->DoomCache(cache_name);
1103   index_write_task_.Cancel();
1104   cache_loader_->WriteIndex(
1105       *cache_index_,
1106       base::BindOnce(&LegacyCacheStorage::DeleteCacheDidWriteIndex,
1107                      weak_factory_.GetWeakPtr(), std::move(cache_handle),
1108                      std::move(callback), trace_id));
1109 }
1110 
DeleteCacheDidWriteIndex(CacheStorageCacheHandle cache_handle,ErrorCallback callback,int64_t trace_id,bool success)1111 void LegacyCacheStorage::DeleteCacheDidWriteIndex(
1112     CacheStorageCacheHandle cache_handle,
1113     ErrorCallback callback,
1114     int64_t trace_id,
1115     bool success) {
1116   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1117   auto* impl = LegacyCacheStorageCache::From(cache_handle);
1118 
1119   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1120                          "LegacyCacheStorage::DeleteCacheDidWriteIndex",
1121                          TRACE_ID_GLOBAL(trace_id),
1122                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1123 
1124   if (!success) {
1125     // Undo any changes if the index couldn't be written to disk.
1126     cache_index_->RestoreDoomedCache();
1127     impl->SetObserver(this);
1128     std::move(callback).Run(
1129         MakeErrorStorage(ErrorStorageType::kDeleteCacheFailed));
1130     return;
1131   }
1132 
1133   cache_index_->FinalizeDoomedCache();
1134 
1135   auto map_iter = cache_map_.find(impl->cache_name());
1136   DCHECK(map_iter != cache_map_.end());
1137 
1138   doomed_caches_.insert(
1139       std::make_pair(map_iter->second.get(), std::move(map_iter->second)));
1140   cache_map_.erase(map_iter);
1141 
1142   cache_loader_->NotifyCacheDoomed(std::move(cache_handle));
1143   if (cache_storage_manager_)
1144     cache_storage_manager_->NotifyCacheListChanged(origin_);
1145 
1146   std::move(callback).Run(CacheStorageError::kSuccess);
1147 }
1148 
1149 // Call this once the last handle to a doomed cache is gone. It's okay if this
1150 // doesn't get to complete before shutdown, the cache will be removed from disk
1151 // on next startup in that case.
DeleteCacheFinalize(LegacyCacheStorageCache * doomed_cache)1152 void LegacyCacheStorage::DeleteCacheFinalize(
1153     LegacyCacheStorageCache* doomed_cache) {
1154   doomed_cache->Size(base::BindOnce(&LegacyCacheStorage::DeleteCacheDidGetSize,
1155                                     weak_factory_.GetWeakPtr(), doomed_cache));
1156 }
1157 
DeleteCacheDidGetSize(LegacyCacheStorageCache * doomed_cache,int64_t cache_size)1158 void LegacyCacheStorage::DeleteCacheDidGetSize(
1159     LegacyCacheStorageCache* doomed_cache,
1160     int64_t cache_size) {
1161   quota_manager_proxy_->NotifyStorageModified(
1162       CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_,
1163       StorageType::kTemporary, -1 * cache_size);
1164 
1165   cache_loader_->CleanUpDeletedCache(doomed_cache);
1166   auto doomed_caches_iter = doomed_caches_.find(doomed_cache);
1167   DCHECK(doomed_caches_iter != doomed_caches_.end());
1168   doomed_caches_.erase(doomed_caches_iter);
1169 }
1170 
EnumerateCachesImpl(int64_t trace_id,EnumerateCachesCallback callback)1171 void LegacyCacheStorage::EnumerateCachesImpl(int64_t trace_id,
1172                                              EnumerateCachesCallback callback) {
1173   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1174                          "LegacyCacheStorage::EnumerateCachesImpl",
1175                          TRACE_ID_GLOBAL(trace_id),
1176                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1177 
1178   std::vector<std::string> list;
1179 
1180   for (const auto& metadata : cache_index_->ordered_cache_metadata()) {
1181     list.push_back(metadata.name);
1182   }
1183 
1184   std::move(callback).Run(std::move(list));
1185 }
1186 
MatchCacheImpl(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1187 void LegacyCacheStorage::MatchCacheImpl(
1188     const std::string& cache_name,
1189     blink::mojom::FetchAPIRequestPtr request,
1190     blink::mojom::CacheQueryOptionsPtr match_options,
1191     CacheStorageSchedulerPriority priority,
1192     int64_t trace_id,
1193     CacheStorageCache::ResponseCallback callback) {
1194   TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::MatchCacheImpl",
1195                          TRACE_ID_GLOBAL(trace_id),
1196                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1197                          "cache_name", cache_name, "request",
1198                          CacheStorageTracedValue(request));
1199 
1200   CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1201 
1202   if (!cache_handle.value()) {
1203     std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound,
1204                             nullptr);
1205     return;
1206   }
1207 
1208   // Pass the cache handle along to the callback to keep the cache open until
1209   // match is done.
1210   CacheStorageCache* cache_ptr = cache_handle.value();
1211   cache_ptr->Match(
1212       std::move(request), std::move(match_options), priority, trace_id,
1213       base::BindOnce(&LegacyCacheStorage::MatchCacheDidMatch,
1214                      weak_factory_.GetWeakPtr(), std::move(cache_handle),
1215                      trace_id, std::move(callback)));
1216 }
1217 
MatchCacheDidMatch(CacheStorageCacheHandle cache_handle,int64_t trace_id,CacheStorageCache::ResponseCallback callback,CacheStorageError error,blink::mojom::FetchAPIResponsePtr response)1218 void LegacyCacheStorage::MatchCacheDidMatch(
1219     CacheStorageCacheHandle cache_handle,
1220     int64_t trace_id,
1221     CacheStorageCache::ResponseCallback callback,
1222     CacheStorageError error,
1223     blink::mojom::FetchAPIResponsePtr response) {
1224   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1225                          "LegacyCacheStorage::MatchCacheDidMatch",
1226                          TRACE_ID_GLOBAL(trace_id),
1227                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1228   std::move(callback).Run(error, std::move(response));
1229 }
1230 
MatchAllCachesImpl(blink::mojom::FetchAPIRequestPtr request,blink::mojom::CacheQueryOptionsPtr match_options,CacheStorageSchedulerPriority priority,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1231 void LegacyCacheStorage::MatchAllCachesImpl(
1232     blink::mojom::FetchAPIRequestPtr request,
1233     blink::mojom::CacheQueryOptionsPtr match_options,
1234     CacheStorageSchedulerPriority priority,
1235     int64_t trace_id,
1236     CacheStorageCache::ResponseCallback callback) {
1237   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1238                          "LegacyCacheStorage::MatchAllCachesImpl",
1239                          TRACE_ID_GLOBAL(trace_id),
1240                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1241 
1242   std::vector<CacheMatchResponse>* match_responses =
1243       new std::vector<CacheMatchResponse>(cache_index_->num_entries());
1244 
1245   base::RepeatingClosure barrier_closure = base::BarrierClosure(
1246       cache_index_->num_entries(),
1247       base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatchAll,
1248                      weak_factory_.GetWeakPtr(),
1249                      base::WrapUnique(match_responses), trace_id,
1250                      std::move(callback)));
1251 
1252   size_t idx = 0;
1253   for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1254     CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name);
1255     DCHECK(cache_handle.value());
1256 
1257     CacheStorageCache* cache_ptr = cache_handle.value();
1258     cache_ptr->Match(
1259         BackgroundFetchSettledFetch::CloneRequest(request),
1260         match_options ? match_options->Clone() : nullptr, priority, trace_id,
1261         base::BindOnce(&LegacyCacheStorage::MatchAllCachesDidMatch,
1262                        weak_factory_.GetWeakPtr(), std::move(cache_handle),
1263                        &match_responses->at(idx), barrier_closure, trace_id));
1264     idx++;
1265   }
1266 }
1267 
MatchAllCachesDidMatch(CacheStorageCacheHandle cache_handle,CacheMatchResponse * out_match_response,const base::RepeatingClosure & barrier_closure,int64_t trace_id,CacheStorageError error,blink::mojom::FetchAPIResponsePtr response)1268 void LegacyCacheStorage::MatchAllCachesDidMatch(
1269     CacheStorageCacheHandle cache_handle,
1270     CacheMatchResponse* out_match_response,
1271     const base::RepeatingClosure& barrier_closure,
1272     int64_t trace_id,
1273     CacheStorageError error,
1274     blink::mojom::FetchAPIResponsePtr response) {
1275   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1276                          "LegacyCacheStorage::MatchAllCachesDidMatch",
1277                          TRACE_ID_GLOBAL(trace_id),
1278                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1279   out_match_response->error = error;
1280   out_match_response->response = std::move(response);
1281   barrier_closure.Run();
1282 }
1283 
MatchAllCachesDidMatchAll(std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,int64_t trace_id,CacheStorageCache::ResponseCallback callback)1284 void LegacyCacheStorage::MatchAllCachesDidMatchAll(
1285     std::unique_ptr<std::vector<CacheMatchResponse>> match_responses,
1286     int64_t trace_id,
1287     CacheStorageCache::ResponseCallback callback) {
1288   TRACE_EVENT_WITH_FLOW0("CacheStorage",
1289                          "LegacyCacheStorage::MatchAllCachesDidMatchAll",
1290                          TRACE_ID_GLOBAL(trace_id),
1291                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1292   for (CacheMatchResponse& match_response : *match_responses) {
1293     if (match_response.error == CacheStorageError::kErrorNotFound)
1294       continue;
1295     std::move(callback).Run(match_response.error,
1296                             std::move(match_response.response));
1297     return;
1298   }
1299   std::move(callback).Run(CacheStorageError::kErrorNotFound, nullptr);
1300 }
1301 
WriteToCacheImpl(const std::string & cache_name,blink::mojom::FetchAPIRequestPtr request,blink::mojom::FetchAPIResponsePtr response,int64_t trace_id,LegacyCacheStorage::ErrorCallback callback)1302 void LegacyCacheStorage::WriteToCacheImpl(
1303     const std::string& cache_name,
1304     blink::mojom::FetchAPIRequestPtr request,
1305     blink::mojom::FetchAPIResponsePtr response,
1306     int64_t trace_id,
1307     LegacyCacheStorage::ErrorCallback callback) {
1308   TRACE_EVENT_WITH_FLOW2("CacheStorage", "LegacyCacheStorage::WriteToCacheImpl",
1309                          TRACE_ID_GLOBAL(trace_id),
1310                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1311                          "cache_name", cache_name, "request",
1312                          CacheStorageTracedValue(request));
1313 
1314   CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_name);
1315 
1316   if (!cache_handle.value()) {
1317     std::move(callback).Run(CacheStorageError::kErrorCacheNameNotFound);
1318     return;
1319   }
1320 
1321   CacheStorageCache* cache_ptr = cache_handle.value();
1322   DCHECK(cache_ptr);
1323 
1324   cache_ptr->Put(std::move(request), std::move(response), trace_id,
1325                  std::move(callback));
1326 }
1327 
GetLoadedCache(const std::string & cache_name)1328 CacheStorageCacheHandle LegacyCacheStorage::GetLoadedCache(
1329     const std::string& cache_name) {
1330   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1331   DCHECK(initialized_);
1332 
1333   auto map_iter = cache_map_.find(cache_name);
1334   if (map_iter == cache_map_.end())
1335     return CacheStorageCacheHandle();
1336 
1337   CacheStorageCache* cache = map_iter->second.get();
1338 
1339   if (!cache) {
1340     const CacheStorageIndex::CacheMetadata* metadata =
1341         cache_index_->GetMetadata(cache_name);
1342     DCHECK(metadata);
1343     std::unique_ptr<LegacyCacheStorageCache> new_cache =
1344         cache_loader_->CreateCache(
1345             cache_name, metadata->size, metadata->padding,
1346             storage::DeserializePaddingKey(metadata->padding_key));
1347     CacheStorageCache* cache_ptr = new_cache.get();
1348     map_iter->second = std::move(new_cache);
1349 
1350     return cache_ptr->CreateHandle();
1351   }
1352 
1353   return cache->CreateHandle();
1354 }
1355 
SizeRetrievedFromCache(CacheStorageCacheHandle cache_handle,base::OnceClosure closure,int64_t * accumulator,int64_t size)1356 void LegacyCacheStorage::SizeRetrievedFromCache(
1357     CacheStorageCacheHandle cache_handle,
1358     base::OnceClosure closure,
1359     int64_t* accumulator,
1360     int64_t size) {
1361   auto* impl = LegacyCacheStorageCache::From(cache_handle);
1362   if (doomed_caches_.find(impl) == doomed_caches_.end())
1363     cache_index_->SetCacheSize(impl->cache_name(), size);
1364   *accumulator += size;
1365   std::move(closure).Run();
1366 }
1367 
GetSizeThenCloseAllCachesImpl(SizeCallback callback)1368 void LegacyCacheStorage::GetSizeThenCloseAllCachesImpl(SizeCallback callback) {
1369   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1370   DCHECK(initialized_);
1371 
1372   std::unique_ptr<int64_t> accumulator(new int64_t(0));
1373   int64_t* accumulator_ptr = accumulator.get();
1374 
1375   base::RepeatingClosure barrier_closure = base::BarrierClosure(
1376       cache_index_->num_entries() + doomed_caches_.size(),
1377       base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator),
1378                      std::move(callback)));
1379 
1380   for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1381     auto cache_handle = GetLoadedCache(cache_metadata.name);
1382     LegacyCacheStorageCache::From(cache_handle)
1383         ->GetSizeThenClose(
1384             base::BindOnce(&LegacyCacheStorage::SizeRetrievedFromCache,
1385                            weak_factory_.GetWeakPtr(), std::move(cache_handle),
1386                            barrier_closure, accumulator_ptr));
1387   }
1388 
1389   for (const auto& cache_it : doomed_caches_) {
1390     LegacyCacheStorageCache* cache = cache_it.first;
1391     cache->GetSizeThenClose(base::BindOnce(
1392         &LegacyCacheStorage::SizeRetrievedFromCache, weak_factory_.GetWeakPtr(),
1393         cache->CreateHandle(), barrier_closure, accumulator_ptr));
1394   }
1395 }
1396 
SizeImpl(SizeCallback callback)1397 void LegacyCacheStorage::SizeImpl(SizeCallback callback) {
1398   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1399   DCHECK(initialized_);
1400 
1401   if (cache_index_->GetPaddedStorageSize() != kSizeUnknown) {
1402     base::SequencedTaskRunnerHandle::Get()->PostTask(
1403         FROM_HERE, base::BindOnce(std::move(callback),
1404                                   cache_index_->GetPaddedStorageSize()));
1405     return;
1406   }
1407 
1408   std::unique_ptr<int64_t> accumulator(new int64_t(0));
1409   int64_t* accumulator_ptr = accumulator.get();
1410 
1411   base::RepeatingClosure barrier_closure = base::BarrierClosure(
1412       cache_index_->num_entries(),
1413       base::BindOnce(&SizeRetrievedFromAllCaches, std::move(accumulator),
1414                      std::move(callback)));
1415 
1416   for (const auto& cache_metadata : cache_index_->ordered_cache_metadata()) {
1417     if (cache_metadata.size != LegacyCacheStorage::kSizeUnknown) {
1418       *accumulator_ptr += cache_metadata.size;
1419       barrier_closure.Run();
1420       continue;
1421     }
1422     CacheStorageCacheHandle cache_handle = GetLoadedCache(cache_metadata.name);
1423     LegacyCacheStorageCache::From(cache_handle)
1424         ->Size(base::BindOnce(&LegacyCacheStorage::SizeRetrievedFromCache,
1425                               weak_factory_.GetWeakPtr(),
1426                               std::move(cache_handle), barrier_closure,
1427                               accumulator_ptr));
1428   }
1429 }
1430 
FlushIndexIfDirty()1431 void LegacyCacheStorage::FlushIndexIfDirty() {
1432   if (!index_write_pending())
1433     return;
1434   index_write_task_.Cancel();
1435   cache_loader_->WriteIndex(*cache_index_, base::DoNothing::Once<bool>());
1436 }
1437 
1438 #if defined(OS_ANDROID)
OnApplicationStateChange(base::android::ApplicationState state)1439 void LegacyCacheStorage::OnApplicationStateChange(
1440     base::android::ApplicationState state) {
1441   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1442   if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) {
1443     app_on_background_ = false;
1444   } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) {
1445     app_on_background_ = true;
1446     FlushIndexIfDirty();
1447   }
1448 }
1449 #endif
1450 
1451 }  // namespace content
1452