remove reference to deprecated kHasFilter16
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob0c18334de1932120b8bc320837315ef8b0798142
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/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
16 namespace net {
18 namespace {
20 const uint64 kBrokenAlternateProtocolDelaySecs = 300;
22 } // namespace
24 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
25 : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
26 alternate_protocol_map_(AlternateProtocolMap::NO_AUTO_EVICT),
27 spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
28 server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT),
29 alternate_protocol_probability_threshold_(1),
30 weak_ptr_factory_(this) {
31 canonical_suffixes_.push_back(".c.youtube.com");
32 canonical_suffixes_.push_back(".googlevideo.com");
33 canonical_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 broken ones since those don't get persisted.
55 for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
56 it != alternate_protocol_map_.end();) {
57 const AlternativeService alternative_service(
58 it->second.protocol, it->first.host(), it->second.port);
59 if (IsAlternativeServiceBroken(alternative_service)) {
60 ++it;
61 } else {
62 it = alternate_protocol_map_.Erase(it);
66 // Add the entries from persisted data.
67 for (AlternateProtocolMap::reverse_iterator it =
68 alternate_protocol_map->rbegin();
69 it != alternate_protocol_map->rend(); ++it) {
70 alternate_protocol_map_.Put(it->first, it->second);
73 // Attempt to find canonical servers.
74 uint16 canonical_ports[] = { 80, 443 };
75 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
76 std::string canonical_suffix = canonical_suffixes_[i];
77 for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
78 HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
79 // If we already have a valid canonical server, we're done.
80 if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
81 (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
82 canonical_host]) != alternate_protocol_map_.end())) {
83 continue;
85 // Now attempt to find a server which matches this origin and set it as
86 // canonical .
87 for (AlternateProtocolMap::const_iterator it =
88 alternate_protocol_map_.begin();
89 it != alternate_protocol_map_.end(); ++it) {
90 if (EndsWith(it->first.host(), canonical_suffixes_[i], false)) {
91 canonical_host_to_origin_map_[canonical_host] = it->first;
92 break;
99 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
100 SpdySettingsMap* spdy_settings_map) {
101 for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
102 it != spdy_settings_map->rend(); ++it) {
103 spdy_settings_map_.Put(it->first, it->second);
107 void HttpServerPropertiesImpl::InitializeSupportsQuic(
108 IPAddressNumber* last_address) {
109 if (last_address)
110 last_quic_address_ = *last_address;
113 void HttpServerPropertiesImpl::InitializeServerNetworkStats(
114 ServerNetworkStatsMap* server_network_stats_map) {
115 for (ServerNetworkStatsMap::reverse_iterator it =
116 server_network_stats_map->rbegin();
117 it != server_network_stats_map->rend(); ++it) {
118 server_network_stats_map_.Put(it->first, it->second);
122 void HttpServerPropertiesImpl::GetSpdyServerList(
123 base::ListValue* spdy_server_list,
124 size_t max_size) const {
125 DCHECK(CalledOnValidThread());
126 DCHECK(spdy_server_list);
127 spdy_server_list->Clear();
128 size_t count = 0;
129 // Get the list of servers (host/port) that support SPDY.
130 for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
131 it != spdy_servers_map_.end() && count < max_size; ++it) {
132 const std::string spdy_server_host_port = it->first;
133 if (it->second) {
134 spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
135 ++count;
140 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
142 // static
143 void HttpServerPropertiesImpl::ForceAlternateProtocol(
144 const AlternateProtocolInfo& info) {
145 // Note: we're going to leak this.
146 if (g_forced_alternate_protocol)
147 delete g_forced_alternate_protocol;
148 g_forced_alternate_protocol = new AlternateProtocolInfo(info);
151 // static
152 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
153 delete g_forced_alternate_protocol;
154 g_forced_alternate_protocol = NULL;
157 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
158 return weak_ptr_factory_.GetWeakPtr();
161 void HttpServerPropertiesImpl::Clear() {
162 DCHECK(CalledOnValidThread());
163 spdy_servers_map_.Clear();
164 alternate_protocol_map_.Clear();
165 canonical_host_to_origin_map_.clear();
166 spdy_settings_map_.Clear();
167 last_quic_address_.clear();
168 server_network_stats_map_.Clear();
171 bool HttpServerPropertiesImpl::SupportsRequestPriority(
172 const HostPortPair& host_port_pair) {
173 DCHECK(CalledOnValidThread());
174 if (host_port_pair.host().empty())
175 return false;
177 SpdyServerHostPortMap::iterator spdy_host_port =
178 spdy_servers_map_.Get(host_port_pair.ToString());
179 if (spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second)
180 return true;
182 const AlternativeService alternative_service =
183 GetAlternativeService(host_port_pair);
184 return alternative_service.protocol == QUIC;
187 void HttpServerPropertiesImpl::SetSupportsSpdy(
188 const HostPortPair& host_port_pair,
189 bool support_spdy) {
190 DCHECK(CalledOnValidThread());
191 if (host_port_pair.host().empty())
192 return;
194 SpdyServerHostPortMap::iterator spdy_host_port =
195 spdy_servers_map_.Get(host_port_pair.ToString());
196 if ((spdy_host_port != spdy_servers_map_.end()) &&
197 (spdy_host_port->second == support_spdy)) {
198 return;
200 // Cache the data.
201 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy);
204 bool HttpServerPropertiesImpl::RequiresHTTP11(
205 const net::HostPortPair& host_port_pair) {
206 DCHECK(CalledOnValidThread());
207 if (host_port_pair.host().empty())
208 return false;
210 return (http11_servers_.find(host_port_pair) != http11_servers_.end());
213 void HttpServerPropertiesImpl::SetHTTP11Required(
214 const net::HostPortPair& host_port_pair) {
215 DCHECK(CalledOnValidThread());
216 if (host_port_pair.host().empty())
217 return;
219 http11_servers_.insert(host_port_pair);
222 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
223 SSLConfig* ssl_config) {
224 if (RequiresHTTP11(server)) {
225 ForceHTTP11(ssl_config);
229 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
230 const std::string& host) {
231 // If this host ends with a canonical suffix, then return the canonical
232 // suffix.
233 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
234 std::string canonical_suffix = canonical_suffixes_[i];
235 if (EndsWith(host, canonical_suffixes_[i], false)) {
236 return canonical_suffix;
239 return std::string();
242 AlternativeService HttpServerPropertiesImpl::GetAlternativeService(
243 const HostPortPair& origin) {
244 AlternateProtocolMap::const_iterator it =
245 GetAlternateProtocolIterator(origin);
246 if (it != alternate_protocol_map_.end() &&
247 it->second.probability >= alternate_protocol_probability_threshold_)
248 return AlternativeService(it->second.protocol, origin.host(),
249 it->second.port);
251 UMA_HISTOGRAM_BOOLEAN("Net.ForceAlternativeService",
252 g_forced_alternate_protocol != nullptr);
253 if (g_forced_alternate_protocol)
254 return AlternativeService(g_forced_alternate_protocol->protocol,
255 origin.host(), g_forced_alternate_protocol->port);
257 AlternativeService uninitialize_alternative_service;
258 return uninitialize_alternative_service;
261 void HttpServerPropertiesImpl::SetAlternativeService(
262 const HostPortPair& origin,
263 const AlternativeService& alternative_service,
264 double alternative_probability) {
265 if (IsAlternativeServiceBroken(alternative_service)) {
266 DVLOG(1) << "Ignore alternative service since it is known to be broken.";
267 return;
270 const AlternateProtocolInfo alternate(alternative_service.port,
271 alternative_service.protocol,
272 alternative_probability);
273 AlternateProtocolMap::const_iterator it =
274 GetAlternateProtocolIterator(origin);
275 if (it != alternate_protocol_map_.end()) {
276 const AlternateProtocolInfo existing_alternate = it->second;
278 if (!existing_alternate.Equals(alternate)) {
279 LOG(WARNING) << "Changing the alternate protocol for: "
280 << origin.ToString()
281 << " from [Port: " << existing_alternate.port
282 << ", Protocol: " << existing_alternate.protocol
283 << ", Probability: " << existing_alternate.probability
284 << "] to [Port: " << alternative_service.port
285 << ", Protocol: " << alternative_service.protocol
286 << ", Probability: " << alternative_probability << "].";
288 } else {
289 if (alternative_probability >= alternate_protocol_probability_threshold_) {
290 // TODO(rch): Consider the case where multiple requests are started
291 // before the first completes. In this case, only one of the jobs
292 // would reach this code, whereas all of them should should have.
293 HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
297 alternate_protocol_map_.Put(origin, alternate);
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 (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 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL) {
314 LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
315 return;
317 int count = ++recently_broken_alternative_services_[alternative_service];
318 base::TimeDelta delay =
319 base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
320 base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
321 auto result = broken_alternative_services_.insert(
322 std::make_pair(alternative_service, when));
323 // Return if alternative service is already in expiration queue.
324 if (!result.second) {
325 return;
328 // If this is the only entry in the list, schedule an expiration task.
329 // Otherwise it will be rescheduled automatically when the pending task runs.
330 if (broken_alternative_services_.size() == 1) {
331 ScheduleBrokenAlternateProtocolMappingsExpiration();
335 void HttpServerPropertiesImpl::MarkAlternativeServiceRecentlyBroken(
336 const AlternativeService& alternative_service) {
337 if (!ContainsKey(recently_broken_alternative_services_, alternative_service))
338 recently_broken_alternative_services_[alternative_service] = 1;
341 bool HttpServerPropertiesImpl::IsAlternativeServiceBroken(
342 const AlternativeService& alternative_service) {
343 return ContainsKey(broken_alternative_services_, alternative_service);
346 bool HttpServerPropertiesImpl::WasAlternativeServiceRecentlyBroken(
347 const AlternativeService& alternative_service) {
348 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
349 return false;
350 return ContainsKey(recently_broken_alternative_services_,
351 alternative_service);
354 void HttpServerPropertiesImpl::ConfirmAlternativeService(
355 const AlternativeService& alternative_service) {
356 if (alternative_service.protocol == UNINITIALIZED_ALTERNATE_PROTOCOL)
357 return;
358 broken_alternative_services_.erase(alternative_service);
359 recently_broken_alternative_services_.erase(alternative_service);
362 void HttpServerPropertiesImpl::ClearAlternativeService(
363 const HostPortPair& origin) {
364 RemoveCanonicalHost(origin);
366 AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(origin);
367 if (it == alternate_protocol_map_.end()) {
368 return;
370 const AlternativeService alternative_service(
371 it->second.protocol, it->first.host(), it->second.port);
372 alternate_protocol_map_.Erase(it);
374 // The following is temporary to keep the existing semantics, which is that if
375 // there is a broken alternative service in the mapping, then this method
376 // leaves it in a non-broken, but recently broken state.
378 // TODO(bnc):
379 // 1. Verify and document the class invariant that no broken alternative
380 // service can be in the mapping.
381 // 2. Remove the rest of this method as it will be moot.
382 // 3. Provide a SetAlternativeServiceRecentlyBroken if necessary.
383 broken_alternative_services_.erase(alternative_service);
386 const AlternateProtocolMap&
387 HttpServerPropertiesImpl::alternate_protocol_map() const {
388 return alternate_protocol_map_;
391 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
392 const HostPortPair& host_port_pair) {
393 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
394 if (it == spdy_settings_map_.end()) {
395 CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
396 return kEmptySettingsMap;
398 return it->second;
401 bool HttpServerPropertiesImpl::SetSpdySetting(
402 const HostPortPair& host_port_pair,
403 SpdySettingsIds id,
404 SpdySettingsFlags flags,
405 uint32 value) {
406 if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
407 return false;
409 SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
410 SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
411 if (it == spdy_settings_map_.end()) {
412 SettingsMap settings_map;
413 settings_map[id] = flags_and_value;
414 spdy_settings_map_.Put(host_port_pair, settings_map);
415 } else {
416 SettingsMap& settings_map = it->second;
417 settings_map[id] = flags_and_value;
419 return true;
422 void HttpServerPropertiesImpl::ClearSpdySettings(
423 const HostPortPair& host_port_pair) {
424 SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
425 if (it != spdy_settings_map_.end())
426 spdy_settings_map_.Erase(it);
429 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
430 spdy_settings_map_.Clear();
433 const SpdySettingsMap&
434 HttpServerPropertiesImpl::spdy_settings_map() const {
435 return spdy_settings_map_;
438 bool HttpServerPropertiesImpl::GetSupportsQuic(
439 IPAddressNumber* last_address) const {
440 if (last_quic_address_.empty())
441 return false;
443 *last_address = last_quic_address_;
444 return true;
447 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic,
448 const IPAddressNumber& address) {
449 if (!used_quic) {
450 last_quic_address_.clear();
451 } else {
452 last_quic_address_ = address;
456 void HttpServerPropertiesImpl::SetServerNetworkStats(
457 const HostPortPair& host_port_pair,
458 ServerNetworkStats stats) {
459 server_network_stats_map_.Put(host_port_pair, stats);
462 const ServerNetworkStats* HttpServerPropertiesImpl::GetServerNetworkStats(
463 const HostPortPair& host_port_pair) {
464 ServerNetworkStatsMap::iterator it =
465 server_network_stats_map_.Get(host_port_pair);
466 if (it == server_network_stats_map_.end()) {
467 return NULL;
469 return &it->second;
472 const ServerNetworkStatsMap&
473 HttpServerPropertiesImpl::server_network_stats_map() const {
474 return server_network_stats_map_;
477 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
478 double threshold) {
479 alternate_protocol_probability_threshold_ = threshold;
482 AlternateProtocolMap::const_iterator
483 HttpServerPropertiesImpl::GetAlternateProtocolIterator(
484 const HostPortPair& server) {
485 AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
486 if (it != alternate_protocol_map_.end())
487 return it;
489 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
490 if (canonical == canonical_host_to_origin_map_.end()) {
491 return alternate_protocol_map_.end();
494 const HostPortPair canonical_host_port = canonical->second;
495 it = alternate_protocol_map_.Get(canonical_host_port);
496 if (it == alternate_protocol_map_.end()) {
497 return alternate_protocol_map_.end();
500 const AlternativeService alternative_service(
501 it->second.protocol, canonical_host_port.host(), it->second.port);
502 if (!IsAlternativeServiceBroken(alternative_service)) {
503 return it;
506 RemoveCanonicalHost(canonical_host_port);
507 return alternate_protocol_map_.end();
510 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
511 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
512 for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
513 std::string canonical_suffix = canonical_suffixes_[i];
514 if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
515 HostPortPair canonical_host(canonical_suffix, server.port());
516 return canonical_host_to_origin_map_.find(canonical_host);
520 return canonical_host_to_origin_map_.end();
523 void HttpServerPropertiesImpl::RemoveCanonicalHost(
524 const HostPortPair& server) {
525 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
526 if (canonical == canonical_host_to_origin_map_.end())
527 return;
529 if (!canonical->second.Equals(server))
530 return;
532 canonical_host_to_origin_map_.erase(canonical->first);
535 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
536 base::TimeTicks now = base::TimeTicks::Now();
537 while (!broken_alternative_services_.empty()) {
538 BrokenAlternativeServices::iterator it =
539 broken_alternative_services_.begin();
540 if (now < it->second) {
541 break;
544 const AlternativeService alternative_service = it->first;
545 broken_alternative_services_.erase(it);
546 ClearAlternativeService(
547 HostPortPair(alternative_service.host, alternative_service.port));
549 ScheduleBrokenAlternateProtocolMappingsExpiration();
552 void
553 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
554 if (broken_alternative_services_.empty()) {
555 return;
557 base::TimeTicks now = base::TimeTicks::Now();
558 base::TimeTicks when = broken_alternative_services_.front().second;
559 base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
560 base::MessageLoop::current()->PostDelayedTask(
561 FROM_HERE,
562 base::Bind(
563 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
564 weak_ptr_factory_.GetWeakPtr()),
565 delay);
568 } // namespace net