// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_server_properties_impl.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "net/http/http_pipelined_host_capability.h" namespace net { // TODO(simonjam): Run experiments with different values of this to see what // value is good at avoiding evictions without eating too much memory. Until // then, this is just a bad guess. static const int kDefaultNumHostsToRemember = 200; HttpServerPropertiesImpl::HttpServerPropertiesImpl() : pipeline_capability_map_( new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)), weak_ptr_factory_(this) { } HttpServerPropertiesImpl::~HttpServerPropertiesImpl() { } void HttpServerPropertiesImpl::InitializeSpdyServers( std::vector* spdy_servers, bool support_spdy) { DCHECK(CalledOnValidThread()); spdy_servers_table_.clear(); if (!spdy_servers) return; for (std::vector::iterator it = spdy_servers->begin(); it != spdy_servers->end(); ++it) { spdy_servers_table_[*it] = support_spdy; } } void HttpServerPropertiesImpl::InitializeAlternateProtocolServers( AlternateProtocolMap* alternate_protocol_map) { // First swap, and then add back all the ALTERNATE_PROTOCOL_BROKEN ones since // those don't get persisted. alternate_protocol_map_.swap(*alternate_protocol_map); for (AlternateProtocolMap::const_iterator it = alternate_protocol_map->begin(); it != alternate_protocol_map->end(); ++it) { if (it->second.protocol == ALTERNATE_PROTOCOL_BROKEN) alternate_protocol_map_[it->first] = it->second; } } void HttpServerPropertiesImpl::InitializeSpdySettingsServers( SpdySettingsMap* spdy_settings_map) { spdy_settings_map_.swap(*spdy_settings_map); } void HttpServerPropertiesImpl::InitializePipelineCapabilities( const PipelineCapabilityMap* pipeline_capability_map) { PipelineCapabilityMap::const_iterator it; pipeline_capability_map_->Clear(); for (it = pipeline_capability_map->begin(); it != pipeline_capability_map->end(); ++it) { pipeline_capability_map_->Put(it->first, it->second); } } void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) { DCHECK(pipeline_capability_map_->empty()); pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size)); } void HttpServerPropertiesImpl::GetSpdyServerList( base::ListValue* spdy_server_list) const { DCHECK(CalledOnValidThread()); DCHECK(spdy_server_list); spdy_server_list->Clear(); // Get the list of servers (host/port) that support SPDY. for (SpdyServerHostPortTable::const_iterator it = spdy_servers_table_.begin(); it != spdy_servers_table_.end(); ++it) { const std::string spdy_server_host_port = it->first; if (it->second) spdy_server_list->Append(new base::StringValue(spdy_server_host_port)); } } // static std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer( const net::HostPortPair& host_port_pair) { std::string spdy_server; spdy_server.append(host_port_pair.host()); spdy_server.append(":"); base::StringAppendF(&spdy_server, "%d", host_port_pair.port()); return spdy_server; } static const PortAlternateProtocolPair* g_forced_alternate_protocol = NULL; // static void HttpServerPropertiesImpl::ForceAlternateProtocol( const PortAlternateProtocolPair& pair) { // Note: we're going to leak this. if (g_forced_alternate_protocol) delete g_forced_alternate_protocol; g_forced_alternate_protocol = new PortAlternateProtocolPair(pair); } // static void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() { delete g_forced_alternate_protocol; g_forced_alternate_protocol = NULL; } base::WeakPtr HttpServerPropertiesImpl::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } void HttpServerPropertiesImpl::Clear() { DCHECK(CalledOnValidThread()); spdy_servers_table_.clear(); alternate_protocol_map_.clear(); spdy_settings_map_.clear(); pipeline_capability_map_->Clear(); } bool HttpServerPropertiesImpl::SupportsSpdy( const net::HostPortPair& host_port_pair) const { DCHECK(CalledOnValidThread()); if (host_port_pair.host().empty()) return false; std::string spdy_server = GetFlattenedSpdyServer(host_port_pair); SpdyServerHostPortTable::const_iterator spdy_host_port = spdy_servers_table_.find(spdy_server); if (spdy_host_port != spdy_servers_table_.end()) return spdy_host_port->second; return false; } void HttpServerPropertiesImpl::SetSupportsSpdy( const net::HostPortPair& host_port_pair, bool support_spdy) { DCHECK(CalledOnValidThread()); if (host_port_pair.host().empty()) return; std::string spdy_server = GetFlattenedSpdyServer(host_port_pair); SpdyServerHostPortTable::iterator spdy_host_port = spdy_servers_table_.find(spdy_server); if ((spdy_host_port != spdy_servers_table_.end()) && (spdy_host_port->second == support_spdy)) { return; } // Cache the data. spdy_servers_table_[spdy_server] = support_spdy; } bool HttpServerPropertiesImpl::HasAlternateProtocol( const HostPortPair& server) const { return ContainsKey(alternate_protocol_map_, server) || g_forced_alternate_protocol; } PortAlternateProtocolPair HttpServerPropertiesImpl::GetAlternateProtocol( const HostPortPair& server) const { DCHECK(HasAlternateProtocol(server)); // First check the map. AlternateProtocolMap::const_iterator it = alternate_protocol_map_.find(server); if (it != alternate_protocol_map_.end()) return it->second; // We must be forcing an alternate. DCHECK(g_forced_alternate_protocol); return *g_forced_alternate_protocol; } void HttpServerPropertiesImpl::SetAlternateProtocol( const HostPortPair& server, uint16 alternate_port, AlternateProtocol alternate_protocol) { if (alternate_protocol == ALTERNATE_PROTOCOL_BROKEN) { LOG(DFATAL) << "Call SetBrokenAlternateProtocol() instead."; return; } PortAlternateProtocolPair alternate; alternate.port = alternate_port; alternate.protocol = alternate_protocol; if (HasAlternateProtocol(server)) { const PortAlternateProtocolPair existing_alternate = GetAlternateProtocol(server); if (existing_alternate.protocol == ALTERNATE_PROTOCOL_BROKEN) { DVLOG(1) << "Ignore alternate protocol since it's known to be broken."; return; } if (alternate_protocol != ALTERNATE_PROTOCOL_BROKEN && !existing_alternate.Equals(alternate)) { LOG(WARNING) << "Changing the alternate protocol for: " << server.ToString() << " from [Port: " << existing_alternate.port << ", Protocol: " << existing_alternate.protocol << "] to [Port: " << alternate_port << ", Protocol: " << alternate_protocol << "]."; } } alternate_protocol_map_[server] = alternate; } void HttpServerPropertiesImpl::SetBrokenAlternateProtocol( const HostPortPair& server) { alternate_protocol_map_[server].protocol = ALTERNATE_PROTOCOL_BROKEN; } const AlternateProtocolMap& HttpServerPropertiesImpl::alternate_protocol_map() const { return alternate_protocol_map_; } const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings( const HostPortPair& host_port_pair) const { SpdySettingsMap::const_iterator it = spdy_settings_map_.find(host_port_pair); if (it == spdy_settings_map_.end()) { CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ()); return kEmptySettingsMap; } return it->second; } bool HttpServerPropertiesImpl::SetSpdySetting( const HostPortPair& host_port_pair, SpdySettingsIds id, SpdySettingsFlags flags, uint32 value) { if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST)) return false; SettingsMap& settings_map = spdy_settings_map_[host_port_pair]; SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value); settings_map[id] = flags_and_value; return true; } void HttpServerPropertiesImpl::ClearSpdySettings( const HostPortPair& host_port_pair) { spdy_settings_map_.erase(host_port_pair); } void HttpServerPropertiesImpl::ClearAllSpdySettings() { spdy_settings_map_.clear(); } const SpdySettingsMap& HttpServerPropertiesImpl::spdy_settings_map() const { return spdy_settings_map_; } HttpPipelinedHostCapability HttpServerPropertiesImpl::GetPipelineCapability( const HostPortPair& origin) { HttpPipelinedHostCapability capability = PIPELINE_UNKNOWN; CachedPipelineCapabilityMap::const_iterator it = pipeline_capability_map_->Get(origin); if (it != pipeline_capability_map_->end()) { capability = it->second; } return capability; } void HttpServerPropertiesImpl::SetPipelineCapability( const HostPortPair& origin, HttpPipelinedHostCapability capability) { CachedPipelineCapabilityMap::iterator it = pipeline_capability_map_->Peek(origin); if (it == pipeline_capability_map_->end() || it->second != PIPELINE_INCAPABLE) { pipeline_capability_map_->Put(origin, capability); } } void HttpServerPropertiesImpl::ClearPipelineCapabilities() { pipeline_capability_map_->Clear(); } PipelineCapabilityMap HttpServerPropertiesImpl::GetPipelineCapabilityMap() const { PipelineCapabilityMap result; CachedPipelineCapabilityMap::const_iterator it; for (it = pipeline_capability_map_->begin(); it != pipeline_capability_map_->end(); ++it) { result[it->first] = it->second; } return result; } } // namespace net