blob: fc83ea5178bfaf0ff0e499866df0e19747711f74 [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 "services/network/http_cache_data_remover.h"
#include <set>
#include <string>
#include "base/location.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
namespace network {
namespace {
bool DoesUrlMatchFilter(mojom::ClearDataFilter_Type filter_type,
const std::set<url::Origin>& origins,
const std::set<std::string>& domains,
const GURL& url) {
std::string url_registerable_domain =
net::registry_controlled_domains::GetDomainAndRegistry(
url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
bool found_domain = (domains.find(url_registerable_domain != ""
? url_registerable_domain
: url.host()) != domains.end());
bool found_origin = (origins.find(url::Origin::Create(url)) != origins.end());
return ((found_domain || found_origin) ==
(filter_type == mojom::ClearDataFilter_Type::DELETE_MATCHES));
}
} // namespace
HttpCacheDataRemover::HttpCacheDataRemover(
mojom::ClearDataFilterPtr url_filter,
base::Time delete_begin,
base::Time delete_end,
HttpCacheDataRemoverCallback done_callback)
: delete_begin_(delete_begin),
delete_end_(delete_end),
done_callback_(std::move(done_callback)),
backend_(nullptr),
weak_factory_(this) {
DCHECK(!done_callback_.is_null());
if (!url_filter)
return;
// Use the filter to create the |url_matcher_| callback.
std::set<std::string> domains;
domains.insert(url_filter->domains.begin(), url_filter->domains.end());
std::set<url::Origin> origins;
origins.insert(url_filter->origins.begin(), url_filter->origins.end());
url_matcher_ = base::BindRepeating(&DoesUrlMatchFilter, url_filter->type,
origins, domains);
}
HttpCacheDataRemover::~HttpCacheDataRemover() = default;
// static.
std::unique_ptr<HttpCacheDataRemover> HttpCacheDataRemover::CreateAndStart(
net::URLRequestContext* url_request_context,
mojom::ClearDataFilterPtr url_filter,
base::Time delete_begin,
base::Time delete_end,
HttpCacheDataRemoverCallback done_callback) {
DCHECK(done_callback);
std::unique_ptr<HttpCacheDataRemover> remover(
new HttpCacheDataRemover(std::move(url_filter), delete_begin, delete_end,
std::move(done_callback)));
net::HttpCache* http_cache =
url_request_context->http_transaction_factory()->GetCache();
if (!http_cache) {
// Some contexts might not have a cache, in which case we are done.
// Notify by posting a task to avoid reentrency.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&HttpCacheDataRemover::ClearHttpCacheDone,
remover->weak_factory_.GetWeakPtr(), net::OK));
return remover;
}
// Clear QUIC server information from memory and the disk cache.
// TODO(crbug.com/817849): add a browser test to validate the QUIC information
// is cleared.
http_cache->GetSession()
->quic_stream_factory()
->ClearCachedStatesInCryptoConfig(remover->url_matcher_);
net::CompletionOnceCallback callback =
base::BindOnce(&HttpCacheDataRemover::CacheRetrieved,
remover->weak_factory_.GetWeakPtr());
int rv = http_cache->GetBackend(&remover->backend_, std::move(callback));
if (rv != net::ERR_IO_PENDING) {
remover->CacheRetrieved(rv);
}
return remover;
}
void HttpCacheDataRemover::CacheRetrieved(int rv) {
DCHECK(done_callback_);
// |backend_| can be null if it cannot be initialized.
if (rv != net::OK || !backend_) {
backend_ = nullptr;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&HttpCacheDataRemover::ClearHttpCacheDone,
weak_factory_.GetWeakPtr(), rv));
return;
}
if (!url_matcher_.is_null()) {
deletion_helper_ = ConditionalCacheDeletionHelper::CreateAndStart(
backend_, url_matcher_, delete_begin_, delete_end_,
base::BindOnce(&HttpCacheDataRemover::ClearHttpCacheDone,
weak_factory_.GetWeakPtr(), net::OK));
return;
}
if (delete_begin_.is_null() && delete_end_.is_max()) {
rv = backend_->DoomAllEntries(base::Bind(
&HttpCacheDataRemover::ClearHttpCacheDone, weak_factory_.GetWeakPtr()));
} else {
rv = backend_->DoomEntriesBetween(
delete_begin_, delete_end_,
base::Bind(&HttpCacheDataRemover::ClearHttpCacheDone,
weak_factory_.GetWeakPtr()));
}
if (rv != net::ERR_IO_PENDING) {
// Notify by posting a task to avoid reentrency.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&HttpCacheDataRemover::ClearHttpCacheDone,
weak_factory_.GetWeakPtr(), rv));
}
}
void HttpCacheDataRemover::ClearHttpCacheDone(int rv) {
std::move(done_callback_).Run(this);
}
} // namespace network