Add include.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob201e19f21a413663747afb52da99f5f22088ac73
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 canoncial_suffixes_.push_back(".c.youtube.com");
30 canoncial_suffixes_.push_back(".googlevideo.com");
31 canoncial_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 ALTERNATE_PROTOCOL_BROKEN ones since those don't
53 // get persisted.
54 for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
55 it != alternate_protocol_map_.end();) {
56 AlternateProtocolMap::iterator old_it = it;
57 ++it;
58 if (old_it->second.protocol != ALTERNATE_PROTOCOL_BROKEN) {
59 alternate_protocol_map_.Erase(old_it);
63 // Add the entries from persisted data.
64 for (AlternateProtocolMap::reverse_iterator it =
65 alternate_protocol_map->rbegin();
66 it != alternate_protocol_map->rend(); ++it) {
67 alternate_protocol_map_.Put(it->first, it->second);
70 // Attempt to find canonical servers.
71 int canonical_ports[] = { 80, 443 };
72 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
73 std::string canonical_suffix = canoncial_suffixes_[i];
74 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
75 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
76 // If we already have a valid canonical server, we're done.
77 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
78 (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
79 canonical_host]) != alternate_protocol_map_.end())) {
80 continue;
82 // Now attempt to find a server which matches this origin and set it as
83 // canonical .
84 for (AlternateProtocolMap::const_iterator it =
85 alternate_protocol_map_.begin();
86 it != alternate_protocol_map_.end(); ++it) {
87 if (EndsWith(it->first.host(), canoncial_suffixes_[i], false)) {
88 canonical_host_to_origin_map_[canonical_host] = it->first;
89 break;
96 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
97 SpdySettingsMap* spdy_settings_map) {
98 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
99 it != spdy_settings_map->rend(); ++it) {
100 spdy_settings_map_.Put(it->first, it->second);
104 void HttpServerPropertiesImpl::InitializeSupportsQuic(
105 SupportsQuicMap* supports_quic_map) {
106 for (SupportsQuicMap::reverse_iterator it = supports_quic_map->rbegin();
107 it != supports_quic_map->rend();
108 ++it) {
109 supports_quic_map_.insert(std::make_pair(it->first, it->second));
113 void HttpServerPropertiesImpl::GetSpdyServerList(
114 base::ListValue* spdy_server_list,
115 size_t max_size) const {
116 DCHECK(CalledOnValidThread());
117 DCHECK(spdy_server_list);
118 spdy_server_list->Clear();
119 size_t count = 0;
120 // Get the list of servers (host/port) that support SPDY.
121 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
122 it != spdy_servers_map_.end() && count < max_size; ++it) {
123 const std::string spdy_server_host_port = it->first;
124 if (it->second) {
125 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
126 ++count;
131 // static
132 std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer(
133 const net::HostPortPair& host_port_pair) {
134 std::string spdy_server;
135 spdy_server.append(host_port_pair.host());
136 spdy_server.append(":");
137 base::StringAppendF(&spdy_server, "%d", host_port_pair.port());
138 return spdy_server;
141 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
143 // static
144 void HttpServerPropertiesImpl::ForceAlternateProtocol(
145 const AlternateProtocolInfo& info) {
146 // Note: we're going to leak this.
147 if (g_forced_alternate_protocol)
148 delete g_forced_alternate_protocol;
149 g_forced_alternate_protocol = new AlternateProtocolInfo(info);
152 // static
153 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
154 delete g_forced_alternate_protocol;
155 g_forced_alternate_protocol = NULL;
158 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
159 return weak_ptr_factory_.GetWeakPtr();
162 void HttpServerPropertiesImpl::Clear() {
163 DCHECK(CalledOnValidThread());
164 spdy_servers_map_.Clear();
165 alternate_protocol_map_.Clear();
166 canonical_host_to_origin_map_.clear();
167 spdy_settings_map_.Clear();
168 supports_quic_map_.clear();
171 bool HttpServerPropertiesImpl::SupportsSpdy(
172 const net::HostPortPair& host_port_pair) {
173 DCHECK(CalledOnValidThread());
174 if (host_port_pair.host().empty())
175 return false;
176 std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
178 SpdyServerHostPortMap::iterator spdy_host_port =
179 spdy_servers_map_.Get(spdy_server);
180 if (spdy_host_port != spdy_servers_map_.end())
181 return spdy_host_port->second;
182 return false;
185 void HttpServerPropertiesImpl::SetSupportsSpdy(
186 const net::HostPortPair& host_port_pair,
187 bool support_spdy) {
188 DCHECK(CalledOnValidThread());
189 if (host_port_pair.host().empty())
190 return;
191 std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
193 SpdyServerHostPortMap::iterator spdy_host_port =
194 spdy_servers_map_.Get(spdy_server);
195 if ((spdy_host_port != spdy_servers_map_.end()) &&
196 (spdy_host_port->second == support_spdy)) {
197 return;
199 // Cache the data.
200 spdy_servers_map_.Put(spdy_server, support_spdy);
203 bool HttpServerPropertiesImpl::HasAlternateProtocol(
204 const HostPortPair& server) {
205 if (g_forced_alternate_protocol)
206 return true;
207 AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
208 if (it != alternate_protocol_map_.end() &&
209 it->second.probability >= alternate_protocol_probability_threshold_) {
210 return true;
213 return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
216 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
217 const HostPortPair& server) {
218 // If this host ends with a canonical suffix, then return the canonical
219 // suffix.
220 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
221 std::string canonical_suffix = canoncial_suffixes_[i];
222 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
223 return canonical_suffix;
226 return std::string();
229 AlternateProtocolInfo
230 HttpServerPropertiesImpl::GetAlternateProtocol(
231 const HostPortPair& server) {
232 DCHECK(HasAlternateProtocol(server));
234 // First check the map.
235 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
236 if (it != alternate_protocol_map_.end())
237 return it->second;
239 // Next check the canonical host.
240 CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
241 if (canonical_host != canonical_host_to_origin_map_.end())
242 return alternate_protocol_map_.Get(canonical_host->second)->second;
244 // We must be forcing an alternate.
245 DCHECK(g_forced_alternate_protocol);
246 return *g_forced_alternate_protocol;
249 void HttpServerPropertiesImpl::SetAlternateProtocol(
250 const HostPortPair& server,
251 uint16 alternate_port,
252 AlternateProtocol alternate_protocol,
253 double alternate_probability) {
254 if (alternate_protocol == ALTERNATE_PROTOCOL_BROKEN) {
255 LOG(DFATAL) << "Call SetBrokenAlternateProtocol() instead.";
256 return;
259 AlternateProtocolInfo alternate(alternate_port,
260 alternate_protocol,
261 alternate_probability);
262 if (HasAlternateProtocol(server)) {
263 const AlternateProtocolInfo existing_alternate =
264 GetAlternateProtocol(server);
266 if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) {
267 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
268 return;
271 if (alternate_protocol != ALTERNATE_PROTOCOL_BROKEN &&
272 !existing_alternate.Equals(alternate)) {
273 LOG(WARNING) << "Changing the alternate protocol for: "
274 << server.ToString()
275 << " from [Port: " << existing_alternate.port
276 << ", Protocol: " << existing_alternate.protocol
277 << ", Probability: " << existing_alternate.probability
278 << "] to [Port: " << alternate_port
279 << ", Protocol: " << alternate_protocol
280 << ", Probability: " << alternate_probability
281 << "].";
283 } else {
284 if (alternate_probability >= alternate_protocol_probability_threshold_) {
285 // TODO(rch): Consider the case where multiple requests are started
286 // before the first completes. In this case, only one of the jobs
287 // would reach this code, whereas all of them should should have.
288 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
292 alternate_protocol_map_.Put(server, alternate);
294 // If this host ends with a canonical suffix, then set it as the
295 // canonical host.
296 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
297 std::string canonical_suffix = canoncial_suffixes_[i];
298 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
299 HostPortPair canonical_host(canonical_suffix, server.port());
300 canonical_host_to_origin_map_[canonical_host] = server;
301 break;
306 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
307 const HostPortPair& server) {
308 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
309 if (it != alternate_protocol_map_.end()) {
310 it->second.protocol = ALTERNATE_PROTOCOL_BROKEN;
311 } else {
312 AlternateProtocolInfo alternate(server.port(),
313 ALTERNATE_PROTOCOL_BROKEN,
315 alternate_protocol_map_.Put(server, alternate);
317 int count = ++broken_alternate_protocol_map_[server];
318 base::TimeDelta delay =
319 base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
320 BrokenAlternateProtocolEntry entry;
321 entry.server = server;
322 entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
323 broken_alternate_protocol_list_.push_back(entry);
325 // Do not leave this host as canonical so that we don't infer the other
326 // hosts are also broken without testing them first.
327 RemoveCanonicalHost(server);
329 // If this is the only entry in the list, schedule an expiration task.
330 // Otherwse it will be rescheduled automatically when the pending
331 // task runs.
332 if (broken_alternate_protocol_list_.size() == 1) {
333 ScheduleBrokenAlternateProtocolMappingsExpiration();
337 bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
338 const HostPortPair& server) {
339 return ContainsKey(broken_alternate_protocol_map_, server);
342 void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
343 const HostPortPair& server) {
344 broken_alternate_protocol_map_.erase(server);
347 void HttpServerPropertiesImpl::ClearAlternateProtocol(
348 const HostPortPair& server) {
349 AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
350 if (it != alternate_protocol_map_.end())
351 alternate_protocol_map_.Erase(it);
353 RemoveCanonicalHost(server);
356 const AlternateProtocolMap&
357 HttpServerPropertiesImpl::alternate_protocol_map() const {
358 return alternate_protocol_map_;
361 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
362 const HostPortPair& host_port_pair) {
363 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
364 if (it == spdy_settings_map_.end()) {
365 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
366 return kEmptySettingsMap;
368 return it->second;
371 bool HttpServerPropertiesImpl::SetSpdySetting(
372 const HostPortPair& host_port_pair,
373 SpdySettingsIds id,
374 SpdySettingsFlags flags,
375 uint32 value) {
376 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
377 return false;
379 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
380 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
381 if (it == spdy_settings_map_.end()) {
382 SettingsMap settings_map;
383 settings_map[id] = flags_and_value;
384 spdy_settings_map_.Put(host_port_pair, settings_map);
385 } else {
386 SettingsMap& settings_map = it->second;
387 settings_map[id] = flags_and_value;
389 return true;
392 void HttpServerPropertiesImpl::ClearSpdySettings(
393 const HostPortPair& host_port_pair) {
394 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
395 if (it != spdy_settings_map_.end())
396 spdy_settings_map_.Erase(it);
399 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
400 spdy_settings_map_.Clear();
403 const SpdySettingsMap&
404 HttpServerPropertiesImpl::spdy_settings_map() const {
405 return spdy_settings_map_;
408 SupportsQuic HttpServerPropertiesImpl::GetSupportsQuic(
409 const HostPortPair& host_port_pair) const {
410 SupportsQuicMap::const_iterator it = supports_quic_map_.find(host_port_pair);
411 if (it == supports_quic_map_.end()) {
412 CR_DEFINE_STATIC_LOCAL(SupportsQuic, kEmptySupportsQuic, ());
413 return kEmptySupportsQuic;
415 return it->second;
418 void HttpServerPropertiesImpl::SetSupportsQuic(
419 const HostPortPair& host_port_pair,
420 bool used_quic,
421 const std::string& address) {
422 SupportsQuic supports_quic(used_quic, address);
423 supports_quic_map_.insert(std::make_pair(host_port_pair, supports_quic));
426 const SupportsQuicMap&
427 HttpServerPropertiesImpl::supports_quic_map() const {
428 return supports_quic_map_;
431 void HttpServerPropertiesImpl::SetServerNetworkStats(
432 const HostPortPair& host_port_pair,
433 NetworkStats stats) {
434 server_network_stats_map_[host_port_pair] = stats;
437 const HttpServerProperties::NetworkStats*
438 HttpServerPropertiesImpl::GetServerNetworkStats(
439 const HostPortPair& host_port_pair) const {
440 ServerNetworkStatsMap::const_iterator it =
441 server_network_stats_map_.find(host_port_pair);
442 if (it == server_network_stats_map_.end()) {
443 return NULL;
445 return &it->second;
448 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
449 double threshold) {
450 alternate_protocol_probability_threshold_ = threshold;
453 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
454 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
455 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
456 std::string canonical_suffix = canoncial_suffixes_[i];
457 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
458 HostPortPair canonical_host(canonical_suffix, server.port());
459 return canonical_host_to_origin_map_.find(canonical_host);
463 return canonical_host_to_origin_map_.end();
466 void HttpServerPropertiesImpl::RemoveCanonicalHost(
467 const HostPortPair& server) {
468 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
469 if (canonical == canonical_host_to_origin_map_.end())
470 return;
472 if (!canonical->second.Equals(server))
473 return;
475 canonical_host_to_origin_map_.erase(canonical->first);
478 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
479 base::TimeTicks now = base::TimeTicks::Now();
480 while (!broken_alternate_protocol_list_.empty()) {
481 BrokenAlternateProtocolEntry entry =
482 broken_alternate_protocol_list_.front();
483 if (now < entry.when) {
484 break;
487 ClearAlternateProtocol(entry.server);
488 broken_alternate_protocol_list_.pop_front();
490 ScheduleBrokenAlternateProtocolMappingsExpiration();
493 void
494 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
495 if (broken_alternate_protocol_list_.empty()) {
496 return;
498 base::TimeTicks now = base::TimeTicks::Now();
499 base::TimeTicks when = broken_alternate_protocol_list_.front().when;
500 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
501 base::MessageLoop::current()->PostDelayedTask(
502 FROM_HERE,
503 base::Bind(
504 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
505 weak_ptr_factory_.GetWeakPtr()),
506 delay);
509 } // namespace net