[Android WebView] Update user agent to match current trunk builds.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blobc55f32b30c6ffef125f9e9d40dd1d7a155973801
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 alternate_protocol_experiment_(
27 ALTERNATE_PROTOCOL_NOT_PART_OF_EXPERIMENT),
28 spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
29 alternate_protocol_probability_threshold_(1),
30 weak_ptr_factory_(this) {
31 canoncial_suffixes_.push_back(".c.youtube.com");
32 canoncial_suffixes_.push_back(".googlevideo.com");
33 canoncial_suffixes_.push_back(".googleusercontent.com");
36 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
39 void HttpServerPropertiesImpl::InitializeSpdyServers(
40 std::vector<std::string>* spdy_servers,
41 bool support_spdy) {
42 DCHECK(CalledOnValidThread());
43 if (!spdy_servers)
44 return;
45 // Add the entries from persisted data.
46 for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
47 it != spdy_servers->rend(); ++it) {
48 spdy_servers_map_.Put(*it, support_spdy);
52 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
53 AlternateProtocolMap* alternate_protocol_map) {
54 // Keep all the ALTERNATE_PROTOCOL_BROKEN ones since those don't
55 // get persisted.
56 for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
57 it != alternate_protocol_map_.end();) {
58 AlternateProtocolMap::iterator old_it = it;
59 ++it;
60 if (old_it->second.protocol != ALTERNATE_PROTOCOL_BROKEN) {
61 alternate_protocol_map_.Erase(old_it);
65 // Add the entries from persisted data.
66 for (AlternateProtocolMap::reverse_iterator it =
67 alternate_protocol_map->rbegin();
68 it != alternate_protocol_map->rend(); ++it) {
69 alternate_protocol_map_.Put(it->first, it->second);
72 // Attempt to find canonical servers.
73 int canonical_ports[] = { 80, 443 };
74 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
75 std::string canonical_suffix = canoncial_suffixes_[i];
76 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
77 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
78 // If we already have a valid canonical server, we're done.
79 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
80 (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
81 canonical_host]) != alternate_protocol_map_.end())) {
82 continue;
84 // Now attempt to find a server which matches this origin and set it as
85 // canonical .
86 for (AlternateProtocolMap::const_iterator it =
87 alternate_protocol_map_.begin();
88 it != alternate_protocol_map_.end(); ++it) {
89 if (EndsWith(it->first.host(), canoncial_suffixes_[i], false)) {
90 canonical_host_to_origin_map_[canonical_host] = it->first;
91 break;
98 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
99 SpdySettingsMap* spdy_settings_map) {
100 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
101 it != spdy_settings_map->rend(); ++it) {
102 spdy_settings_map_.Put(it->first, it->second);
106 void HttpServerPropertiesImpl::InitializeSupportsQuic(
107 SupportsQuicMap* supports_quic_map) {
108 for (SupportsQuicMap::reverse_iterator it = supports_quic_map->rbegin();
109 it != supports_quic_map->rend();
110 ++it) {
111 supports_quic_map_.insert(std::make_pair(it->first, it->second));
115 void HttpServerPropertiesImpl::GetSpdyServerList(
116 base::ListValue* spdy_server_list,
117 size_t max_size) const {
118 DCHECK(CalledOnValidThread());
119 DCHECK(spdy_server_list);
120 spdy_server_list->Clear();
121 size_t count = 0;
122 // Get the list of servers (host/port) that support SPDY.
123 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
124 it != spdy_servers_map_.end() && count < max_size; ++it) {
125 const std::string spdy_server_host_port = it->first;
126 if (it->second) {
127 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
128 ++count;
133 // static
134 std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer(
135 const net::HostPortPair& host_port_pair) {
136 std::string spdy_server;
137 spdy_server.append(host_port_pair.host());
138 spdy_server.append(":");
139 base::StringAppendF(&spdy_server, "%d", host_port_pair.port());
140 return spdy_server;
143 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
145 // static
146 void HttpServerPropertiesImpl::ForceAlternateProtocol(
147 const AlternateProtocolInfo& info) {
148 // Note: we're going to leak this.
149 if (g_forced_alternate_protocol)
150 delete g_forced_alternate_protocol;
151 g_forced_alternate_protocol = new AlternateProtocolInfo(info);
154 // static
155 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
156 delete g_forced_alternate_protocol;
157 g_forced_alternate_protocol = NULL;
160 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
161 return weak_ptr_factory_.GetWeakPtr();
164 void HttpServerPropertiesImpl::Clear() {
165 DCHECK(CalledOnValidThread());
166 spdy_servers_map_.Clear();
167 alternate_protocol_map_.Clear();
168 canonical_host_to_origin_map_.clear();
169 spdy_settings_map_.Clear();
170 supports_quic_map_.clear();
173 bool HttpServerPropertiesImpl::SupportsSpdy(
174 const net::HostPortPair& host_port_pair) {
175 DCHECK(CalledOnValidThread());
176 if (host_port_pair.host().empty())
177 return false;
178 std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
180 SpdyServerHostPortMap::iterator spdy_host_port =
181 spdy_servers_map_.Get(spdy_server);
182 if (spdy_host_port != spdy_servers_map_.end())
183 return spdy_host_port->second;
184 return false;
187 void HttpServerPropertiesImpl::SetSupportsSpdy(
188 const net::HostPortPair& host_port_pair,
189 bool support_spdy) {
190 DCHECK(CalledOnValidThread());
191 if (host_port_pair.host().empty())
192 return;
193 std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
195 SpdyServerHostPortMap::iterator spdy_host_port =
196 spdy_servers_map_.Get(spdy_server);
197 if ((spdy_host_port != spdy_servers_map_.end()) &&
198 (spdy_host_port->second == support_spdy)) {
199 return;
201 // Cache the data.
202 spdy_servers_map_.Put(spdy_server, support_spdy);
205 bool HttpServerPropertiesImpl::HasAlternateProtocol(
206 const HostPortPair& server) {
207 if (g_forced_alternate_protocol)
208 return true;
209 AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
210 if (it != alternate_protocol_map_.end() &&
211 it->second.probability >= alternate_protocol_probability_threshold_) {
212 return true;
215 return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
218 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
219 const HostPortPair& server) {
220 // If this host ends with a canonical suffix, then return the canonical
221 // suffix.
222 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
223 std::string canonical_suffix = canoncial_suffixes_[i];
224 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
225 return canonical_suffix;
228 return std::string();
231 AlternateProtocolInfo
232 HttpServerPropertiesImpl::GetAlternateProtocol(
233 const HostPortPair& server) {
234 DCHECK(HasAlternateProtocol(server));
236 // First check the map.
237 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
238 if (it != alternate_protocol_map_.end())
239 return it->second;
241 // Next check the canonical host.
242 CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
243 if (canonical_host != canonical_host_to_origin_map_.end())
244 return alternate_protocol_map_.Get(canonical_host->second)->second;
246 // We must be forcing an alternate.
247 DCHECK(g_forced_alternate_protocol);
248 return *g_forced_alternate_protocol;
251 void HttpServerPropertiesImpl::SetAlternateProtocol(
252 const HostPortPair& server,
253 uint16 alternate_port,
254 AlternateProtocol alternate_protocol,
255 double alternate_probability) {
256 if (alternate_protocol == ALTERNATE_PROTOCOL_BROKEN) {
257 LOG(DFATAL) << "Call SetBrokenAlternateProtocol() instead.";
258 return;
261 AlternateProtocolInfo alternate(alternate_port,
262 alternate_protocol,
263 alternate_probability);
264 if (HasAlternateProtocol(server)) {
265 const AlternateProtocolInfo existing_alternate =
266 GetAlternateProtocol(server);
268 if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) {
269 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
270 return;
273 if (alternate_protocol != ALTERNATE_PROTOCOL_BROKEN &&
274 !existing_alternate.Equals(alternate)) {
275 LOG(WARNING) << "Changing the alternate protocol for: "
276 << server.ToString()
277 << " from [Port: " << existing_alternate.port
278 << ", Protocol: " << existing_alternate.protocol
279 << ", Probability: " << existing_alternate.probability
280 << "] to [Port: " << alternate_port
281 << ", Protocol: " << alternate_protocol
282 << ", Probability: " << alternate_probability
283 << "].";
285 } else {
286 if (alternate_probability >= alternate_protocol_probability_threshold_) {
287 // TODO(rch): Consider the case where multiple requests are started
288 // before the first completes. In this case, only one of the jobs
289 // would reach this code, whereas all of them should should have.
290 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING,
291 alternate_protocol_experiment_);
295 alternate_protocol_map_.Put(server, alternate);
297 // If this host ends with a canonical suffix, then set it as the
298 // canonical host.
299 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
300 std::string canonical_suffix = canoncial_suffixes_[i];
301 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
302 HostPortPair canonical_host(canonical_suffix, server.port());
303 canonical_host_to_origin_map_[canonical_host] = server;
304 break;
309 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
310 const HostPortPair& server) {
311 AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
312 if (it != alternate_protocol_map_.end()) {
313 it->second.protocol = ALTERNATE_PROTOCOL_BROKEN;
314 } else {
315 AlternateProtocolInfo alternate(server.port(),
316 ALTERNATE_PROTOCOL_BROKEN,
318 alternate_protocol_map_.Put(server, alternate);
320 int count = ++broken_alternate_protocol_map_[server];
321 base::TimeDelta delay =
322 base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
323 BrokenAlternateProtocolEntry entry;
324 entry.server = server;
325 entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
326 broken_alternate_protocol_list_.push_back(entry);
328 // Do not leave this host as canonical so that we don't infer the other
329 // hosts are also broken without testing them first.
330 RemoveCanonicalHost(server);
332 // If this is the only entry in the list, schedule an expiration task.
333 // Otherwse it will be rescheduled automatically when the pending
334 // task runs.
335 if (broken_alternate_protocol_list_.size() == 1) {
336 ScheduleBrokenAlternateProtocolMappingsExpiration();
340 bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
341 const HostPortPair& server) {
342 return ContainsKey(broken_alternate_protocol_map_, server);
345 void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
346 const HostPortPair& server) {
347 broken_alternate_protocol_map_.erase(server);
350 void HttpServerPropertiesImpl::ClearAlternateProtocol(
351 const HostPortPair& server) {
352 AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
353 if (it != alternate_protocol_map_.end())
354 alternate_protocol_map_.Erase(it);
356 RemoveCanonicalHost(server);
359 const AlternateProtocolMap&
360 HttpServerPropertiesImpl::alternate_protocol_map() const {
361 return alternate_protocol_map_;
364 void HttpServerPropertiesImpl::SetAlternateProtocolExperiment(
365 AlternateProtocolExperiment experiment) {
366 alternate_protocol_experiment_ = experiment;
369 AlternateProtocolExperiment
370 HttpServerPropertiesImpl::GetAlternateProtocolExperiment() const {
371 return alternate_protocol_experiment_;
374 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
375 const HostPortPair& host_port_pair) {
376 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
377 if (it == spdy_settings_map_.end()) {
378 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
379 return kEmptySettingsMap;
381 return it->second;
384 bool HttpServerPropertiesImpl::SetSpdySetting(
385 const HostPortPair& host_port_pair,
386 SpdySettingsIds id,
387 SpdySettingsFlags flags,
388 uint32 value) {
389 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
390 return false;
392 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
393 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
394 if (it == spdy_settings_map_.end()) {
395 SettingsMap settings_map;
396 settings_map[id] = flags_and_value;
397 spdy_settings_map_.Put(host_port_pair, settings_map);
398 } else {
399 SettingsMap& settings_map = it->second;
400 settings_map[id] = flags_and_value;
402 return true;
405 void HttpServerPropertiesImpl::ClearSpdySettings(
406 const HostPortPair& host_port_pair) {
407 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
408 if (it != spdy_settings_map_.end())
409 spdy_settings_map_.Erase(it);
412 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
413 spdy_settings_map_.Clear();
416 const SpdySettingsMap&
417 HttpServerPropertiesImpl::spdy_settings_map() const {
418 return spdy_settings_map_;
421 SupportsQuic HttpServerPropertiesImpl::GetSupportsQuic(
422 const HostPortPair& host_port_pair) const {
423 SupportsQuicMap::const_iterator it = supports_quic_map_.find(host_port_pair);
424 if (it == supports_quic_map_.end()) {
425 CR_DEFINE_STATIC_LOCAL(SupportsQuic, kEmptySupportsQuic, ());
426 return kEmptySupportsQuic;
428 return it->second;
431 void HttpServerPropertiesImpl::SetSupportsQuic(
432 const HostPortPair& host_port_pair,
433 bool used_quic,
434 const std::string& address) {
435 SupportsQuic supports_quic(used_quic, address);
436 supports_quic_map_.insert(std::make_pair(host_port_pair, supports_quic));
439 const SupportsQuicMap&
440 HttpServerPropertiesImpl::supports_quic_map() const {
441 return supports_quic_map_;
444 void HttpServerPropertiesImpl::SetServerNetworkStats(
445 const HostPortPair& host_port_pair,
446 NetworkStats stats) {
447 server_network_stats_map_[host_port_pair] = stats;
450 const HttpServerProperties::NetworkStats*
451 HttpServerPropertiesImpl::GetServerNetworkStats(
452 const HostPortPair& host_port_pair) const {
453 ServerNetworkStatsMap::const_iterator it =
454 server_network_stats_map_.find(host_port_pair);
455 if (it == server_network_stats_map_.end()) {
456 return NULL;
458 return &it->second;
461 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
462 double threshold) {
463 alternate_protocol_probability_threshold_ = threshold;
466 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
467 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
468 for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
469 std::string canonical_suffix = canoncial_suffixes_[i];
470 if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
471 HostPortPair canonical_host(canonical_suffix, server.port());
472 return canonical_host_to_origin_map_.find(canonical_host);
476 return canonical_host_to_origin_map_.end();
479 void HttpServerPropertiesImpl::RemoveCanonicalHost(
480 const HostPortPair& server) {
481 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
482 if (canonical == canonical_host_to_origin_map_.end())
483 return;
485 if (!canonical->second.Equals(server))
486 return;
488 canonical_host_to_origin_map_.erase(canonical->first);
491 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
492 base::TimeTicks now = base::TimeTicks::Now();
493 while (!broken_alternate_protocol_list_.empty()) {
494 BrokenAlternateProtocolEntry entry =
495 broken_alternate_protocol_list_.front();
496 if (now < entry.when) {
497 break;
500 ClearAlternateProtocol(entry.server);
501 broken_alternate_protocol_list_.pop_front();
503 ScheduleBrokenAlternateProtocolMappingsExpiration();
506 void
507 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
508 if (broken_alternate_protocol_list_.empty()) {
509 return;
511 base::TimeTicks now = base::TimeTicks::Now();
512 base::TimeTicks when = broken_alternate_protocol_list_.front().when;
513 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
514 base::MessageLoop::current()->PostDelayedTask(
515 FROM_HERE,
516 base::Bind(
517 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
518 weak_ptr_factory_.GetWeakPtr()),
519 delay);
522 } // namespace net