blob: d262819188d62448adf30f7d5c2498176ade58fb [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/browsing_data/storage_partition_code_cache_data_remover.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/browsing_data/conditional_cache_deletion_helper.h"
#include "content/browser/code_cache/generated_code_cache.h"
#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_features.h"
#include "net/base/completion_repeating_callback.h"
#include "net/disk_cache/disk_cache.h"
namespace content {
StoragePartitionCodeCacheDataRemover::StoragePartitionCodeCacheDataRemover(
GeneratedCodeCacheContext* generated_code_cache_context,
base::RepeatingCallback<bool(const GURL&)> url_predicate,
base::Time begin_time,
base::Time end_time)
: generated_code_cache_context_(generated_code_cache_context),
begin_time_(begin_time),
end_time_(end_time),
url_predicate_(std::move(url_predicate)) {}
// static
StoragePartitionCodeCacheDataRemover*
StoragePartitionCodeCacheDataRemover::Create(
content::StoragePartition* storage_partition,
base::RepeatingCallback<bool(const GURL&)> url_predicate,
base::Time begin_time,
base::Time end_time) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
return new StoragePartitionCodeCacheDataRemover(
storage_partition->GetGeneratedCodeCacheContext(),
std::move(url_predicate), begin_time, end_time);
}
StoragePartitionCodeCacheDataRemover::~StoragePartitionCodeCacheDataRemover() {}
void StoragePartitionCodeCacheDataRemover::Remove(
base::OnceClosure done_callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!done_callback.is_null())
<< __func__ << " called with a null callback";
done_callback_ = std::move(done_callback);
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearJSCodeCache,
base::Unretained(this)));
}
void StoragePartitionCodeCacheDataRemover::ClearedCodeCache() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::move(done_callback_).Run();
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
}
void StoragePartitionCodeCacheDataRemover::ClearCache(
net::CompletionOnceCallback callback,
disk_cache::Backend* backend) {
if (backend == nullptr) {
std::move(callback).Run(net::ERR_FAILED);
return;
}
// Create a callback that is copyable, even though it can only be called once,
// so that we can use it synchronously in case result != net::ERR_IO_PENDING.
net::CompletionRepeatingCallback copyable_callback =
base::AdaptCallbackForRepeating(std::move(callback));
int result = net::ERR_FAILED;
if (!url_predicate_.is_null()) {
result =
(new ConditionalCacheDeletionHelper(
backend,
ConditionalCacheDeletionHelper::CreateCustomKeyURLAndTimeCondition(
std::move(url_predicate_),
base::BindRepeating(
&GeneratedCodeCache::GetResourceURLFromKey),
begin_time_, end_time_)))
->DeleteAndDestroySelfWhenFinished(copyable_callback);
} else if (begin_time_.is_null() && end_time_.is_max()) {
result = backend->DoomAllEntries(copyable_callback);
} else {
result =
backend->DoomEntriesBetween(begin_time_, end_time_, copyable_callback);
}
// When result is ERR_IO_PENDING the callback would be called after the
// operation has finished.
if (result != net::ERR_IO_PENDING) {
DCHECK(copyable_callback);
copyable_callback.Run(result);
}
}
void StoragePartitionCodeCacheDataRemover::ClearJSCodeCache() {
if (generated_code_cache_context_ &&
generated_code_cache_context_->generated_js_code_cache()) {
net::CompletionCallback callback = base::BindRepeating(
&StoragePartitionCodeCacheDataRemover::ClearWASMCodeCache,
base::Unretained(this));
generated_code_cache_context_->generated_js_code_cache()->GetBackend(
base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearCache,
base::Unretained(this), std::move(callback)));
} else {
// When there is no JS cache, see if we need to remove WASM cache. When
// there is JS cache, the WASM cache would be removed after the JS cache.
ClearWASMCodeCache(net::ERR_FAILED);
}
}
// |rv| is the returned when clearing the code cache. We don't handle
// any errors here, so the result value is ignored.
void StoragePartitionCodeCacheDataRemover::ClearWASMCodeCache(int rv) {
if (generated_code_cache_context_ &&
generated_code_cache_context_->generated_wasm_code_cache()) {
net::CompletionCallback callback = base::BindRepeating(
&StoragePartitionCodeCacheDataRemover::DoneClearCodeCache,
base::Unretained(this));
generated_code_cache_context_->generated_wasm_code_cache()->GetBackend(
base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearCache,
base::Unretained(this), std::move(callback)));
} else {
// There is no Wasm cache, done with clearing caches.
DoneClearCodeCache(net::ERR_FAILED);
}
}
// |rv| is the returned when clearing the code cache. We don't handle
// any errors here, so the result value is ignored.
void StoragePartitionCodeCacheDataRemover::DoneClearCodeCache(int rv) {
// Notify the UI thread that we are done.
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&StoragePartitionCodeCacheDataRemover::ClearedCodeCache,
base::Unretained(this)));
}
} // namespace content