1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/http/broken_alternative_services.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/containers/adapters.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/memory/singleton.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/time/tick_clock.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
12*6777b538SAndroid Build Coastguard Worker #include "net/http/http_server_properties.h"
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker namespace net {
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker // Default broken alternative services, which is used when
19*6777b538SAndroid Build Coastguard Worker // exponential_backoff_on_initial_delay is false.
20*6777b538SAndroid Build Coastguard Worker constexpr base::TimeDelta kDefaultBrokenAlternativeProtocolDelay =
21*6777b538SAndroid Build Coastguard Worker base::Seconds(300);
22*6777b538SAndroid Build Coastguard Worker // Subsequent failures result in exponential (base 2) backoff.
23*6777b538SAndroid Build Coastguard Worker // Given the shortest broken delay is 1s, limit binary shift to limit delay to
24*6777b538SAndroid Build Coastguard Worker // approximately 2 days.
25*6777b538SAndroid Build Coastguard Worker const int kBrokenDelayMaxShift = 18;
26*6777b538SAndroid Build Coastguard Worker // Lower and upper limits of broken alternative service delay.
27*6777b538SAndroid Build Coastguard Worker constexpr base::TimeDelta kMinBrokenAlternativeProtocolDelay = base::Seconds(1);
28*6777b538SAndroid Build Coastguard Worker constexpr base::TimeDelta kMaxBrokenAlternativeProtocolDelay = base::Days(2);
29*6777b538SAndroid Build Coastguard Worker
ComputeBrokenAlternativeServiceExpirationDelay(int broken_count,base::TimeDelta initial_delay,bool exponential_backoff_on_initial_delay)30*6777b538SAndroid Build Coastguard Worker base::TimeDelta ComputeBrokenAlternativeServiceExpirationDelay(
31*6777b538SAndroid Build Coastguard Worker int broken_count,
32*6777b538SAndroid Build Coastguard Worker base::TimeDelta initial_delay,
33*6777b538SAndroid Build Coastguard Worker bool exponential_backoff_on_initial_delay) {
34*6777b538SAndroid Build Coastguard Worker DCHECK_GE(broken_count, 0);
35*6777b538SAndroid Build Coastguard Worker // Make sure initial delay is within [1s, 300s].
36*6777b538SAndroid Build Coastguard Worker if (initial_delay < kMinBrokenAlternativeProtocolDelay) {
37*6777b538SAndroid Build Coastguard Worker initial_delay = kMinBrokenAlternativeProtocolDelay;
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker if (initial_delay > kDefaultBrokenAlternativeProtocolDelay) {
40*6777b538SAndroid Build Coastguard Worker initial_delay = kDefaultBrokenAlternativeProtocolDelay;
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker if (broken_count == 0) {
43*6777b538SAndroid Build Coastguard Worker return initial_delay;
44*6777b538SAndroid Build Coastguard Worker }
45*6777b538SAndroid Build Coastguard Worker // Limit broken_count to avoid overflow.
46*6777b538SAndroid Build Coastguard Worker if (broken_count > kBrokenDelayMaxShift) {
47*6777b538SAndroid Build Coastguard Worker broken_count = kBrokenDelayMaxShift;
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker base::TimeDelta delay;
50*6777b538SAndroid Build Coastguard Worker if (exponential_backoff_on_initial_delay) {
51*6777b538SAndroid Build Coastguard Worker delay = initial_delay * (1 << broken_count);
52*6777b538SAndroid Build Coastguard Worker } else {
53*6777b538SAndroid Build Coastguard Worker delay = kDefaultBrokenAlternativeProtocolDelay * (1 << (broken_count - 1));
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker return std::min(delay, kMaxBrokenAlternativeProtocolDelay);
56*6777b538SAndroid Build Coastguard Worker }
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker } // namespace
59*6777b538SAndroid Build Coastguard Worker
BrokenAlternativeService(const AlternativeService & alternative_service,const NetworkAnonymizationKey & network_anonymization_key,bool use_network_anonymization_key)60*6777b538SAndroid Build Coastguard Worker BrokenAlternativeService::BrokenAlternativeService(
61*6777b538SAndroid Build Coastguard Worker const AlternativeService& alternative_service,
62*6777b538SAndroid Build Coastguard Worker const NetworkAnonymizationKey& network_anonymization_key,
63*6777b538SAndroid Build Coastguard Worker bool use_network_anonymization_key)
64*6777b538SAndroid Build Coastguard Worker : alternative_service(alternative_service),
65*6777b538SAndroid Build Coastguard Worker network_anonymization_key(use_network_anonymization_key
66*6777b538SAndroid Build Coastguard Worker ? network_anonymization_key
67*6777b538SAndroid Build Coastguard Worker : NetworkAnonymizationKey()) {}
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker BrokenAlternativeService::~BrokenAlternativeService() = default;
70*6777b538SAndroid Build Coastguard Worker
operator <(const BrokenAlternativeService & other) const71*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeService::operator<(
72*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& other) const {
73*6777b538SAndroid Build Coastguard Worker return std::tie(alternative_service, network_anonymization_key) <
74*6777b538SAndroid Build Coastguard Worker std::tie(other.alternative_service, other.network_anonymization_key);
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker
BrokenAlternativeServices(int max_recently_broken_alternative_service_entries,Delegate * delegate,const base::TickClock * clock)77*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServices::BrokenAlternativeServices(
78*6777b538SAndroid Build Coastguard Worker int max_recently_broken_alternative_service_entries,
79*6777b538SAndroid Build Coastguard Worker Delegate* delegate,
80*6777b538SAndroid Build Coastguard Worker const base::TickClock* clock)
81*6777b538SAndroid Build Coastguard Worker : delegate_(delegate),
82*6777b538SAndroid Build Coastguard Worker clock_(clock),
83*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_(
84*6777b538SAndroid Build Coastguard Worker max_recently_broken_alternative_service_entries),
85*6777b538SAndroid Build Coastguard Worker initial_delay_(kDefaultBrokenAlternativeProtocolDelay) {
86*6777b538SAndroid Build Coastguard Worker DCHECK(delegate_);
87*6777b538SAndroid Build Coastguard Worker DCHECK(clock_);
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServices::~BrokenAlternativeServices() = default;
91*6777b538SAndroid Build Coastguard Worker
Clear()92*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::Clear() {
93*6777b538SAndroid Build Coastguard Worker expiration_timer_.Stop();
94*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.clear();
95*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.clear();
96*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Clear();
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker
MarkBrokenUntilDefaultNetworkChanges(const BrokenAlternativeService & broken_alternative_service)99*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::MarkBrokenUntilDefaultNetworkChanges(
100*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
101*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service.alternative_service.host.empty());
102*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kProtoUnknown,
103*6777b538SAndroid Build Coastguard Worker broken_alternative_service.alternative_service.protocol);
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker // The brokenness will expire on the default network change or based on
106*6777b538SAndroid Build Coastguard Worker // timer.
107*6777b538SAndroid Build Coastguard Worker broken_alternative_services_on_default_network_.insert(
108*6777b538SAndroid Build Coastguard Worker broken_alternative_service);
109*6777b538SAndroid Build Coastguard Worker MarkBrokenImpl(broken_alternative_service);
110*6777b538SAndroid Build Coastguard Worker }
111*6777b538SAndroid Build Coastguard Worker
MarkBroken(const BrokenAlternativeService & broken_alternative_service)112*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::MarkBroken(
113*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
114*6777b538SAndroid Build Coastguard Worker // The brokenness expires based only on the timer, not on the default network
115*6777b538SAndroid Build Coastguard Worker // change.
116*6777b538SAndroid Build Coastguard Worker broken_alternative_services_on_default_network_.erase(
117*6777b538SAndroid Build Coastguard Worker broken_alternative_service);
118*6777b538SAndroid Build Coastguard Worker MarkBrokenImpl(broken_alternative_service);
119*6777b538SAndroid Build Coastguard Worker }
120*6777b538SAndroid Build Coastguard Worker
MarkBrokenImpl(const BrokenAlternativeService & broken_alternative_service)121*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::MarkBrokenImpl(
122*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
123*6777b538SAndroid Build Coastguard Worker // Empty host means use host of origin, callers are supposed to substitute.
124*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service.alternative_service.host.empty());
125*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kProtoUnknown,
126*6777b538SAndroid Build Coastguard Worker broken_alternative_service.alternative_service.protocol);
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker auto it =
129*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Get(broken_alternative_service);
130*6777b538SAndroid Build Coastguard Worker int broken_count = 0;
131*6777b538SAndroid Build Coastguard Worker if (it == recently_broken_alternative_services_.end()) {
132*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Put(broken_alternative_service, 1);
133*6777b538SAndroid Build Coastguard Worker } else {
134*6777b538SAndroid Build Coastguard Worker broken_count = it->second++;
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker base::TimeTicks expiration =
137*6777b538SAndroid Build Coastguard Worker clock_->NowTicks() +
138*6777b538SAndroid Build Coastguard Worker ComputeBrokenAlternativeServiceExpirationDelay(
139*6777b538SAndroid Build Coastguard Worker broken_count, initial_delay_, exponential_backoff_on_initial_delay_);
140*6777b538SAndroid Build Coastguard Worker // Return if alternative service is already in expiration queue.
141*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServiceList::iterator list_it;
142*6777b538SAndroid Build Coastguard Worker if (!AddToBrokenListAndMap(broken_alternative_service, expiration,
143*6777b538SAndroid Build Coastguard Worker &list_it)) {
144*6777b538SAndroid Build Coastguard Worker return;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker // If this is now the first entry in the list (i.e.
148*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service| is the next alt svc to expire), schedule
149*6777b538SAndroid Build Coastguard Worker // an expiration task for it.
150*6777b538SAndroid Build Coastguard Worker if (list_it == broken_alternative_service_list_.begin()) {
151*6777b538SAndroid Build Coastguard Worker ScheduleBrokenAlternateProtocolMappingsExpiration();
152*6777b538SAndroid Build Coastguard Worker }
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker
MarkRecentlyBroken(const BrokenAlternativeService & broken_alternative_service)155*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::MarkRecentlyBroken(
156*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
157*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kProtoUnknown,
158*6777b538SAndroid Build Coastguard Worker broken_alternative_service.alternative_service.protocol);
159*6777b538SAndroid Build Coastguard Worker if (recently_broken_alternative_services_.Get(broken_alternative_service) ==
160*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.end()) {
161*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Put(broken_alternative_service, 1);
162*6777b538SAndroid Build Coastguard Worker }
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker
IsBroken(const BrokenAlternativeService & broken_alternative_service) const165*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeServices::IsBroken(
166*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) const {
167*6777b538SAndroid Build Coastguard Worker // Empty host means use host of origin, callers are supposed to substitute.
168*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service.alternative_service.host.empty());
169*6777b538SAndroid Build Coastguard Worker return broken_alternative_service_map_.find(broken_alternative_service) !=
170*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.end();
171*6777b538SAndroid Build Coastguard Worker }
172*6777b538SAndroid Build Coastguard Worker
IsBroken(const BrokenAlternativeService & broken_alternative_service,base::TimeTicks * brokenness_expiration) const173*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeServices::IsBroken(
174*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service,
175*6777b538SAndroid Build Coastguard Worker base::TimeTicks* brokenness_expiration) const {
176*6777b538SAndroid Build Coastguard Worker DCHECK(brokenness_expiration != nullptr);
177*6777b538SAndroid Build Coastguard Worker // Empty host means use host of origin, callers are supposed to substitute.
178*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service.alternative_service.host.empty());
179*6777b538SAndroid Build Coastguard Worker auto map_it =
180*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.find(broken_alternative_service);
181*6777b538SAndroid Build Coastguard Worker if (map_it == broken_alternative_service_map_.end()) {
182*6777b538SAndroid Build Coastguard Worker return false;
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker auto list_it = map_it->second;
185*6777b538SAndroid Build Coastguard Worker *brokenness_expiration = list_it->second;
186*6777b538SAndroid Build Coastguard Worker return true;
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker
WasRecentlyBroken(const BrokenAlternativeService & broken_alternative_service)189*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeServices::WasRecentlyBroken(
190*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
191*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service.alternative_service.host.empty());
192*6777b538SAndroid Build Coastguard Worker return recently_broken_alternative_services_.Get(
193*6777b538SAndroid Build Coastguard Worker broken_alternative_service) !=
194*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.end() ||
195*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.find(broken_alternative_service) !=
196*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.end();
197*6777b538SAndroid Build Coastguard Worker }
198*6777b538SAndroid Build Coastguard Worker
Confirm(const BrokenAlternativeService & broken_alternative_service)199*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::Confirm(
200*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service) {
201*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kProtoUnknown,
202*6777b538SAndroid Build Coastguard Worker broken_alternative_service.alternative_service.protocol);
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker // Remove |broken_alternative_service| from
205*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service_list_|, |broken_alternative_service_map_| and
206*6777b538SAndroid Build Coastguard Worker // |broken_alternative_services_on_default_network_|.
207*6777b538SAndroid Build Coastguard Worker auto map_it =
208*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.find(broken_alternative_service);
209*6777b538SAndroid Build Coastguard Worker if (map_it != broken_alternative_service_map_.end()) {
210*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.erase(map_it->second);
211*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.erase(map_it);
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker
214*6777b538SAndroid Build Coastguard Worker auto it =
215*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Get(broken_alternative_service);
216*6777b538SAndroid Build Coastguard Worker if (it != recently_broken_alternative_services_.end()) {
217*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Erase(it);
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker broken_alternative_services_on_default_network_.erase(
221*6777b538SAndroid Build Coastguard Worker broken_alternative_service);
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
OnDefaultNetworkChanged()224*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeServices::OnDefaultNetworkChanged() {
225*6777b538SAndroid Build Coastguard Worker bool changed = !broken_alternative_services_on_default_network_.empty();
226*6777b538SAndroid Build Coastguard Worker while (!broken_alternative_services_on_default_network_.empty()) {
227*6777b538SAndroid Build Coastguard Worker Confirm(*broken_alternative_services_on_default_network_.begin());
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker return changed;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker
SetBrokenAndRecentlyBrokenAlternativeServices(std::unique_ptr<BrokenAlternativeServiceList> broken_alternative_service_list,std::unique_ptr<RecentlyBrokenAlternativeServices> recently_broken_alternative_services)232*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::SetBrokenAndRecentlyBrokenAlternativeServices(
233*6777b538SAndroid Build Coastguard Worker std::unique_ptr<BrokenAlternativeServiceList>
234*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list,
235*6777b538SAndroid Build Coastguard Worker std::unique_ptr<RecentlyBrokenAlternativeServices>
236*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services) {
237*6777b538SAndroid Build Coastguard Worker DCHECK(broken_alternative_service_list);
238*6777b538SAndroid Build Coastguard Worker DCHECK(recently_broken_alternative_services);
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker base::TimeTicks next_expiration =
241*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.empty()
242*6777b538SAndroid Build Coastguard Worker ? base::TimeTicks::Max()
243*6777b538SAndroid Build Coastguard Worker : broken_alternative_service_list_.front().second;
244*6777b538SAndroid Build Coastguard Worker
245*6777b538SAndroid Build Coastguard Worker // Add |recently_broken_alternative_services| to
246*6777b538SAndroid Build Coastguard Worker // |recently_broken_alternative_services_|.
247*6777b538SAndroid Build Coastguard Worker // If an alt-svc already exists, overwrite its broken-count to the one in
248*6777b538SAndroid Build Coastguard Worker // |recently_broken_alternative_services|.
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Swap(
251*6777b538SAndroid Build Coastguard Worker *recently_broken_alternative_services);
252*6777b538SAndroid Build Coastguard Worker // Add back all existing recently broken alt svcs to cache so they're at
253*6777b538SAndroid Build Coastguard Worker // front of recency list (LRUCache::Get() does this automatically).
254*6777b538SAndroid Build Coastguard Worker for (const auto& [service, broken_count] :
255*6777b538SAndroid Build Coastguard Worker base::Reversed(*recently_broken_alternative_services)) {
256*6777b538SAndroid Build Coastguard Worker if (recently_broken_alternative_services_.Get(service) ==
257*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.end()) {
258*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Put(service, broken_count);
259*6777b538SAndroid Build Coastguard Worker }
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker // Append |broken_alternative_service_list| to
263*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service_list_|
264*6777b538SAndroid Build Coastguard Worker size_t num_broken_alt_svcs_added = broken_alternative_service_list->size();
265*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.splice(
266*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.begin(),
267*6777b538SAndroid Build Coastguard Worker *broken_alternative_service_list);
268*6777b538SAndroid Build Coastguard Worker // For each newly-appended alt svc in |broken_alternative_service_list_|,
269*6777b538SAndroid Build Coastguard Worker // add an entry to |broken_alternative_service_map_| that points to its
270*6777b538SAndroid Build Coastguard Worker // list iterator. Also, add an entry for that alt svc in
271*6777b538SAndroid Build Coastguard Worker // |recently_broken_alternative_services_| if one doesn't exist.
272*6777b538SAndroid Build Coastguard Worker auto list_it = broken_alternative_service_list_.begin();
273*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < num_broken_alt_svcs_added; ++i) {
274*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service = list_it->first;
275*6777b538SAndroid Build Coastguard Worker auto map_it =
276*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.find(broken_alternative_service);
277*6777b538SAndroid Build Coastguard Worker if (map_it != broken_alternative_service_map_.end()) {
278*6777b538SAndroid Build Coastguard Worker // Implies this entry already exists somewhere else in
279*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service_list_|. Remove the existing entry from
280*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service_list_|, and update the
281*6777b538SAndroid Build Coastguard Worker // |broken_alternative_service_map_| entry to point to this list entry
282*6777b538SAndroid Build Coastguard Worker // instead.
283*6777b538SAndroid Build Coastguard Worker auto list_existing_entry_it = map_it->second;
284*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.erase(list_existing_entry_it);
285*6777b538SAndroid Build Coastguard Worker map_it->second = list_it;
286*6777b538SAndroid Build Coastguard Worker } else {
287*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.emplace(broken_alternative_service,
288*6777b538SAndroid Build Coastguard Worker list_it);
289*6777b538SAndroid Build Coastguard Worker }
290*6777b538SAndroid Build Coastguard Worker
291*6777b538SAndroid Build Coastguard Worker if (recently_broken_alternative_services_.Peek(
292*6777b538SAndroid Build Coastguard Worker broken_alternative_service) ==
293*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.end()) {
294*6777b538SAndroid Build Coastguard Worker recently_broken_alternative_services_.Put(broken_alternative_service, 1);
295*6777b538SAndroid Build Coastguard Worker }
296*6777b538SAndroid Build Coastguard Worker
297*6777b538SAndroid Build Coastguard Worker ++list_it;
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker
300*6777b538SAndroid Build Coastguard Worker // Sort |broken_alternative_service_list_| by expiration time. This operation
301*6777b538SAndroid Build Coastguard Worker // does not invalidate list iterators, so |broken_alternative_service_map_|
302*6777b538SAndroid Build Coastguard Worker // does not need to be updated.
303*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.sort(
304*6777b538SAndroid Build Coastguard Worker [](const std::pair<BrokenAlternativeService, base::TimeTicks>& lhs,
305*6777b538SAndroid Build Coastguard Worker const std::pair<BrokenAlternativeService, base::TimeTicks>& rhs)
306*6777b538SAndroid Build Coastguard Worker -> bool { return lhs.second < rhs.second; });
307*6777b538SAndroid Build Coastguard Worker
308*6777b538SAndroid Build Coastguard Worker base::TimeTicks new_next_expiration =
309*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.empty()
310*6777b538SAndroid Build Coastguard Worker ? base::TimeTicks::Max()
311*6777b538SAndroid Build Coastguard Worker : broken_alternative_service_list_.front().second;
312*6777b538SAndroid Build Coastguard Worker
313*6777b538SAndroid Build Coastguard Worker if (new_next_expiration != next_expiration)
314*6777b538SAndroid Build Coastguard Worker ScheduleBrokenAlternateProtocolMappingsExpiration();
315*6777b538SAndroid Build Coastguard Worker }
316*6777b538SAndroid Build Coastguard Worker
SetDelayParams(std::optional<base::TimeDelta> initial_delay,std::optional<bool> exponential_backoff_on_initial_delay)317*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::SetDelayParams(
318*6777b538SAndroid Build Coastguard Worker std::optional<base::TimeDelta> initial_delay,
319*6777b538SAndroid Build Coastguard Worker std::optional<bool> exponential_backoff_on_initial_delay) {
320*6777b538SAndroid Build Coastguard Worker if (initial_delay.has_value()) {
321*6777b538SAndroid Build Coastguard Worker initial_delay_ = initial_delay.value();
322*6777b538SAndroid Build Coastguard Worker }
323*6777b538SAndroid Build Coastguard Worker if (exponential_backoff_on_initial_delay.has_value()) {
324*6777b538SAndroid Build Coastguard Worker exponential_backoff_on_initial_delay_ =
325*6777b538SAndroid Build Coastguard Worker exponential_backoff_on_initial_delay.value();
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker }
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeServiceList&
broken_alternative_service_list() const330*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServices::broken_alternative_service_list() const {
331*6777b538SAndroid Build Coastguard Worker return broken_alternative_service_list_;
332*6777b538SAndroid Build Coastguard Worker }
333*6777b538SAndroid Build Coastguard Worker
334*6777b538SAndroid Build Coastguard Worker const RecentlyBrokenAlternativeServices&
recently_broken_alternative_services() const335*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServices::recently_broken_alternative_services() const {
336*6777b538SAndroid Build Coastguard Worker return recently_broken_alternative_services_;
337*6777b538SAndroid Build Coastguard Worker }
338*6777b538SAndroid Build Coastguard Worker
AddToBrokenListAndMap(const BrokenAlternativeService & broken_alternative_service,base::TimeTicks expiration,BrokenAlternativeServiceList::iterator * it)339*6777b538SAndroid Build Coastguard Worker bool BrokenAlternativeServices::AddToBrokenListAndMap(
340*6777b538SAndroid Build Coastguard Worker const BrokenAlternativeService& broken_alternative_service,
341*6777b538SAndroid Build Coastguard Worker base::TimeTicks expiration,
342*6777b538SAndroid Build Coastguard Worker BrokenAlternativeServiceList::iterator* it) {
343*6777b538SAndroid Build Coastguard Worker DCHECK(it);
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker auto map_it =
346*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.find(broken_alternative_service);
347*6777b538SAndroid Build Coastguard Worker if (map_it != broken_alternative_service_map_.end())
348*6777b538SAndroid Build Coastguard Worker return false;
349*6777b538SAndroid Build Coastguard Worker
350*6777b538SAndroid Build Coastguard Worker // Iterate from end of |broken_alternative_service_list_| to find where to
351*6777b538SAndroid Build Coastguard Worker // insert it to keep the list sorted by expiration time.
352*6777b538SAndroid Build Coastguard Worker auto list_it = broken_alternative_service_list_.end();
353*6777b538SAndroid Build Coastguard Worker while (list_it != broken_alternative_service_list_.begin()) {
354*6777b538SAndroid Build Coastguard Worker --list_it;
355*6777b538SAndroid Build Coastguard Worker if (list_it->second <= expiration) {
356*6777b538SAndroid Build Coastguard Worker ++list_it;
357*6777b538SAndroid Build Coastguard Worker break;
358*6777b538SAndroid Build Coastguard Worker }
359*6777b538SAndroid Build Coastguard Worker }
360*6777b538SAndroid Build Coastguard Worker
361*6777b538SAndroid Build Coastguard Worker // Insert |broken_alternative_service| into the list and the map.
362*6777b538SAndroid Build Coastguard Worker list_it = broken_alternative_service_list_.insert(
363*6777b538SAndroid Build Coastguard Worker list_it, std::pair(broken_alternative_service, expiration));
364*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.emplace(broken_alternative_service, list_it);
365*6777b538SAndroid Build Coastguard Worker
366*6777b538SAndroid Build Coastguard Worker *it = list_it;
367*6777b538SAndroid Build Coastguard Worker return true;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker
ExpireBrokenAlternateProtocolMappings()370*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices::ExpireBrokenAlternateProtocolMappings() {
371*6777b538SAndroid Build Coastguard Worker base::TimeTicks now = clock_->NowTicks();
372*6777b538SAndroid Build Coastguard Worker
373*6777b538SAndroid Build Coastguard Worker while (!broken_alternative_service_list_.empty()) {
374*6777b538SAndroid Build Coastguard Worker auto it = broken_alternative_service_list_.begin();
375*6777b538SAndroid Build Coastguard Worker if (now < it->second) {
376*6777b538SAndroid Build Coastguard Worker break;
377*6777b538SAndroid Build Coastguard Worker }
378*6777b538SAndroid Build Coastguard Worker
379*6777b538SAndroid Build Coastguard Worker delegate_->OnExpireBrokenAlternativeService(
380*6777b538SAndroid Build Coastguard Worker it->first.alternative_service, it->first.network_anonymization_key);
381*6777b538SAndroid Build Coastguard Worker
382*6777b538SAndroid Build Coastguard Worker broken_alternative_service_map_.erase(it->first);
383*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.erase(it);
384*6777b538SAndroid Build Coastguard Worker }
385*6777b538SAndroid Build Coastguard Worker
386*6777b538SAndroid Build Coastguard Worker if (!broken_alternative_service_list_.empty())
387*6777b538SAndroid Build Coastguard Worker ScheduleBrokenAlternateProtocolMappingsExpiration();
388*6777b538SAndroid Build Coastguard Worker }
389*6777b538SAndroid Build Coastguard Worker
390*6777b538SAndroid Build Coastguard Worker void BrokenAlternativeServices ::
ScheduleBrokenAlternateProtocolMappingsExpiration()391*6777b538SAndroid Build Coastguard Worker ScheduleBrokenAlternateProtocolMappingsExpiration() {
392*6777b538SAndroid Build Coastguard Worker DCHECK(!broken_alternative_service_list_.empty());
393*6777b538SAndroid Build Coastguard Worker base::TimeTicks now = clock_->NowTicks();
394*6777b538SAndroid Build Coastguard Worker base::TimeTicks next_expiration =
395*6777b538SAndroid Build Coastguard Worker broken_alternative_service_list_.front().second;
396*6777b538SAndroid Build Coastguard Worker base::TimeDelta delay =
397*6777b538SAndroid Build Coastguard Worker next_expiration > now ? next_expiration - now : base::TimeDelta();
398*6777b538SAndroid Build Coastguard Worker expiration_timer_.Stop();
399*6777b538SAndroid Build Coastguard Worker expiration_timer_.Start(
400*6777b538SAndroid Build Coastguard Worker FROM_HERE, delay,
401*6777b538SAndroid Build Coastguard Worker base::BindOnce(
402*6777b538SAndroid Build Coastguard Worker &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings,
403*6777b538SAndroid Build Coastguard Worker weak_ptr_factory_.GetWeakPtr()));
404*6777b538SAndroid Build Coastguard Worker }
405*6777b538SAndroid Build Coastguard Worker
406*6777b538SAndroid Build Coastguard Worker } // namespace net
407