Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / http / http_server_properties_impl.cc
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       alternate_protocol_probability_threshold_(1),
28       weak_ptr_factory_(this) {
29   canonical_suffixes_.push_back(".c.youtube.com");
30   canonical_suffixes_.push_back(".googlevideo.com");
31   canonical_suffixes_.push_back(".googleusercontent.com");
32 }
33
34 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
35 }
36
37 void HttpServerPropertiesImpl::InitializeSpdyServers(
38     std::vector<std::string>* spdy_servers,
39     bool support_spdy) {
40   DCHECK(CalledOnValidThread());
41   if (!spdy_servers)
42     return;
43   // Add the entries from persisted data.
44   for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
45        it != spdy_servers->rend(); ++it) {
46     spdy_servers_map_.Put(*it, support_spdy);
47   }
48 }
49
50 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
51     AlternateProtocolMap* alternate_protocol_map) {
52   // Keep all the broken ones since those don't get persisted.
53   for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
54        it != alternate_protocol_map_.end();) {
55     AlternateProtocolMap::iterator old_it = it;
56     ++it;
57     if (!old_it->second.is_broken) {
58       alternate_protocol_map_.Erase(old_it);
59     }
60   }
61
62   // Add the entries from persisted data.
63   for (AlternateProtocolMap::reverse_iterator it =
64            alternate_protocol_map->rbegin();
65        it != alternate_protocol_map->rend(); ++it) {
66     alternate_protocol_map_.Put(it->first, it->second);
67   }
68
69   // Attempt to find canonical servers.
70   int canonical_ports[] = { 80, 443 };
71   for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
72     std::string canonical_suffix = canonical_suffixes_[i];
73     for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
74       HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
75       // If we already have a valid canonical server, we're done.
76       if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
77           (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
78                canonical_host]) != alternate_protocol_map_.end())) {
79         continue;
80       }
81       // Now attempt to find a server which matches this origin and set it as
82       // canonical .
83       for (AlternateProtocolMap::const_iterator it =
84                alternate_protocol_map_.begin();
85            it != alternate_protocol_map_.end(); ++it) {
86         if (EndsWith(it->first.host(), canonical_suffixes_[i], false)) {
87           canonical_host_to_origin_map_[canonical_host] = it->first;
88           break;
89         }
90       }
91     }
92   }
93 }
94
95 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
96     SpdySettingsMap* spdy_settings_map) {
97   for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
98        it != spdy_settings_map->rend(); ++it) {
99     spdy_settings_map_.Put(it->first, it->second);
100   }
101 }
102
103 void HttpServerPropertiesImpl::InitializeSupportsQuic(
104     SupportsQuicMap* supports_quic_map) {
105   for (SupportsQuicMap::reverse_iterator it = supports_quic_map->rbegin();
106        it != supports_quic_map->rend();
107        ++it) {
108     supports_quic_map_.insert(std::make_pair(it->first, it->second));
109   }
110 }
111
112 void HttpServerPropertiesImpl::GetSpdyServerList(
113     base::ListValue* spdy_server_list,
114     size_t max_size) const {
115   DCHECK(CalledOnValidThread());
116   DCHECK(spdy_server_list);
117   spdy_server_list->Clear();
118   size_t count = 0;
119   // Get the list of servers (host/port) that support SPDY.
120   for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
121        it != spdy_servers_map_.end() && count < max_size; ++it) {
122     const std::string spdy_server_host_port = it->first;
123     if (it->second) {
124       spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
125       ++count;
126     }
127   }
128 }
129
130 // static
131 std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer(
132     const net::HostPortPair& host_port_pair) {
133   std::string spdy_server;
134   spdy_server.append(host_port_pair.host());
135   spdy_server.append(":");
136   base::StringAppendF(&spdy_server, "%d", host_port_pair.port());
137   return spdy_server;
138 }
139
140 static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
141
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);
149 }
150
151 // static
152 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
153   delete g_forced_alternate_protocol;
154   g_forced_alternate_protocol = NULL;
155 }
156
157 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
158   return weak_ptr_factory_.GetWeakPtr();
159 }
160
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   supports_quic_map_.clear();
168 }
169
170 bool HttpServerPropertiesImpl::SupportsSpdy(
171     const net::HostPortPair& host_port_pair) {
172   DCHECK(CalledOnValidThread());
173   if (host_port_pair.host().empty())
174     return false;
175   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
176
177   SpdyServerHostPortMap::iterator spdy_host_port =
178       spdy_servers_map_.Get(spdy_server);
179   if (spdy_host_port != spdy_servers_map_.end())
180     return spdy_host_port->second;
181   return false;
182 }
183
184 void HttpServerPropertiesImpl::SetSupportsSpdy(
185     const net::HostPortPair& host_port_pair,
186     bool support_spdy) {
187   DCHECK(CalledOnValidThread());
188   if (host_port_pair.host().empty())
189     return;
190   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
191
192   SpdyServerHostPortMap::iterator spdy_host_port =
193       spdy_servers_map_.Get(spdy_server);
194   if ((spdy_host_port != spdy_servers_map_.end()) &&
195       (spdy_host_port->second == support_spdy)) {
196     return;
197   }
198   // Cache the data.
199   spdy_servers_map_.Put(spdy_server, support_spdy);
200 }
201
202 bool HttpServerPropertiesImpl::HasAlternateProtocol(
203     const HostPortPair& server) {
204   if (g_forced_alternate_protocol)
205     return true;
206   AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server);
207   if (it != alternate_protocol_map_.end() &&
208       it->second.probability >= alternate_protocol_probability_threshold_) {
209     return true;
210   }
211
212   return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
213 }
214
215 std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
216     const HostPortPair& server) {
217   // If this host ends with a canonical suffix, then return the canonical
218   // suffix.
219   for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
220     std::string canonical_suffix = canonical_suffixes_[i];
221     if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
222       return canonical_suffix;
223     }
224   }
225   return std::string();
226 }
227
228 AlternateProtocolInfo
229 HttpServerPropertiesImpl::GetAlternateProtocol(
230     const HostPortPair& server) {
231   DCHECK(HasAlternateProtocol(server));
232
233   // First check the map.
234   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
235   if (it != alternate_protocol_map_.end())
236     return it->second;
237
238   // Next check the canonical host.
239   CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
240   if (canonical_host != canonical_host_to_origin_map_.end())
241     return alternate_protocol_map_.Get(canonical_host->second)->second;
242
243   // We must be forcing an alternate.
244   DCHECK(g_forced_alternate_protocol);
245   return *g_forced_alternate_protocol;
246 }
247
248 void HttpServerPropertiesImpl::SetAlternateProtocol(
249     const HostPortPair& server,
250     uint16 alternate_port,
251     AlternateProtocol alternate_protocol,
252     double alternate_probability) {
253
254   AlternateProtocolInfo alternate(alternate_port,
255                                   alternate_protocol,
256                                   alternate_probability);
257   if (HasAlternateProtocol(server)) {
258     const AlternateProtocolInfo existing_alternate =
259         GetAlternateProtocol(server);
260
261     if (existing_alternate.is_broken) {
262       DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
263       return;
264     }
265
266     if (!existing_alternate.Equals(alternate)) {
267       LOG(WARNING) << "Changing the alternate protocol for: "
268                    << server.ToString()
269                    << " from [Port: " << existing_alternate.port
270                    << ", Protocol: " << existing_alternate.protocol
271                    << ", Probability: " << existing_alternate.probability
272                    << "] to [Port: " << alternate_port
273                    << ", Protocol: " << alternate_protocol
274                    << ", Probability: " << alternate_probability
275                    << "].";
276     }
277   } else {
278     if (alternate_probability >= alternate_protocol_probability_threshold_) {
279       // TODO(rch): Consider the case where multiple requests are started
280       // before the first completes. In this case, only one of the jobs
281       // would reach this code, whereas all of them should should have.
282       HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
283     }
284   }
285
286   alternate_protocol_map_.Put(server, alternate);
287
288   // If this host ends with a canonical suffix, then set it as the
289   // canonical host.
290   for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
291     std::string canonical_suffix = canonical_suffixes_[i];
292     if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
293       HostPortPair canonical_host(canonical_suffix, server.port());
294       canonical_host_to_origin_map_[canonical_host] = server;
295       break;
296     }
297   }
298 }
299
300 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
301     const HostPortPair& server) {
302   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
303   if (it == alternate_protocol_map_.end()) {
304     LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
305     return;
306   }
307   it->second.is_broken = true;
308   int count = ++broken_alternate_protocol_map_[server];
309   base::TimeDelta delay =
310       base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
311   BrokenAlternateProtocolEntry entry;
312   entry.server = server;
313   entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
314   broken_alternate_protocol_list_.push_back(entry);
315
316   // Do not leave this host as canonical so that we don't infer the other
317   // hosts are also broken without testing them first.
318   RemoveCanonicalHost(server);
319
320   // If this is the only entry in the list, schedule an expiration task.
321   // Otherwse it will be rescheduled automatically when the pending
322   // task runs.
323   if (broken_alternate_protocol_list_.size() == 1) {
324     ScheduleBrokenAlternateProtocolMappingsExpiration();
325   }
326 }
327
328 bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
329     const HostPortPair& server) {
330   return ContainsKey(broken_alternate_protocol_map_, server);
331 }
332
333 void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
334     const HostPortPair& server) {
335   broken_alternate_protocol_map_.erase(server);
336 }
337
338 void HttpServerPropertiesImpl::ClearAlternateProtocol(
339     const HostPortPair& server) {
340   AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
341   if (it != alternate_protocol_map_.end())
342     alternate_protocol_map_.Erase(it);
343
344   RemoveCanonicalHost(server);
345 }
346
347 const AlternateProtocolMap&
348 HttpServerPropertiesImpl::alternate_protocol_map() const {
349   return alternate_protocol_map_;
350 }
351
352 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
353     const HostPortPair& host_port_pair) {
354   SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
355   if (it == spdy_settings_map_.end()) {
356     CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
357     return kEmptySettingsMap;
358   }
359   return it->second;
360 }
361
362 bool HttpServerPropertiesImpl::SetSpdySetting(
363     const HostPortPair& host_port_pair,
364     SpdySettingsIds id,
365     SpdySettingsFlags flags,
366     uint32 value) {
367   if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
368       return false;
369
370   SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
371   SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
372   if (it == spdy_settings_map_.end()) {
373     SettingsMap settings_map;
374     settings_map[id] = flags_and_value;
375     spdy_settings_map_.Put(host_port_pair, settings_map);
376   } else {
377     SettingsMap& settings_map = it->second;
378     settings_map[id] = flags_and_value;
379   }
380   return true;
381 }
382
383 void HttpServerPropertiesImpl::ClearSpdySettings(
384     const HostPortPair& host_port_pair) {
385   SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
386   if (it != spdy_settings_map_.end())
387     spdy_settings_map_.Erase(it);
388 }
389
390 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
391   spdy_settings_map_.Clear();
392 }
393
394 const SpdySettingsMap&
395 HttpServerPropertiesImpl::spdy_settings_map() const {
396   return spdy_settings_map_;
397 }
398
399 SupportsQuic HttpServerPropertiesImpl::GetSupportsQuic(
400     const HostPortPair& host_port_pair) const {
401   SupportsQuicMap::const_iterator it = supports_quic_map_.find(host_port_pair);
402   if (it == supports_quic_map_.end()) {
403     CR_DEFINE_STATIC_LOCAL(SupportsQuic, kEmptySupportsQuic, ());
404     return kEmptySupportsQuic;
405   }
406   return it->second;
407 }
408
409 void HttpServerPropertiesImpl::SetSupportsQuic(
410     const HostPortPair& host_port_pair,
411     bool used_quic,
412     const std::string& address) {
413   SupportsQuic supports_quic(used_quic, address);
414   supports_quic_map_.insert(std::make_pair(host_port_pair, supports_quic));
415 }
416
417 const SupportsQuicMap&
418 HttpServerPropertiesImpl::supports_quic_map() const {
419   return supports_quic_map_;
420 }
421
422 void HttpServerPropertiesImpl::SetServerNetworkStats(
423     const HostPortPair& host_port_pair,
424     NetworkStats stats) {
425   server_network_stats_map_[host_port_pair] = stats;
426 }
427
428 const HttpServerProperties::NetworkStats*
429 HttpServerPropertiesImpl::GetServerNetworkStats(
430     const HostPortPair& host_port_pair) const {
431   ServerNetworkStatsMap::const_iterator it =
432       server_network_stats_map_.find(host_port_pair);
433   if (it == server_network_stats_map_.end()) {
434     return NULL;
435   }
436   return &it->second;
437 }
438
439 void HttpServerPropertiesImpl::SetAlternateProtocolProbabilityThreshold(
440     double threshold) {
441   alternate_protocol_probability_threshold_ = threshold;
442 }
443
444 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
445 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
446   for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
447     std::string canonical_suffix = canonical_suffixes_[i];
448     if (EndsWith(server.host(), canonical_suffixes_[i], false)) {
449       HostPortPair canonical_host(canonical_suffix, server.port());
450       return canonical_host_to_origin_map_.find(canonical_host);
451     }
452   }
453
454   return canonical_host_to_origin_map_.end();
455 }
456
457 void HttpServerPropertiesImpl::RemoveCanonicalHost(
458     const HostPortPair& server) {
459   CanonicalHostMap::const_iterator canonical = GetCanonicalHost(server);
460   if (canonical == canonical_host_to_origin_map_.end())
461     return;
462
463   if (!canonical->second.Equals(server))
464     return;
465
466   canonical_host_to_origin_map_.erase(canonical->first);
467 }
468
469 void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
470   base::TimeTicks now = base::TimeTicks::Now();
471   while (!broken_alternate_protocol_list_.empty()) {
472     BrokenAlternateProtocolEntry entry =
473         broken_alternate_protocol_list_.front();
474     if (now < entry.when) {
475       break;
476     }
477
478     ClearAlternateProtocol(entry.server);
479     broken_alternate_protocol_list_.pop_front();
480   }
481   ScheduleBrokenAlternateProtocolMappingsExpiration();
482 }
483
484 void
485 HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
486   if (broken_alternate_protocol_list_.empty()) {
487     return;
488   }
489   base::TimeTicks now = base::TimeTicks::Now();
490   base::TimeTicks when = broken_alternate_protocol_list_.front().when;
491   base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
492   base::MessageLoop::current()->PostDelayedTask(
493       FROM_HERE,
494       base::Bind(
495           &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
496           weak_ptr_factory_.GetWeakPtr()),
497       delay);
498 }
499
500 }  // namespace net