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.
5 #include "net/http/http_server_properties_impl.h"
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"
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;
20 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
21 : weak_ptr_factory_(this),
22 pipeline_capability_map_(
23 new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember
)) {
26 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
29 void HttpServerPropertiesImpl::InitializeSpdyServers(
30 std::vector
<std::string
>* spdy_servers
,
32 DCHECK(CalledOnValidThread());
33 spdy_servers_table_
.clear();
36 for (std::vector
<std::string
>::iterator it
= spdy_servers
->begin();
37 it
!= spdy_servers
->end(); ++it
) {
38 spdy_servers_table_
[*it
] = support_spdy
;
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
;
55 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
56 SpdySettingsMap
* spdy_settings_map
) {
57 spdy_settings_map_
.swap(*spdy_settings_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
);
70 void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size
) {
71 DCHECK(pipeline_capability_map_
->empty());
72 pipeline_capability_map_
.reset(new CachedPipelineCapabilityMap(max_size
));
75 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
;
85 spdy_server_list
->Append(new base::StringValue(spdy_server_host_port
));
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());
99 static const PortAlternateProtocolPair
* g_forced_alternate_protocol
= NULL
;
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
);
111 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
112 delete g_forced_alternate_protocol
;
113 g_forced_alternate_protocol
= NULL
;
116 base::WeakPtr
<HttpServerProperties
> HttpServerPropertiesImpl::GetWeakPtr() {
117 return weak_ptr_factory_
.GetWeakPtr();
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();
128 bool HttpServerPropertiesImpl::SupportsSpdy(
129 const net::HostPortPair
& host_port_pair
) const {
130 DCHECK(CalledOnValidThread());
131 if (host_port_pair
.host().empty())
133 std::string spdy_server
= GetFlattenedSpdyServer(host_port_pair
);
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
;
142 void HttpServerPropertiesImpl::SetSupportsSpdy(
143 const net::HostPortPair
& host_port_pair
,
145 DCHECK(CalledOnValidThread());
146 if (host_port_pair
.host().empty())
148 std::string spdy_server
= GetFlattenedSpdyServer(host_port_pair
);
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
)) {
157 spdy_servers_table_
[spdy_server
] = support_spdy
;
160 bool HttpServerPropertiesImpl::HasAlternateProtocol(
161 const HostPortPair
& server
) const {
162 return ContainsKey(alternate_protocol_map_
, server
) ||
163 g_forced_alternate_protocol
;
166 PortAlternateProtocolPair
167 HttpServerPropertiesImpl::GetAlternateProtocol(
168 const HostPortPair
& server
) const {
169 DCHECK(HasAlternateProtocol(server
));
171 // First check the map.
172 AlternateProtocolMap::const_iterator it
=
173 alternate_protocol_map_
.find(server
);
174 if (it
!= alternate_protocol_map_
.end())
177 // We must be forcing an alternate.
178 DCHECK(g_forced_alternate_protocol
);
179 return *g_forced_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.";
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
);
198 if (existing_alternate
.protocol
== ALTERNATE_PROTOCOL_BROKEN
) {
199 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
203 if (alternate_protocol
!= ALTERNATE_PROTOCOL_BROKEN
&&
204 !existing_alternate
.Equals(alternate
)) {
205 LOG(WARNING
) << "Changing the alternate protocol for: "
207 << " from [Port: " << existing_alternate
.port
208 << ", Protocol: " << existing_alternate
.protocol
209 << "] to [Port: " << alternate_port
210 << ", Protocol: " << alternate_protocol
215 alternate_protocol_map_
[server
] = alternate
;
218 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
219 const HostPortPair
& server
) {
220 alternate_protocol_map_
[server
].protocol
= ALTERNATE_PROTOCOL_BROKEN
;
223 const AlternateProtocolMap
&
224 HttpServerPropertiesImpl::alternate_protocol_map() const {
225 return alternate_protocol_map_
;
228 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
;
238 bool HttpServerPropertiesImpl::SetSpdySetting(
239 const HostPortPair
& host_port_pair
,
241 SpdySettingsFlags flags
,
243 if (!(flags
& SETTINGS_FLAG_PLEASE_PERSIST
))
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
;
252 void HttpServerPropertiesImpl::ClearSpdySettings(
253 const HostPortPair
& host_port_pair
) {
254 spdy_settings_map_
.erase(host_port_pair
);
257 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
258 spdy_settings_map_
.clear();
261 const SpdySettingsMap
&
262 HttpServerPropertiesImpl::spdy_settings_map() const {
263 return spdy_settings_map_
;
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
;
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
);
288 void HttpServerPropertiesImpl::ClearPipelineCapabilities() {
289 pipeline_capability_map_
->Clear();
292 PipelineCapabilityMap
293 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
;