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

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

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

Powered by Google App Engine
This is Rietveld 408576698