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 20 HttpServerPropertiesImpl::HttpServerPropertiesImpl() 21 : pipeline_capability_map_( 22 new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)), 23 weak_ptr_factory_(this) { 24 } 25 26 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() { 27 } 28 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 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 55 void HttpServerPropertiesImpl::InitializeSpdySettingsServers( 56 SpdySettingsMap* spdy_settings_map) { 57 spdy_settings_map_.swap(*spdy_settings_map); 58 } 59 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 70 void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) { 71 DCHECK(pipeline_capability_map_->empty()); 72 pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size)); 73 } 74 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; 84 if (it->second) 85 spdy_server_list->Append(new base::StringValue(spdy_server_host_port)); 86 } 87 } 88 89 // static 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 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 111 void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() { 112 delete g_forced_alternate_protocol; 113 g_forced_alternate_protocol = NULL; 114 } 115 116 base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() { 117 return weak_ptr_factory_.GetWeakPtr(); 118 } 119 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 128 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 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 160 bool HttpServerPropertiesImpl::HasAlternateProtocol( 161 const HostPortPair& server) const { 162 return ContainsKey(alternate_protocol_map_, server) || 163 g_forced_alternate_protocol; 164 } 165 166 PortAlternateProtocolPair 167 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 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 218 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol( 219 const HostPortPair& server) { 220 alternate_protocol_map_[server].protocol = ALTERNATE_PROTOCOL_BROKEN; 221 } 222 223 const AlternateProtocolMap& 224 HttpServerPropertiesImpl::alternate_protocol_map() const { 225 return alternate_protocol_map_; 226 } 227 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; 234 } 235 return it->second; 236 } 237 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 252 void HttpServerPropertiesImpl::ClearSpdySettings( 253 const HostPortPair& host_port_pair) { 254 spdy_settings_map_.erase(host_port_pair); 255 } 256 257 void HttpServerPropertiesImpl::ClearAllSpdySettings() { 258 spdy_settings_map_.clear(); 259 } 260 261 const SpdySettingsMap& 262 HttpServerPropertiesImpl::spdy_settings_map() const { 263 return spdy_settings_map_; 264 } 265 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 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 288 void HttpServerPropertiesImpl::ClearPipelineCapabilities() { 289 pipeline_capability_map_->Clear(); 290 } 291 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; 299 } 300 return result; 301 } 302 303 } // namespace net 304