Prevent bookmark apps from triggering a sync loop.
[chromium-blink-merge.git] / net / http / http_server_properties_impl.cc
blob7fb42054dbc9dcce514a634ed9de91b67e556f70
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/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "net/http/http_pipelined_host_capability.h"
14 namespace net {
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;
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");
31 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
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;
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);
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);
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;
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;
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);
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);
111 void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) {
112 DCHECK(pipeline_capability_map_->empty());
113 pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size));
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));
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;
140 static const PortAlternateProtocolPair* g_forced_alternate_protocol = NULL;
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);
151 // static
152 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
153 delete g_forced_alternate_protocol;
154 g_forced_alternate_protocol = NULL;
157 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
158 return weak_ptr_factory_.GetWeakPtr();
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();
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);
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;
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);
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;
197 // Cache the data.
198 spdy_servers_table_[spdy_server] = support_spdy;
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;
207 return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
210 PortAlternateProtocolPair
211 HttpServerPropertiesImpl::GetAlternateProtocol(
212 const HostPortPair& server) {
213 DCHECK(HasAlternateProtocol(server));
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;
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;
225 // We must be forcing an alternate.
226 DCHECK(g_forced_alternate_protocol);
227 return *g_forced_alternate_protocol;
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;
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);
246 if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) {
247 DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
248 return;
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 << "].";
263 alternate_protocol_map_.Put(server, alternate);
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;
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;
284 PortAlternateProtocolPair alternate;
285 alternate.protocol = ALTERNATE_PROTOCOL_BROKEN;
286 alternate_protocol_map_.Put(server, alternate);
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);
296 const AlternateProtocolMap&
297 HttpServerPropertiesImpl::alternate_protocol_map() const {
298 return alternate_protocol_map_;
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;
308 return it->second;
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;
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;
329 return true;
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);
339 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
340 spdy_settings_map_.Clear();
343 const SpdySettingsMap&
344 HttpServerPropertiesImpl::spdy_settings_map() const {
345 return spdy_settings_map_;
348 void HttpServerPropertiesImpl::SetServerNetworkStats(
349 const HostPortPair& host_port_pair,
350 NetworkStats stats) {
351 server_network_stats_map_[host_port_pair] = stats;
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;
362 return &it->second;
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;
373 return capability;
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);
387 void HttpServerPropertiesImpl::ClearPipelineCapabilities() {
388 pipeline_capability_map_->Clear();
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;
399 return result;
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);
412 return canonical_host_to_origin_map_.end();
415 } // namespace net