Add long running gmail memory benchmark for background tab.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blobf8bffb8585364e4a755312b2c1d8d83ad5d70af2
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 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);
284 continue;
286 if (it->probability < alternative_service_probability_threshold_) {
287 ++it;
288 continue;
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
296 // return it here.
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) {
300 ++it;
301 continue;
303 alternative_services_above_threshold.push_back(alternative_service);
304 ++it;
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);
321 continue;
323 if (it->probability < alternative_service_probability_threshold_) {
324 ++it;
325 continue;
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)) {
331 ++it;
332 continue;
334 alternative_service.host = origin.host();
335 } else if (IsAlternativeServiceBroken(alternative_service)) {
336 ++it;
337 continue;
339 alternative_services_above_threshold.push_back(alternative_service);
340 ++it;
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(
352 /*size=*/1,
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()) {
364 return false;
366 ClearAlternativeServices(origin);
367 return true;
370 bool changed = true;
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
393 // canonical host.
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;
400 break;
404 return changed;
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.";
413 return;
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) {
423 return;
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)
449 return false;
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)
457 return;
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()) {
468 return;
470 alternative_service_map_.Erase(it);
473 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
474 const {
475 return alternative_service_map_;
478 scoped_ptr<base::Value>
479 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
480 const {
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())
501 continue;
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;
518 return it->second;
521 bool HttpServerPropertiesImpl::SetSpdySetting(
522 const HostPortPair& host_port_pair,
523 SpdySettingsIds id,
524 SpdySettingsFlags flags,
525 uint32 value) {
526 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
527 return false;
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);
535 } else {
536 SettingsMap& settings_map = it->second;
537 settings_map[id] = flags_and_value;
539 return true;
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())
561 return false;
563 *last_address = last_quic_address_;
564 return true;
567 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
568 const IPAddressNumber& address) {
569 if (!used_quic) {
570 last_quic_address_.clear();
571 } else {
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()) {
587 return NULL;
589 return &it->second;
592 const ServerNetworkStatsMap&
593 HttpServerPropertiesImpl::server_network_stats_map() const {
594 return server_network_stats_map_;
597 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
598 double threshold) {
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())
608 return it;
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)) {
628 return it;
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())
654 return;
656 if (!canonical->second.Equals(server))
657 return;
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) {
668 break;
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);
689 continue;
691 ++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);
699 continue;
701 ++map_it;
704 ScheduleBrokenAlternateProtocolMappingsExpiration();
707 void
708 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
709 if (broken_alternative_services_.empty()) {
710 return;
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(
716 FROM_HERE,
717 base::Bind(
718 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
719 weak_ptr_factory_.GetWeakPtr()),
720 delay);
723 } // namespace net