1 // Copyright 2018 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/browsing_data/storage_partition_code_cache_data_remover.h"
6 
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/sequenced_task_runner_helpers.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/task/post_task.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "content/browser/browsing_data/conditional_cache_deletion_helper.h"
15 #include "content/browser/code_cache/generated_code_cache.h"
16 #include "content/browser/code_cache/generated_code_cache_context.h"
17 #include "content/public/browser/browser_task_traits.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/storage_partition.h"
20 #include "content/public/common/content_features.h"
21 #include "net/base/completion_repeating_callback.h"
22 #include "net/disk_cache/disk_cache.h"
23 
24 namespace content {
25 
StoragePartitionCodeCacheDataRemover(GeneratedCodeCacheContext * generated_code_cache_context,base::RepeatingCallback<bool (const GURL &)> url_predicate,base::Time begin_time,base::Time end_time)26 StoragePartitionCodeCacheDataRemover::StoragePartitionCodeCacheDataRemover(
27     GeneratedCodeCacheContext* generated_code_cache_context,
28     base::RepeatingCallback<bool(const GURL&)> url_predicate,
29     base::Time begin_time,
30     base::Time end_time)
31     : generated_code_cache_context_(generated_code_cache_context),
32       begin_time_(begin_time),
33       end_time_(end_time),
34       url_predicate_(std::move(url_predicate)) {}
35 
36 // static
37 StoragePartitionCodeCacheDataRemover*
Create(content::StoragePartition * storage_partition,base::RepeatingCallback<bool (const GURL &)> url_predicate,base::Time begin_time,base::Time end_time)38 StoragePartitionCodeCacheDataRemover::Create(
39     content::StoragePartition* storage_partition,
40     base::RepeatingCallback<bool(const GURL&)> url_predicate,
41     base::Time begin_time,
42     base::Time end_time) {
43   DCHECK_CURRENTLY_ON(BrowserThread::UI);
44   return new StoragePartitionCodeCacheDataRemover(
45       storage_partition->GetGeneratedCodeCacheContext(),
46       std::move(url_predicate), begin_time, end_time);
47 }
48 
~StoragePartitionCodeCacheDataRemover()49 StoragePartitionCodeCacheDataRemover::~StoragePartitionCodeCacheDataRemover() {}
50 
Remove(base::OnceClosure done_callback)51 void StoragePartitionCodeCacheDataRemover::Remove(
52     base::OnceClosure done_callback) {
53   DCHECK_CURRENTLY_ON(BrowserThread::UI);
54   DCHECK(!done_callback.is_null())
55       << __func__ << " called with a null callback";
56   done_callback_ = std::move(done_callback);
57 
58   ClearJSCodeCache();
59 }
60 
ClearCache(net::CompletionOnceCallback callback,disk_cache::Backend * backend)61 void StoragePartitionCodeCacheDataRemover::ClearCache(
62     net::CompletionOnceCallback callback,
63     disk_cache::Backend* backend) {
64   if (backend == nullptr) {
65     std::move(callback).Run(net::ERR_FAILED);
66     return;
67   }
68 
69   // Create a callback that is copyable, even though it can only be called once,
70   // so that we can use it synchronously in case result != net::ERR_IO_PENDING.
71   net::CompletionRepeatingCallback copyable_callback =
72       base::AdaptCallbackForRepeating(std::move(callback));
73   int result = net::ERR_FAILED;
74   if (!url_predicate_.is_null()) {
75     result =
76         (new ConditionalCacheDeletionHelper(
77              backend, ConditionalCacheDeletionHelper::CreateURLAndTimeCondition(
78                           std::move(url_predicate_),
79                           base::BindRepeating(
80                               &GeneratedCodeCache::GetResourceURLFromKey),
81                           begin_time_, end_time_)))
82             ->DeleteAndDestroySelfWhenFinished(copyable_callback);
83   } else if (begin_time_.is_null() && end_time_.is_max()) {
84     result = backend->DoomAllEntries(copyable_callback);
85   } else {
86     result =
87         backend->DoomEntriesBetween(begin_time_, end_time_, copyable_callback);
88   }
89   // When result is ERR_IO_PENDING the callback would be called after the
90   // operation has finished.
91   if (result != net::ERR_IO_PENDING) {
92     DCHECK(copyable_callback);
93     copyable_callback.Run(result);
94   }
95 }
96 
ClearJSCodeCache()97 void StoragePartitionCodeCacheDataRemover::ClearJSCodeCache() {
98   if (generated_code_cache_context_ &&
99       generated_code_cache_context_->generated_js_code_cache()) {
100     net::CompletionOnceCallback callback = base::BindOnce(
101         &StoragePartitionCodeCacheDataRemover::ClearWASMCodeCache,
102         base::Unretained(this));
103     generated_code_cache_context_->generated_js_code_cache()->GetBackend(
104         base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearCache,
105                        base::Unretained(this), std::move(callback)));
106   } else {
107     // When there is no JS cache, see if we need to remove WASM cache. When
108     // there is JS cache, the WASM cache would be removed after the JS cache.
109     ClearWASMCodeCache(net::ERR_FAILED);
110   }
111 }
112 
113 // |rv| is the returned when clearing the code cache. We don't handle
114 // any errors here, so the result value is ignored.
ClearWASMCodeCache(int rv)115 void StoragePartitionCodeCacheDataRemover::ClearWASMCodeCache(int rv) {
116   if (generated_code_cache_context_ &&
117       generated_code_cache_context_->generated_wasm_code_cache()) {
118     net::CompletionOnceCallback callback = base::BindOnce(
119         &StoragePartitionCodeCacheDataRemover::DoneClearCodeCache,
120         base::Unretained(this));
121     generated_code_cache_context_->generated_wasm_code_cache()->GetBackend(
122         base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearCache,
123                        base::Unretained(this), std::move(callback)));
124   } else {
125     // There is no Wasm cache, done with clearing caches.
126     DoneClearCodeCache(net::ERR_FAILED);
127   }
128 }
129 
130 // |rv| is the returned when clearing the code cache. We don't handle
131 // any errors here, so the result value is ignored.
DoneClearCodeCache(int rv)132 void StoragePartitionCodeCacheDataRemover::DoneClearCodeCache(int rv) {
133   // Notify that we are done.
134   std::move(done_callback_).Run();
135   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
136 }
137 
138 }  // namespace content
139