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