123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- // Copyright 2017 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 "net/reporting/reporting_endpoint_manager.h"
- #include <map>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/check.h"
- #include "base/containers/lru_cache.h"
- #include "base/memory/raw_ptr.h"
- #include "base/notreached.h"
- #include "base/rand_util.h"
- #include "base/time/tick_clock.h"
- #include "net/base/backoff_entry.h"
- #include "net/base/network_isolation_key.h"
- #include "net/base/rand_callback.h"
- #include "net/reporting/reporting_cache.h"
- #include "net/reporting/reporting_delegate.h"
- #include "net/reporting/reporting_endpoint.h"
- #include "net/reporting/reporting_policy.h"
- #include "url/gurl.h"
- #include "url/origin.h"
- namespace net {
- namespace {
- class ReportingEndpointManagerImpl : public ReportingEndpointManager {
- public:
- ReportingEndpointManagerImpl(const ReportingPolicy* policy,
- const base::TickClock* tick_clock,
- const ReportingDelegate* delegate,
- ReportingCache* cache,
- const RandIntCallback& rand_callback)
- : policy_(policy),
- tick_clock_(tick_clock),
- delegate_(delegate),
- cache_(cache),
- rand_callback_(rand_callback),
- endpoint_backoff_(kMaxEndpointBackoffCacheSize) {
- DCHECK(policy);
- DCHECK(tick_clock);
- DCHECK(delegate);
- DCHECK(cache);
- }
- ReportingEndpointManagerImpl(const ReportingEndpointManagerImpl&) = delete;
- ReportingEndpointManagerImpl& operator=(const ReportingEndpointManagerImpl&) =
- delete;
- ~ReportingEndpointManagerImpl() override = default;
- const ReportingEndpoint FindEndpointForDelivery(
- const ReportingEndpointGroupKey& group_key) override {
- // Get unexpired endpoints that apply to a delivery to |origin| and |group|.
- // May have been configured by a superdomain of |origin|.
- std::vector<ReportingEndpoint> endpoints =
- cache_->GetCandidateEndpointsForDelivery(group_key);
- // Highest-priority endpoint(s) that are not expired, failing, or
- // forbidden for use by the ReportingDelegate.
- std::vector<ReportingEndpoint> available_endpoints;
- // Total weight of endpoints in |available_endpoints|.
- int total_weight = 0;
- for (const ReportingEndpoint& endpoint : endpoints) {
- if (!delegate_->CanUseClient(endpoint.group_key.origin,
- endpoint.info.url)) {
- continue;
- }
- // If this client is lower priority than the ones we've found, skip it.
- if (!available_endpoints.empty() &&
- endpoint.info.priority > available_endpoints[0].info.priority) {
- continue;
- }
- // This brings each match to the front of the MRU cache, so if an entry
- // frequently matches requests, it's more likely to stay in the cache.
- auto endpoint_backoff_it = endpoint_backoff_.Get(EndpointBackoffKey(
- group_key.network_isolation_key, endpoint.info.url));
- if (endpoint_backoff_it != endpoint_backoff_.end() &&
- endpoint_backoff_it->second->ShouldRejectRequest()) {
- continue;
- }
- // If this client is higher priority than the ones we've found (or we
- // haven't found any), forget about those ones and remember this one.
- if (available_endpoints.empty() ||
- endpoint.info.priority < available_endpoints[0].info.priority) {
- available_endpoints.clear();
- total_weight = 0;
- }
- available_endpoints.push_back(endpoint);
- total_weight += endpoint.info.weight;
- }
- if (available_endpoints.empty()) {
- return ReportingEndpoint();
- }
- if (total_weight == 0) {
- int random_index = rand_callback_.Run(0, available_endpoints.size() - 1);
- return available_endpoints[random_index];
- }
- int random_index = rand_callback_.Run(0, total_weight - 1);
- int weight_so_far = 0;
- for (const auto& endpoint : available_endpoints) {
- weight_so_far += endpoint.info.weight;
- if (random_index < weight_so_far) {
- return endpoint;
- }
- }
- // TODO(juliatuttle): Can we reach this in some weird overflow case?
- NOTREACHED();
- return ReportingEndpoint();
- }
- void InformOfEndpointRequest(const NetworkIsolationKey& network_isolation_key,
- const GURL& endpoint,
- bool succeeded) override {
- EndpointBackoffKey endpoint_backoff_key(network_isolation_key, endpoint);
- // This will bring the entry to the front of the cache, if it exists.
- auto endpoint_backoff_it = endpoint_backoff_.Get(endpoint_backoff_key);
- if (endpoint_backoff_it == endpoint_backoff_.end()) {
- endpoint_backoff_it = endpoint_backoff_.Put(
- std::move(endpoint_backoff_key),
- std::make_unique<BackoffEntry>(&policy_->endpoint_backoff_policy,
- tick_clock_));
- }
- endpoint_backoff_it->second->InformOfRequest(succeeded);
- }
- private:
- using EndpointBackoffKey = std::pair<NetworkIsolationKey, GURL>;
- const raw_ptr<const ReportingPolicy> policy_;
- const raw_ptr<const base::TickClock> tick_clock_;
- const raw_ptr<const ReportingDelegate> delegate_;
- const raw_ptr<ReportingCache> cache_;
- RandIntCallback rand_callback_;
- // Note: Currently the ReportingBrowsingDataRemover does not clear this data
- // because it's not persisted to disk. If it's ever persisted, it will need
- // to be cleared as well.
- // TODO(chlily): clear this data when endpoints are deleted to avoid unbounded
- // growth of this map.
- base::LRUCache<EndpointBackoffKey, std::unique_ptr<net::BackoffEntry>>
- endpoint_backoff_;
- };
- } // namespace
- // static
- std::unique_ptr<ReportingEndpointManager> ReportingEndpointManager::Create(
- const ReportingPolicy* policy,
- const base::TickClock* tick_clock,
- const ReportingDelegate* delegate,
- ReportingCache* cache,
- const RandIntCallback& rand_callback) {
- return std::make_unique<ReportingEndpointManagerImpl>(
- policy, tick_clock, delegate, cache, rand_callback);
- }
- ReportingEndpointManager::~ReportingEndpointManager() = default;
- } // namespace net
|