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"
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"
24 const uint64 kBrokenAlternativeProtocolDelaySecs
= 300;
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
,
46 DCHECK(CalledOnValidThread());
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
)) {
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
);
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 AlternativeServiceMap::iterator output_it
=
87 alternative_service_map_
.Peek(input_it
->first
);
88 if (output_it
== alternative_service_map_
.end()) {
89 // There is no value in alternative_service_map_ for input_it->first:
90 // inserting in AlternativeServiceVectorInfo.
91 alternative_service_map_
.Put(input_it
->first
, input_it
->second
);
94 // There are some broken alternative services in alternative_service_map_
95 // for input_it->first: appending AlternativeServiceInfo one by one.
96 for (const AlternativeServiceInfo
& alternative_service_info
:
98 output_it
->second
.push_back(alternative_service_info
);
102 // Attempt to find canonical servers.
103 uint16 canonical_ports
[] = { 80, 443 };
104 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
105 std::string canonical_suffix
= canonical_suffixes_
[i
];
106 for (size_t j
= 0; j
< arraysize(canonical_ports
); ++j
) {
107 HostPortPair
canonical_host(canonical_suffix
, canonical_ports
[j
]);
108 // If we already have a valid canonical server, we're done.
109 if (ContainsKey(canonical_host_to_origin_map_
, canonical_host
) &&
110 (alternative_service_map_
.Peek(
111 canonical_host_to_origin_map_
[canonical_host
]) !=
112 alternative_service_map_
.end())) {
115 // Now attempt to find a server which matches this origin and set it as
117 for (AlternativeServiceMap::const_iterator it
=
118 alternative_service_map_
.begin();
119 it
!= alternative_service_map_
.end(); ++it
) {
120 if (base::EndsWith(it
->first
.host(), canonical_suffixes_
[i
],
121 base::CompareCase::INSENSITIVE_ASCII
)) {
122 canonical_host_to_origin_map_
[canonical_host
] = it
->first
;
130 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
131 SpdySettingsMap
* spdy_settings_map
) {
132 for (SpdySettingsMap::reverse_iterator it
= spdy_settings_map
->rbegin();
133 it
!= spdy_settings_map
->rend(); ++it
) {
134 spdy_settings_map_
.Put(it
->first
, it
->second
);
138 void HttpServerPropertiesImpl::InitializeSupportsQuic(
139 IPAddressNumber
* last_address
) {
141 last_quic_address_
= *last_address
;
144 void HttpServerPropertiesImpl::InitializeServerNetworkStats(
145 ServerNetworkStatsMap
* server_network_stats_map
) {
146 for (ServerNetworkStatsMap::reverse_iterator it
=
147 server_network_stats_map
->rbegin();
148 it
!= server_network_stats_map
->rend(); ++it
) {
149 server_network_stats_map_
.Put(it
->first
, it
->second
);
153 void HttpServerPropertiesImpl::GetSpdyServerList(
154 base::ListValue
* spdy_server_list
,
155 size_t max_size
) const {
156 DCHECK(CalledOnValidThread());
157 DCHECK(spdy_server_list
);
158 spdy_server_list
->Clear();
160 // Get the list of servers (host/port) that support SPDY.
161 for (SpdyServerHostPortMap::const_iterator it
= spdy_servers_map_
.begin();
162 it
!= spdy_servers_map_
.end() && count
< max_size
; ++it
) {
163 const std::string spdy_server_host_port
= it
->first
;
165 spdy_server_list
->Append(new base::StringValue(spdy_server_host_port
));
171 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesImpl::GetWeakPtr() {
172 return weak_ptr_factory_
.GetWeakPtr();
175 void HttpServerPropertiesImpl::Clear() {
176 DCHECK(CalledOnValidThread());
177 spdy_servers_map_
.Clear();
178 alternative_service_map_
.Clear();
179 canonical_host_to_origin_map_
.clear();
180 spdy_settings_map_
.Clear();
181 last_quic_address_
.clear();
182 server_network_stats_map_
.Clear();
185 bool HttpServerPropertiesImpl::SupportsRequestPriority(
186 const HostPortPair
& host_port_pair
) {
187 DCHECK(CalledOnValidThread());
188 if (host_port_pair
.host().empty())
191 if (GetSupportsSpdy(host_port_pair
))
194 const AlternativeServiceVector alternative_service_vector
=
195 GetAlternativeServices(host_port_pair
);
196 for (const AlternativeService
& alternative_service
:
197 alternative_service_vector
) {
198 if (alternative_service
.protocol
== QUIC
) {
205 bool HttpServerPropertiesImpl::GetSupportsSpdy(
206 const HostPortPair
& host_port_pair
) {
207 DCHECK(CalledOnValidThread());
208 if (host_port_pair
.host().empty())
211 SpdyServerHostPortMap::iterator spdy_host_port
=
212 spdy_servers_map_
.Get(host_port_pair
.ToString());
213 return spdy_host_port
!= spdy_servers_map_
.end() && spdy_host_port
->second
;
216 void HttpServerPropertiesImpl::SetSupportsSpdy(
217 const HostPortPair
& host_port_pair
,
219 DCHECK(CalledOnValidThread());
220 if (host_port_pair
.host().empty())
223 SpdyServerHostPortMap::iterator spdy_host_port
=
224 spdy_servers_map_
.Get(host_port_pair
.ToString());
225 if ((spdy_host_port
!= spdy_servers_map_
.end()) &&
226 (spdy_host_port
->second
== support_spdy
)) {
230 spdy_servers_map_
.Put(host_port_pair
.ToString(), support_spdy
);
233 bool HttpServerPropertiesImpl::RequiresHTTP11(
234 const HostPortPair
& host_port_pair
) {
235 DCHECK(CalledOnValidThread());
236 if (host_port_pair
.host().empty())
239 return (http11_servers_
.find(host_port_pair
) != http11_servers_
.end());
242 void HttpServerPropertiesImpl::SetHTTP11Required(
243 const HostPortPair
& host_port_pair
) {
244 DCHECK(CalledOnValidThread());
245 if (host_port_pair
.host().empty())
248 http11_servers_
.insert(host_port_pair
);
251 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair
& server
,
252 SSLConfig
* ssl_config
) {
253 if (RequiresHTTP11(server
)) {
254 ForceHTTP11(ssl_config
);
258 std::string
HttpServerPropertiesImpl::GetCanonicalSuffix(
259 const std::string
& host
) {
260 // If this host ends with a canonical suffix, then return the canonical
262 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
263 std::string canonical_suffix
= canonical_suffixes_
[i
];
264 if (base::EndsWith(host
, canonical_suffixes_
[i
],
265 base::CompareCase::INSENSITIVE_ASCII
)) {
266 return canonical_suffix
;
269 return std::string();
272 AlternativeServiceVector
HttpServerPropertiesImpl::GetAlternativeServices(
273 const HostPortPair
& origin
) {
274 // Copy alternative services with probability greater than or equal to the
275 // threshold into |alternative_services_above_threshold|.
276 AlternativeServiceVector alternative_services_above_threshold
;
277 const base::Time now
= base::Time::Now();
278 AlternativeServiceMap::iterator map_it
= alternative_service_map_
.Get(origin
);
279 if (map_it
!= alternative_service_map_
.end()) {
280 for (AlternativeServiceInfoVector::iterator it
= map_it
->second
.begin();
281 it
!= map_it
->second
.end();) {
282 if (it
->expiration
< now
) {
283 it
= map_it
->second
.erase(it
);
286 if (it
->probability
< alternative_service_probability_threshold_
) {
290 AlternativeService
alternative_service(it
->alternative_service
);
291 if (alternative_service
.host
.empty()) {
292 alternative_service
.host
= origin
.host();
294 // If the alternative service is equivalent to the origin (same host, same
295 // port, and both TCP), then there is already a Job for it, so do not
297 if (origin
.Equals(alternative_service
.host_port_pair()) &&
298 NPN_SPDY_MINIMUM_VERSION
<= alternative_service
.protocol
&&
299 alternative_service
.protocol
<= NPN_SPDY_MAXIMUM_VERSION
) {
303 alternative_services_above_threshold
.push_back(alternative_service
);
306 return alternative_services_above_threshold
;
309 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(origin
);
310 if (canonical
== canonical_host_to_origin_map_
.end()) {
311 return AlternativeServiceVector();
313 map_it
= alternative_service_map_
.Get(canonical
->second
);
314 if (map_it
== alternative_service_map_
.end()) {
315 return AlternativeServiceVector();
317 for (AlternativeServiceInfoVector::iterator it
= map_it
->second
.begin();
318 it
!= map_it
->second
.end();) {
319 if (it
->expiration
< now
) {
320 it
= map_it
->second
.erase(it
);
323 if (it
->probability
< alternative_service_probability_threshold_
) {
327 AlternativeService
alternative_service(it
->alternative_service
);
328 if (alternative_service
.host
.empty()) {
329 alternative_service
.host
= canonical
->second
.host();
330 if (IsAlternativeServiceBroken(alternative_service
)) {
334 alternative_service
.host
= origin
.host();
335 } else if (IsAlternativeServiceBroken(alternative_service
)) {
339 alternative_services_above_threshold
.push_back(alternative_service
);
342 return alternative_services_above_threshold
;
345 bool HttpServerPropertiesImpl::SetAlternativeService(
346 const HostPortPair
& origin
,
347 const AlternativeService
& alternative_service
,
348 double alternative_probability
,
349 base::Time expiration
) {
350 return SetAlternativeServices(
351 origin
, AlternativeServiceInfoVector(
353 AlternativeServiceInfo(alternative_service
,
354 alternative_probability
, expiration
)));
357 bool HttpServerPropertiesImpl::SetAlternativeServices(
358 const HostPortPair
& origin
,
359 const AlternativeServiceInfoVector
& alternative_service_info_vector
) {
360 AlternativeServiceMap::iterator it
= alternative_service_map_
.Peek(origin
);
362 if (alternative_service_info_vector
.empty()) {
363 if (it
== alternative_service_map_
.end()) {
366 ClearAlternativeServices(origin
);
371 if (it
!= alternative_service_map_
.end()) {
372 DCHECK(!it
->second
.empty());
373 if (it
->second
.size() == alternative_service_info_vector
.size()) {
374 changed
= !std::equal(it
->second
.begin(), it
->second
.end(),
375 alternative_service_info_vector
.begin());
379 const bool previously_no_alternative_services
=
380 (GetAlternateProtocolIterator(origin
) == alternative_service_map_
.end());
382 alternative_service_map_
.Put(origin
, alternative_service_info_vector
);
384 if (previously_no_alternative_services
&&
385 !GetAlternativeServices(origin
).empty()) {
386 // TODO(rch): Consider the case where multiple requests are started
387 // before the first completes. In this case, only one of the jobs
388 // would reach this code, whereas all of them should should have.
389 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING
);
392 // If this host ends with a canonical suffix, then set it as the
394 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
395 std::string canonical_suffix
= canonical_suffixes_
[i
];
396 if (base::EndsWith(origin
.host(), canonical_suffixes_
[i
],
397 base::CompareCase::INSENSITIVE_ASCII
)) {
398 HostPortPair
canonical_host(canonical_suffix
, origin
.port());
399 canonical_host_to_origin_map_
[canonical_host
] = origin
;
407 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
408 const AlternativeService
& alternative_service
) {
409 // Empty host means use host of origin, callers are supposed to substitute.
410 DCHECK(!alternative_service
.host
.empty());
411 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
) {
412 LOG(DFATAL
) << "Trying to mark unknown alternate protocol broken.";
415 int count
= ++recently_broken_alternative_services_
[alternative_service
];
416 base::TimeDelta delay
=
417 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs
);
418 base::TimeTicks when
= base::TimeTicks::Now() + delay
* (1 << (count
- 1));
419 auto result
= broken_alternative_services_
.insert(
420 std::make_pair(alternative_service
, when
));
421 // Return if alternative service is already in expiration queue.
422 if (!result
.second
) {
426 // If this is the only entry in the list, schedule an expiration task.
427 // Otherwise it will be rescheduled automatically when the pending task runs.
428 if (broken_alternative_services_
.size() == 1) {
429 ScheduleBrokenAlternateProtocolMappingsExpiration();
433 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
434 const AlternativeService
& alternative_service
) {
435 if (!ContainsKey(recently_broken_alternative_services_
, alternative_service
))
436 recently_broken_alternative_services_
[alternative_service
] = 1;
439 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
440 const AlternativeService
& alternative_service
) const {
441 // Empty host means use host of origin, callers are supposed to substitute.
442 DCHECK(!alternative_service
.host
.empty());
443 return ContainsKey(broken_alternative_services_
, alternative_service
);
446 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
447 const AlternativeService
& alternative_service
) {
448 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
)
450 return ContainsKey(recently_broken_alternative_services_
,
451 alternative_service
);
454 void HttpServerPropertiesImpl::ConfirmAlternativeService(
455 const AlternativeService
& alternative_service
) {
456 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
)
458 broken_alternative_services_
.erase(alternative_service
);
459 recently_broken_alternative_services_
.erase(alternative_service
);
462 void HttpServerPropertiesImpl::ClearAlternativeServices(
463 const HostPortPair
& origin
) {
464 RemoveCanonicalHost(origin
);
466 AlternativeServiceMap::iterator it
= alternative_service_map_
.Peek(origin
);
467 if (it
== alternative_service_map_
.end()) {
470 alternative_service_map_
.Erase(it
);
473 const AlternativeServiceMap
& HttpServerPropertiesImpl::alternative_service_map()
475 return alternative_service_map_
;
478 scoped_ptr
<base::Value
>
479 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
481 scoped_ptr
<base::ListValue
> dict_list(new base::ListValue
);
482 for (const auto& alternative_service_map_item
: alternative_service_map_
) {
483 scoped_ptr
<base::ListValue
> alternative_service_list(new base::ListValue
);
484 const HostPortPair
& host_port_pair
= alternative_service_map_item
.first
;
485 for (const AlternativeServiceInfo
& alternative_service_info
:
486 alternative_service_map_item
.second
) {
487 std::string
alternative_service_string(
488 alternative_service_info
.ToString());
489 AlternativeService
alternative_service(
490 alternative_service_info
.alternative_service
);
491 if (alternative_service
.host
.empty()) {
492 alternative_service
.host
= host_port_pair
.host();
494 if (IsAlternativeServiceBroken(alternative_service
)) {
495 alternative_service_string
.append(" (broken)");
497 alternative_service_list
->Append(
498 new base::StringValue(alternative_service_string
));
500 if (alternative_service_list
->empty())
502 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
503 dict
->SetString("host_port_pair", host_port_pair
.ToString());
504 dict
->Set("alternative_service",
505 scoped_ptr
<base::Value
>(alternative_service_list
.Pass()));
506 dict_list
->Append(dict
.Pass());
508 return dict_list
.Pass();
511 const SettingsMap
& HttpServerPropertiesImpl::GetSpdySettings(
512 const HostPortPair
& host_port_pair
) {
513 SpdySettingsMap::iterator it
= spdy_settings_map_
.Get(host_port_pair
);
514 if (it
== spdy_settings_map_
.end()) {
515 CR_DEFINE_STATIC_LOCAL(SettingsMap
, kEmptySettingsMap
, ());
516 return kEmptySettingsMap
;
521 bool HttpServerPropertiesImpl::SetSpdySetting(
522 const HostPortPair
& host_port_pair
,
524 SpdySettingsFlags flags
,
526 if (!(flags
& SETTINGS_FLAG_PLEASE_PERSIST
))
529 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
530 SpdySettingsMap::iterator it
= spdy_settings_map_
.Get(host_port_pair
);
531 if (it
== spdy_settings_map_
.end()) {
532 SettingsMap settings_map
;
533 settings_map
[id
] = flags_and_value
;
534 spdy_settings_map_
.Put(host_port_pair
, settings_map
);
536 SettingsMap
& settings_map
= it
->second
;
537 settings_map
[id
] = flags_and_value
;
542 void HttpServerPropertiesImpl::ClearSpdySettings(
543 const HostPortPair
& host_port_pair
) {
544 SpdySettingsMap::iterator it
= spdy_settings_map_
.Peek(host_port_pair
);
545 if (it
!= spdy_settings_map_
.end())
546 spdy_settings_map_
.Erase(it
);
549 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
550 spdy_settings_map_
.Clear();
553 const SpdySettingsMap
&
554 HttpServerPropertiesImpl::spdy_settings_map() const {
555 return spdy_settings_map_
;
558 bool HttpServerPropertiesImpl::GetSupportsQuic(
559 IPAddressNumber
* last_address
) const {
560 if (last_quic_address_
.empty())
563 *last_address
= last_quic_address_
;
567 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic
,
568 const IPAddressNumber
& address
) {
570 last_quic_address_
.clear();
572 last_quic_address_
= address
;
576 void HttpServerPropertiesImpl::SetServerNetworkStats(
577 const HostPortPair
& host_port_pair
,
578 ServerNetworkStats stats
) {
579 server_network_stats_map_
.Put(host_port_pair
, stats
);
582 const ServerNetworkStats
* HttpServerPropertiesImpl::GetServerNetworkStats(
583 const HostPortPair
& host_port_pair
) {
584 ServerNetworkStatsMap::iterator it
=
585 server_network_stats_map_
.Get(host_port_pair
);
586 if (it
== server_network_stats_map_
.end()) {
592 const ServerNetworkStatsMap
&
593 HttpServerPropertiesImpl::server_network_stats_map() const {
594 return server_network_stats_map_
;
597 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
599 alternative_service_probability_threshold_
= threshold
;
602 AlternativeServiceMap::const_iterator
603 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
604 const HostPortPair
& server
) {
605 AlternativeServiceMap::const_iterator it
=
606 alternative_service_map_
.Get(server
);
607 if (it
!= alternative_service_map_
.end())
610 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(server
);
611 if (canonical
== canonical_host_to_origin_map_
.end()) {
612 return alternative_service_map_
.end();
615 const HostPortPair canonical_host_port
= canonical
->second
;
616 it
= alternative_service_map_
.Get(canonical_host_port
);
617 if (it
== alternative_service_map_
.end()) {
618 return alternative_service_map_
.end();
621 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
622 AlternativeService
alternative_service(
623 alternative_service_info
.alternative_service
);
624 if (alternative_service
.host
.empty()) {
625 alternative_service
.host
= canonical_host_port
.host();
627 if (!IsAlternativeServiceBroken(alternative_service
)) {
632 RemoveCanonicalHost(canonical_host_port
);
633 return alternative_service_map_
.end();
636 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
637 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server
) const {
638 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
639 std::string canonical_suffix
= canonical_suffixes_
[i
];
640 if (base::EndsWith(server
.host(), canonical_suffixes_
[i
],
641 base::CompareCase::INSENSITIVE_ASCII
)) {
642 HostPortPair
canonical_host(canonical_suffix
, server
.port());
643 return canonical_host_to_origin_map_
.find(canonical_host
);
647 return canonical_host_to_origin_map_
.end();
650 void HttpServerPropertiesImpl::RemoveCanonicalHost(
651 const HostPortPair
& server
) {
652 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(server
);
653 if (canonical
== canonical_host_to_origin_map_
.end())
656 if (!canonical
->second
.Equals(server
))
659 canonical_host_to_origin_map_
.erase(canonical
->first
);
662 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
663 base::TimeTicks now
= base::TimeTicks::Now();
664 while (!broken_alternative_services_
.empty()) {
665 BrokenAlternativeServices::iterator it
=
666 broken_alternative_services_
.begin();
667 if (now
< it
->second
) {
671 const AlternativeService expired_alternative_service
= it
->first
;
672 broken_alternative_services_
.erase(it
);
674 // Remove every occurrence of |expired_alternative_service| from
675 // |alternative_service_map_|.
676 for (AlternativeServiceMap::iterator map_it
=
677 alternative_service_map_
.begin();
678 map_it
!= alternative_service_map_
.end();) {
679 for (AlternativeServiceInfoVector::iterator it
= map_it
->second
.begin();
680 it
!= map_it
->second
.end();) {
681 AlternativeService
alternative_service(it
->alternative_service
);
682 // Empty hostname in map means hostname of key: substitute before
683 // comparing to |expired_alternative_service|.
684 if (alternative_service
.host
.empty()) {
685 alternative_service
.host
= map_it
->first
.host();
687 if (alternative_service
== expired_alternative_service
) {
688 it
= map_it
->second
.erase(it
);
693 // If an origin has an empty list of alternative services, then remove it
694 // from both |canonical_host_to_origin_map_| and
695 // |alternative_service_map_|.
696 if (map_it
->second
.empty()) {
697 RemoveCanonicalHost(map_it
->first
);
698 map_it
= alternative_service_map_
.Erase(map_it
);
704 ScheduleBrokenAlternateProtocolMappingsExpiration();
708 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
709 if (broken_alternative_services_
.empty()) {
712 base::TimeTicks now
= base::TimeTicks::Now();
713 base::TimeTicks when
= broken_alternative_services_
.front().second
;
714 base::TimeDelta delay
= when
> now
? when
- now
: base::TimeDelta();
715 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
718 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings
,
719 weak_ptr_factory_
.GetWeakPtr()),