summaryrefslogtreecommitdiffstats
path: root/chromium/net/http/http_server_properties_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/http/http_server_properties_impl.cc')
-rw-r--r--chromium/net/http/http_server_properties_impl.cc330
1 files changed, 240 insertions, 90 deletions
diff --git a/chromium/net/http/http_server_properties_impl.cc b/chromium/net/http/http_server_properties_impl.cc
index a4ac6dc3804..1def87f71a0 100644
--- a/chromium/net/http/http_server_properties_impl.cc
+++ b/chromium/net/http/http_server_properties_impl.cc
@@ -4,23 +4,32 @@
#include "net/http/http_server_properties_impl.h"
+#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
+#include "base/strings/string_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;
+namespace {
+
+const uint64 kBrokenAlternateProtocolDelaySecs = 300;
+
+} // namespace
HttpServerPropertiesImpl::HttpServerPropertiesImpl()
- : pipeline_capability_map_(
- new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)),
+ : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
+ alternate_protocol_map_(AlternateProtocolMap::NO_AUTO_EVICT),
+ alternate_protocol_experiment_(
+ ALTERNATE_PROTOCOL_NOT_PART_OF_EXPERIMENT),
+ spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
weak_ptr_factory_(this) {
+ canoncial_suffixes_.push_back(".c.youtube.com");
+ canoncial_suffixes_.push_back(".googlevideo.com");
+ canoncial_suffixes_.push_back(".googleusercontent.com");
}
HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
@@ -30,59 +39,84 @@ 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;
+ // Add the entries from persisted data.
+ for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
+ it != spdy_servers->rend(); ++it) {
+ spdy_servers_map_.Put(*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;
+ // Keep all the ALTERNATE_PROTOCOL_BROKEN ones since those don't
+ // get persisted.
+ for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
+ it != alternate_protocol_map_.end();) {
+ AlternateProtocolMap::iterator old_it = it;
+ ++it;
+ if (old_it->second.protocol != ALTERNATE_PROTOCOL_BROKEN) {
+ alternate_protocol_map_.Erase(old_it);
+ }
}
-}
-void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
- SpdySettingsMap* spdy_settings_map) {
- spdy_settings_map_.swap(*spdy_settings_map);
-}
+ // Add the entries from persisted data.
+ for (AlternateProtocolMap::reverse_iterator it =
+ alternate_protocol_map->rbegin();
+ it != alternate_protocol_map->rend(); ++it) {
+ alternate_protocol_map_.Put(it->first, it->second);
+ }
-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);
+ // Attempt to find canonical servers.
+ int canonical_ports[] = { 80, 443 };
+ for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+ std::string canonical_suffix = canoncial_suffixes_[i];
+ for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
+ HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
+ // If we already have a valid canonical server, we're done.
+ if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
+ (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
+ canonical_host]) != alternate_protocol_map_.end())) {
+ continue;
+ }
+ // Now attempt to find a server which matches this origin and set it as
+ // canonical .
+ for (AlternateProtocolMap::const_iterator it =
+ alternate_protocol_map_.begin();
+ it != alternate_protocol_map_.end(); ++it) {
+ if (EndsWith(it->first.host(), canoncial_suffixes_[i], false)) {
+ canonical_host_to_origin_map_[canonical_host] = it->first;
+ break;
+ }
+ }
+ }
}
}
-void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) {
- DCHECK(pipeline_capability_map_->empty());
- pipeline_capability_map_.reset(new CachedPipelineCapabilityMap(max_size));
+void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
+ SpdySettingsMap* spdy_settings_map) {
+ for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
+ it != spdy_settings_map->rend(); ++it) {
+ spdy_settings_map_.Put(it->first, it->second);
+ }
}
void HttpServerPropertiesImpl::GetSpdyServerList(
- base::ListValue* spdy_server_list) const {
+ base::ListValue* spdy_server_list,
+ size_t max_size) const {
DCHECK(CalledOnValidThread());
DCHECK(spdy_server_list);
spdy_server_list->Clear();
+ size_t count = 0;
// 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) {
+ for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
+ it != spdy_servers_map_.end() && count < max_size; ++it) {
const std::string spdy_server_host_port = it->first;
- if (it->second)
+ if (it->second) {
spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
+ ++count;
+ }
}
}
@@ -119,22 +153,21 @@ base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
void HttpServerPropertiesImpl::Clear() {
DCHECK(CalledOnValidThread());
- spdy_servers_table_.clear();
- alternate_protocol_map_.clear();
- spdy_settings_map_.clear();
- pipeline_capability_map_->Clear();
+ spdy_servers_map_.Clear();
+ alternate_protocol_map_.Clear();
+ spdy_settings_map_.Clear();
}
bool HttpServerPropertiesImpl::SupportsSpdy(
- const net::HostPortPair& host_port_pair) const {
+ const net::HostPortPair& host_port_pair) {
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())
+ SpdyServerHostPortMap::iterator spdy_host_port =
+ spdy_servers_map_.Get(spdy_server);
+ if (spdy_host_port != spdy_servers_map_.end())
return spdy_host_port->second;
return false;
}
@@ -147,33 +180,53 @@ void HttpServerPropertiesImpl::SetSupportsSpdy(
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()) &&
+ SpdyServerHostPortMap::iterator spdy_host_port =
+ spdy_servers_map_.Get(spdy_server);
+ if ((spdy_host_port != spdy_servers_map_.end()) &&
(spdy_host_port->second == support_spdy)) {
return;
}
// Cache the data.
- spdy_servers_table_[spdy_server] = support_spdy;
+ spdy_servers_map_.Put(spdy_server, support_spdy);
}
bool HttpServerPropertiesImpl::HasAlternateProtocol(
- const HostPortPair& server) const {
- return ContainsKey(alternate_protocol_map_, server) ||
- g_forced_alternate_protocol;
+ const HostPortPair& server) {
+ if (alternate_protocol_map_.Get(server) != alternate_protocol_map_.end() ||
+ g_forced_alternate_protocol)
+ return true;
+
+ return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
+}
+
+std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
+ const HostPortPair& server) {
+ // If this host ends with a canonical suffix, then return the canonical
+ // suffix.
+ for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+ std::string canonical_suffix = canoncial_suffixes_[i];
+ if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
+ return canonical_suffix;
+ }
+ }
+ return std::string();
}
PortAlternateProtocolPair
HttpServerPropertiesImpl::GetAlternateProtocol(
- const HostPortPair& server) const {
+ const HostPortPair& server) {
DCHECK(HasAlternateProtocol(server));
// First check the map.
- AlternateProtocolMap::const_iterator it =
- alternate_protocol_map_.find(server);
+ AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
if (it != alternate_protocol_map_.end())
return it->second;
+ // Next check the canonical host.
+ CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
+ if (canonical_host != canonical_host_to_origin_map_.end())
+ return alternate_protocol_map_.Get(canonical_host->second)->second;
+
// We must be forcing an alternate.
DCHECK(g_forced_alternate_protocol);
return *g_forced_alternate_protocol;
@@ -210,14 +263,68 @@ void HttpServerPropertiesImpl::SetAlternateProtocol(
<< ", Protocol: " << alternate_protocol
<< "].";
}
+ } else {
+ // TODO(rch): Consider the case where multiple requests are started
+ // before the first completes. In this case, only one of the jobs
+ // would reach this code, whereas all of them should should have.
+ HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING,
+ alternate_protocol_experiment_);
}
- alternate_protocol_map_[server] = alternate;
+ alternate_protocol_map_.Put(server, alternate);
+
+ // If this host ends with a canonical suffix, then set it as the
+ // canonical host.
+ for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+ std::string canonical_suffix = canoncial_suffixes_[i];
+ if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
+ HostPortPair canonical_host(canonical_suffix, server.port());
+ canonical_host_to_origin_map_[canonical_host] = server;
+ break;
+ }
+ }
}
void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
const HostPortPair& server) {
- alternate_protocol_map_[server].protocol = ALTERNATE_PROTOCOL_BROKEN;
+ AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
+ if (it != alternate_protocol_map_.end()) {
+ it->second.protocol = ALTERNATE_PROTOCOL_BROKEN;
+ } else {
+ PortAlternateProtocolPair alternate;
+ alternate.protocol = ALTERNATE_PROTOCOL_BROKEN;
+ alternate_protocol_map_.Put(server, alternate);
+ }
+ int count = ++broken_alternate_protocol_map_[server];
+ base::TimeDelta delay =
+ base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
+ BrokenAlternateProtocolEntry entry;
+ entry.server = server;
+ entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
+ broken_alternate_protocol_list_.push_back(entry);
+ // If this is the only entry in the list, schedule an expiration task.
+ // Otherwse it will be rescheduled automatically when the pending
+ // task runs.
+ if (broken_alternate_protocol_list_.size() == 1) {
+ ScheduleBrokenAlternateProtocolMappingsExpiration();
+ }
+}
+
+bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
+ const HostPortPair& server) {
+ return ContainsKey(broken_alternate_protocol_map_, server);
+}
+
+void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
+ const HostPortPair& server) {
+ broken_alternate_protocol_map_.erase(server);
+}
+
+void HttpServerPropertiesImpl::ClearAlternateProtocol(
+ const HostPortPair& server) {
+ AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
+ if (it != alternate_protocol_map_.end())
+ alternate_protocol_map_.Erase(it);
}
const AlternateProtocolMap&
@@ -225,9 +332,19 @@ HttpServerPropertiesImpl::alternate_protocol_map() const {
return alternate_protocol_map_;
}
+void HttpServerPropertiesImpl::SetAlternateProtocolExperiment(
+ AlternateProtocolExperiment experiment) {
+ alternate_protocol_experiment_ = experiment;
+}
+
+AlternateProtocolExperiment
+HttpServerPropertiesImpl::GetAlternateProtocolExperiment() const {
+ return alternate_protocol_experiment_;
+}
+
const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
- const HostPortPair& host_port_pair) const {
- SpdySettingsMap::const_iterator it = spdy_settings_map_.find(host_port_pair);
+ const HostPortPair& host_port_pair) {
+ SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
if (it == spdy_settings_map_.end()) {
CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
return kEmptySettingsMap;
@@ -243,19 +360,28 @@ bool HttpServerPropertiesImpl::SetSpdySetting(
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;
+ SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
+ if (it == spdy_settings_map_.end()) {
+ SettingsMap settings_map;
+ settings_map[id] = flags_and_value;
+ spdy_settings_map_.Put(host_port_pair, settings_map);
+ } else {
+ SettingsMap& settings_map = it->second;
+ settings_map[id] = flags_and_value;
+ }
return true;
}
void HttpServerPropertiesImpl::ClearSpdySettings(
const HostPortPair& host_port_pair) {
- spdy_settings_map_.erase(host_port_pair);
+ SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
+ if (it != spdy_settings_map_.end())
+ spdy_settings_map_.Erase(it);
}
void HttpServerPropertiesImpl::ClearAllSpdySettings() {
- spdy_settings_map_.clear();
+ spdy_settings_map_.Clear();
}
const SpdySettingsMap&
@@ -263,41 +389,65 @@ 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;
+void HttpServerPropertiesImpl::SetServerNetworkStats(
+ const HostPortPair& host_port_pair,
+ NetworkStats stats) {
+ server_network_stats_map_[host_port_pair] = stats;
+}
+
+const HttpServerProperties::NetworkStats*
+HttpServerPropertiesImpl::GetServerNetworkStats(
+ const HostPortPair& host_port_pair) const {
+ ServerNetworkStatsMap::const_iterator it =
+ server_network_stats_map_.find(host_port_pair);
+ if (it == server_network_stats_map_.end()) {
+ return NULL;
}
- return capability;
+ return &it->second;
}
-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);
+HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
+HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
+ for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+ std::string canonical_suffix = canoncial_suffixes_[i];
+ if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
+ HostPortPair canonical_host(canonical_suffix, server.port());
+ return canonical_host_to_origin_map_.find(canonical_host);
+ }
}
+
+ return canonical_host_to_origin_map_.end();
}
-void HttpServerPropertiesImpl::ClearPipelineCapabilities() {
- pipeline_capability_map_->Clear();
+void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
+ base::TimeTicks now = base::TimeTicks::Now();
+ while (!broken_alternate_protocol_list_.empty()) {
+ BrokenAlternateProtocolEntry entry =
+ broken_alternate_protocol_list_.front();
+ if (now < entry.when) {
+ break;
+ }
+
+ ClearAlternateProtocol(entry.server);
+ broken_alternate_protocol_list_.pop_front();
+ }
+ ScheduleBrokenAlternateProtocolMappingsExpiration();
}
-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;
+void
+HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
+ if (broken_alternate_protocol_list_.empty()) {
+ return;
}
- return result;
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks when = broken_alternate_protocol_list_.front().when;
+ base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(
+ &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
+ weak_ptr_factory_.GetWeakPtr()),
+ delay);
}
} // namespace net