Chromium Code Reviews| 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 |