OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/http/http_server_properties_impl.h" | |
6 | |
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" | |
14 | |
15 namespace net { | |
16 | |
17 namespace { | |
18 | |
19 const uint64 kBrokenAlternateProtocolDelaySecs = 300; | |
20 | |
21 } // namespace | |
22 | |
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"); | |
33 } | |
34 | |
35 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() { | |
36 } | |
37 | |
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); | |
48 } | |
49 } | |
50 | |
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); | |
60 } | |
61 } | |
62 | |
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); | |
68 } | |
69 | |
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; | |
81 } | |
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; | |
90 } | |
91 } | |
92 } | |
93 } | |
94 } | |
95 | |
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); | |
101 } | |
102 } | |
103 | |
104 void HttpServerPropertiesImpl::InitializeSupportsQuic( | |
105 IPAddressNumber* last_address) { | |
106 if (last_address) | |
107 last_quic_address_ = *last_address; | |
108 } | |
109 | |
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); | |
116 } | |
117 } | |
118 | |
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; | |
133 } | |
134 } | |
135 } | |
136 | |
137 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL; | |
138 | |
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); | |
146 } | |
147 | |
148 // static | |
149 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() { | |
150 delete g_forced_alternate_protocol; | |
151 g_forced_alternate_protocol = NULL; | |
152 } | |
153 | |
154 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() { | |
155 return weak_ptr_factory_.GetWeakPtr(); | |
156 } | |
157 | |
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(); | |
166 } | |
167 | |
168 bool HttpServerPropertiesImpl::SupportsRequestPriority( | |
169 const HostPortPair& host_port_pair) { | |
170 DCHECK(CalledOnValidThread()); | |
171 if (host_port_pair.host().empty()) | |
172 return false; | |
173 | |
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; | |
178 | |
179 const AlternateProtocolInfo info = GetAlternateProtocol(host_port_pair); | |
180 return info.protocol == QUIC; | |
181 } | |
182 | |
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; | |
189 | |
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; | |
195 } | |
196 // Cache the data. | |
197 spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy); | |
198 } | |
199 | |
200 bool HttpServerPropertiesImpl::RequiresHTTP11( | |
201 const net::HostPortPair& host_port_pair) { | |
202 DCHECK(CalledOnValidThread()); | |
203 if (host_port_pair.host().empty()) | |
204 return false; | |
205 | |
206 return (http11_servers_.find(host_port_pair) != http11_servers_.end()); | |
207 } | |
208 | |
209 void HttpServerPropertiesImpl::SetHTTP11Required( | |
210 const net::HostPortPair& host_port_pair) { | |
211 DCHECK(CalledOnValidThread()); | |
212 if (host_port_pair.host().empty()) | |
213 return; | |
214 | |
215 http11_servers_.insert(host_port_pair); | |
216 } | |
217 | |
218 void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server, | |
219 SSLConfig* ssl_config) { | |
220 if (RequiresHTTP11(server)) { | |
221 ForceHTTP11(ssl_config); | |
222 } | |
223 } | |
224 | |
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; | |
233 } | |
234 } | |
235 return std::string(); | |
236 } | |
237 | |
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; | |
245 | |
246 if (g_forced_alternate_protocol) | |
247 return *g_forced_alternate_protocol; | |
248 | |
249 AlternateProtocolInfo uninitialized_alternate_protocol; | |
250 return uninitialized_alternate_protocol; | |
251 } | |
252 | |
253 void HttpServerPropertiesImpl::SetAlternateProtocol( | |
254 const HostPortPair& server, | |
255 uint16 alternate_port, | |
256 AlternateProtocol alternate_protocol, | |
257 double alternate_probability) { | |
258 | |
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; | |
266 | |
267 if (existing_alternate.is_broken) { | |
268 DVLOG(1) << "Ignore alternate protocol since it's known to be broken."; | |
269 return; | |
270 } | |
271 | |
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 << "]."; | |
282 } | |
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); | |
289 } | |
290 } | |
291 | |
292 alternate_protocol_map_.Put(server, alternate); | |
293 | |
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; | |
302 } | |
303 } | |
304 } | |
305 | |
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; | |
314 } | |
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); | |
319 } | |
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)); | |
329 | |
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); | |
333 | |
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(); | |
338 } | |
339 } | |
340 | |
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); | |
349 } | |
350 | |
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); | |
359 } | |
360 | |
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); | |
366 | |
367 RemoveCanonicalHost(server); | |
368 } | |
369 | |
370 const AlternateProtocolMap& | |
371 HttpServerPropertiesImpl::alternate_protocol_map() const { | |
372 return alternate_protocol_map_; | |
373 } | |
374 | |
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; | |
381 } | |
382 return it->second; | |
383 } | |
384 | |
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; | |
392 | |
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; | |
402 } | |
403 return true; | |
404 } | |
405 | |
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); | |
411 } | |
412 | |
413 void HttpServerPropertiesImpl::ClearAllSpdySettings() { | |
414 spdy_settings_map_.Clear(); | |
415 } | |
416 | |
417 const SpdySettingsMap& | |
418 HttpServerPropertiesImpl::spdy_settings_map() const { | |
419 return spdy_settings_map_; | |
420 } | |
421 | |
422 bool HttpServerPropertiesImpl::GetSupportsQuic( | |
423 IPAddressNumber* last_address) const { | |
424 if (last_quic_address_.empty()) | |
425 return false; | |
426 | |
427 *last_address = last_quic_address_; | |
428 return true; | |
429 } | |
430 | |
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; | |
437 } | |
438 } | |
439 | |
440 void HttpServerPropertiesImpl::SetServerNetworkStats( | |
441 const HostPortPair& host_port_pair, | |
442 ServerNetworkStats stats) { | |
443 server_network_stats_map_.Put(host_port_pair, stats); | |
444 } | |
445 | |
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; | |
452 } | |
453 return &it->second; | |
454 } | |
455 | |
456 const ServerNetworkStatsMap& | |
457 HttpServerPropertiesImpl::server_network_stats_map() const { | |
458 return server_network_stats_map_; | |
459 } | |
460 | |
461 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold( | |
462 double threshold) { | |
463 alternate_protocol_probability_threshold_ = threshold; | |
464 } | |
465 | |
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; | |
472 | |
473 CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server); | |
474 if (canonical != canonical_host_to_origin_map_.end()) | |
475 return alternate_protocol_map_.Get(canonical->second); | |
476 | |
477 return alternate_protocol_map_.end(); | |
478 } | |
479 | |
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); | |
487 } | |
488 } | |
489 | |
490 return canonical_host_to_origin_map_.end(); | |
491 } | |
492 | |
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; | |
498 | |
499 if (!canonical->second.Equals(server)) | |
500 return; | |
501 | |
502 canonical_host_to_origin_map_.erase(canonical->first); | |
503 } | |
504 | |
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; | |
512 } | |
513 | |
514 const BrokenAlternateProtocolEntry& entry = | |
515 entry_with_time.broken_alternate_protocol_entry; | |
516 ClearAlternateProtocol(entry.server); | |
517 broken_alternate_protocol_list_.pop_front(); | |
518 } | |
519 ScheduleBrokenAlternateProtocolMappingsExpiration(); | |
520 } | |
521 | |
522 void | |
523 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() { | |
524 if (broken_alternate_protocol_list_.empty()) { | |
525 return; | |
526 } | |
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); | |
536 } | |
537 | |
538 } // namespace net | |
OLD | NEW |