blob: 928896ed5c98330e85dfa808ec9255e6dccf4a80 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/shared_dictionary/shared_dictionary_storage_on_disk.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/pattern.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_id_helper.h"
#include "net/base/io_buffer.h"
#include "services/network/shared_dictionary/shared_dictionary_manager_on_disk.h"
#include "services/network/shared_dictionary/shared_dictionary_on_disk.h"
#include "services/network/shared_dictionary/shared_dictionary_writer_on_disk.h"
#include "url/scheme_host_port.h"
namespace network {
// This is a RefCounted subclass of SharedDictionaryOnDisk. This is used to
// share a SharedDictionaryOnDisk for multiple concurrent network requests.
class SharedDictionaryStorageOnDisk::RefCountedSharedDictionary
: public SharedDictionaryOnDisk,
public base::RefCounted<RefCountedSharedDictionary> {
public:
// `on_deleted_closure_runner` will be called when `this` is deleted.
RefCountedSharedDictionary(
size_t size,
const net::SHA256HashValue& hash,
const base::UnguessableToken& disk_cache_key_token,
SharedDictionaryDiskCache& disk_cahe,
base::OnceClosure disk_cache_error_callback,
base::ScopedClosureRunner on_deleted_closure_runner)
: SharedDictionaryOnDisk(size,
hash,
disk_cache_key_token,
&disk_cahe,
std::move(disk_cache_error_callback)),
on_deleted_closure_runner_(std::move(on_deleted_closure_runner)) {}
private:
friend class RefCounted<RefCountedSharedDictionary>;
~RefCountedSharedDictionary() override = default;
base::ScopedClosureRunner on_deleted_closure_runner_;
};
// This is a subclass of SharedDictionaryOnDisk. This holds a reference to a
// RefCountedSharedDictionary.
class SharedDictionaryStorageOnDisk::WrappedSharedDictionary
: public SharedDictionary {
public:
explicit WrappedSharedDictionary(
scoped_refptr<RefCountedSharedDictionary> ref_counted_shared_dictionary)
: ref_counted_shared_dictionary_(
std::move(ref_counted_shared_dictionary)) {}
WrappedSharedDictionary(const WrappedSharedDictionary&) = delete;
WrappedSharedDictionary& operator=(const WrappedSharedDictionary&) = delete;
// SharedDictionary
int ReadAll(base::OnceCallback<void(int)> callback) override {
return ref_counted_shared_dictionary_->ReadAll(std::move(callback));
}
scoped_refptr<net::IOBuffer> data() const override {
return ref_counted_shared_dictionary_->data();
}
size_t size() const override {
return ref_counted_shared_dictionary_->size();
}
const net::SHA256HashValue& hash() const override {
return ref_counted_shared_dictionary_->hash();
}
private:
scoped_refptr<RefCountedSharedDictionary> ref_counted_shared_dictionary_;
};
SharedDictionaryStorageOnDisk::SharedDictionaryStorageOnDisk(
base::WeakPtr<SharedDictionaryManagerOnDisk> manager,
const net::SharedDictionaryStorageIsolationKey& isolation_key,
base::ScopedClosureRunner on_deleted_closure_runner)
: manager_(manager),
isolation_key_(isolation_key),
on_deleted_closure_runner_(std::move(on_deleted_closure_runner)) {
manager_->metadata_store().GetDictionaries(
isolation_key_,
base::BindOnce(&SharedDictionaryStorageOnDisk::OnDatabaseRead,
weak_factory_.GetWeakPtr()));
}
SharedDictionaryStorageOnDisk::~SharedDictionaryStorageOnDisk() = default;
std::unique_ptr<SharedDictionary> SharedDictionaryStorageOnDisk::GetDictionary(
const GURL& url) {
if (!manager_) {
return nullptr;
}
net::SharedDictionaryInfo* info =
GetMatchingDictionaryFromDictionaryInfoMap(dictionary_info_map_, url);
if (!info) {
return nullptr;
}
manager_->UpdateDictionaryLastUsedTime(*info);
auto it = dictionaries_.find(info->disk_cache_key_token());
if (it != dictionaries_.end()) {
CHECK_EQ(info->size(), it->second->size());
CHECK(info->hash() == it->second->hash());
return std::make_unique<WrappedSharedDictionary>(it->second.get());
}
auto ref_counted_shared_dictionary = base::MakeRefCounted<
RefCountedSharedDictionary>(
info->size(), info->hash(), info->disk_cache_key_token(),
manager_->disk_cache(),
base::BindOnce(
&SharedDictionaryManagerOnDisk::MaybePostMismatchingEntryDeletionTask,
manager_),
base::ScopedClosureRunner(base::BindOnce(
&SharedDictionaryStorageOnDisk::OnRefCountedSharedDictionaryDeleted,
weak_factory_.GetWeakPtr(), info->disk_cache_key_token())));
dictionaries_.emplace(info->disk_cache_key_token(),
ref_counted_shared_dictionary.get());
return std::make_unique<WrappedSharedDictionary>(
std::move(ref_counted_shared_dictionary));
}
scoped_refptr<SharedDictionaryWriter>
SharedDictionaryStorageOnDisk::CreateWriter(const GURL& url,
base::Time response_time,
base::TimeDelta expiration,
const std::string& match) {
if (!manager_) {
return nullptr;
}
return manager_->CreateWriter(
isolation_key_, url, response_time, expiration, match,
base::BindOnce(&SharedDictionaryStorageOnDisk::OnDictionaryWritten,
weak_factory_.GetWeakPtr()));
}
void SharedDictionaryStorageOnDisk::OnDatabaseRead(
net::SQLitePersistentSharedDictionaryStore::DictionaryListOrError result) {
CHECK(dictionary_info_map_.empty());
if (!result.has_value()) {
return;
}
std::set<base::UnguessableToken> deleted_cache_tokens;
for (auto& info : result.value()) {
const url::SchemeHostPort scheme_host_port =
url::SchemeHostPort(info.url());
const std::string match = info.match();
(dictionary_info_map_[scheme_host_port])
.insert(std::make_pair(match, std::move(info)));
}
}
void SharedDictionaryStorageOnDisk::OnDictionaryWritten(
net::SharedDictionaryInfo info) {
const url::SchemeHostPort scheme_host_port = url::SchemeHostPort(info.url());
const std::string match = info.match();
(dictionary_info_map_[scheme_host_port])
.insert_or_assign(match, std::move(info));
}
void SharedDictionaryStorageOnDisk::OnRefCountedSharedDictionaryDeleted(
const base::UnguessableToken& disk_cache_key_token) {
dictionaries_.erase(disk_cache_key_token);
}
void SharedDictionaryStorageOnDisk::OnDictionaryDeleted(
const std::set<base::UnguessableToken>& disk_cache_key_tokens) {
std::erase_if(dictionaries_, [&disk_cache_key_tokens](const auto& it) {
return disk_cache_key_tokens.find(it.first) != disk_cache_key_tokens.end();
});
for (auto& it1 : dictionary_info_map_) {
std::erase_if(it1.second, [&disk_cache_key_tokens](const auto& it2) {
return disk_cache_key_tokens.find(it2.second.disk_cache_key_token()) !=
disk_cache_key_tokens.end();
});
}
std::erase_if(dictionary_info_map_,
[](const auto& it) { return it.second.empty(); });
}
} // namespace network