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 AlternativeServiceMap::const_iterator it
=
278 alternative_service_map_
.Get(origin
);
279 if (it
!= alternative_service_map_
.end()) {
280 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
281 if (alternative_service_info
.probability
<
282 alternative_service_probability_threshold_
) {
285 AlternativeService
alternative_service(
286 alternative_service_info
.alternative_service
);
287 if (alternative_service
.host
.empty()) {
288 alternative_service
.host
= origin
.host();
290 // If the alternative service is equivalent to the origin (same host, same
291 // port, and both TCP), then there is already a Job for it, so do not
293 if (origin
.Equals(alternative_service
.host_port_pair()) &&
294 NPN_SPDY_MINIMUM_VERSION
<= alternative_service
.protocol
&&
295 alternative_service
.protocol
<= NPN_SPDY_MAXIMUM_VERSION
) {
298 alternative_services_above_threshold
.push_back(alternative_service
);
300 return alternative_services_above_threshold
;
303 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(origin
);
304 if (canonical
== canonical_host_to_origin_map_
.end()) {
305 return AlternativeServiceVector();
307 it
= alternative_service_map_
.Get(canonical
->second
);
308 if (it
== alternative_service_map_
.end()) {
309 return AlternativeServiceVector();
311 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
312 if (alternative_service_info
.probability
<
313 alternative_service_probability_threshold_
) {
316 AlternativeService
alternative_service(
317 alternative_service_info
.alternative_service
);
318 if (alternative_service
.host
.empty()) {
319 alternative_service
.host
= canonical
->second
.host();
320 if (IsAlternativeServiceBroken(alternative_service
)) {
323 alternative_service
.host
= origin
.host();
324 } else if (IsAlternativeServiceBroken(alternative_service
)) {
327 alternative_services_above_threshold
.push_back(alternative_service
);
329 return alternative_services_above_threshold
;
332 bool HttpServerPropertiesImpl::SetAlternativeService(
333 const HostPortPair
& origin
,
334 const AlternativeService
& alternative_service
,
335 double alternative_probability
) {
336 return SetAlternativeServices(
337 origin
, AlternativeServiceInfoVector(
338 /*size=*/1, AlternativeServiceInfo(alternative_service
,
339 alternative_probability
)));
342 bool HttpServerPropertiesImpl::SetAlternativeServices(
343 const HostPortPair
& origin
,
344 const AlternativeServiceInfoVector
& alternative_service_info_vector
) {
345 AlternativeServiceMap::iterator it
= alternative_service_map_
.Peek(origin
);
347 if (alternative_service_info_vector
.empty()) {
348 if (it
== alternative_service_map_
.end()) {
351 ClearAlternativeServices(origin
);
356 if (it
!= alternative_service_map_
.end()) {
357 DCHECK(!it
->second
.empty());
358 if (it
->second
.size() == alternative_service_info_vector
.size()) {
359 changed
= !std::equal(it
->second
.begin(), it
->second
.end(),
360 alternative_service_info_vector
.begin());
364 const bool previously_no_alternative_services
=
365 (GetAlternateProtocolIterator(origin
) == alternative_service_map_
.end());
367 alternative_service_map_
.Put(origin
, alternative_service_info_vector
);
369 if (previously_no_alternative_services
&&
370 !GetAlternativeServices(origin
).empty()) {
371 // TODO(rch): Consider the case where multiple requests are started
372 // before the first completes. In this case, only one of the jobs
373 // would reach this code, whereas all of them should should have.
374 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING
);
377 // If this host ends with a canonical suffix, then set it as the
379 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
380 std::string canonical_suffix
= canonical_suffixes_
[i
];
381 if (base::EndsWith(origin
.host(), canonical_suffixes_
[i
],
382 base::CompareCase::INSENSITIVE_ASCII
)) {
383 HostPortPair
canonical_host(canonical_suffix
, origin
.port());
384 canonical_host_to_origin_map_
[canonical_host
] = origin
;
392 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
393 const AlternativeService
& alternative_service
) {
394 // Empty host means use host of origin, callers are supposed to substitute.
395 DCHECK(!alternative_service
.host
.empty());
396 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
) {
397 LOG(DFATAL
) << "Trying to mark unknown alternate protocol broken.";
400 int count
= ++recently_broken_alternative_services_
[alternative_service
];
401 base::TimeDelta delay
=
402 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs
);
403 base::TimeTicks when
= base::TimeTicks::Now() + delay
* (1 << (count
- 1));
404 auto result
= broken_alternative_services_
.insert(
405 std::make_pair(alternative_service
, when
));
406 // Return if alternative service is already in expiration queue.
407 if (!result
.second
) {
411 // If this is the only entry in the list, schedule an expiration task.
412 // Otherwise it will be rescheduled automatically when the pending task runs.
413 if (broken_alternative_services_
.size() == 1) {
414 ScheduleBrokenAlternateProtocolMappingsExpiration();
418 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
419 const AlternativeService
& alternative_service
) {
420 if (!ContainsKey(recently_broken_alternative_services_
, alternative_service
))
421 recently_broken_alternative_services_
[alternative_service
] = 1;
424 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
425 const AlternativeService
& alternative_service
) const {
426 // Empty host means use host of origin, callers are supposed to substitute.
427 DCHECK(!alternative_service
.host
.empty());
428 return ContainsKey(broken_alternative_services_
, alternative_service
);
431 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
432 const AlternativeService
& alternative_service
) {
433 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
)
435 return ContainsKey(recently_broken_alternative_services_
,
436 alternative_service
);
439 void HttpServerPropertiesImpl::ConfirmAlternativeService(
440 const AlternativeService
& alternative_service
) {
441 if (alternative_service
.protocol
== UNINITIALIZED_ALTERNATE_PROTOCOL
)
443 broken_alternative_services_
.erase(alternative_service
);
444 recently_broken_alternative_services_
.erase(alternative_service
);
447 void HttpServerPropertiesImpl::ClearAlternativeServices(
448 const HostPortPair
& origin
) {
449 RemoveCanonicalHost(origin
);
451 AlternativeServiceMap::iterator it
= alternative_service_map_
.Peek(origin
);
452 if (it
== alternative_service_map_
.end()) {
455 alternative_service_map_
.Erase(it
);
458 const AlternativeServiceMap
& HttpServerPropertiesImpl::alternative_service_map()
460 return alternative_service_map_
;
463 scoped_ptr
<base::Value
>
464 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
466 scoped_ptr
<base::ListValue
> dict_list(new base::ListValue
);
467 for (const auto& alternative_service_map_item
: alternative_service_map_
) {
468 scoped_ptr
<base::ListValue
> alternative_service_list(new base::ListValue
);
469 const HostPortPair
& host_port_pair
= alternative_service_map_item
.first
;
470 for (const AlternativeServiceInfo
& alternative_service_info
:
471 alternative_service_map_item
.second
) {
472 std::string
alternative_service_string(
473 alternative_service_info
.ToString());
474 AlternativeService
alternative_service(
475 alternative_service_info
.alternative_service
);
476 if (alternative_service
.host
.empty()) {
477 alternative_service
.host
= host_port_pair
.host();
479 if (IsAlternativeServiceBroken(alternative_service
)) {
480 alternative_service_string
.append(" (broken)");
482 alternative_service_list
->Append(
483 new base::StringValue(alternative_service_string
));
485 if (alternative_service_list
->empty())
487 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
488 dict
->SetString("host_port_pair", host_port_pair
.ToString());
489 dict
->Set("alternative_service",
490 scoped_ptr
<base::Value
>(alternative_service_list
.Pass()));
491 dict_list
->Append(dict
.Pass());
493 return dict_list
.Pass();
496 const SettingsMap
& HttpServerPropertiesImpl::GetSpdySettings(
497 const HostPortPair
& host_port_pair
) {
498 SpdySettingsMap::iterator it
= spdy_settings_map_
.Get(host_port_pair
);
499 if (it
== spdy_settings_map_
.end()) {
500 CR_DEFINE_STATIC_LOCAL(SettingsMap
, kEmptySettingsMap
, ());
501 return kEmptySettingsMap
;
506 bool HttpServerPropertiesImpl::SetSpdySetting(
507 const HostPortPair
& host_port_pair
,
509 SpdySettingsFlags flags
,
511 if (!(flags
& SETTINGS_FLAG_PLEASE_PERSIST
))
514 SettingsFlagsAndValue
flags_and_value(SETTINGS_FLAG_PERSISTED
, value
);
515 SpdySettingsMap::iterator it
= spdy_settings_map_
.Get(host_port_pair
);
516 if (it
== spdy_settings_map_
.end()) {
517 SettingsMap settings_map
;
518 settings_map
[id
] = flags_and_value
;
519 spdy_settings_map_
.Put(host_port_pair
, settings_map
);
521 SettingsMap
& settings_map
= it
->second
;
522 settings_map
[id
] = flags_and_value
;
527 void HttpServerPropertiesImpl::ClearSpdySettings(
528 const HostPortPair
& host_port_pair
) {
529 SpdySettingsMap::iterator it
= spdy_settings_map_
.Peek(host_port_pair
);
530 if (it
!= spdy_settings_map_
.end())
531 spdy_settings_map_
.Erase(it
);
534 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
535 spdy_settings_map_
.Clear();
538 const SpdySettingsMap
&
539 HttpServerPropertiesImpl::spdy_settings_map() const {
540 return spdy_settings_map_
;
543 bool HttpServerPropertiesImpl::GetSupportsQuic(
544 IPAddressNumber
* last_address
) const {
545 if (last_quic_address_
.empty())
548 *last_address
= last_quic_address_
;
552 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic
,
553 const IPAddressNumber
& address
) {
555 last_quic_address_
.clear();
557 last_quic_address_
= address
;
561 void HttpServerPropertiesImpl::SetServerNetworkStats(
562 const HostPortPair
& host_port_pair
,
563 ServerNetworkStats stats
) {
564 server_network_stats_map_
.Put(host_port_pair
, stats
);
567 const ServerNetworkStats
* HttpServerPropertiesImpl::GetServerNetworkStats(
568 const HostPortPair
& host_port_pair
) {
569 ServerNetworkStatsMap::iterator it
=
570 server_network_stats_map_
.Get(host_port_pair
);
571 if (it
== server_network_stats_map_
.end()) {
577 const ServerNetworkStatsMap
&
578 HttpServerPropertiesImpl::server_network_stats_map() const {
579 return server_network_stats_map_
;
582 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
584 alternative_service_probability_threshold_
= threshold
;
587 AlternativeServiceMap::const_iterator
588 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
589 const HostPortPair
& server
) {
590 AlternativeServiceMap::const_iterator it
=
591 alternative_service_map_
.Get(server
);
592 if (it
!= alternative_service_map_
.end())
595 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(server
);
596 if (canonical
== canonical_host_to_origin_map_
.end()) {
597 return alternative_service_map_
.end();
600 const HostPortPair canonical_host_port
= canonical
->second
;
601 it
= alternative_service_map_
.Get(canonical_host_port
);
602 if (it
== alternative_service_map_
.end()) {
603 return alternative_service_map_
.end();
606 for (const AlternativeServiceInfo
& alternative_service_info
: it
->second
) {
607 AlternativeService
alternative_service(
608 alternative_service_info
.alternative_service
);
609 if (alternative_service
.host
.empty()) {
610 alternative_service
.host
= canonical_host_port
.host();
612 if (!IsAlternativeServiceBroken(alternative_service
)) {
617 RemoveCanonicalHost(canonical_host_port
);
618 return alternative_service_map_
.end();
621 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
622 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server
) const {
623 for (size_t i
= 0; i
< canonical_suffixes_
.size(); ++i
) {
624 std::string canonical_suffix
= canonical_suffixes_
[i
];
625 if (base::EndsWith(server
.host(), canonical_suffixes_
[i
],
626 base::CompareCase::INSENSITIVE_ASCII
)) {
627 HostPortPair
canonical_host(canonical_suffix
, server
.port());
628 return canonical_host_to_origin_map_
.find(canonical_host
);
632 return canonical_host_to_origin_map_
.end();
635 void HttpServerPropertiesImpl::RemoveCanonicalHost(
636 const HostPortPair
& server
) {
637 CanonicalHostMap::const_iterator canonical
= GetCanonicalHost(server
);
638 if (canonical
== canonical_host_to_origin_map_
.end())
641 if (!canonical
->second
.Equals(server
))
644 canonical_host_to_origin_map_
.erase(canonical
->first
);
647 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
648 base::TimeTicks now
= base::TimeTicks::Now();
649 while (!broken_alternative_services_
.empty()) {
650 BrokenAlternativeServices::iterator it
=
651 broken_alternative_services_
.begin();
652 if (now
< it
->second
) {
656 const AlternativeService expired_alternative_service
= it
->first
;
657 broken_alternative_services_
.erase(it
);
659 // Remove every occurrence of |expired_alternative_service| from
660 // |alternative_service_map_|.
661 for (AlternativeServiceMap::iterator map_it
=
662 alternative_service_map_
.begin();
663 map_it
!= alternative_service_map_
.end();) {
664 for (AlternativeServiceInfoVector::iterator it
= map_it
->second
.begin();
665 it
!= map_it
->second
.end();) {
666 AlternativeService
alternative_service(it
->alternative_service
);
667 // Empty hostname in map means hostname of key: substitute before
668 // comparing to |expired_alternative_service|.
669 if (alternative_service
.host
.empty()) {
670 alternative_service
.host
= map_it
->first
.host();
672 if (alternative_service
== expired_alternative_service
) {
673 it
= map_it
->second
.erase(it
);
678 // If an origin has an empty list of alternative services, then remove it
679 // from both |canonical_host_to_origin_map_| and
680 // |alternative_service_map_|.
681 if (map_it
->second
.empty()) {
682 RemoveCanonicalHost(map_it
->first
);
683 map_it
= alternative_service_map_
.Erase(map_it
);
689 ScheduleBrokenAlternateProtocolMappingsExpiration();
693 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
694 if (broken_alternative_services_
.empty()) {
697 base::TimeTicks now
= base::TimeTicks::Now();
698 base::TimeTicks when
= broken_alternative_services_
.front().second
;
699 base::TimeDelta delay
= when
> now
? when
- now
: base::TimeDelta();
700 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
703 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings
,
704 weak_ptr_factory_
.GetWeakPtr()),