• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/stringprintf.h"
11 #include "net/http/http_pipelined_host_capability.h"
12 
13 namespace net {
14 
15 // TODO(simonjam): Run experiments with different values of this to see what
16 // value is good at avoiding evictions without eating too much memory. Until
17 // then, this is just a bad guess.
18 static const int kDefaultNumHostsToRemember = 200;
19 
HttpServerPropertiesImpl()20 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
21     : pipeline_capability_map_(
22         new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)),
23       weak_ptr_factory_(this) {
24 }
25 
~HttpServerPropertiesImpl()26 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
27 }
28 
InitializeSpdyServers(std::vector<std::string> * spdy_servers,bool support_spdy)29 void HttpServerPropertiesImpl::InitializeSpdyServers(
30     std::vector<std::string>* spdy_servers,
31     bool support_spdy) {
32   DCHECK(CalledOnValidThread());
33   spdy_servers_table_.clear();
34   if (!spdy_servers)
35     return;
36   for (std::vector<std::string>::iterator it = spdy_servers->begin();
37        it != spdy_servers->end(); ++it) {
38     spdy_servers_table_[*it] = support_spdy;
39   }
40 }
41 
InitializeAlternateProtocolServers(AlternateProtocolMap * alternate_protocol_map)42 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
43     AlternateProtocolMap* alternate_protocol_map) {
44   // First swap, and then add back all the ALTERNATE_PROTOCOL_BROKEN ones since
45   // those don't get persisted.
46   alternate_protocol_map_.swap(*alternate_protocol_map);
47   for (AlternateProtocolMap::const_iterator it =
48        alternate_protocol_map->begin();
49        it != alternate_protocol_map->end(); ++it) {
50     if (it->second.protocol == ALTERNATE_PROTOCOL_BROKEN)
51       alternate_protocol_map_[it->first] = it->second;
52   }
53 }
54 
InitializeSpdySettingsServers(SpdySettingsMap * spdy_settings_map)55 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
56     SpdySettingsMap* spdy_settings_map) {
57   spdy_settings_map_.swap(*spdy_settings_map);
58 }
59 
InitializePipelineCapabilities(const PipelineCapabilityMap * pipeline_capability_map)60 void HttpServerPropertiesImpl::InitializePipelineCapabilities(
61     const PipelineCapabilityMap* pipeline_capability_map) {
62   PipelineCapabilityMap::const_iterator it;
63   pipeline_capability_map_->Clear();
64   for (it = pipeline_capability_map->begin();
65        it != pipeline_capability_map->end(); ++it) {
66     pipeline_capability_map_->Put(it->first, it->second);
67   }
68 }
69 
SetNumPipelinedHostsToRemember(int max_size)70 void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) {
71   DCHECK(pipeline_capability_map_->empty());
72   pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size));
73 }
74 
GetSpdyServerList(base::ListValue * spdy_server_list) const75 void HttpServerPropertiesImpl::GetSpdyServerList(
76     base::ListValue* spdy_server_list) const {
77   DCHECK(CalledOnValidThread());
78   DCHECK(spdy_server_list);
79   spdy_server_list->Clear();
80   // Get the list of servers (host/port) that support SPDY.
81   for (SpdyServerHostPortTable::const_iterator it = spdy_servers_table_.begin();
82        it != spdy_servers_table_.end(); ++it) {
83     const std::string spdy_server_host_port = it->first;
84     if (it->second)
85       spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
86   }
87 }
88 
89 // static
GetFlattenedSpdyServer(const net::HostPortPair & host_port_pair)90 std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer(
91     const net::HostPortPair& host_port_pair) {
92   std::string spdy_server;
93   spdy_server.append(host_port_pair.host());
94   spdy_server.append(":");
95   base::StringAppendF(&spdy_server, "%d", host_port_pair.port());
96   return spdy_server;
97 }
98 
99 static const PortAlternateProtocolPair* g_forced_alternate_protocol = NULL;
100 
101 // static
ForceAlternateProtocol(const PortAlternateProtocolPair & pair)102 void HttpServerPropertiesImpl::ForceAlternateProtocol(
103     const PortAlternateProtocolPair& pair) {
104   // Note: we're going to leak this.
105   if (g_forced_alternate_protocol)
106     delete g_forced_alternate_protocol;
107   g_forced_alternate_protocol = new PortAlternateProtocolPair(pair);
108 }
109 
110 // static
DisableForcedAlternateProtocol()111 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
112   delete g_forced_alternate_protocol;
113   g_forced_alternate_protocol = NULL;
114 }
115 
GetWeakPtr()116 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
117   return weak_ptr_factory_.GetWeakPtr();
118 }
119 
Clear()120 void HttpServerPropertiesImpl::Clear() {
121   DCHECK(CalledOnValidThread());
122   spdy_servers_table_.clear();
123   alternate_protocol_map_.clear();
124   spdy_settings_map_.clear();
125   pipeline_capability_map_->Clear();
126 }
127 
SupportsSpdy(const net::HostPortPair & host_port_pair) const128 bool HttpServerPropertiesImpl::SupportsSpdy(
129     const net::HostPortPair& host_port_pair) const {
130   DCHECK(CalledOnValidThread());
131   if (host_port_pair.host().empty())
132     return false;
133   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
134 
135   SpdyServerHostPortTable::const_iterator spdy_host_port =
136       spdy_servers_table_.find(spdy_server);
137   if (spdy_host_port != spdy_servers_table_.end())
138     return spdy_host_port->second;
139   return false;
140 }
141 
SetSupportsSpdy(const net::HostPortPair & host_port_pair,bool support_spdy)142 void HttpServerPropertiesImpl::SetSupportsSpdy(
143     const net::HostPortPair& host_port_pair,
144     bool support_spdy) {
145   DCHECK(CalledOnValidThread());
146   if (host_port_pair.host().empty())
147     return;
148   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
149 
150   SpdyServerHostPortTable::iterator spdy_host_port =
151       spdy_servers_table_.find(spdy_server);
152   if ((spdy_host_port != spdy_servers_table_.end()) &&
153       (spdy_host_port->second == support_spdy)) {
154     return;
155   }
156   // Cache the data.
157   spdy_servers_table_[spdy_server] = support_spdy;
158 }
159 
HasAlternateProtocol(const HostPortPair & server) const160 bool HttpServerPropertiesImpl::HasAlternateProtocol(
161     const HostPortPair& server) const {
162   return ContainsKey(alternate_protocol_map_, server) ||
163       g_forced_alternate_protocol;
164 }
165 
166 PortAlternateProtocolPair
GetAlternateProtocol(const HostPortPair & server) const167 HttpServerPropertiesImpl::GetAlternateProtocol(
168     const HostPortPair& server) const {
169   DCHECK(HasAlternateProtocol(server));
170 
171   // First check the map.
172   AlternateProtocolMap::const_iterator it =
173       alternate_protocol_map_.find(server);
174   if (it != alternate_protocol_map_.end())
175     return it->second;
176 
177   // We must be forcing an alternate.
178   DCHECK(g_forced_alternate_protocol);
179   return *g_forced_alternate_protocol;
180 }
181 
SetAlternateProtocol(const HostPortPair & server,uint16 alternate_port,AlternateProtocol alternate_protocol)182 void HttpServerPropertiesImpl::SetAlternateProtocol(
183     const HostPortPair& server,
184     uint16 alternate_port,
185     AlternateProtocol alternate_protocol) {
186   if (alternate_protocol == ALTERNATE_PROTOCOL_BROKEN) {
187     LOG(DFATAL) << "Call SetBrokenAlternateProtocol() instead.";
188     return;
189   }
190 
191   PortAlternateProtocolPair alternate;
192   alternate.port = alternate_port;
193   alternate.protocol = alternate_protocol;
194   if (HasAlternateProtocol(server)) {
195     const PortAlternateProtocolPair existing_alternate =
196         GetAlternateProtocol(server);
197 
198     if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) {
199       DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
200       return;
201     }
202 
203     if (alternate_protocol != ALTERNATE_PROTOCOL_BROKEN &&
204         !existing_alternate.Equals(alternate)) {
205       LOG(WARNING) << "Changing the alternate protocol for: "
206                    << server.ToString()
207                    << " from [Port: " << existing_alternate.port
208                    << ", Protocol: " << existing_alternate.protocol
209                    << "] to [Port: " << alternate_port
210                    << ", Protocol: " << alternate_protocol
211                    << "].";
212     }
213   }
214 
215   alternate_protocol_map_[server] = alternate;
216 }
217 
SetBrokenAlternateProtocol(const HostPortPair & server)218 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
219     const HostPortPair& server) {
220   alternate_protocol_map_[server].protocol = ALTERNATE_PROTOCOL_BROKEN;
221 }
222 
223 const AlternateProtocolMap&
alternate_protocol_map() const224 HttpServerPropertiesImpl::alternate_protocol_map() const {
225   return alternate_protocol_map_;
226 }
227 
GetSpdySettings(const HostPortPair & host_port_pair) const228 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
229     const HostPortPair& host_port_pair) const {
230   SpdySettingsMap::const_iterator it = spdy_settings_map_.find(host_port_pair);
231   if (it == spdy_settings_map_.end()) {
232     CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
233     return kEmptySettingsMap;
234   }
235   return it->second;
236 }
237 
SetSpdySetting(const HostPortPair & host_port_pair,SpdySettingsIds id,SpdySettingsFlags flags,uint32 value)238 bool HttpServerPropertiesImpl::SetSpdySetting(
239     const HostPortPair& host_port_pair,
240     SpdySettingsIds id,
241     SpdySettingsFlags flags,
242     uint32 value) {
243   if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
244       return false;
245 
246   SettingsMap& settings_map = spdy_settings_map_[host_port_pair];
247   SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
248   settings_map[id] = flags_and_value;
249   return true;
250 }
251 
ClearSpdySettings(const HostPortPair & host_port_pair)252 void HttpServerPropertiesImpl::ClearSpdySettings(
253     const HostPortPair& host_port_pair) {
254   spdy_settings_map_.erase(host_port_pair);
255 }
256 
ClearAllSpdySettings()257 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
258   spdy_settings_map_.clear();
259 }
260 
261 const SpdySettingsMap&
spdy_settings_map() const262 HttpServerPropertiesImpl::spdy_settings_map() const {
263   return spdy_settings_map_;
264 }
265 
GetPipelineCapability(const HostPortPair & origin)266 HttpPipelinedHostCapability HttpServerPropertiesImpl::GetPipelineCapability(
267     const HostPortPair& origin) {
268   HttpPipelinedHostCapability capability = PIPELINE_UNKNOWN;
269   CachedPipelineCapabilityMap::const_iterator it =
270       pipeline_capability_map_->Get(origin);
271   if (it != pipeline_capability_map_->end()) {
272     capability = it->second;
273   }
274   return capability;
275 }
276 
SetPipelineCapability(const HostPortPair & origin,HttpPipelinedHostCapability capability)277 void HttpServerPropertiesImpl::SetPipelineCapability(
278       const HostPortPair& origin,
279       HttpPipelinedHostCapability capability) {
280   CachedPipelineCapabilityMap::iterator it =
281       pipeline_capability_map_->Peek(origin);
282   if (it == pipeline_capability_map_->end() ||
283       it->second != PIPELINE_INCAPABLE) {
284     pipeline_capability_map_->Put(origin, capability);
285   }
286 }
287 
ClearPipelineCapabilities()288 void HttpServerPropertiesImpl::ClearPipelineCapabilities() {
289   pipeline_capability_map_->Clear();
290 }
291 
292 PipelineCapabilityMap
GetPipelineCapabilityMap() const293 HttpServerPropertiesImpl::GetPipelineCapabilityMap() const {
294   PipelineCapabilityMap result;
295   CachedPipelineCapabilityMap::const_iterator it;
296   for (it = pipeline_capability_map_->begin();
297        it != pipeline_capability_map_->end(); ++it) {
298     result[it->first] = it->second;
299   }
300   return result;
301 }
302 
303 }  // namespace net
304