Roll src/third_party/WebKit 6cdd902:94953d6 (svn 197985:197991)
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob535c915477358ae03584c23ef39b8c33f9ef5548
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 "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
18 namespace net {
20 namespace {
22 const uint64 kBrokenAlternativeProtocolDelaySecs = 300;
24 } // namespace
26 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
27 : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
28 alternative_service_map_(AlternativeServiceMap::NO_AUTO_EVICT),
29 spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
30 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
31 alternative_service_probability_threshold_(1.0),
32 weak_ptr_factory_(this) {
33 canonical_suffixes_.push_back(".c.youtube.com");
34 canonical_suffixes_.push_back(".googlevideo.com");
35 canonical_suffixes_.push_back(".googleusercontent.com");
38 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
41 void HttpServerPropertiesImpl::InitializeSpdyServers(
42 std::vector<std::string>* spdy_servers,
43 bool support_spdy) {
44 DCHECK(CalledOnValidThread());
45 if (!spdy_servers)
46 return;
47 // Add the entries from persisted data.
48 for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
49 it != spdy_servers->rend(); ++it) {
50 spdy_servers_map_.Put(*it, support_spdy);
54 void HttpServerPropertiesImpl::InitializeAlternativeServiceServers(
55 AlternativeServiceMap* alternative_service_map) {
56 // Keep all the broken ones since those don't get persisted.
57 for (AlternativeServiceMap::iterator it = alternative_service_map_.begin();
58 it != alternative_service_map_.end();) {
59 AlternativeService alternative_service(it->second.alternative_service);
60 if (alternative_service.host.empty()) {
61 alternative_service.host = it->first.host();
63 if (IsAlternativeServiceBroken(alternative_service)) {
64 ++it;
65 } else {
66 it = alternative_service_map_.Erase(it);
70 // Add the entries from persisted data.
71 for (AlternativeServiceMap::reverse_iterator it =
72 alternative_service_map->rbegin();
73 it != alternative_service_map->rend(); ++it) {
74 alternative_service_map_.Put(it->first, it->second);
77 // Attempt to find canonical servers.
78 uint16 canonical_ports[] = { 80, 443 };
79 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
80 std::string canonical_suffix = canonical_suffixes_[i];
81 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
82 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
83 // If we already have a valid canonical server, we're done.
84 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
85 (alternative_service_map_.Peek(
86 canonical_host_to_origin_map_[canonical_host]) !=
87 alternative_service_map_.end())) {
88 continue;
90 // Now attempt to find a server which matches this origin and set it as
91 // canonical.
92 for (AlternativeServiceMap::const_iterator it =
93 alternative_service_map_.begin();
94 it != alternative_service_map_.end(); ++it) {
95 if (base::EndsWith(it->first.host(), canonical_suffixes_[i], false)) {
96 canonical_host_to_origin_map_[canonical_host] = it->first;
97 break;
104 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
105 SpdySettingsMap* spdy_settings_map) {
106 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
107 it != spdy_settings_map->rend(); ++it) {
108 spdy_settings_map_.Put(it->first, it->second);
112 void HttpServerPropertiesImpl::InitializeSupportsQuic(
113 IPAddressNumber* last_address) {
114 if (last_address)
115 last_quic_address_ = *last_address;
118 void HttpServerPropertiesImpl::InitializeServerNetworkStats(
119 ServerNetworkStatsMap* server_network_stats_map) {
120 for (ServerNetworkStatsMap::reverse_iterator it =
121 server_network_stats_map->rbegin();
122 it != server_network_stats_map->rend(); ++it) {
123 server_network_stats_map_.Put(it->first, it->second);
127 void HttpServerPropertiesImpl::GetSpdyServerList(
128 base::ListValue* spdy_server_list,
129 size_t max_size) const {
130 DCHECK(CalledOnValidThread());
131 DCHECK(spdy_server_list);
132 spdy_server_list->Clear();
133 size_t count = 0;
134 // Get the list of servers (host/port) that support SPDY.
135 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
136 it != spdy_servers_map_.end() && count < max_size; ++it) {
137 const std::string spdy_server_host_port = it->first;
138 if (it->second) {
139 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
140 ++count;
145 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
146 return weak_ptr_factory_.GetWeakPtr();
149 void HttpServerPropertiesImpl::Clear() {
150 DCHECK(CalledOnValidThread());
151 spdy_servers_map_.Clear();
152 alternative_service_map_.Clear();
153 canonical_host_to_origin_map_.clear();
154 spdy_settings_map_.Clear();
155 last_quic_address_.clear();
156 server_network_stats_map_.Clear();
159 bool HttpServerPropertiesImpl::SupportsRequestPriority(
160 const HostPortPair& host_port_pair) {
161 DCHECK(CalledOnValidThread());
162 if (host_port_pair.host().empty())
163 return false;
165 if (GetSupportsSpdy(host_port_pair))
166 return true;
168 const AlternativeService alternative_service =
169 GetAlternativeService(host_port_pair);
170 return alternative_service.protocol == QUIC;
173 bool HttpServerPropertiesImpl::GetSupportsSpdy(
174 const HostPortPair& host_port_pair) {
175 DCHECK(CalledOnValidThread());
176 if (host_port_pair.host().empty())
177 return false;
179 SpdyServerHostPortMap::iterator spdy_host_port =
180 spdy_servers_map_.Get(host_port_pair.ToString());
181 return spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second;
184 void HttpServerPropertiesImpl::SetSupportsSpdy(
185 const HostPortPair& host_port_pair,
186 bool support_spdy) {
187 DCHECK(CalledOnValidThread());
188 if (host_port_pair.host().empty())
189 return;
191 SpdyServerHostPortMap::iterator spdy_host_port =
192 spdy_servers_map_.Get(host_port_pair.ToString());
193 if ((spdy_host_port != spdy_servers_map_.end()) &&
194 (spdy_host_port->second == support_spdy)) {
195 return;
197 // Cache the data.
198 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
201 bool HttpServerPropertiesImpl::RequiresHTTP11(
202 const HostPortPair& host_port_pair) {
203 DCHECK(CalledOnValidThread());
204 if (host_port_pair.host().empty())
205 return false;
207 return (http11_servers_.find(host_port_pair) != http11_servers_.end());
210 void HttpServerPropertiesImpl::SetHTTP11Required(
211 const HostPortPair& host_port_pair) {
212 DCHECK(CalledOnValidThread());
213 if (host_port_pair.host().empty())
214 return;
216 http11_servers_.insert(host_port_pair);
219 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
220 SSLConfig* ssl_config) {
221 if (RequiresHTTP11(server)) {
222 ForceHTTP11(ssl_config);
226 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
227 const std::string& host) {
228 // If this host ends with a canonical suffix, then return the canonical
229 // suffix.
230 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
231 std::string canonical_suffix = canonical_suffixes_[i];
232 if (base::EndsWith(host, canonical_suffixes_[i], false)) {
233 return canonical_suffix;
236 return std::string();
239 AlternativeService HttpServerPropertiesImpl::GetAlternativeService(
240 const HostPortPair& origin) {
241 AlternativeServiceMap::const_iterator it =
242 alternative_service_map_.Get(origin);
243 if (it != alternative_service_map_.end()) {
244 if (it->second.probability < alternative_service_probability_threshold_) {
245 return AlternativeService();
247 AlternativeService alternative_service(it->second.alternative_service);
248 if (alternative_service.host.empty()) {
249 alternative_service.host = origin.host();
251 return alternative_service;
254 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(origin);
255 if (canonical == canonical_host_to_origin_map_.end()) {
256 return AlternativeService();
258 it = alternative_service_map_.Get(canonical->second);
259 if (it == alternative_service_map_.end()) {
260 return AlternativeService();
262 if (it->second.probability < alternative_service_probability_threshold_) {
263 return AlternativeService();
265 AlternativeService alternative_service(it->second.alternative_service);
266 if (alternative_service.host.empty()) {
267 alternative_service.host = canonical->second.host();
269 if (IsAlternativeServiceBroken(alternative_service)) {
270 RemoveCanonicalHost(canonical->second);
271 return AlternativeService();
273 // Empty hostname: if alternative service for with hostname of canonical host
274 // is not broken, then return alternative service with hostname of origin.
275 if (it->second.alternative_service.host.empty()) {
276 alternative_service.host = origin.host();
278 return alternative_service;
281 void HttpServerPropertiesImpl::SetAlternativeService(
282 const HostPortPair& origin,
283 const AlternativeService& alternative_service,
284 double alternative_probability) {
285 const AlternativeServiceInfo alternative_service_info(
286 alternative_service, alternative_probability);
287 AlternativeServiceMap::const_iterator it =
288 GetAlternateProtocolIterator(origin);
289 if (it == alternative_service_map_.end() &&
290 alternative_probability >= alternative_service_probability_threshold_) {
291 // TODO(rch): Consider the case where multiple requests are started
292 // before the first completes. In this case, only one of the jobs
293 // would reach this code, whereas all of them should should have.
294 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
297 alternative_service_map_.Put(origin, alternative_service_info);
299 // If this host ends with a canonical suffix, then set it as the
300 // canonical host.
301 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
302 std::string canonical_suffix = canonical_suffixes_[i];
303 if (base::EndsWith(origin.host(), canonical_suffixes_[i], false)) {
304 HostPortPair canonical_host(canonical_suffix, origin.port());
305 canonical_host_to_origin_map_[canonical_host] = origin;
306 break;
311 void HttpServerPropertiesImpl::MarkAlternativeServiceBroken(
312 const AlternativeService& alternative_service) {
313 // Empty host means use host of origin, callers are supposed to substitute.
314 DCHECK(!alternative_service.host.empty());
315 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
316 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
317 return;
319 int count = ++recently_broken_alternative_services_[alternative_service];
320 base::TimeDelta delay =
321 base::TimeDelta::FromSeconds(kBrokenAlternativeProtocolDelaySecs);
322 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
323 auto result = broken_alternative_services_.insert(
324 std::make_pair(alternative_service, when));
325 // Return if alternative service is already in expiration queue.
326 if (!result.second) {
327 return;
330 // If this is the only entry in the list, schedule an expiration task.
331 // Otherwise it will be rescheduled automatically when the pending task runs.
332 if (broken_alternative_services_.size() == 1) {
333 ScheduleBrokenAlternateProtocolMappingsExpiration();
337 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
338 const AlternativeService& alternative_service) {
339 if (!ContainsKey(recently_broken_alternative_services_, alternative_service))
340 recently_broken_alternative_services_[alternative_service] = 1;
343 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
344 const AlternativeService& alternative_service) const {
345 // Empty host means use host of origin, callers are supposed to substitute.
346 DCHECK(!alternative_service.host.empty());
347 return ContainsKey(broken_alternative_services_, alternative_service);
350 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
351 const AlternativeService& alternative_service) {
352 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
353 return false;
354 return ContainsKey(recently_broken_alternative_services_,
355 alternative_service);
358 void HttpServerPropertiesImpl::ConfirmAlternativeService(
359 const AlternativeService& alternative_service) {
360 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
361 return;
362 broken_alternative_services_.erase(alternative_service);
363 recently_broken_alternative_services_.erase(alternative_service);
366 void HttpServerPropertiesImpl::ClearAlternativeService(
367 const HostPortPair& origin) {
368 RemoveCanonicalHost(origin);
370 AlternativeServiceMap::iterator it = alternative_service_map_.Peek(origin);
371 if (it == alternative_service_map_.end()) {
372 return;
374 alternative_service_map_.Erase(it);
377 const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map()
378 const {
379 return alternative_service_map_;
382 scoped_ptr<base::Value>
383 HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
384 const {
385 scoped_ptr<base::ListValue> dict_list(new base::ListValue());
386 for (const auto& alternative_service_map_item : alternative_service_map_) {
387 const HostPortPair& host_port_pair = alternative_service_map_item.first;
388 const AlternativeServiceInfo& alternative_service_info =
389 alternative_service_map_item.second;
390 std::string alternative_service_string(alternative_service_info.ToString());
391 AlternativeService alternative_service(
392 alternative_service_info.alternative_service);
393 if (alternative_service.host.empty()) {
394 alternative_service.host = host_port_pair.host();
396 if (IsAlternativeServiceBroken(alternative_service)) {
397 alternative_service_string.append(" (broken)");
400 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
401 dict->SetString("host_port_pair", host_port_pair.ToString());
402 dict->SetString("alternative_service", alternative_service_string);
403 dict_list->Append(dict.Pass());
405 return dict_list.Pass();
408 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
409 const HostPortPair& host_port_pair) {
410 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
411 if (it == spdy_settings_map_.end()) {
412 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
413 return kEmptySettingsMap;
415 return it->second;
418 bool HttpServerPropertiesImpl::SetSpdySetting(
419 const HostPortPair& host_port_pair,
420 SpdySettingsIds id,
421 SpdySettingsFlags flags,
422 uint32 value) {
423 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
424 return false;
426 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
427 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
428 if (it == spdy_settings_map_.end()) {
429 SettingsMap settings_map;
430 settings_map[id] = flags_and_value;
431 spdy_settings_map_.Put(host_port_pair, settings_map);
432 } else {
433 SettingsMap& settings_map = it->second;
434 settings_map[id] = flags_and_value;
436 return true;
439 void HttpServerPropertiesImpl::ClearSpdySettings(
440 const HostPortPair& host_port_pair) {
441 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
442 if (it != spdy_settings_map_.end())
443 spdy_settings_map_.Erase(it);
446 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
447 spdy_settings_map_.Clear();
450 const SpdySettingsMap&
451 HttpServerPropertiesImpl::spdy_settings_map() const {
452 return spdy_settings_map_;
455 bool HttpServerPropertiesImpl::GetSupportsQuic(
456 IPAddressNumber* last_address) const {
457 if (last_quic_address_.empty())
458 return false;
460 *last_address = last_quic_address_;
461 return true;
464 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
465 const IPAddressNumber& address) {
466 if (!used_quic) {
467 last_quic_address_.clear();
468 } else {
469 last_quic_address_ = address;
473 void HttpServerPropertiesImpl::SetServerNetworkStats(
474 const HostPortPair& host_port_pair,
475 ServerNetworkStats stats) {
476 server_network_stats_map_.Put(host_port_pair, stats);
479 const ServerNetworkStats* HttpServerPropertiesImpl::GetServerNetworkStats(
480 const HostPortPair& host_port_pair) {
481 ServerNetworkStatsMap::iterator it =
482 server_network_stats_map_.Get(host_port_pair);
483 if (it == server_network_stats_map_.end()) {
484 return NULL;
486 return &it->second;
489 const ServerNetworkStatsMap&
490 HttpServerPropertiesImpl::server_network_stats_map() const {
491 return server_network_stats_map_;
494 void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold(
495 double threshold) {
496 alternative_service_probability_threshold_ = threshold;
499 AlternativeServiceMap::const_iterator
500 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
501 const HostPortPair& server) {
502 AlternativeServiceMap::const_iterator it =
503 alternative_service_map_.Get(server);
504 if (it != alternative_service_map_.end())
505 return it;
507 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
508 if (canonical == canonical_host_to_origin_map_.end()) {
509 return alternative_service_map_.end();
512 const HostPortPair canonical_host_port = canonical->second;
513 it = alternative_service_map_.Get(canonical_host_port);
514 if (it == alternative_service_map_.end()) {
515 return alternative_service_map_.end();
518 const AlternativeService alternative_service(
519 it->second.alternative_service.protocol, canonical_host_port.host(),
520 it->second.alternative_service.port);
521 if (!IsAlternativeServiceBroken(alternative_service)) {
522 return it;
525 RemoveCanonicalHost(canonical_host_port);
526 return alternative_service_map_.end();
529 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
530 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
531 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
532 std::string canonical_suffix = canonical_suffixes_[i];
533 if (base::EndsWith(server.host(), canonical_suffixes_[i], false)) {
534 HostPortPair canonical_host(canonical_suffix, server.port());
535 return canonical_host_to_origin_map_.find(canonical_host);
539 return canonical_host_to_origin_map_.end();
542 void HttpServerPropertiesImpl::RemoveCanonicalHost(
543 const HostPortPair& server) {
544 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
545 if (canonical == canonical_host_to_origin_map_.end())
546 return;
548 if (!canonical->second.Equals(server))
549 return;
551 canonical_host_to_origin_map_.erase(canonical->first);
554 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
555 base::TimeTicks now = base::TimeTicks::Now();
556 while (!broken_alternative_services_.empty()) {
557 BrokenAlternativeServices::iterator it =
558 broken_alternative_services_.begin();
559 if (now < it->second) {
560 break;
563 const AlternativeService alternative_service = it->first;
564 broken_alternative_services_.erase(it);
565 // TODO(bnc): Make sure broken alternative services are not in the mapping.
566 ClearAlternativeService(
567 HostPortPair(alternative_service.host, alternative_service.port));
569 ScheduleBrokenAlternateProtocolMappingsExpiration();
572 void
573 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
574 if (broken_alternative_services_.empty()) {
575 return;
577 base::TimeTicks now = base::TimeTicks::Now();
578 base::TimeTicks when = broken_alternative_services_.front().second;
579 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
580 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
581 FROM_HERE,
582 base::Bind(
583 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
584 weak_ptr_factory_.GetWeakPtr()),
585 delay);
588 } // namespace net