| Index: net/reporting/reporting_cache.cc
|
| diff --git a/net/reporting/reporting_cache.cc b/net/reporting/reporting_cache.cc
|
| index 7e147b38008a390266e047ab20ce457c2a012697..24eea0e87518e50f0ec5cda9b5a1e0f498b2dfa7 100644
|
| --- a/net/reporting/reporting_cache.cc
|
| +++ b/net/reporting/reporting_cache.cc
|
| @@ -12,6 +12,7 @@
|
|
|
| #include "base/memory/ptr_util.h"
|
| #include "base/stl_util.h"
|
| +#include "base/time/tick_clock.h"
|
| #include "base/time/time.h"
|
| #include "net/reporting/reporting_client.h"
|
| #include "net/reporting/reporting_context.h"
|
| @@ -191,56 +192,77 @@ void ReportingCache::SetClient(const url::Origin& origin,
|
| base::TimeTicks expires) {
|
| DCHECK(endpoint.SchemeIsCryptographic());
|
|
|
| - // Since |subdomains| may differ from a previous call to SetClient for this
|
| - // origin and endpoint, the cache needs to remove and re-add the client to the
|
| - // index of wildcard clients, if applicable.
|
| - if (base::ContainsKey(clients_, origin) &&
|
| - base::ContainsKey(clients_[origin], endpoint)) {
|
| - MaybeRemoveWildcardClient(clients_[origin][endpoint].get());
|
| - }
|
| + base::TimeTicks last_used = tick_clock()->NowTicks();
|
|
|
| - clients_[origin][endpoint] = base::MakeUnique<ReportingClient>(
|
| - origin, endpoint, subdomains, group, expires);
|
| + const ReportingClient* old_client =
|
| + GetClientByOriginAndEndpoint(origin, endpoint);
|
| + if (old_client) {
|
| + last_used = client_last_used_[old_client];
|
| + RemoveClient(old_client);
|
| + }
|
|
|
| - MaybeAddWildcardClient(clients_[origin][endpoint].get());
|
| + AddClient(base::MakeUnique<ReportingClient>(origin, endpoint, subdomains,
|
| + group, expires),
|
| + last_used);
|
| +
|
| + if (client_last_used_.size() > context_->policy().max_client_count) {
|
| + // There should only ever be one extra client, added above.
|
| + DCHECK_EQ(context_->policy().max_client_count + 1,
|
| + client_last_used_.size());
|
| + // And that shouldn't happen if it was replaced, not added.
|
| + DCHECK(!old_client);
|
| + const ReportingClient* to_evict =
|
| + FindClientToEvict(tick_clock()->NowTicks());
|
| + DCHECK(to_evict);
|
| + RemoveClient(to_evict);
|
| + }
|
|
|
| context_->NotifyCacheUpdated();
|
| }
|
|
|
| +void ReportingCache::MarkClientUsed(const url::Origin& origin,
|
| + const GURL& endpoint) {
|
| + const ReportingClient* client =
|
| + GetClientByOriginAndEndpoint(origin, endpoint);
|
| + DCHECK(client);
|
| + client_last_used_[client] = tick_clock()->NowTicks();
|
| +}
|
| +
|
| void ReportingCache::RemoveClients(
|
| const std::vector<const ReportingClient*>& clients_to_remove) {
|
| - for (const ReportingClient* client : clients_to_remove) {
|
| - MaybeRemoveWildcardClient(client);
|
| - size_t erased = clients_[client->origin].erase(client->endpoint);
|
| - DCHECK_EQ(1u, erased);
|
| - }
|
| + for (const ReportingClient* client : clients_to_remove)
|
| + RemoveClient(client);
|
|
|
| context_->NotifyCacheUpdated();
|
| }
|
|
|
| void ReportingCache::RemoveClientForOriginAndEndpoint(const url::Origin& origin,
|
| const GURL& endpoint) {
|
| - MaybeRemoveWildcardClient(clients_[origin][endpoint].get());
|
| - size_t erased = clients_[origin].erase(endpoint);
|
| - DCHECK_EQ(1u, erased);
|
| + const ReportingClient* client =
|
| + GetClientByOriginAndEndpoint(origin, endpoint);
|
| + RemoveClient(client);
|
|
|
| context_->NotifyCacheUpdated();
|
| }
|
|
|
| void ReportingCache::RemoveClientsForEndpoint(const GURL& endpoint) {
|
| - for (auto& origin_and_endpoints : clients_) {
|
| - if (base::ContainsKey(origin_and_endpoints.second, endpoint)) {
|
| - MaybeRemoveWildcardClient(origin_and_endpoints.second[endpoint].get());
|
| - origin_and_endpoints.second.erase(endpoint);
|
| - }
|
| - }
|
| + std::vector<const ReportingClient*> clients_to_remove;
|
|
|
| - context_->NotifyCacheUpdated();
|
| + for (auto& origin_and_endpoints : clients_)
|
| + if (base::ContainsKey(origin_and_endpoints.second, endpoint))
|
| + clients_to_remove.push_back(origin_and_endpoints.second[endpoint].get());
|
| +
|
| + for (const ReportingClient* client : clients_to_remove)
|
| + RemoveClient(client);
|
| +
|
| + if (!clients_to_remove.empty())
|
| + context_->NotifyCacheUpdated();
|
| }
|
|
|
| void ReportingCache::RemoveAllClients() {
|
| clients_.clear();
|
| wildcard_clients_.clear();
|
| + client_last_used_.clear();
|
|
|
| context_->NotifyCacheUpdated();
|
| }
|
| @@ -260,22 +282,68 @@ const ReportingReport* ReportingCache::FindReportToEvict() const {
|
| return earliest_queued;
|
| }
|
|
|
| -void ReportingCache::MaybeAddWildcardClient(const ReportingClient* client) {
|
| - if (client->subdomains != ReportingClient::Subdomains::INCLUDE)
|
| - return;
|
| +void ReportingCache::AddClient(std::unique_ptr<ReportingClient> client,
|
| + base::TimeTicks last_used) {
|
| + DCHECK(client);
|
|
|
| - const std::string& domain = client->origin.host();
|
| - auto inserted = wildcard_clients_[domain].insert(client);
|
| - DCHECK(inserted.second);
|
| + url::Origin origin = client->origin;
|
| + GURL endpoint = client->endpoint;
|
| +
|
| + auto inserted_last_used =
|
| + client_last_used_.insert(std::make_pair(client.get(), last_used));
|
| + DCHECK(inserted_last_used.second);
|
| +
|
| + if (client->subdomains == ReportingClient::Subdomains::INCLUDE) {
|
| + const std::string& domain = origin.host();
|
| + auto inserted_wildcard_client =
|
| + wildcard_clients_[domain].insert(client.get());
|
| + DCHECK(inserted_wildcard_client.second);
|
| + }
|
| +
|
| + auto inserted_client =
|
| + clients_[origin].insert(std::make_pair(endpoint, std::move(client)));
|
| + DCHECK(inserted_client.second);
|
| }
|
|
|
| -void ReportingCache::MaybeRemoveWildcardClient(const ReportingClient* client) {
|
| - if (client->subdomains != ReportingClient::Subdomains::INCLUDE)
|
| - return;
|
| +void ReportingCache::RemoveClient(const ReportingClient* client) {
|
| + DCHECK(client);
|
|
|
| - const std::string& domain = client->origin.host();
|
| - size_t erased = wildcard_clients_[domain].erase(client);
|
| - DCHECK_EQ(1u, erased);
|
| + url::Origin origin = client->origin;
|
| + GURL endpoint = client->endpoint;
|
| +
|
| + if (client->subdomains == ReportingClient::Subdomains::INCLUDE) {
|
| + const std::string& domain = origin.host();
|
| + size_t erased_wildcard_client = wildcard_clients_[domain].erase(client);
|
| + DCHECK_EQ(1u, erased_wildcard_client);
|
| + if (wildcard_clients_[domain].empty()) {
|
| + size_t erased_wildcard_domain = wildcard_clients_.erase(domain);
|
| + DCHECK_EQ(1u, erased_wildcard_domain);
|
| + }
|
| + }
|
| +
|
| + size_t erased_last_used = client_last_used_.erase(client);
|
| + DCHECK_EQ(1u, erased_last_used);
|
| +
|
| + size_t erased_endpoint = clients_[origin].erase(endpoint);
|
| + DCHECK_EQ(1u, erased_endpoint);
|
| + if (clients_[origin].empty()) {
|
| + size_t erased_origin = clients_.erase(origin);
|
| + DCHECK_EQ(1u, erased_origin);
|
| + }
|
| +}
|
| +
|
| +const ReportingClient* ReportingCache::GetClientByOriginAndEndpoint(
|
| + const url::Origin& origin,
|
| + const GURL& endpoint) const {
|
| + const auto& origin_it = clients_.find(origin);
|
| + if (origin_it == clients_.end())
|
| + return nullptr;
|
| +
|
| + const auto& endpoint_it = origin_it->second.find(endpoint);
|
| + if (endpoint_it == origin_it->second.end())
|
| + return nullptr;
|
| +
|
| + return endpoint_it->second.get();
|
| }
|
|
|
| void ReportingCache::GetWildcardClientsForDomainAndGroup(
|
| @@ -295,4 +363,37 @@ void ReportingCache::GetWildcardClientsForDomainAndGroup(
|
| }
|
| }
|
|
|
| +const ReportingClient* ReportingCache::FindClientToEvict(
|
| + base::TimeTicks now) const {
|
| + DCHECK(!client_last_used_.empty());
|
| +
|
| + const ReportingClient* earliest_used = nullptr;
|
| + base::TimeTicks earliest_used_last_used;
|
| + const ReportingClient* earliest_expired = nullptr;
|
| +
|
| + for (const auto& it : client_last_used_) {
|
| + const ReportingClient* client = it.first;
|
| + base::TimeTicks client_last_used = it.second;
|
| + if (earliest_used == nullptr ||
|
| + client_last_used < earliest_used_last_used) {
|
| + earliest_used = client;
|
| + earliest_used_last_used = client_last_used;
|
| + }
|
| + if (earliest_expired == nullptr ||
|
| + client->expires < earliest_expired->expires) {
|
| + earliest_expired = client;
|
| + }
|
| + }
|
| +
|
| + // If there are expired clients, return the earliest-expired.
|
| + if (earliest_expired->expires < now)
|
| + return earliest_expired;
|
| + else
|
| + return earliest_used;
|
| +}
|
| +
|
| +base::TickClock* ReportingCache::tick_clock() {
|
| + return context_->tick_clock();
|
| +}
|
| +
|
| } // namespace net
|
|
|