Update V8 to version 4.7.53.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob6278f3627bf4f71c2fe3970311733bd6869f0f21
1 // Copyright (c) 2012 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.
5 #include "net/http/http_server_properties_impl.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "base/values.h"
20 namespace net {
22 namespace {
24 const uint64 kBrokenAlternativeProtocolDelaySecs = 300;
26 } // namespace
28 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
29 : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
30 alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT),
31 spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
32 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
33 alternative_service_probability_threshold_(1.0),
34 weak_ptr_factory_(this) {
35 canonical_suffixes_.push_back(".c.youtube.com");
36 canonical_suffixes_.push_back(".googlevideo.com");
37 canonical_suffixes_.push_back(".googleusercontent.com");
40 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
43 void HttpServerPropertiesImpl::InitializeSpdyServers(
44 std::vector<std::string>* spdy_servers,
45 bool support_spdy) {
46 DCHECK(CalledOnValidThread());
47 if (!spdy_servers)
48 return;
49 // Add the entries from persisted data.
50 for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
51 it != spdy_servers->rend(); ++it) {
52 spdy_servers_map_.Put(*it, support_spdy);
56 void HttpServerPropertiesImpl::InitializeAlternativeServiceServers(
57 AlternativeServiceMap* alternative_service_map) {
58 for (AlternativeServiceMap::iterator map_it =
59 alternative_service_map_.begin();
60 map_it != alternative_service_map_.end();) {
61 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
62 it != map_it->second.end();) {
63 // Keep all the broken ones since those do not get persisted.
64 AlternativeService alternative_service(it->alternative_service);
65 if (alternative_service.host.empty()) {
66 alternative_service.host = map_it->first.host();
68 if (IsAlternativeServiceBroken(alternative_service)) {
69 ++it;
70 continue;
72 it = map_it->second.erase(it);
74 if (map_it->second.empty()) {
75 RemoveCanonicalHost(map_it->first);
76 map_it = alternative_service_map_.Erase(map_it);
77 continue;
79 ++map_it;
82 // Add the entries from persisted data.
83 for (AlternativeServiceMap::reverse_iterator input_it =
84 alternative_service_map->rbegin();
85 input_it != alternative_service_map->rend(); ++input_it) {
86 DCHECK(!input_it->second.empty());
87 AlternativeServiceMap::iterator output_it =
88 alternative_service_map_.Peek(input_it->first);
89 if (output_it == alternative_service_map_.end()) {
90 // There is no value in alternative_service_map_ for input_it->first:
91 // inserting in AlternativeServiceVectorInfo.
92 alternative_service_map_.Put(input_it->first, input_it->second);
93 continue;
95 // There are some broken alternative services in alternative_service_map_
96 // for input_it->first: appending AlternativeServiceInfo one by one.
97 for (const AlternativeServiceInfo& alternative_service_info :
98 input_it->second) {
99 output_it->second.push_back(alternative_service_info);
103 // Attempt to find canonical servers.
104 uint16 canonical_ports[] = { 80, 443 };
105 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
106 std::string canonical_suffix = canonical_suffixes_[i];
107 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
108 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
109 // If we already have a valid canonical server, we're done.
110 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
111 (alternative_service_map_.Peek(
112 canonical_host_to_origin_map_[canonical_host]) !=
113 alternative_service_map_.end())) {
114 continue;
116 // Now attempt to find a server which matches this origin and set it as
117 // canonical.
118 for (AlternativeServiceMap::const_iterator it =
119 alternative_service_map_.begin();
120 it != alternative_service_map_.end(); ++it) {
121 if (base::EndsWith(it->first.host(), canonical_suffixes_[i],
122 base::CompareCase::INSENSITIVE_ASCII)) {
123 canonical_host_to_origin_map_[canonical_host] = it->first;
124 break;
131 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
132 SpdySettingsMap* spdy_settings_map) {
133 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
134 it != spdy_settings_map->rend(); ++it) {
135 spdy_settings_map_.Put(it->first, it->second);
139 void HttpServerPropertiesImpl::InitializeSupportsQuic(
140 IPAddressNumber* last_address) {
141 if (last_address)
142 last_quic_address_ = *last_address;
145 void HttpServerPropertiesImpl::InitializeServerNetworkStats(
146 ServerNetworkStatsMap* server_network_stats_map) {
147 for (ServerNetworkStatsMap::reverse_iterator it =
148 server_network_stats_map->rbegin();
149 it != server_network_stats_map->rend(); ++it) {
150 server_network_stats_map_.Put(it->first, it->second);
154 void HttpServerPropertiesImpl::GetSpdyServerList(
155 base::ListValue* spdy_server_list,
156 size_t max_size) const {
157 DCHECK(CalledOnValidThread());
158 DCHECK(spdy_server_list);
159 spdy_server_list->Clear();
160 size_t count = 0;
161 // Get the list of servers (host/port) that support SPDY.
162 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
163 it != spdy_servers_map_.end() && count < max_size; ++it) {
164 const std::string spdy_server_host_port = it->first;
165 if (it->second) {
166 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
167 ++count;
172 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
173 return weak_ptr_factory_.GetWeakPtr();
176 void HttpServerPropertiesImpl::Clear() {
177 DCHECK(CalledOnValidThread());
178 spdy_servers_map_.Clear();
179 alternative_service_map_.Clear();
180 canonical_host_to_origin_map_.clear();
181 spdy_settings_map_.Clear();
182 last_quic_address_.clear();
183 server_network_stats_map_.Clear();
186 bool HttpServerPropertiesImpl::SupportsRequestPriority(
187 const HostPortPair& host_port_pair) {
188 DCHECK(CalledOnValidThread());
189 if (host_port_pair.host().empty())
190 return false;
192 if (GetSupportsSpdy(host_port_pair))
193 return true;
195 const AlternativeServiceVector alternative_service_vector =
196 GetAlternativeServices(host_port_pair);
197 for (const AlternativeService& alternative_service :
198 alternative_service_vector) {
199 if (alternative_service.protocol == QUIC) {
200 return true;
203 return false;
206 bool HttpServerPropertiesImpl::GetSupportsSpdy(
207 const HostPortPair& host_port_pair) {
208 DCHECK(CalledOnValidThread());
209 if (host_port_pair.host().empty())
210 return false;
212 SpdyServerHostPortMap::iterator spdy_host_port =
213 spdy_servers_map_.Get(host_port_pair.ToString());
214 return spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second;
217 void HttpServerPropertiesImpl::SetSupportsSpdy(
218 const HostPortPair& host_port_pair,
219 bool support_spdy) {
220 DCHECK(CalledOnValidThread());
221 if (host_port_pair.host().empty())
222 return;
224 SpdyServerHostPortMap::iterator spdy_host_port =
225 spdy_servers_map_.Get(host_port_pair.ToString());
226 if ((spdy_host_port != spdy_servers_map_.end()) &&
227 (spdy_host_port->second == support_spdy)) {
228 return;
230 // Cache the data.
231 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
234 bool HttpServerPropertiesImpl::RequiresHTTP11(
235 const HostPortPair& host_port_pair) {
236 DCHECK(CalledOnValidThread());
237 if (host_port_pair.host().empty())
238 return false;
240 return (http11_servers_.find(host_port_pair) != http11_servers_.end());
243 void HttpServerPropertiesImpl::SetHTTP11Required(
244 const HostPortPair& host_port_pair) {
245 DCHECK(CalledOnValidThread());
246 if (host_port_pair.host().empty())
247 return;
249 http11_servers_.insert(host_port_pair);
252 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
253 SSLConfig* ssl_config) {
254 if (RequiresHTTP11(server)) {
255 ForceHTTP11(ssl_config);
259 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
260 const std::string& host) {
261 // If this host ends with a canonical suffix, then return the canonical
262 // suffix.
263 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
264 std::string canonical_suffix = canonical_suffixes_[i];
265 if (base::EndsWith(host, canonical_suffixes_[i],
266 base::CompareCase::INSENSITIVE_ASCII)) {
267 return canonical_suffix;
270 return std::string();
273 AlternativeServiceVector HttpServerPropertiesImpl::GetAlternativeServices(
274 const HostPortPair& origin) {
275 // Copy alternative services with probability greater than or equal to the
276 // threshold into |alternative_services_above_threshold|.
277 AlternativeServiceVector alternative_services_above_threshold;
278 const base::Time now = base::Time::Now();
279 AlternativeServiceMap::iterator map_it = alternative_service_map_.Get(origin);
280 if (map_it != alternative_service_map_.end()) {
281 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
282 it != map_it->second.end();) {
283 if (it->expiration < now) {
284 it = map_it->second.erase(it);
285 continue;
287 if (it->probability < alternative_service_probability_threshold_) {
288 ++it;
289 continue;
291 AlternativeService alternative_service(it->alternative_service);
292 if (alternative_service.host.empty()) {
293 alternative_service.host = origin.host();
295 // If the alternative service is equivalent to the origin (same host, same
296 // port, and both TCP), then there is already a Job for it, so do not
297 // return it here.
298 if (origin.Equals(alternative_service.host_port_pair()) &&
299 NPN_SPDY_MINIMUM_VERSION <= alternative_service.protocol &&
300 alternative_service.protocol <= NPN_SPDY_MAXIMUM_VERSION) {
301 ++it;
302 continue;
304 alternative_services_above_threshold.push_back(alternative_service);
305 ++it;
307 if (map_it->second.empty()) {
308 alternative_service_map_.Erase(map_it);
310 return alternative_services_above_threshold;
313 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(origin);
314 if (canonical == canonical_host_to_origin_map_.end()) {
315 return AlternativeServiceVector();
317 map_it = alternative_service_map_.Get(canonical->second);
318 if (map_it == alternative_service_map_.end()) {
319 return AlternativeServiceVector();
321 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
322 it != map_it->second.end();) {
323 if (it->expiration < now) {
324 it = map_it->second.erase(it);
325 continue;
327 if (it->probability < alternative_service_probability_threshold_) {
328 ++it;
329 continue;
331 AlternativeService alternative_service(it->alternative_service);
332 if (alternative_service.host.empty()) {
333 alternative_service.host = canonical->second.host();
334 if (IsAlternativeServiceBroken(alternative_service)) {
335 ++it;
336 continue;
338 alternative_service.host = origin.host();
339 } else if (IsAlternativeServiceBroken(alternative_service)) {
340 ++it;
341 continue;
343 alternative_services_above_threshold.push_back(alternative_service);
344 ++it;
346 if (map_it->second.empty()) {
347 alternative_service_map_.Erase(map_it);
349 return alternative_services_above_threshold;
352 bool HttpServerPropertiesImpl::SetAlternativeService(
353 const HostPortPair& origin,
354 const AlternativeService& alternative_service,
355 double alternative_probability,
356 base::Time expiration) {
357 return SetAlternativeServices(
358 origin, AlternativeServiceInfoVector(
359 /*size=*/1,
360 AlternativeServiceInfo(alternative_service,
361 alternative_probability, expiration)));
364 bool HttpServerPropertiesImpl::SetAlternativeServices(
365 const HostPortPair& origin,
366 const AlternativeServiceInfoVector& alternative_service_info_vector) {
367 AlternativeServiceMap::iterator it = alternative_service_map_.Peek(origin);
369 if (alternative_service_info_vector.empty()) {
370 if (it == alternative_service_map_.end()) {
371 return false;
373 ClearAlternativeServices(origin);
374 return true;
377 bool changed = true;
378 if (it != alternative_service_map_.end()) {
379 DCHECK(!it->second.empty());
380 if (it->second.size() == alternative_service_info_vector.size()) {
381 changed = !std::equal(it->second.begin(), it->second.end(),
382 alternative_service_info_vector.begin());
386 const bool previously_no_alternative_services =
387 (GetAlternateProtocolIterator(origin) == alternative_service_map_.end());
389 alternative_service_map_.Put(origin, alternative_service_info_vector);
391 if (previously_no_alternative_services &&
392 !GetAlternativeServices(origin).empty()) {
393 // TODO(rch): Consider the case where multiple requests are started
394 // before the first completes. In this case, only one of the jobs
395 // would reach this code, whereas all of them should should have.
396 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
399 // If this host ends with a canonical suffix, then set it as the
400 // canonical host.
401 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
402 std::string canonical_suffix = canonical_suffixes_[i];
403 if (base::EndsWith(origin.host(), canonical_suffixes_[i],
404 base::CompareCase::INSENSITIVE_ASCII)) {
405 HostPortPair canonical_host(canonical_suffix, origin.port());
406 canonical_host_to_origin_map_[canonical_host] = origin;
407 break;
411 return changed;
414 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
415 const AlternativeService& alternative_service) {
416 // Empty host means use host of origin, callers are supposed to substitute.
417 DCHECK(!alternative_service.host.empty());
418 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
419 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
420 return;
422 int count = ++recently_broken_alternative_services_[alternative_service];
423 base::TimeDelta delay =
424 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs);
425 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
426 auto result = broken_alternative_services_.insert(
427 std::make_pair(alternative_service, when));
428 // Return if alternative service is already in expiration queue.
429 if (!result.second) {
430 return;
433 // If this is the only entry in the list, schedule an expiration task.
434 // Otherwise it will be rescheduled automatically when the pending task runs.
435 if (broken_alternative_services_.size() == 1) {
436 ScheduleBrokenAlternateProtocolMappingsExpiration();
440 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
441 const AlternativeService& alternative_service) {
442 if (!ContainsKey(recently_broken_alternative_services_, alternative_service))
443 recently_broken_alternative_services_[alternative_service] = 1;
446 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
447 const AlternativeService& alternative_service) const {
448 // Empty host means use host of origin, callers are supposed to substitute.
449 DCHECK(!alternative_service.host.empty());
450 return ContainsKey(broken_alternative_services_, alternative_service);
453 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
454 const AlternativeService& alternative_service) {
455 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
456 return false;
457 return ContainsKey(recently_broken_alternative_services_,
458 alternative_service);
461 void HttpServerPropertiesImpl::ConfirmAlternativeService(
462 const AlternativeService& alternative_service) {
463 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
464 return;
465 broken_alternative_services_.erase(alternative_service);
466 recently_broken_alternative_services_.erase(alternative_service);
469 void HttpServerPropertiesImpl::ClearAlternativeServices(
470 const HostPortPair& origin) {
471 RemoveCanonicalHost(origin);
473 AlternativeServiceMap::iterator it = alternative_service_map_.Peek(origin);
474 if (it == alternative_service_map_.end()) {
475 return;
477 alternative_service_map_.Erase(it);
480 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
481 const {
482 return alternative_service_map_;
485 scoped_ptr<base::Value>
486 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
487 const {
488 scoped_ptr<base::ListValue> dict_list(new base::ListValue);
489 for (const auto& alternative_service_map_item : alternative_service_map_) {
490 scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue);
491 const HostPortPair& host_port_pair = alternative_service_map_item.first;
492 for (const AlternativeServiceInfo& alternative_service_info :
493 alternative_service_map_item.second) {
494 std::string alternative_service_string(
495 alternative_service_info.ToString());
496 AlternativeService alternative_service(
497 alternative_service_info.alternative_service);
498 if (alternative_service.host.empty()) {
499 alternative_service.host = host_port_pair.host();
501 if (IsAlternativeServiceBroken(alternative_service)) {
502 alternative_service_string.append(" (broken)");
504 alternative_service_list->Append(
505 new base::StringValue(alternative_service_string));
507 if (alternative_service_list->empty())
508 continue;
509 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
510 dict->SetString("host_port_pair", host_port_pair.ToString());
511 dict->Set("alternative_service",
512 scoped_ptr<base::Value>(alternative_service_list.Pass()));
513 dict_list->Append(dict.Pass());
515 return dict_list.Pass();
518 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
519 const HostPortPair& host_port_pair) {
520 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
521 if (it == spdy_settings_map_.end()) {
522 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
523 return kEmptySettingsMap;
525 return it->second;
528 bool HttpServerPropertiesImpl::SetSpdySetting(
529 const HostPortPair& host_port_pair,
530 SpdySettingsIds id,
531 SpdySettingsFlags flags,
532 uint32 value) {
533 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
534 return false;
536 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
537 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
538 if (it == spdy_settings_map_.end()) {
539 SettingsMap settings_map;
540 settings_map[id] = flags_and_value;
541 spdy_settings_map_.Put(host_port_pair, settings_map);
542 } else {
543 SettingsMap& settings_map = it->second;
544 settings_map[id] = flags_and_value;
546 return true;
549 void HttpServerPropertiesImpl::ClearSpdySettings(
550 const HostPortPair& host_port_pair) {
551 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
552 if (it != spdy_settings_map_.end())
553 spdy_settings_map_.Erase(it);
556 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
557 spdy_settings_map_.Clear();
560 const SpdySettingsMap&
561 HttpServerPropertiesImpl::spdy_settings_map() const {
562 return spdy_settings_map_;
565 bool HttpServerPropertiesImpl::GetSupportsQuic(
566 IPAddressNumber* last_address) const {
567 if (last_quic_address_.empty())
568 return false;
570 *last_address = last_quic_address_;
571 return true;
574 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
575 const IPAddressNumber& address) {
576 if (!used_quic) {
577 last_quic_address_.clear();
578 } else {
579 last_quic_address_ = address;
583 void HttpServerPropertiesImpl::SetServerNetworkStats(
584 const HostPortPair& host_port_pair,
585 ServerNetworkStats stats) {
586 server_network_stats_map_.Put(host_port_pair, stats);
589 const ServerNetworkStats* HttpServerPropertiesImpl::GetServerNetworkStats(
590 const HostPortPair& host_port_pair) {
591 ServerNetworkStatsMap::iterator it =
592 server_network_stats_map_.Get(host_port_pair);
593 if (it == server_network_stats_map_.end()) {
594 return NULL;
596 return &it->second;
599 const ServerNetworkStatsMap&
600 HttpServerPropertiesImpl::server_network_stats_map() const {
601 return server_network_stats_map_;
604 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
605 double threshold) {
606 alternative_service_probability_threshold_ = threshold;
609 AlternativeServiceMap::const_iterator
610 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
611 const HostPortPair& server) {
612 AlternativeServiceMap::const_iterator it =
613 alternative_service_map_.Get(server);
614 if (it != alternative_service_map_.end())
615 return it;
617 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
618 if (canonical == canonical_host_to_origin_map_.end()) {
619 return alternative_service_map_.end();
622 const HostPortPair canonical_host_port = canonical->second;
623 it = alternative_service_map_.Get(canonical_host_port);
624 if (it == alternative_service_map_.end()) {
625 return alternative_service_map_.end();
628 for (const AlternativeServiceInfo& alternative_service_info : it->second) {
629 AlternativeService alternative_service(
630 alternative_service_info.alternative_service);
631 if (alternative_service.host.empty()) {
632 alternative_service.host = canonical_host_port.host();
634 if (!IsAlternativeServiceBroken(alternative_service)) {
635 return it;
639 RemoveCanonicalHost(canonical_host_port);
640 return alternative_service_map_.end();
643 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
644 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
645 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
646 std::string canonical_suffix = canonical_suffixes_[i];
647 if (base::EndsWith(server.host(), canonical_suffixes_[i],
648 base::CompareCase::INSENSITIVE_ASCII)) {
649 HostPortPair canonical_host(canonical_suffix, server.port());
650 return canonical_host_to_origin_map_.find(canonical_host);
654 return canonical_host_to_origin_map_.end();
657 void HttpServerPropertiesImpl::RemoveCanonicalHost(
658 const HostPortPair& server) {
659 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
660 if (canonical == canonical_host_to_origin_map_.end())
661 return;
663 if (!canonical->second.Equals(server))
664 return;
666 canonical_host_to_origin_map_.erase(canonical->first);
669 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
670 base::TimeTicks now = base::TimeTicks::Now();
671 while (!broken_alternative_services_.empty()) {
672 BrokenAlternativeServices::iterator it =
673 broken_alternative_services_.begin();
674 if (now < it->second) {
675 break;
678 const AlternativeService expired_alternative_service = it->first;
679 broken_alternative_services_.erase(it);
681 // Remove every occurrence of |expired_alternative_service| from
682 // |alternative_service_map_|.
683 for (AlternativeServiceMap::iterator map_it =
684 alternative_service_map_.begin();
685 map_it != alternative_service_map_.end();) {
686 for (AlternativeServiceInfoVector::iterator it = map_it->second.begin();
687 it != map_it->second.end();) {
688 AlternativeService alternative_service(it->alternative_service);
689 // Empty hostname in map means hostname of key: substitute before
690 // comparing to |expired_alternative_service|.
691 if (alternative_service.host.empty()) {
692 alternative_service.host = map_it->first.host();
694 if (alternative_service == expired_alternative_service) {
695 it = map_it->second.erase(it);
696 continue;
698 ++it;
700 // If an origin has an empty list of alternative services, then remove it
701 // from both |canonical_host_to_origin_map_| and
702 // |alternative_service_map_|.
703 if (map_it->second.empty()) {
704 RemoveCanonicalHost(map_it->first);
705 map_it = alternative_service_map_.Erase(map_it);
706 continue;
708 ++map_it;
711 ScheduleBrokenAlternateProtocolMappingsExpiration();
714 void
715 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
716 if (broken_alternative_services_.empty()) {
717 return;
719 base::TimeTicks now = base::TimeTicks::Now();
720 base::TimeTicks when = broken_alternative_services_.front().second;
721 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
722 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
723 FROM_HERE,
724 base::Bind(
725 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
726 weak_ptr_factory_.GetWeakPtr()),
727 delay);
730 } // namespace net