Rewrite AndroidSyncSettings to be significantly simpler.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob9f17afc9ca054a0f9a78a2e6efd03a6db6091016
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 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
28 alternate_protocol_probability_threshold_(1),
29 weak_ptr_factory_(this) {
30 canonical_suffixes_.push_back(".c.youtube.com");
31 canonical_suffixes_.push_back(".googlevideo.com");
32 canonical_suffixes_.push_back(".googleusercontent.com");
35 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
38 void HttpServerPropertiesImpl::InitializeSpdyServers(
39 std::vector<std::string>* spdy_servers,
40 bool support_spdy) {
41 DCHECK(CalledOnValidThread());
42 if (!spdy_servers)
43 return;
44 // Add the entries from persisted data.
45 for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
46 it != spdy_servers->rend(); ++it) {
47 spdy_servers_map_.Put(*it, support_spdy);
51 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
52 AlternateProtocolMap* alternate_protocol_map) {
53 // Keep all the broken ones since those don't 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.is_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 uint16 canonical_ports[] = { 80, 443 };
72 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
73 std::string canonical_suffix = canonical_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(), canonical_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 IPAddressNumber* last_address) {
106 if (last_address)
107 last_quic_address_ = *last_address;
110 void HttpServerPropertiesImpl::InitializeServerNetworkStats(
111 ServerNetworkStatsMap* server_network_stats_map) {
112 for (ServerNetworkStatsMap::reverse_iterator it =
113 server_network_stats_map->rbegin();
114 it != server_network_stats_map->rend(); ++it) {
115 server_network_stats_map_.Put(it->first, it->second);
119 void HttpServerPropertiesImpl::GetSpdyServerList(
120 base::ListValue* spdy_server_list,
121 size_t max_size) const {
122 DCHECK(CalledOnValidThread());
123 DCHECK(spdy_server_list);
124 spdy_server_list->Clear();
125 size_t count = 0;
126 // Get the list of servers (host/port) that support SPDY.
127 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
128 it != spdy_servers_map_.end() && count < max_size; ++it) {
129 const std::string spdy_server_host_port = it->first;
130 if (it->second) {
131 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
132 ++count;
137 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
139 // static
140 void HttpServerPropertiesImpl::ForceAlternateProtocol(
141 const AlternateProtocolInfo& info) {
142 // Note: we're going to leak this.
143 if (g_forced_alternate_protocol)
144 delete g_forced_alternate_protocol;
145 g_forced_alternate_protocol = new AlternateProtocolInfo(info);
148 // static
149 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
150 delete g_forced_alternate_protocol;
151 g_forced_alternate_protocol = NULL;
154 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
155 return weak_ptr_factory_.GetWeakPtr();
158 void HttpServerPropertiesImpl::Clear() {
159 DCHECK(CalledOnValidThread());
160 spdy_servers_map_.Clear();
161 alternate_protocol_map_.Clear();
162 canonical_host_to_origin_map_.clear();
163 spdy_settings_map_.Clear();
164 last_quic_address_.clear();
165 server_network_stats_map_.Clear();
168 bool HttpServerPropertiesImpl::SupportsRequestPriority(
169 const HostPortPair& host_port_pair) {
170 DCHECK(CalledOnValidThread());
171 if (host_port_pair.host().empty())
172 return false;
174 SpdyServerHostPortMap::iterator spdy_host_port =
175 spdy_servers_map_.Get(host_port_pair.ToString());
176 if (spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second)
177 return true;
179 const AlternateProtocolInfo info = GetAlternateProtocol(host_port_pair);
180 return info.protocol == QUIC;
183 void HttpServerPropertiesImpl::SetSupportsSpdy(
184 const HostPortPair& host_port_pair,
185 bool support_spdy) {
186 DCHECK(CalledOnValidThread());
187 if (host_port_pair.host().empty())
188 return;
190 SpdyServerHostPortMap::iterator spdy_host_port =
191 spdy_servers_map_.Get(host_port_pair.ToString());
192 if ((spdy_host_port != spdy_servers_map_.end()) &&
193 (spdy_host_port->second == support_spdy)) {
194 return;
196 // Cache the data.
197 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
200 bool HttpServerPropertiesImpl::RequiresHTTP11(
201 const net::HostPortPair& host_port_pair) {
202 DCHECK(CalledOnValidThread());
203 if (host_port_pair.host().empty())
204 return false;
206 return (http11_servers_.find(host_port_pair) != http11_servers_.end());
209 void HttpServerPropertiesImpl::SetHTTP11Required(
210 const net::HostPortPair& host_port_pair) {
211 DCHECK(CalledOnValidThread());
212 if (host_port_pair.host().empty())
213 return;
215 http11_servers_.insert(host_port_pair);
218 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
219 SSLConfig* ssl_config) {
220 if (RequiresHTTP11(server)) {
221 ForceHTTP11(ssl_config);
225 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
226 const std::string& host) {
227 // If this host ends with a canonical suffix, then return the canonical
228 // suffix.
229 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
230 std::string canonical_suffix = canonical_suffixes_[i];
231 if (EndsWith(host, canonical_suffixes_[i], false)) {
232 return canonical_suffix;
235 return std::string();
238 AlternateProtocolInfo HttpServerPropertiesImpl::GetAlternateProtocol(
239 const HostPortPair& server) {
240 AlternateProtocolMap::const_iterator it =
241 GetAlternateProtocolIterator(server);
242 if (it != alternate_protocol_map_.end() &&
243 it->second.probability >= alternate_protocol_probability_threshold_)
244 return it->second;
246 if (g_forced_alternate_protocol)
247 return *g_forced_alternate_protocol;
249 AlternateProtocolInfo uninitialized_alternate_protocol;
250 return uninitialized_alternate_protocol;
253 void HttpServerPropertiesImpl::SetAlternateProtocol(
254 const HostPortPair& server,
255 uint16 alternate_port,
256 AlternateProtocol alternate_protocol,
257 double alternate_probability) {
259 AlternateProtocolInfo alternate(alternate_port,
260 alternate_protocol,
261 alternate_probability);
262 AlternateProtocolMap::const_iterator it =
263 GetAlternateProtocolIterator(server);
264 if (it != alternate_protocol_map_.end()) {
265 const AlternateProtocolInfo existing_alternate = it->second;
267 if (existing_alternate.is_broken) {
268 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
269 return;
272 if (!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 < canonical_suffixes_.size(); ++i) {
297 std::string canonical_suffix = canonical_suffixes_[i];
298 if (EndsWith(server.host(), canonical_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 const AlternateProtocolInfo alternate = GetAlternateProtocol(server);
310 if (it == alternate_protocol_map_.end()) {
311 if (alternate.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
312 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
313 return;
315 // This server's alternate protocol information is coming from a canonical
316 // server. Add an entry in the map for this server explicitly so that
317 // it can be marked as broken.
318 it = alternate_protocol_map_.Put(server, alternate);
320 it->second.is_broken = true;
321 const BrokenAlternateProtocolEntry entry(server, alternate.port,
322 alternate.protocol);
323 int count = ++broken_alternate_protocol_map_[entry];
324 base::TimeDelta delay =
325 base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
326 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
327 broken_alternate_protocol_list_.push_back(
328 BrokenAlternateProtocolEntryWithTime(entry, when));
330 // Do not leave this host as canonical so that we don't infer the other
331 // hosts are also broken without testing them first.
332 RemoveCanonicalHost(server);
334 // If this is the only entry in the list, schedule an expiration task.
335 // Otherwise it will be rescheduled automatically when the pending task runs.
336 if (broken_alternate_protocol_list_.size() == 1) {
337 ScheduleBrokenAlternateProtocolMappingsExpiration();
341 bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
342 const HostPortPair& server) {
343 const AlternateProtocolInfo alternate_protocol = GetAlternateProtocol(server);
344 if (alternate_protocol.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
345 return false;
346 const BrokenAlternateProtocolEntry entry(server, alternate_protocol.port,
347 alternate_protocol.protocol);
348 return ContainsKey(broken_alternate_protocol_map_, entry);
351 void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
352 const HostPortPair& server) {
353 const AlternateProtocolInfo alternate_protocol = GetAlternateProtocol(server);
354 if (alternate_protocol.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
355 return;
356 const BrokenAlternateProtocolEntry entry(server, alternate_protocol.port,
357 alternate_protocol.protocol);
358 broken_alternate_protocol_map_.erase(entry);
361 void HttpServerPropertiesImpl::ClearAlternateProtocol(
362 const HostPortPair& server) {
363 AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
364 if (it != alternate_protocol_map_.end())
365 alternate_protocol_map_.Erase(it);
367 RemoveCanonicalHost(server);
370 const AlternateProtocolMap&
371 HttpServerPropertiesImpl::alternate_protocol_map() const {
372 return alternate_protocol_map_;
375 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
376 const HostPortPair& host_port_pair) {
377 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
378 if (it == spdy_settings_map_.end()) {
379 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
380 return kEmptySettingsMap;
382 return it->second;
385 bool HttpServerPropertiesImpl::SetSpdySetting(
386 const HostPortPair& host_port_pair,
387 SpdySettingsIds id,
388 SpdySettingsFlags flags,
389 uint32 value) {
390 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
391 return false;
393 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
394 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
395 if (it == spdy_settings_map_.end()) {
396 SettingsMap settings_map;
397 settings_map[id] = flags_and_value;
398 spdy_settings_map_.Put(host_port_pair, settings_map);
399 } else {
400 SettingsMap& settings_map = it->second;
401 settings_map[id] = flags_and_value;
403 return true;
406 void HttpServerPropertiesImpl::ClearSpdySettings(
407 const HostPortPair& host_port_pair) {
408 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
409 if (it != spdy_settings_map_.end())
410 spdy_settings_map_.Erase(it);
413 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
414 spdy_settings_map_.Clear();
417 const SpdySettingsMap&
418 HttpServerPropertiesImpl::spdy_settings_map() const {
419 return spdy_settings_map_;
422 bool HttpServerPropertiesImpl::GetSupportsQuic(
423 IPAddressNumber* last_address) const {
424 if (last_quic_address_.empty())
425 return false;
427 *last_address = last_quic_address_;
428 return true;
431 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
432 const IPAddressNumber& address) {
433 if (!used_quic) {
434 last_quic_address_.clear();
435 } else {
436 last_quic_address_ = address;
440 void HttpServerPropertiesImpl::SetServerNetworkStats(
441 const HostPortPair& host_port_pair,
442 ServerNetworkStats stats) {
443 server_network_stats_map_.Put(host_port_pair, stats);
446 const ServerNetworkStats* HttpServerPropertiesImpl::GetServerNetworkStats(
447 const HostPortPair& host_port_pair) {
448 ServerNetworkStatsMap::iterator it =
449 server_network_stats_map_.Get(host_port_pair);
450 if (it == server_network_stats_map_.end()) {
451 return NULL;
453 return &it->second;
456 const ServerNetworkStatsMap&
457 HttpServerPropertiesImpl::server_network_stats_map() const {
458 return server_network_stats_map_;
461 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
462 double threshold) {
463 alternate_protocol_probability_threshold_ = threshold;
466 AlternateProtocolMap::const_iterator
467 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
468 const HostPortPair& server) {
469 AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
470 if (it != alternate_protocol_map_.end())
471 return it;
473 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
474 if (canonical != canonical_host_to_origin_map_.end())
475 return alternate_protocol_map_.Get(canonical->second);
477 return alternate_protocol_map_.end();
480 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
481 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
482 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
483 std::string canonical_suffix = canonical_suffixes_[i];
484 if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
485 HostPortPair canonical_host(canonical_suffix, server.port());
486 return canonical_host_to_origin_map_.find(canonical_host);
490 return canonical_host_to_origin_map_.end();
493 void HttpServerPropertiesImpl::RemoveCanonicalHost(
494 const HostPortPair& server) {
495 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
496 if (canonical == canonical_host_to_origin_map_.end())
497 return;
499 if (!canonical->second.Equals(server))
500 return;
502 canonical_host_to_origin_map_.erase(canonical->first);
505 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
506 base::TimeTicks now = base::TimeTicks::Now();
507 while (!broken_alternate_protocol_list_.empty()) {
508 BrokenAlternateProtocolEntryWithTime entry_with_time =
509 broken_alternate_protocol_list_.front();
510 if (now < entry_with_time.when) {
511 break;
514 const BrokenAlternateProtocolEntry& entry =
515 entry_with_time.broken_alternate_protocol_entry;
516 ClearAlternateProtocol(entry.server);
517 broken_alternate_protocol_list_.pop_front();
519 ScheduleBrokenAlternateProtocolMappingsExpiration();
522 void
523 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
524 if (broken_alternate_protocol_list_.empty()) {
525 return;
527 base::TimeTicks now = base::TimeTicks::Now();
528 base::TimeTicks when = broken_alternate_protocol_list_.front().when;
529 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
530 base::MessageLoop::current()->PostDelayedTask(
531 FROM_HERE,
532 base::Bind(
533 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
534 weak_ptr_factory_.GetWeakPtr()),
535 delay);
538 } // namespace net