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 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
);
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
:
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())) {
116 // Now attempt to find a server which matches this origin and set it as
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
;
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
) {
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();
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
;
166 spdy_server_list
->Append(new base::StringValue(spdy_server_host_port
));
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())
192 if (GetSupportsSpdy(host_port_pair
))
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
) {
206 bool HttpServerPropertiesImpl::GetSupportsSpdy(
207 const HostPortPair
& host_port_pair
) {
208 DCHECK(CalledOnValidThread());
209 if (host_port_pair
.host().empty())
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
,
220 DCHECK(CalledOnValidThread());
221 if (host_port_pair
.host().empty())
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
)) {
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())
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())
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
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
);
287 if (it
->probability
< alternative_service_probability_threshold_
) {
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
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
) {
304 alternative_services_above_threshold
.push_back(alternative_service
);
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
);
327 if (it
->probability
< alternative_service_probability_threshold_
) {
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
)) {
338 alternative_service
.host
= origin
.host();
339 } else if (IsAlternativeServiceBroken(alternative_service
)) {
343 alternative_services_above_threshold
.push_back(alternative_service
);
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(
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()) {
373 ClearAlternativeServices(origin
);
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
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
;
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.";
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
) {
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
)
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
)
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()) {
477 alternative_service_map_
.Erase(it
);
480 const AlternativeServiceMap
& HttpServerPropertiesImpl::alternative_service_map()
482 return alternative_service_map_
;
485 scoped_ptr
<base::Value
>
486 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
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())
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
;
528 bool HttpServerPropertiesImpl::SetSpdySetting(
529 const HostPortPair
& host_port_pair
,
531 SpdySettingsFlags flags
,
533 if (!(flags
& SETTINGS_FLAG_PLEASE_PERSIST
))
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
);
543 SettingsMap
& settings_map
= it
->second
;
544 settings_map
[id
] = flags_and_value
;
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())
570 *last_address
= last_quic_address_
;
574 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic
,
575 const IPAddressNumber
& address
) {
577 last_quic_address_
.clear();
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()) {
599 const ServerNetworkStatsMap
&
600 HttpServerPropertiesImpl::server_network_stats_map() const {
601 return server_network_stats_map_
;
604 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
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())
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
)) {
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())
663 if (!canonical
->second
.Equals(server
))
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
) {
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
);
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
);
711 ScheduleBrokenAlternateProtocolMappingsExpiration();
715 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
716 if (broken_alternative_services_
.empty()) {
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(
725 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings
,
726 weak_ptr_factory_
.GetWeakPtr()),