Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob7bdd30ec84dbe959f7a391b82ae1ee1b9e2dd428
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 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);
92 continue;
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 :
97 input_it->second) {
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())) {
113 continue;
115 // Now attempt to find a server which matches this origin and set it as
116 // canonical.
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;
123 break;
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) {
140 if (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();
159 size_t count = 0;
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;
164 if (it->second) {
165 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
166 ++count;
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())
189 return false;
191 if (GetSupportsSpdy(host_port_pair))
192 return true;
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) {
199 return true;
202 return false;
205 bool HttpServerPropertiesImpl::GetSupportsSpdy(
206 const HostPortPair& host_port_pair) {
207 DCHECK(CalledOnValidThread());
208 if (host_port_pair.host().empty())
209 return false;
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,
218 bool support_spdy) {
219 DCHECK(CalledOnValidThread());
220 if (host_port_pair.host().empty())
221 return;
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)) {
227 return;
229 // Cache the data.
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())
237 return false;
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())
246 return;
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
261 // suffix.
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_) {
283 continue;
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
292 // return it here.
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) {
296 continue;
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_) {
314 continue;
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)) {
321 continue;
323 alternative_service.host = origin.host();
324 } else if (IsAlternativeServiceBroken(alternative_service)) {
325 continue;
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()) {
349 return false;
351 ClearAlternativeServices(origin);
352 return true;
355 bool changed = true;
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
378 // canonical host.
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;
385 break;
389 return changed;
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.";
398 return;
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) {
408 return;
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)
434 return false;
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)
442 return;
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()) {
453 return;
455 alternative_service_map_.Erase(it);
458 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
459 const {
460 return alternative_service_map_;
463 scoped_ptr<base::Value>
464 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
465 const {
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())
486 continue;
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;
503 return it->second;
506 bool HttpServerPropertiesImpl::SetSpdySetting(
507 const HostPortPair& host_port_pair,
508 SpdySettingsIds id,
509 SpdySettingsFlags flags,
510 uint32 value) {
511 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
512 return false;
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);
520 } else {
521 SettingsMap& settings_map = it->second;
522 settings_map[id] = flags_and_value;
524 return true;
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())
546 return false;
548 *last_address = last_quic_address_;
549 return true;
552 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
553 const IPAddressNumber& address) {
554 if (!used_quic) {
555 last_quic_address_.clear();
556 } else {
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()) {
572 return NULL;
574 return &it->second;
577 const ServerNetworkStatsMap&
578 HttpServerPropertiesImpl::server_network_stats_map() const {
579 return server_network_stats_map_;
582 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
583 double threshold) {
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())
593 return it;
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)) {
613 return it;
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())
639 return;
641 if (!canonical->second.Equals(server))
642 return;
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) {
653 break;
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);
674 continue;
676 ++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);
684 continue;
686 ++map_it;
689 ScheduleBrokenAlternateProtocolMappingsExpiration();
692 void
693 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
694 if (broken_alternative_services_.empty()) {
695 return;
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(
701 FROM_HERE,
702 base::Bind(
703 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
704 weak_ptr_factory_.GetWeakPtr()),
705 delay);
708 } // namespace net