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