#ifndef SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_H_
#define SERVICES_NETWORK_SHARED_DICTIONARY_SHARED_DICTIONARY_STORAGE_H_
#include <map>
#include <set>
#include <string>
#include "base/component_export.h"
#include "base/containers/contains.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/strings/pattern.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"
class GURL;
namespace net {
class HttpResponseHeaders;
class SharedDictionary;
}
namespace url_pattern {
class SimpleUrlPatternMatcher;
}
namespace network {
namespace mojom {
enum class FetchResponseType : int32_t;
enum class RequestDestination : int32_t;
enum class RequestMode : int32_t;
enum class SharedDictionaryError : int32_t;
}
class SharedDictionaryWriter;
class COMPONENT_EXPORT(NETWORK_SERVICE) SharedDictionaryStorage
: public base::RefCounted<SharedDictionaryStorage> {
public:
SharedDictionaryStorage(const SharedDictionaryStorage&) = delete;
SharedDictionaryStorage& operator=(const SharedDictionaryStorage&) = delete;
static base::expected<scoped_refptr<SharedDictionaryWriter>,
mojom::SharedDictionaryError>
MaybeCreateWriter(const std::string& use_as_dictionary_header,
bool shared_dictionary_writer_enabled,
SharedDictionaryStorage* storage,
mojom::RequestMode request_mode,
mojom::FetchResponseType response_tainting,
const GURL& url,
const base::Time request_time,
const base::Time response_time,
const net::HttpResponseHeaders& headers,
bool was_fetched_via_cache,
base::OnceCallback<bool()> access_allowed_check_callback);
virtual scoped_refptr<net::SharedDictionary> GetDictionarySync(
const GURL& url,
mojom::RequestDestination destination) = 0;
virtual void GetDictionary(
const GURL& url,
mojom::RequestDestination destination,
base::OnceCallback<void(scoped_refptr<net::SharedDictionary>)>
callback) = 0;
protected:
friend class base::RefCounted<SharedDictionaryStorage>;
SharedDictionaryStorage();
virtual ~SharedDictionaryStorage();
virtual base::expected<scoped_refptr<SharedDictionaryWriter>,
mojom::SharedDictionaryError>
CreateWriter(
const GURL& url,
base::Time last_fetch_time,
base::Time response_time,
base::TimeDelta expiration,
const std::string& match,
const std::set<mojom::RequestDestination>& match_dest,
const std::string& id,
std::unique_ptr<url_pattern::SimpleUrlPatternMatcher> matcher) = 0;
virtual bool UpdateLastFetchTimeIfAlreadyRegistered(
const GURL& url,
base::Time response_time,
base::TimeDelta expiration,
const std::string& match,
const std::set<mojom::RequestDestination>& match_dest,
const std::string& id,
const std::optional<base::TimeDelta>& ttl,
base::Time last_fetch_time) = 0;
};
template <class DictionaryInfoType>
DictionaryInfoType* GetMatchingDictionaryFromDictionaryInfoMap(
std::map<
url::SchemeHostPort,
std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
DictionaryInfoType>>& dictionary_info_map,
const GURL& url,
mojom::RequestDestination destination) {
auto it = dictionary_info_map.find(url::SchemeHostPort(url));
if (it == dictionary_info_map.end()) {
return nullptr;
}
DictionaryInfoType* matched_info = nullptr;
for (auto& item : it->second) {
DictionaryInfoType& info = item.second;
CHECK(std::make_tuple(info.match(), info.match_dest()) == item.first);
if (matched_info &&
((matched_info->match().size() > info.match().size()) ||
(matched_info->match().size() == info.match().size() &&
matched_info->last_fetch_time() > info.last_fetch_time()))) {
continue;
}
if (!info.match_dest().empty() &&
!base::Contains(info.match_dest(), destination)) {
continue;
}
CHECK(info.matcher());
if (info.matcher()->Match(url)) {
matched_info = &info;
}
}
return matched_info;
}
template <class DictionaryInfoType>
DictionaryInfoType* FindRegisteredInDictionaryInfoMap(
std::map<
url::SchemeHostPort,
std::map<std::tuple<std::string, std::set<mojom::RequestDestination>>,
DictionaryInfoType>>& dictionary_info_map,
const GURL& url,
base::Time response_time,
base::TimeDelta expiration,
const std::string& match,
const std::set<mojom::RequestDestination>& match_dest,
const std::string& id,
const std::optional<base::TimeDelta>& ttl) {
auto it1 = dictionary_info_map.find(url::SchemeHostPort(url));
if (it1 == dictionary_info_map.end()) {
return nullptr;
}
auto it2 = it1->second.find(std::make_tuple(match, match_dest));
if (it2 == it1->second.end()) {
return nullptr;
}
if (it2->second.url() == url &&
(ttl || it2->second.response_time() == response_time) &&
it2->second.expiration() == expiration && it2->second.id() == id) {
return &it2->second;
} else {
return nullptr;
}
}
}
#endif