Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: net/http/broken_alternative_services.cc

Issue 2898983006: Fix and refactor HttpServerPropertiesImpl's alternative services brokenness expiration behavior (Closed)
Patch Set: Added checks for contents of expired_alt_svcs_ in BrokenAlternativeServicesTest Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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/http/broken_alternative_services.h"
6
7 #include "base/memory/singleton.h"
8 #include "base/time/tick_clock.h"
9 #include "base/time/time.h"
10 #include "net/http/http_server_properties_impl.h"
11
12 namespace net {
13
14 namespace {
15
16 // Initial delay for broken alternative services.
17 const uint64_t kBrokenAlternativeProtocolDelaySecs = 300;
18 // Subsequent failures result in exponential (base 2) backoff.
19 // Limit binary shift to limit delay to approximately 2 days.
20 const int kBrokenDelayMaxShift = 9;
21
22 base::TimeDelta ComputeBrokenAlternativeServiceExpirationDelay(
23 int broken_count) {
24 DCHECK(broken_count >= 0);
25 if (broken_count > kBrokenDelayMaxShift)
26 broken_count = kBrokenDelayMaxShift;
27 return base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs) *
28 (1 << broken_count);
29 }
30
31 } // namespace
32
33 BrokenAlternativeServices::BrokenAlternativeServices(Delegate* delegate,
34 base::TickClock* clock)
35 : delegate_(delegate),
36 clock_(clock),
37 recently_broken_alternative_services_(
38 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT),
39 weak_ptr_factory_(this) {
40 DCHECK(delegate_);
41 DCHECK(clock_);
42 }
43
44 BrokenAlternativeServices::~BrokenAlternativeServices() {}
45
46 void BrokenAlternativeServices::MarkAlternativeServiceBroken(
47 const AlternativeService& alternative_service) {
48 // Empty host means use host of origin, callers are supposed to substitute.
49 DCHECK(!alternative_service.host.empty());
50 DCHECK(alternative_service.protocol != kProtoUnknown);
51
52 auto it = recently_broken_alternative_services_.Get(alternative_service);
53 int broken_count = 0;
54 if (it == recently_broken_alternative_services_.end()) {
55 recently_broken_alternative_services_.Put(alternative_service, 1);
56 } else {
57 broken_count = it->second++;
58 }
59 base::TimeTicks expiration =
60 clock_->NowTicks() +
61 ComputeBrokenAlternativeServiceExpirationDelay(broken_count);
62 // Return if alternative service is already in expiration queue.
63 BrokenAlternativeServiceList::iterator list_it;
64 if (!AddToBrokenAlternativeServiceListAndMap(alternative_service, expiration,
65 &list_it)) {
66 return;
67 }
68
69 // If this is now the first entry in the list (i.e. |alternative_service| is
70 // the next alt svc to expire), schedule an expiration task for it.
71 if (list_it == broken_alternative_service_list_.begin()) {
72 ScheduleBrokenAlternateProtocolMappingsExpiration();
73 }
74 }
75
76 void BrokenAlternativeServices::MarkAlternativeServiceRecentlyBroken(
77 const AlternativeService& alternative_service) {
78 DCHECK(alternative_service.protocol != kProtoUnknown);
79 if (recently_broken_alternative_services_.Get(alternative_service) ==
80 recently_broken_alternative_services_.end()) {
81 recently_broken_alternative_services_.Put(alternative_service, 1);
82 }
83 }
84
85 bool BrokenAlternativeServices::IsAlternativeServiceBroken(
86 const AlternativeService& alternative_service) const {
87 // Empty host means use host of origin, callers are supposed to substitute.
88 DCHECK(!alternative_service.host.empty());
89 return broken_alternative_service_map_.find(alternative_service) !=
90 broken_alternative_service_map_.end();
91 }
92
93 bool BrokenAlternativeServices::WasAlternativeServiceRecentlyBroken(
94 const AlternativeService& alternative_service) {
95 return recently_broken_alternative_services_.Get(alternative_service) !=
96 recently_broken_alternative_services_.end();
97 }
98
99 void BrokenAlternativeServices::ConfirmAlternativeService(
100 const AlternativeService& alternative_service) {
101 if (alternative_service.protocol == kProtoUnknown)
102 return;
Ryan Hamilton 2017/05/27 13:28:15 nit: since we can't mark unknown as broken it does
wangyix1 2017/05/30 21:18:17 Done.
103
104 // Remove |alternative_service| from |alternative_service_list_| and
105 // |alternative_service_map_|.
106 auto map_it = broken_alternative_service_map_.find(alternative_service);
107 if (map_it != broken_alternative_service_map_.end()) {
108 broken_alternative_service_list_.erase(map_it->second);
109 broken_alternative_service_map_.erase(map_it);
110 }
111
112 auto it = recently_broken_alternative_services_.Get(alternative_service);
113 if (it != recently_broken_alternative_services_.end()) {
114 recently_broken_alternative_services_.Erase(it);
115 }
116 }
117
118 bool BrokenAlternativeServices::AddToBrokenAlternativeServiceListAndMap(
119 const AlternativeService& alternative_service,
120 base::TimeTicks expiration,
121 BrokenAlternativeServiceList::iterator* it) {
122 DCHECK(it);
123
124 auto map_it = broken_alternative_service_map_.find(alternative_service);
125 if (map_it != broken_alternative_service_map_.end())
126 return false;
127
128 // Iterate from end of |broken_alternative_service_list_| to find where to
129 // insert it to keep the list sorted by expiration time.
130 auto list_it = broken_alternative_service_list_.end();
131 while (list_it != broken_alternative_service_list_.begin()) {
132 --list_it;
133 if (list_it->expiration <= expiration) {
134 ++list_it;
135 break;
136 }
137 }
138
139 // Insert |alternative_service| into the list and the map
140 list_it = broken_alternative_service_list_.insert(
141 list_it, BrokenAltSvcExpireInfo(alternative_service, expiration));
142 broken_alternative_service_map_.insert(
143 std::make_pair(alternative_service, list_it));
144
145 *it = list_it;
146 return true;
147 }
148
149 void BrokenAlternativeServices::ExpireBrokenAlternateProtocolMappings() {
150 base::TimeTicks now = clock_->NowTicks();
151
152 while (!broken_alternative_service_list_.empty()) {
153 auto it = broken_alternative_service_list_.begin();
154 if (now < it->expiration) {
155 break;
156 }
157
158 delegate_->OnExpireBrokenAlternativeService(it->alternative_service);
159
160 broken_alternative_service_map_.erase(it->alternative_service);
161 broken_alternative_service_list_.erase(it);
162 }
163
164 if (!broken_alternative_service_list_.empty())
165 ScheduleBrokenAlternateProtocolMappingsExpiration();
166 }
167
168 void BrokenAlternativeServices ::
169 ScheduleBrokenAlternateProtocolMappingsExpiration() {
170 DCHECK(!broken_alternative_service_list_.empty());
171 base::TimeTicks now = clock_->NowTicks();
172 base::TimeTicks when = broken_alternative_service_list_.front().expiration;
173 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
174 expiration_timer_.Stop();
175 expiration_timer_.Start(
176 FROM_HERE, delay,
177 base::Bind(
178 &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings,
179 weak_ptr_factory_.GetWeakPtr()));
180 }
181
182 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698