普通文本  |  304行  |  9.57 KB

// 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<std::string>* spdy_servers,
    bool support_spdy) {
  DCHECK(CalledOnValidThread());
  spdy_servers_table_.clear();
  if (!spdy_servers)
    return;
  for (std::vector<std::string>::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<HttpServerProperties> 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