diff options
Diffstat (limited to 'chromium/net/http/http_server_properties_impl.cc')
-rw-r--r-- | chromium/net/http/http_server_properties_impl.cc | 330 |
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 |