Upstream version 6.35.121.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/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "net/http/http_pipelined_host_capability.h"
13
14 namespace net {
15
16 // TODO(simonjam): Run experiments with different values of this to see what
17 // value is good at avoiding evictions without eating too much memory. Until
18 // then, this is just a bad guess.
19 static const int kDefaultNumHostsToRemember = 200;
20
21 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
22     : alternate_protocol_map_(AlternateProtocolMap::NO_AUTO_EVICT),
23       spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
24       pipeline_capability_map_(
25         new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)),
26       weak_ptr_factory_(this) {
27   canoncial_suffixes_.push_back(".c.youtube.com");
28   canoncial_suffixes_.push_back(".googlevideo.com");
29 }
30
31 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
32 }
33
34 void HttpServerPropertiesImpl::InitializeSpdyServers(
35     std::vector<std::string>* spdy_servers,
36     bool support_spdy) {
37   DCHECK(CalledOnValidThread());
38   spdy_servers_table_.clear();
39   if (!spdy_servers)
40     return;
41   for (std::vector<std::string>::iterator it = spdy_servers->begin();
42        it != spdy_servers->end(); ++it) {
43     spdy_servers_table_[*it] = support_spdy;
44   }
45 }
46
47 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
48     AlternateProtocolMap* alternate_protocol_map) {
49   // Keep all the ALTERNATE_PROTOCOL_BROKEN ones since those don't
50   // get persisted.
51   for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
52        it != alternate_protocol_map_.end();) {
53     AlternateProtocolMap::iterator old_it = it;
54     ++it;
55     if (old_it->second.protocol != ALTERNATE_PROTOCOL_BROKEN) {
56       alternate_protocol_map_.Erase(old_it);
57     }
58   }
59
60   // Add the entries from persisted data.
61   for (AlternateProtocolMap::reverse_iterator it =
62            alternate_protocol_map->rbegin();
63        it != alternate_protocol_map->rend(); ++it) {
64     alternate_protocol_map_.Put(it->first, it->second);
65   }
66
67   // Attempt to find canonical servers.
68   int canonical_ports[] = { 80, 443 };
69   for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
70     std::string canonical_suffix = canoncial_suffixes_[i];
71     for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
72       HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
73       // If we already have a valid canonical server, we're done.
74       if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
75           (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
76                canonical_host]) != alternate_protocol_map_.end())) {
77         continue;
78       }
79       // Now attempt to find a server which matches this origin and set it as
80       // canonical .
81       for (AlternateProtocolMap::const_iterator it =
82                alternate_protocol_map_.begin();
83            it != alternate_protocol_map_.end(); ++it) {
84         if (EndsWith(it->first.host(), canoncial_suffixes_[i], false)) {
85           canonical_host_to_origin_map_[canonical_host] = it->first;
86           break;
87         }
88       }
89     }
90   }
91 }
92
93 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
94     SpdySettingsMap* spdy_settings_map) {
95   for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
96        it != spdy_settings_map->rend(); ++it) {
97     spdy_settings_map_.Put(it->first, it->second);
98   }
99 }
100
101 void HttpServerPropertiesImpl::InitializePipelineCapabilities(
102     const PipelineCapabilityMap* pipeline_capability_map) {
103   PipelineCapabilityMap::const_iterator it;
104   pipeline_capability_map_->Clear();
105   for (it = pipeline_capability_map->begin();
106        it != pipeline_capability_map->end(); ++it) {
107     pipeline_capability_map_->Put(it->first, it->second);
108   }
109 }
110
111 void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) {
112   DCHECK(pipeline_capability_map_->empty());
113   pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size));
114 }
115
116 void HttpServerPropertiesImpl::GetSpdyServerList(
117     base::ListValue* spdy_server_list) const {
118   DCHECK(CalledOnValidThread());
119   DCHECK(spdy_server_list);
120   spdy_server_list->Clear();
121   // Get the list of servers (host/port) that support SPDY.
122   for (SpdyServerHostPortTable::const_iterator it = spdy_servers_table_.begin();
123        it != spdy_servers_table_.end(); ++it) {
124     const std::string spdy_server_host_port = it->first;
125     if (it->second)
126       spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
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 PortAlternateProtocolPair* g_forced_alternate_protocol = NULL;
141
142 // static
143 void HttpServerPropertiesImpl::ForceAlternateProtocol(
144     const PortAlternateProtocolPair& pair) {
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 PortAlternateProtocolPair(pair);
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_table_.clear();
164   alternate_protocol_map_.Clear();
165   spdy_settings_map_.Clear();
166   pipeline_capability_map_->Clear();
167 }
168
169 bool HttpServerPropertiesImpl::SupportsSpdy(
170     const net::HostPortPair& host_port_pair) const {
171   DCHECK(CalledOnValidThread());
172   if (host_port_pair.host().empty())
173     return false;
174   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
175
176   SpdyServerHostPortTable::const_iterator spdy_host_port =
177       spdy_servers_table_.find(spdy_server);
178   if (spdy_host_port != spdy_servers_table_.end())
179     return spdy_host_port->second;
180   return false;
181 }
182
183 void HttpServerPropertiesImpl::SetSupportsSpdy(
184     const net::HostPortPair& host_port_pair,
185     bool support_spdy) {
186   DCHECK(CalledOnValidThread());
187   if (host_port_pair.host().empty())
188     return;
189   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
190
191   SpdyServerHostPortTable::iterator spdy_host_port =
192       spdy_servers_table_.find(spdy_server);
193   if ((spdy_host_port != spdy_servers_table_.end()) &&
194       (spdy_host_port->second == support_spdy)) {
195     return;
196   }
197   // Cache the data.
198   spdy_servers_table_[spdy_server] = support_spdy;
199 }
200
201 bool HttpServerPropertiesImpl::HasAlternateProtocol(
202     const HostPortPair& server) {
203   if (alternate_protocol_map_.Get(server) != alternate_protocol_map_.end() ||
204       g_forced_alternate_protocol)
205     return true;
206
207   return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
208 }
209
210 PortAlternateProtocolPair
211 HttpServerPropertiesImpl::GetAlternateProtocol(
212     const HostPortPair& server) {
213   DCHECK(HasAlternateProtocol(server));
214
215   // First check the map.
216   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
217   if (it != alternate_protocol_map_.end())
218     return it->second;
219
220   // Next check the canonical host.
221   CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
222   if (canonical_host != canonical_host_to_origin_map_.end())
223     return alternate_protocol_map_.Get(canonical_host->second)->second;
224
225   // We must be forcing an alternate.
226   DCHECK(g_forced_alternate_protocol);
227   return *g_forced_alternate_protocol;
228 }
229
230 void HttpServerPropertiesImpl::SetAlternateProtocol(
231     const HostPortPair& server,
232     uint16 alternate_port,
233     AlternateProtocol alternate_protocol) {
234   if (alternate_protocol == ALTERNATE_PROTOCOL_BROKEN) {
235     LOG(DFATAL) << "Call SetBrokenAlternateProtocol() instead.";
236     return;
237   }
238
239   PortAlternateProtocolPair alternate;
240   alternate.port = alternate_port;
241   alternate.protocol = alternate_protocol;
242   if (HasAlternateProtocol(server)) {
243     const PortAlternateProtocolPair existing_alternate =
244         GetAlternateProtocol(server);
245
246     if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) {
247       DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
248       return;
249     }
250
251     if (alternate_protocol != ALTERNATE_PROTOCOL_BROKEN &&
252         !existing_alternate.Equals(alternate)) {
253       LOG(WARNING) << "Changing the alternate protocol for: "
254                    << server.ToString()
255                    << " from [Port: " << existing_alternate.port
256                    << ", Protocol: " << existing_alternate.protocol
257                    << "] to [Port: " << alternate_port
258                    << ", Protocol: " << alternate_protocol
259                    << "].";
260     }
261   }
262
263   alternate_protocol_map_.Put(server, alternate);
264
265   // If this host ends with a canonical suffix, then set it as the
266   // canonical host.
267   for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
268     std::string canonical_suffix = canoncial_suffixes_[i];
269     if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
270       HostPortPair canonical_host(canonical_suffix, server.port());
271       canonical_host_to_origin_map_[canonical_host] = server;
272       break;
273     }
274   }
275 }
276
277 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
278     const HostPortPair& server) {
279   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
280   if (it != alternate_protocol_map_.end()) {
281     it->second.protocol = ALTERNATE_PROTOCOL_BROKEN;
282     return;
283   }
284   PortAlternateProtocolPair alternate;
285   alternate.protocol = ALTERNATE_PROTOCOL_BROKEN;
286   alternate_protocol_map_.Put(server, alternate);
287 }
288
289 void HttpServerPropertiesImpl::ClearAlternateProtocol(
290     const HostPortPair& server) {
291   AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
292   if (it != alternate_protocol_map_.end())
293     alternate_protocol_map_.Erase(it);
294 }
295
296 const AlternateProtocolMap&
297 HttpServerPropertiesImpl::alternate_protocol_map() const {
298   return alternate_protocol_map_;
299 }
300
301 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
302     const HostPortPair& host_port_pair) {
303   SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
304   if (it == spdy_settings_map_.end()) {
305     CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
306     return kEmptySettingsMap;
307   }
308   return it->second;
309 }
310
311 bool HttpServerPropertiesImpl::SetSpdySetting(
312     const HostPortPair& host_port_pair,
313     SpdySettingsIds id,
314     SpdySettingsFlags flags,
315     uint32 value) {
316   if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
317       return false;
318
319   SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
320   SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
321   if (it == spdy_settings_map_.end()) {
322     SettingsMap settings_map;
323     settings_map[id] = flags_and_value;
324     spdy_settings_map_.Put(host_port_pair, settings_map);
325   } else {
326     SettingsMap& settings_map = it->second;
327     settings_map[id] = flags_and_value;
328   }
329   return true;
330 }
331
332 void HttpServerPropertiesImpl::ClearSpdySettings(
333     const HostPortPair& host_port_pair) {
334   SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
335   if (it != spdy_settings_map_.end())
336     spdy_settings_map_.Erase(it);
337 }
338
339 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
340   spdy_settings_map_.Clear();
341 }
342
343 const SpdySettingsMap&
344 HttpServerPropertiesImpl::spdy_settings_map() const {
345   return spdy_settings_map_;
346 }
347
348 void HttpServerPropertiesImpl::SetServerNetworkStats(
349     const HostPortPair& host_port_pair,
350     NetworkStats stats) {
351   server_network_stats_map_[host_port_pair] = stats;
352 }
353
354 const HttpServerProperties::NetworkStats*
355 HttpServerPropertiesImpl::GetServerNetworkStats(
356     const HostPortPair& host_port_pair) const {
357   ServerNetworkStatsMap::const_iterator it =
358       server_network_stats_map_.find(host_port_pair);
359   if (it == server_network_stats_map_.end()) {
360     return NULL;
361   }
362   return &it->second;
363 }
364
365 HttpPipelinedHostCapability HttpServerPropertiesImpl::GetPipelineCapability(
366     const HostPortPair& origin) {
367   HttpPipelinedHostCapability capability = PIPELINE_UNKNOWN;
368   CachedPipelineCapabilityMap::const_iterator it =
369       pipeline_capability_map_->Get(origin);
370   if (it != pipeline_capability_map_->end()) {
371     capability = it->second;
372   }
373   return capability;
374 }
375
376 void HttpServerPropertiesImpl::SetPipelineCapability(
377       const HostPortPair& origin,
378       HttpPipelinedHostCapability capability) {
379   CachedPipelineCapabilityMap::iterator it =
380       pipeline_capability_map_->Peek(origin);
381   if (it == pipeline_capability_map_->end() ||
382       it->second != PIPELINE_INCAPABLE) {
383     pipeline_capability_map_->Put(origin, capability);
384   }
385 }
386
387 void HttpServerPropertiesImpl::ClearPipelineCapabilities() {
388   pipeline_capability_map_->Clear();
389 }
390
391 PipelineCapabilityMap
392 HttpServerPropertiesImpl::GetPipelineCapabilityMap() const {
393   PipelineCapabilityMap result;
394   CachedPipelineCapabilityMap::const_iterator it;
395   for (it = pipeline_capability_map_->begin();
396        it != pipeline_capability_map_->end(); ++it) {
397     result[it->first] = it->second;
398   }
399   return result;
400 }
401
402 HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
403 HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
404   for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
405     std::string canonical_suffix = canoncial_suffixes_[i];
406     if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
407       HostPortPair canonical_host(canonical_suffix, server.port());
408       return canonical_host_to_origin_map_.find(canonical_host);
409     }
410   }
411
412   return canonical_host_to_origin_map_.end();
413 }
414
415 }  // namespace net