Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob8a8e49a328761497d09ba392e1892b4097691df6
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/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
15 namespace net {
17 namespace {
19 const uint64 kBrokenAlternateProtocolDelaySecs = 300;
21 } // namespace
23 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
24 : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
25 alternate_protocol_map_(AlternateProtocolMap::NO_AUTO_EVICT),
26 spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
27 alternate_protocol_probability_threshold_(1),
28 weak_ptr_factory_(this) {
29 canonical_suffixes_.push_back(".c.youtube.com");
30 canonical_suffixes_.push_back(".googlevideo.com");
31 canonical_suffixes_.push_back(".googleusercontent.com");
34 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
37 void HttpServerPropertiesImpl::InitializeSpdyServers(
38 std::vector<std::string>* spdy_servers,
39 bool support_spdy) {
40 DCHECK(CalledOnValidThread());
41 if (!spdy_servers)
42 return;
43 // Add the entries from persisted data.
44 for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
45 it != spdy_servers->rend(); ++it) {
46 spdy_servers_map_.Put(*it, support_spdy);
50 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
51 AlternateProtocolMap* alternate_protocol_map) {
52 // Keep all the broken ones since those don't get persisted.
53 for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
54 it != alternate_protocol_map_.end();) {
55 AlternateProtocolMap::iterator old_it = it;
56 ++it;
57 if (!old_it->second.is_broken) {
58 alternate_protocol_map_.Erase(old_it);
62 // Add the entries from persisted data.
63 for (AlternateProtocolMap::reverse_iterator it =
64 alternate_protocol_map->rbegin();
65 it != alternate_protocol_map->rend(); ++it) {
66 alternate_protocol_map_.Put(it->first, it->second);
69 // Attempt to find canonical servers.
70 uint16 canonical_ports[] = { 80, 443 };
71 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
72 std::string canonical_suffix = canonical_suffixes_[i];
73 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
74 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
75 // If we already have a valid canonical server, we're done.
76 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
77 (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
78 canonical_host]) != alternate_protocol_map_.end())) {
79 continue;
81 // Now attempt to find a server which matches this origin and set it as
82 // canonical .
83 for (AlternateProtocolMap::const_iterator it =
84 alternate_protocol_map_.begin();
85 it != alternate_protocol_map_.end(); ++it) {
86 if (EndsWith(it->first.host(), canonical_suffixes_[i], false)) {
87 canonical_host_to_origin_map_[canonical_host] = it->first;
88 break;
95 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
96 SpdySettingsMap* spdy_settings_map) {
97 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
98 it != spdy_settings_map->rend(); ++it) {
99 spdy_settings_map_.Put(it->first, it->second);
103 void HttpServerPropertiesImpl::InitializeSupportsQuic(
104 SupportsQuicMap* supports_quic_map) {
105 for (SupportsQuicMap::reverse_iterator it = supports_quic_map->rbegin();
106 it != supports_quic_map->rend();
107 ++it) {
108 supports_quic_map_.insert(std::make_pair(it->first, it->second));
112 void HttpServerPropertiesImpl::GetSpdyServerList(
113 base::ListValue* spdy_server_list,
114 size_t max_size) const {
115 DCHECK(CalledOnValidThread());
116 DCHECK(spdy_server_list);
117 spdy_server_list->Clear();
118 size_t count = 0;
119 // Get the list of servers (host/port) that support SPDY.
120 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
121 it != spdy_servers_map_.end() && count < max_size; ++it) {
122 const std::string spdy_server_host_port = it->first;
123 if (it->second) {
124 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
125 ++count;
130 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
132 // static
133 void HttpServerPropertiesImpl::ForceAlternateProtocol(
134 const AlternateProtocolInfo& info) {
135 // Note: we're going to leak this.
136 if (g_forced_alternate_protocol)
137 delete g_forced_alternate_protocol;
138 g_forced_alternate_protocol = new AlternateProtocolInfo(info);
141 // static
142 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
143 delete g_forced_alternate_protocol;
144 g_forced_alternate_protocol = NULL;
147 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
148 return weak_ptr_factory_.GetWeakPtr();
151 void HttpServerPropertiesImpl::Clear() {
152 DCHECK(CalledOnValidThread());
153 spdy_servers_map_.Clear();
154 alternate_protocol_map_.Clear();
155 canonical_host_to_origin_map_.clear();
156 spdy_settings_map_.Clear();
157 supports_quic_map_.clear();
160 bool HttpServerPropertiesImpl::SupportsSpdy(
161 const net::HostPortPair& host_port_pair) {
162 DCHECK(CalledOnValidThread());
163 if (host_port_pair.host().empty())
164 return false;
166 SpdyServerHostPortMap::iterator spdy_host_port =
167 spdy_servers_map_.Get(host_port_pair.ToString());
168 if (spdy_host_port != spdy_servers_map_.end())
169 return spdy_host_port->second;
170 return false;
173 void HttpServerPropertiesImpl::SetSupportsSpdy(
174 const net::HostPortPair& host_port_pair,
175 bool support_spdy) {
176 DCHECK(CalledOnValidThread());
177 if (host_port_pair.host().empty())
178 return;
180 SpdyServerHostPortMap::iterator spdy_host_port =
181 spdy_servers_map_.Get(host_port_pair.ToString());
182 if ((spdy_host_port != spdy_servers_map_.end()) &&
183 (spdy_host_port->second == support_spdy)) {
184 return;
186 // Cache the data.
187 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
190 bool HttpServerPropertiesImpl::HasAlternateProtocol(
191 const HostPortPair& server) {
192 if (g_forced_alternate_protocol)
193 return true;
194 AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
195 if (it != alternate_protocol_map_.end())
196 return it->second.probability >= alternate_protocol_probability_threshold_;
198 auto canonical = GetCanonicalHost(server);
199 if (canonical == canonical_host_to_origin_map_.end() ||
200 canonical->second.Equals(server)) {
201 return false;
204 return HasAlternateProtocol(canonical->second);
207 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
208 const HostPortPair& server) {
209 // If this host ends with a canonical suffix, then return the canonical
210 // suffix.
211 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
212 std::string canonical_suffix = canonical_suffixes_[i];
213 if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
214 return canonical_suffix;
217 return std::string();
220 AlternateProtocolInfo
221 HttpServerPropertiesImpl::GetAlternateProtocol(
222 const HostPortPair& server) {
223 DCHECK(HasAlternateProtocol(server));
225 // First check the map.
226 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
227 if (it != alternate_protocol_map_.end())
228 return it->second;
230 // Next check the canonical host.
231 CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
232 if (canonical_host != canonical_host_to_origin_map_.end())
233 return alternate_protocol_map_.Get(canonical_host->second)->second;
235 // We must be forcing an alternate.
236 DCHECK(g_forced_alternate_protocol);
237 return *g_forced_alternate_protocol;
240 void HttpServerPropertiesImpl::SetAlternateProtocol(
241 const HostPortPair& server,
242 uint16 alternate_port,
243 AlternateProtocol alternate_protocol,
244 double alternate_probability) {
246 AlternateProtocolInfo alternate(alternate_port,
247 alternate_protocol,
248 alternate_probability);
249 if (HasAlternateProtocol(server)) {
250 const AlternateProtocolInfo existing_alternate =
251 GetAlternateProtocol(server);
253 if (existing_alternate.is_broken) {
254 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
255 return;
258 if (!existing_alternate.Equals(alternate)) {
259 LOG(WARNING) << "Changing the alternate protocol for: "
260 << server.ToString()
261 << " from [Port: " << existing_alternate.port
262 << ", Protocol: " << existing_alternate.protocol
263 << ", Probability: " << existing_alternate.probability
264 << "] to [Port: " << alternate_port
265 << ", Protocol: " << alternate_protocol
266 << ", Probability: " << alternate_probability
267 << "].";
269 } else {
270 if (alternate_probability >= alternate_protocol_probability_threshold_) {
271 // TODO(rch): Consider the case where multiple requests are started
272 // before the first completes. In this case, only one of the jobs
273 // would reach this code, whereas all of them should should have.
274 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
278 alternate_protocol_map_.Put(server, alternate);
280 // If this host ends with a canonical suffix, then set it as the
281 // canonical host.
282 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
283 std::string canonical_suffix = canonical_suffixes_[i];
284 if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
285 HostPortPair canonical_host(canonical_suffix, server.port());
286 canonical_host_to_origin_map_[canonical_host] = server;
287 break;
292 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
293 const HostPortPair& server) {
294 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
295 if (it == alternate_protocol_map_.end()) {
296 if (!HasAlternateProtocol(server)) {
297 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
298 return;
300 // This server's alternate protocol information is coming from a canonical
301 // server. Add an entry in the map for this server explicitly so that
302 // it can be marked as broken.
303 it = alternate_protocol_map_.Put(server, GetAlternateProtocol(server));
305 it->second.is_broken = true;
306 int count = ++broken_alternate_protocol_map_[server];
307 base::TimeDelta delay =
308 base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
309 BrokenAlternateProtocolEntry entry;
310 entry.server = server;
311 entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
312 broken_alternate_protocol_list_.push_back(entry);
314 // Do not leave this host as canonical so that we don't infer the other
315 // hosts are also broken without testing them first.
316 RemoveCanonicalHost(server);
318 // If this is the only entry in the list, schedule an expiration task.
319 // Otherwse it will be rescheduled automatically when the pending
320 // task runs.
321 if (broken_alternate_protocol_list_.size() == 1) {
322 ScheduleBrokenAlternateProtocolMappingsExpiration();
326 bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
327 const HostPortPair& server) {
328 return ContainsKey(broken_alternate_protocol_map_, server);
331 void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
332 const HostPortPair& server) {
333 broken_alternate_protocol_map_.erase(server);
336 void HttpServerPropertiesImpl::ClearAlternateProtocol(
337 const HostPortPair& server) {
338 AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
339 if (it != alternate_protocol_map_.end())
340 alternate_protocol_map_.Erase(it);
342 RemoveCanonicalHost(server);
345 const AlternateProtocolMap&
346 HttpServerPropertiesImpl::alternate_protocol_map() const {
347 return alternate_protocol_map_;
350 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
351 const HostPortPair& host_port_pair) {
352 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
353 if (it == spdy_settings_map_.end()) {
354 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
355 return kEmptySettingsMap;
357 return it->second;
360 bool HttpServerPropertiesImpl::SetSpdySetting(
361 const HostPortPair& host_port_pair,
362 SpdySettingsIds id,
363 SpdySettingsFlags flags,
364 uint32 value) {
365 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
366 return false;
368 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
369 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
370 if (it == spdy_settings_map_.end()) {
371 SettingsMap settings_map;
372 settings_map[id] = flags_and_value;
373 spdy_settings_map_.Put(host_port_pair, settings_map);
374 } else {
375 SettingsMap& settings_map = it->second;
376 settings_map[id] = flags_and_value;
378 return true;
381 void HttpServerPropertiesImpl::ClearSpdySettings(
382 const HostPortPair& host_port_pair) {
383 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
384 if (it != spdy_settings_map_.end())
385 spdy_settings_map_.Erase(it);
388 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
389 spdy_settings_map_.Clear();
392 const SpdySettingsMap&
393 HttpServerPropertiesImpl::spdy_settings_map() const {
394 return spdy_settings_map_;
397 SupportsQuic HttpServerPropertiesImpl::GetSupportsQuic(
398 const HostPortPair& host_port_pair) const {
399 SupportsQuicMap::const_iterator it = supports_quic_map_.find(host_port_pair);
400 if (it == supports_quic_map_.end()) {
401 CR_DEFINE_STATIC_LOCAL(SupportsQuic, kEmptySupportsQuic, ());
402 return kEmptySupportsQuic;
404 return it->second;
407 void HttpServerPropertiesImpl::SetSupportsQuic(
408 const HostPortPair& host_port_pair,
409 bool used_quic,
410 const std::string& address) {
411 SupportsQuic supports_quic(used_quic, address);
412 supports_quic_map_.insert(std::make_pair(host_port_pair, supports_quic));
415 const SupportsQuicMap&
416 HttpServerPropertiesImpl::supports_quic_map() const {
417 return supports_quic_map_;
420 void HttpServerPropertiesImpl::SetServerNetworkStats(
421 const HostPortPair& host_port_pair,
422 NetworkStats stats) {
423 server_network_stats_map_[host_port_pair] = stats;
426 const HttpServerProperties::NetworkStats*
427 HttpServerPropertiesImpl::GetServerNetworkStats(
428 const HostPortPair& host_port_pair) const {
429 ServerNetworkStatsMap::const_iterator it =
430 server_network_stats_map_.find(host_port_pair);
431 if (it == server_network_stats_map_.end()) {
432 return NULL;
434 return &it->second;
437 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
438 double threshold) {
439 alternate_protocol_probability_threshold_ = threshold;
442 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
443 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
444 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
445 std::string canonical_suffix = canonical_suffixes_[i];
446 if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
447 HostPortPair canonical_host(canonical_suffix, server.port());
448 return canonical_host_to_origin_map_.find(canonical_host);
452 return canonical_host_to_origin_map_.end();
455 void HttpServerPropertiesImpl::RemoveCanonicalHost(
456 const HostPortPair& server) {
457 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
458 if (canonical == canonical_host_to_origin_map_.end())
459 return;
461 if (!canonical->second.Equals(server))
462 return;
464 canonical_host_to_origin_map_.erase(canonical->first);
467 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
468 base::TimeTicks now = base::TimeTicks::Now();
469 while (!broken_alternate_protocol_list_.empty()) {
470 BrokenAlternateProtocolEntry entry =
471 broken_alternate_protocol_list_.front();
472 if (now < entry.when) {
473 break;
476 ClearAlternateProtocol(entry.server);
477 broken_alternate_protocol_list_.pop_front();
479 ScheduleBrokenAlternateProtocolMappingsExpiration();
482 void
483 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
484 if (broken_alternate_protocol_list_.empty()) {
485 return;
487 base::TimeTicks now = base::TimeTicks::Now();
488 base::TimeTicks when = broken_alternate_protocol_list_.front().when;
489 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
490 base::MessageLoop::current()->PostDelayedTask(
491 FROM_HERE,
492 base::Bind(
493 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
494 weak_ptr_factory_.GetWeakPtr()),
495 delay);
498 } // namespace net