Home | History | Annotate | Download | only in http
      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     : weak_ptr_factory_(this),
     22       pipeline_capability_map_(
     23         new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)) {
     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