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"
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"
19 const uint64 kBrokenAlternateProtocolDelaySecs
= 300;
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
,
41 DCHECK(CalledOnValidThread());
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
;
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())) {
82 // Now attempt to find a server which matches this origin and set it as
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
;
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
) {
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();
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
;
131 spdy_server_list
->Append(new base::StringValue(spdy_server_host_port
));
137 static const AlternateProtocolInfo
* g_forced_alternate_protocol
= NULL
;
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
);
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())
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
)
179 const AlternateProtocolInfo info
= GetAlternateProtocol(host_port_pair
);
180 return info
.protocol
== QUIC
;
183 void HttpServerPropertiesImpl::SetSupportsSpdy(
184 const HostPortPair
& host_port_pair
,
186 DCHECK(CalledOnValidThread());
187 if (host_port_pair
.host().empty())
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
)) {
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())
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())
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
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_
)
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
,
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.";
272 if (!existing_alternate
.Equals(alternate
)) {
273 LOG(WARNING
) << "Changing the alternate protocol for: "
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
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
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
;
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.";
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
,
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
)
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
)
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
;
385 bool HttpServerPropertiesImpl::SetSpdySetting(
386 const HostPortPair
& host_port_pair
,
388 SpdySettingsFlags flags
,
390 if (!(flags
& SETTINGS_FLAG_PLEASE_PERSIST
))
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
);
400 SettingsMap
& settings_map
= it
->second
;
401 settings_map
[id
] = flags_and_value
;
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())
427 *last_address
= last_quic_address_
;
431 void HttpServerPropertiesImpl::SetSupportsQuic(bool used_quic
,
432 const IPAddressNumber
& address
) {
434 last_quic_address_
.clear();
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()) {
456 const ServerNetworkStatsMap
&
457 HttpServerPropertiesImpl::server_network_stats_map() const {
458 return server_network_stats_map_
;
461 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
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())
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())
499 if (!canonical
->second
.Equals(server
))
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
) {
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();
523 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
524 if (broken_alternate_protocol_list_
.empty()) {
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(
533 &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings
,
534 weak_ptr_factory_
.GetWeakPtr()),