blob: c903335b5e7b6cba3ebb79571b766abf3fcc2137 [file] [log] [blame]
juliatuttleadd0a382017-04-03 16:27:151// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/reporting/reporting_endpoint_manager.h"
6
juliatuttle3d2b0532017-06-05 18:45:467#include <map>
8#include <set>
juliatuttleadd0a382017-04-03 16:27:159#include <string>
Matt Menke515136d2019-10-05 00:27:0910#include <utility>
juliatuttleadd0a382017-04-03 16:27:1511#include <vector>
12
Hans Wennborg0924470b2020-04-27 21:08:0513#include "base/check.h"
Matt Menke67f33762019-10-11 01:24:3214#include "base/containers/mru_cache.h"
juliatuttle3d2b0532017-06-05 18:45:4615#include "base/macros.h"
Hans Wennborg0924470b2020-04-27 21:08:0516#include "base/notreached.h"
juliatuttleadd0a382017-04-03 16:27:1517#include "base/rand_util.h"
18#include "base/stl_util.h"
19#include "base/time/tick_clock.h"
20#include "net/base/backoff_entry.h"
Matt Menke515136d2019-10-05 00:27:0921#include "net/base/network_isolation_key.h"
Julia Tuttled56350d2017-12-07 19:11:1722#include "net/base/rand_callback.h"
juliatuttleadd0a382017-04-03 16:27:1523#include "net/reporting/reporting_cache.h"
juliatuttle587548912017-05-23 14:17:2124#include "net/reporting/reporting_delegate.h"
Lily Chenfc92ff42019-05-06 22:59:1025#include "net/reporting/reporting_endpoint.h"
juliatuttleee4b55e2017-04-07 17:09:4526#include "net/reporting/reporting_policy.h"
juliatuttleadd0a382017-04-03 16:27:1527#include "url/gurl.h"
28#include "url/origin.h"
29
30namespace net {
31
juliatuttle3d2b0532017-06-05 18:45:4632namespace {
33
34class ReportingEndpointManagerImpl : public ReportingEndpointManager {
35 public:
Matt Menke515136d2019-10-05 00:27:0936 ReportingEndpointManagerImpl(const ReportingPolicy* policy,
37 const base::TickClock* tick_clock,
38 const ReportingDelegate* delegate,
39 ReportingCache* cache,
Julia Tuttled56350d2017-12-07 19:11:1740 const RandIntCallback& rand_callback)
Matt Menke515136d2019-10-05 00:27:0941 : policy_(policy),
42 tick_clock_(tick_clock),
43 delegate_(delegate),
44 cache_(cache),
Matt Menke67f33762019-10-11 01:24:3245 rand_callback_(rand_callback),
46 endpoint_backoff_(kMaxEndpointBackoffCacheSize) {
Matt Menke515136d2019-10-05 00:27:0947 DCHECK(policy);
48 DCHECK(tick_clock);
49 DCHECK(delegate);
50 DCHECK(cache);
51 }
juliatuttle3d2b0532017-06-05 18:45:4652
Chris Watkins806691b2017-12-01 06:01:2253 ~ReportingEndpointManagerImpl() override = default;
juliatuttle3d2b0532017-06-05 18:45:4654
Lily Chenfc92ff42019-05-06 22:59:1055 const ReportingEndpoint FindEndpointForDelivery(
Lily Chenad5dd0802020-03-10 21:58:0956 const ReportingEndpointGroupKey& group_key) override {
Lily Chenefb6fcf2019-04-19 04:17:5457 // Get unexpired endpoints that apply to a delivery to |origin| and |group|.
58 // May have been configured by a superdomain of |origin|.
Lily Chenfc92ff42019-05-06 22:59:1059 std::vector<ReportingEndpoint> endpoints =
Lily Chenad5dd0802020-03-10 21:58:0960 cache_->GetCandidateEndpointsForDelivery(group_key);
juliatuttle3d2b0532017-06-05 18:45:4661
Lily Chenefb6fcf2019-04-19 04:17:5462 // Highest-priority endpoint(s) that are not expired, failing, or
Julia Tuttled56350d2017-12-07 19:11:1763 // forbidden for use by the ReportingDelegate.
Lily Chenfc92ff42019-05-06 22:59:1064 std::vector<ReportingEndpoint> available_endpoints;
Lily Chenefb6fcf2019-04-19 04:17:5465 // Total weight of endpoints in |available_endpoints|.
Julia Tuttled56350d2017-12-07 19:11:1766 int total_weight = 0;
67
Nico Weber6dcde5b2020-02-22 20:49:2068 for (const ReportingEndpoint& endpoint : endpoints) {
Matt Menke515136d2019-10-05 00:27:0969 if (!delegate_->CanUseClient(endpoint.group_key.origin,
70 endpoint.info.url)) {
juliatuttle3d2b0532017-06-05 18:45:4671 continue;
Lily Chenefb6fcf2019-04-19 04:17:5472 }
Julia Tuttled56350d2017-12-07 19:11:1773
74 // If this client is lower priority than the ones we've found, skip it.
Lily Chenefb6fcf2019-04-19 04:17:5475 if (!available_endpoints.empty() &&
76 endpoint.info.priority > available_endpoints[0].info.priority) {
Julia Tuttled56350d2017-12-07 19:11:1777 continue;
78 }
79
Matt Menke67f33762019-10-11 01:24:3280 // This brings each match to the front of the MRU cache, so if an entry
81 // frequently matches requests, it's more likely to stay in the cache.
Lily Chenad5dd0802020-03-10 21:58:0982 auto endpoint_backoff_it = endpoint_backoff_.Get(EndpointBackoffKey(
83 group_key.network_isolation_key, endpoint.info.url));
Matt Menke67f33762019-10-11 01:24:3284 if (endpoint_backoff_it != endpoint_backoff_.end() &&
85 endpoint_backoff_it->second->ShouldRejectRequest()) {
86 continue;
87 }
88
Julia Tuttled56350d2017-12-07 19:11:1789 // If this client is higher priority than the ones we've found (or we
90 // haven't found any), forget about those ones and remember this one.
Lily Chenefb6fcf2019-04-19 04:17:5491 if (available_endpoints.empty() ||
92 endpoint.info.priority < available_endpoints[0].info.priority) {
93 available_endpoints.clear();
Julia Tuttled56350d2017-12-07 19:11:1794 total_weight = 0;
95 }
96
Lily Chenefb6fcf2019-04-19 04:17:5497 available_endpoints.push_back(endpoint);
98 total_weight += endpoint.info.weight;
juliatuttle3d2b0532017-06-05 18:45:4699 }
100
Lily Chenefb6fcf2019-04-19 04:17:54101 if (available_endpoints.empty()) {
Lily Chenfc92ff42019-05-06 22:59:10102 return ReportingEndpoint();
juliatuttle3d2b0532017-06-05 18:45:46103 }
104
Sam Burnett148e5262019-05-09 01:13:48105 if (total_weight == 0) {
106 int random_index = rand_callback_.Run(0, available_endpoints.size() - 1);
107 return available_endpoints[random_index];
108 }
109
Julia Tuttled56350d2017-12-07 19:11:17110 int random_index = rand_callback_.Run(0, total_weight - 1);
111 int weight_so_far = 0;
Lily Chenefb6fcf2019-04-19 04:17:54112 for (size_t i = 0; i < available_endpoints.size(); ++i) {
Lily Chenfc92ff42019-05-06 22:59:10113 const ReportingEndpoint& endpoint = available_endpoints[i];
Lily Chenefb6fcf2019-04-19 04:17:54114 weight_so_far += endpoint.info.weight;
Julia Tuttled56350d2017-12-07 19:11:17115 if (random_index < weight_so_far) {
Lily Chenefb6fcf2019-04-19 04:17:54116 return endpoint;
Julia Tuttled56350d2017-12-07 19:11:17117 }
118 }
119
120 // TODO(juliatuttle): Can we reach this in some weird overflow case?
121 NOTREACHED();
Lily Chenfc92ff42019-05-06 22:59:10122 return ReportingEndpoint();
juliatuttle3d2b0532017-06-05 18:45:46123 }
124
Matt Menke515136d2019-10-05 00:27:09125 void InformOfEndpointRequest(const NetworkIsolationKey& network_isolation_key,
126 const GURL& endpoint,
127 bool succeeded) override {
128 EndpointBackoffKey endpoint_backoff_key(network_isolation_key, endpoint);
Matt Menke67f33762019-10-11 01:24:32129 // This will bring the entry to the front of the cache, if it exists.
130 auto endpoint_backoff_it = endpoint_backoff_.Get(endpoint_backoff_key);
Matt Menke515136d2019-10-05 00:27:09131 if (endpoint_backoff_it == endpoint_backoff_.end()) {
Matt Menke67f33762019-10-11 01:24:32132 endpoint_backoff_it = endpoint_backoff_.Put(
133 std::move(endpoint_backoff_key),
134 std::make_unique<BackoffEntry>(&policy_->endpoint_backoff_policy,
135 tick_clock_));
juliatuttle3d2b0532017-06-05 18:45:46136 }
Matt Menke515136d2019-10-05 00:27:09137 endpoint_backoff_it->second->InformOfRequest(succeeded);
juliatuttle3d2b0532017-06-05 18:45:46138 }
139
140 private:
Matt Menke515136d2019-10-05 00:27:09141 using EndpointBackoffKey = std::pair<NetworkIsolationKey, GURL>;
juliatuttle3d2b0532017-06-05 18:45:46142
Matt Menke515136d2019-10-05 00:27:09143 const ReportingPolicy* const policy_;
144 const base::TickClock* const tick_clock_;
145 const ReportingDelegate* const delegate_;
146 ReportingCache* const cache_;
juliatuttle3d2b0532017-06-05 18:45:46147
Julia Tuttled56350d2017-12-07 19:11:17148 RandIntCallback rand_callback_;
149
juliatuttle3d2b0532017-06-05 18:45:46150 // Note: Currently the ReportingBrowsingDataRemover does not clear this data
151 // because it's not persisted to disk. If it's ever persisted, it will need
152 // to be cleared as well.
Lily Chenefb6fcf2019-04-19 04:17:54153 // TODO(chlily): clear this data when endpoints are deleted to avoid unbounded
154 // growth of this map.
Matt Menke67f33762019-10-11 01:24:32155 base::MRUCache<EndpointBackoffKey, std::unique_ptr<net::BackoffEntry>>
Matt Menke515136d2019-10-05 00:27:09156 endpoint_backoff_;
juliatuttle3d2b0532017-06-05 18:45:46157
158 DISALLOW_COPY_AND_ASSIGN(ReportingEndpointManagerImpl);
159};
160
161} // namespace
162
163// static
164std::unique_ptr<ReportingEndpointManager> ReportingEndpointManager::Create(
Matt Menke515136d2019-10-05 00:27:09165 const ReportingPolicy* policy,
166 const base::TickClock* tick_clock,
167 const ReportingDelegate* delegate,
168 ReportingCache* cache,
Julia Tuttled56350d2017-12-07 19:11:17169 const RandIntCallback& rand_callback) {
Matt Menke515136d2019-10-05 00:27:09170 return std::make_unique<ReportingEndpointManagerImpl>(
171 policy, tick_clock, delegate, cache, rand_callback);
juliatuttle3d2b0532017-06-05 18:45:46172}
juliatuttleadd0a382017-04-03 16:27:15173
Chris Watkins806691b2017-12-01 06:01:22174ReportingEndpointManager::~ReportingEndpointManager() = default;
juliatuttleadd0a382017-04-03 16:27:15175
juliatuttleadd0a382017-04-03 16:27:15176} // namespace net