OLD | NEW |
---|---|
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/broken_alternative_services.h" | 5 #include "net/http/broken_alternative_services.h" |
6 | 6 |
7 #include "base/memory/singleton.h" | 7 #include "base/memory/singleton.h" |
8 #include "base/time/tick_clock.h" | 8 #include "base/time/tick_clock.h" |
9 #include "base/time/time.h" | 9 #include "base/time/time.h" |
10 #include "net/http/http_server_properties_impl.h" | 10 #include "net/http/http_server_properties_impl.h" |
(...skipping 12 matching lines...) Expand all Loading... | |
23 int broken_count) { | 23 int broken_count) { |
24 DCHECK_GE(broken_count, 0); | 24 DCHECK_GE(broken_count, 0); |
25 if (broken_count > kBrokenDelayMaxShift) | 25 if (broken_count > kBrokenDelayMaxShift) |
26 broken_count = kBrokenDelayMaxShift; | 26 broken_count = kBrokenDelayMaxShift; |
27 return base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs) * | 27 return base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs) * |
28 (1 << broken_count); | 28 (1 << broken_count); |
29 } | 29 } |
30 | 30 |
31 } // namespace | 31 } // namespace |
32 | 32 |
33 BrokenAlternativeServices::BrokenAlternativeServices(Delegate* delegate, | 33 BrokenAlternativeServices::BrokenAlternativeServices(Delegate* delegate) |
34 base::TickClock* clock) | |
35 : delegate_(delegate), | 34 : delegate_(delegate), |
36 clock_(clock), | 35 clock_(&default_clock_), |
37 recently_broken_alternative_services_( | 36 recently_broken_alternative_services_( |
38 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT), | 37 RecentlyBrokenAlternativeServices::NO_AUTO_EVICT), |
39 weak_ptr_factory_(this) { | 38 weak_ptr_factory_(this) { |
40 DCHECK(delegate_); | 39 DCHECK(delegate_); |
41 DCHECK(clock_); | |
42 } | 40 } |
43 | 41 |
44 BrokenAlternativeServices::~BrokenAlternativeServices() {} | 42 BrokenAlternativeServices::~BrokenAlternativeServices() {} |
45 | 43 |
44 void BrokenAlternativeServices::Clear() { | |
45 expiration_timer_.Stop(); | |
46 broken_alternative_service_list_.clear(); | |
47 broken_alternative_service_map_.clear(); | |
48 recently_broken_alternative_services_.Clear(); | |
49 } | |
50 | |
46 void BrokenAlternativeServices::MarkAlternativeServiceBroken( | 51 void BrokenAlternativeServices::MarkAlternativeServiceBroken( |
47 const AlternativeService& alternative_service) { | 52 const AlternativeService& alternative_service) { |
48 // Empty host means use host of origin, callers are supposed to substitute. | 53 // Empty host means use host of origin, callers are supposed to substitute. |
49 DCHECK(!alternative_service.host.empty()); | 54 DCHECK(!alternative_service.host.empty()); |
50 DCHECK_NE(kProtoUnknown, alternative_service.protocol); | 55 DCHECK_NE(kProtoUnknown, alternative_service.protocol); |
51 | 56 |
52 auto it = recently_broken_alternative_services_.Get(alternative_service); | 57 auto it = recently_broken_alternative_services_.Get(alternative_service); |
53 int broken_count = 0; | 58 int broken_count = 0; |
54 if (it == recently_broken_alternative_services_.end()) { | 59 if (it == recently_broken_alternative_services_.end()) { |
55 recently_broken_alternative_services_.Put(alternative_service, 1); | 60 recently_broken_alternative_services_.Put(alternative_service, 1); |
56 } else { | 61 } else { |
57 broken_count = it->second++; | 62 broken_count = it->second++; |
58 } | 63 } |
59 base::TimeTicks expiration = | 64 base::TimeTicks expiration = |
60 clock_->NowTicks() + | 65 clock_->NowTicks() + |
61 ComputeBrokenAlternativeServiceExpirationDelay(broken_count); | 66 ComputeBrokenAlternativeServiceExpirationDelay(broken_count); |
62 // Return if alternative service is already in expiration queue. | 67 // Return if alternative service is already in expiration queue. |
63 BrokenAlternativeServiceList::iterator list_it; | 68 BrokenAlternativeServiceList::iterator list_it; |
64 if (!AddToBrokenAlternativeServiceListAndMap(alternative_service, expiration, | 69 if (!AddToBrokenAlternativeServiceListAndMap(alternative_service, expiration, |
65 &list_it)) { | 70 &list_it)) { |
66 return; | 71 return; |
67 } | 72 } |
68 | 73 |
69 // If this is now the first entry in the list (i.e. |alternative_service| is | 74 // 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. | 75 // the next alt svc to expire), schedule an expiration task for it. |
71 if (list_it == broken_alternative_service_list_.begin()) { | 76 if (list_it == broken_alternative_service_list_.begin()) { |
72 ScheduleBrokenAlternateProtocolMappingsExpiration(); | 77 ScheduleBrokenAlternateProtocolMappingsExpiration( |
78 broken_alternative_service_list_.front().second); | |
73 } | 79 } |
74 } | 80 } |
75 | 81 |
76 void BrokenAlternativeServices::MarkAlternativeServiceRecentlyBroken( | 82 void BrokenAlternativeServices::MarkAlternativeServiceRecentlyBroken( |
77 const AlternativeService& alternative_service) { | 83 const AlternativeService& alternative_service) { |
78 DCHECK_NE(kProtoUnknown, alternative_service.protocol); | 84 DCHECK_NE(kProtoUnknown, alternative_service.protocol); |
79 if (recently_broken_alternative_services_.Get(alternative_service) == | 85 if (recently_broken_alternative_services_.Get(alternative_service) == |
80 recently_broken_alternative_services_.end()) { | 86 recently_broken_alternative_services_.end()) { |
81 recently_broken_alternative_services_.Put(alternative_service, 1); | 87 recently_broken_alternative_services_.Put(alternative_service, 1); |
82 } | 88 } |
(...skipping 24 matching lines...) Expand all Loading... | |
107 broken_alternative_service_list_.erase(map_it->second); | 113 broken_alternative_service_list_.erase(map_it->second); |
108 broken_alternative_service_map_.erase(map_it); | 114 broken_alternative_service_map_.erase(map_it); |
109 } | 115 } |
110 | 116 |
111 auto it = recently_broken_alternative_services_.Get(alternative_service); | 117 auto it = recently_broken_alternative_services_.Get(alternative_service); |
112 if (it != recently_broken_alternative_services_.end()) { | 118 if (it != recently_broken_alternative_services_.end()) { |
113 recently_broken_alternative_services_.Erase(it); | 119 recently_broken_alternative_services_.Erase(it); |
114 } | 120 } |
115 } | 121 } |
116 | 122 |
117 const BrokenAlternativeServiceList& | 123 void BrokenAlternativeServices::SetTickClockForTesting(base::TickClock* clock) { |
118 BrokenAlternativeServices::broken_alternative_service_list() const { | 124 DCHECK(clock); |
119 return broken_alternative_service_list_; | 125 clock_ = clock; |
Ryan Hamilton
2017/06/12 18:57:32
I don't think I understand the clock-related chang
wangyix1
2017/06/14 00:01:25
Acknowledged. Will go back to clock being set usin
| |
120 } | 126 } |
121 | 127 |
122 const RecentlyBrokenAlternativeServices& | 128 void BrokenAlternativeServices::AddBrokenAndRecentlyBrokenAlternativeServices( |
123 BrokenAlternativeServices::recently_broken_alternative_services() const { | |
124 return recently_broken_alternative_services_; | |
125 } | |
126 | |
127 bool BrokenAlternativeServices::AddBrokenAndRecentlyBrokenAlternativeServices( | |
128 std::unique_ptr<BrokenAlternativeServiceList> | 129 std::unique_ptr<BrokenAlternativeServiceList> |
129 broken_alternative_service_list, | 130 broken_alternative_service_list, |
130 std::unique_ptr<RecentlyBrokenAlternativeServices> | 131 std::unique_ptr<RecentlyBrokenAlternativeServices> |
131 recently_broken_alternative_services) { | 132 recently_broken_alternative_services) { |
132 DCHECK(broken_alternative_service_list); | 133 DCHECK(broken_alternative_service_list); |
133 DCHECK(recently_broken_alternative_services); | 134 DCHECK(recently_broken_alternative_services); |
134 | 135 |
135 // Make sure all alt svcs in |broken_alternative_service_list| has an entry | 136 // Make sure all alt svcs in |broken_alternative_service_list| has an entry |
136 // in |recently_broken_alternative_services| | 137 // in |recently_broken_alternative_services| |
137 for (const auto& pair : *broken_alternative_service_list) { | 138 for (const auto& pair : *broken_alternative_service_list) { |
138 DCHECK(recently_broken_alternative_services->Peek(pair.first) != | 139 DCHECK(recently_broken_alternative_services->Peek(pair.first) != |
139 recently_broken_alternative_services->end()); | 140 recently_broken_alternative_services->end()); |
140 } | 141 } |
141 | 142 |
142 bool added = false; | 143 base::TimeTicks next_expiration = |
144 broken_alternative_service_list_.empty() | |
145 ? base::TimeTicks::Max() | |
146 : broken_alternative_service_list_.front().second; | |
147 | |
148 // Add recently broken alt svcs to |recently_broken_alternative_services_|. | |
149 // If an alt-svc already exists, update its broken-count to the one provided | |
150 // in |recently_broken_alternative_services|. | |
143 | 151 |
144 recently_broken_alternative_services_.Swap( | 152 recently_broken_alternative_services_.Swap( |
145 *recently_broken_alternative_services); | 153 *recently_broken_alternative_services); |
146 // Add back all existing recently broken alt svcs to cache so they're at | 154 // Add back all existing recently broken alt svcs to cache so they're at |
147 // front of recency list. | 155 // front of recency list (MRUCache::Get() does this automatically). |
148 for (auto it = recently_broken_alternative_services->rbegin(); | 156 for (auto it = recently_broken_alternative_services->rbegin(); |
149 it != recently_broken_alternative_services->rend(); ++it) { | 157 it != recently_broken_alternative_services->rend(); ++it) { |
150 if (recently_broken_alternative_services_.Get(it->first) == | 158 if (recently_broken_alternative_services_.Get(it->first) == |
151 recently_broken_alternative_services_.end()) { | 159 recently_broken_alternative_services_.end()) { |
152 recently_broken_alternative_services_.Put(it->first, it->second); | 160 recently_broken_alternative_services_.Put(it->first, it->second); |
153 added = true; | |
154 } | 161 } |
155 } | 162 } |
156 | 163 |
157 // Add broken alt svcs to |broken_alternative_service_map_|. Remove all | 164 // Add broken alt svcs to |broken_alternative_service_map_|. If an entry |
158 // that already exist in the map. | 165 // already exists, delete its corresponding entry in |
159 auto it = broken_alternative_service_list->begin(); | 166 // |broken_alternative_service_list_| and update its map entry to point to |
160 while (it != broken_alternative_service_list->end()) { | 167 // its position in |broken_alternative_service_list|. |
168 for (auto it = broken_alternative_service_list->begin(); | |
169 it != broken_alternative_service_list->end(); ++it) { | |
161 const AlternativeService& alternative_service = it->first; | 170 const AlternativeService& alternative_service = it->first; |
162 if (broken_alternative_service_map_.find(alternative_service) == | 171 auto map_it = broken_alternative_service_map_.find(alternative_service); |
163 broken_alternative_service_map_.end()) { | 172 if (map_it != broken_alternative_service_map_.end()) { |
173 broken_alternative_service_list_.erase(map_it->second); | |
174 map_it->second = it; | |
175 } else { | |
164 broken_alternative_service_map_.insert( | 176 broken_alternative_service_map_.insert( |
165 std::make_pair(alternative_service, it)); | 177 std::make_pair(alternative_service, it)); |
166 ++it; | |
167 } else { | |
168 broken_alternative_service_list->erase(it++); | |
169 } | 178 } |
170 } | 179 } |
171 | 180 |
172 if (!broken_alternative_service_list->empty()) | |
173 added = true; | |
174 | |
175 // Merge |broken_alternative_service_list| with | 181 // Merge |broken_alternative_service_list| with |
176 // |broken_alternative_service_list_|. Both should already be sorted by | 182 // |broken_alternative_service_list_|. Both should already be sorted by |
177 // expiration time. | 183 // expiration time. std::list::merge() will not invalidate any iterators |
178 bool schedule_expiration = | 184 // of either list, so all iterators in |broken_alternative_service_map_| |
179 (!broken_alternative_service_list->empty() && | 185 // remain valid. |
180 (broken_alternative_service_list_.empty() || | |
181 broken_alternative_service_list->front().second < | |
182 broken_alternative_service_list_.front().second)); | |
183 | |
184 broken_alternative_service_list_.merge( | 186 broken_alternative_service_list_.merge( |
185 *broken_alternative_service_list, | 187 *broken_alternative_service_list, |
186 [](const std::pair<AlternativeService, base::TimeTicks>& lhs, | 188 [](const std::pair<AlternativeService, base::TimeTicks>& lhs, |
187 const std::pair<AlternativeService, base::TimeTicks>& rhs) -> bool { | 189 const std::pair<AlternativeService, base::TimeTicks>& rhs) -> bool { |
188 return lhs.second < rhs.second; | 190 return lhs.second < rhs.second; |
189 }); | 191 }); |
190 | 192 |
191 if (schedule_expiration) | 193 base::TimeTicks new_next_expiration = |
192 ScheduleBrokenAlternateProtocolMappingsExpiration(); | 194 broken_alternative_service_list_.empty() |
195 ? base::TimeTicks::Max() | |
196 : broken_alternative_service_list_.front().second; | |
193 | 197 |
194 return added; | 198 if (new_next_expiration != next_expiration) |
199 ScheduleBrokenAlternateProtocolMappingsExpiration(new_next_expiration); | |
200 } | |
201 | |
202 const BrokenAlternativeServiceList& | |
203 BrokenAlternativeServices::broken_alternative_service_list() const { | |
204 return broken_alternative_service_list_; | |
205 } | |
206 | |
207 const RecentlyBrokenAlternativeServices& | |
208 BrokenAlternativeServices::recently_broken_alternative_services() const { | |
209 return recently_broken_alternative_services_; | |
195 } | 210 } |
196 | 211 |
197 bool BrokenAlternativeServices::AddToBrokenAlternativeServiceListAndMap( | 212 bool BrokenAlternativeServices::AddToBrokenAlternativeServiceListAndMap( |
198 const AlternativeService& alternative_service, | 213 const AlternativeService& alternative_service, |
199 base::TimeTicks expiration, | 214 base::TimeTicks expiration, |
200 BrokenAlternativeServiceList::iterator* it) { | 215 BrokenAlternativeServiceList::iterator* it) { |
201 DCHECK(it); | 216 DCHECK(it); |
202 | 217 |
203 auto map_it = broken_alternative_service_map_.find(alternative_service); | 218 auto map_it = broken_alternative_service_map_.find(alternative_service); |
204 if (map_it != broken_alternative_service_map_.end()) | 219 if (map_it != broken_alternative_service_map_.end()) |
(...skipping 29 matching lines...) Expand all Loading... | |
234 break; | 249 break; |
235 } | 250 } |
236 | 251 |
237 delegate_->OnExpireBrokenAlternativeService(it->first); | 252 delegate_->OnExpireBrokenAlternativeService(it->first); |
238 | 253 |
239 broken_alternative_service_map_.erase(it->first); | 254 broken_alternative_service_map_.erase(it->first); |
240 broken_alternative_service_list_.erase(it); | 255 broken_alternative_service_list_.erase(it); |
241 } | 256 } |
242 | 257 |
243 if (!broken_alternative_service_list_.empty()) | 258 if (!broken_alternative_service_list_.empty()) |
244 ScheduleBrokenAlternateProtocolMappingsExpiration(); | 259 ScheduleBrokenAlternateProtocolMappingsExpiration( |
260 broken_alternative_service_list_.front().second); | |
245 } | 261 } |
246 | 262 |
247 void BrokenAlternativeServices :: | 263 void BrokenAlternativeServices :: |
248 ScheduleBrokenAlternateProtocolMappingsExpiration() { | 264 ScheduleBrokenAlternateProtocolMappingsExpiration(base::TimeTicks when) { |
249 DCHECK(!broken_alternative_service_list_.empty()); | 265 DCHECK(!broken_alternative_service_list_.empty()); |
250 base::TimeTicks now = clock_->NowTicks(); | 266 base::TimeTicks now = clock_->NowTicks(); |
251 base::TimeTicks when = broken_alternative_service_list_.front().second; | |
252 base::TimeDelta delay = when > now ? when - now : base::TimeDelta(); | 267 base::TimeDelta delay = when > now ? when - now : base::TimeDelta(); |
253 expiration_timer_.Stop(); | 268 expiration_timer_.Stop(); |
254 expiration_timer_.Start( | 269 expiration_timer_.Start( |
255 FROM_HERE, delay, | 270 FROM_HERE, delay, |
256 base::Bind( | 271 base::Bind( |
257 &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings, | 272 &BrokenAlternativeServices ::ExpireBrokenAlternateProtocolMappings, |
258 weak_ptr_factory_.GetWeakPtr())); | 273 weak_ptr_factory_.GetWeakPtr())); |
259 } | 274 } |
260 | 275 |
261 } // namespace net | 276 } // namespace net |
OLD | NEW |