| Index: net/http/http_server_properties_impl.cc
|
| diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
|
| index d048e98871acba04071ccae2c0c81d51d494bc26..a22a470722c1b0823da2ceb87d03b01d40af607f 100644
|
| --- a/net/http/http_server_properties_impl.cc
|
| +++ b/net/http/http_server_properties_impl.cc
|
| @@ -50,13 +50,22 @@ void HttpServerPropertiesImpl::InitializeSpdyServers(
|
|
|
| void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
|
| AlternateProtocolMap* alternate_protocol_map) {
|
| - // Keep all the 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.is_broken) {
|
| - alternate_protocol_map_.Erase(old_it);
|
| + for (AlternateProtocolMap::iterator alternate_protocols =
|
| + alternate_protocol_map_.begin();
|
| + alternate_protocols != alternate_protocol_map_.end();) {
|
| + // Keep all the broken ones since those don't get persisted.
|
| + for (AlternateProtocols::iterator it = alternate_protocols->second.begin();
|
| + it != alternate_protocols->second.end();) {
|
| + if (!it->is_broken) {
|
| + it = alternate_protocols->second.erase(it);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| + if (alternate_protocols->second.size() == 0) {
|
| + alternate_protocols = alternate_protocol_map_.Erase(alternate_protocols);
|
| + } else {
|
| + ++alternate_protocols;
|
| }
|
| }
|
|
|
| @@ -137,21 +146,20 @@ void HttpServerPropertiesImpl::GetSpdyServerList(
|
| }
|
| }
|
|
|
| -static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL;
|
| +static AlternateProtocols* g_forced_alternate_protocol =
|
| + new AlternateProtocols();
|
|
|
| // static
|
| void HttpServerPropertiesImpl::ForceAlternateProtocol(
|
| const AlternateProtocolInfo& info) {
|
| + DisableForcedAlternateProtocol();
|
| // Note: we're going to leak this.
|
| - if (g_forced_alternate_protocol)
|
| - delete g_forced_alternate_protocol;
|
| - g_forced_alternate_protocol = new AlternateProtocolInfo(info);
|
| + g_forced_alternate_protocol->push_back(info);
|
| }
|
|
|
| // static
|
| void HttpServerPropertiesImpl::DisableForcedAlternateProtocol() {
|
| - delete g_forced_alternate_protocol;
|
| - g_forced_alternate_protocol = NULL;
|
| + g_forced_alternate_protocol->clear();
|
| }
|
|
|
| base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
|
| @@ -225,12 +233,22 @@ void HttpServerPropertiesImpl::MaybeForceHTTP11(const HostPortPair& server,
|
|
|
| bool HttpServerPropertiesImpl::HasAlternateProtocol(
|
| const HostPortPair& server) {
|
| - if (g_forced_alternate_protocol)
|
| + if (!g_forced_alternate_protocol->empty())
|
| return true;
|
| - AlternateProtocolMap::const_iterator it =
|
| + AlternateProtocolMap::const_iterator alternate_protocols =
|
| GetAlternateProtocolIterator(server);
|
| - return it != alternate_protocol_map_.end() &&
|
| - it->second.probability >= alternate_protocol_probability_threshold_;
|
| + if (alternate_protocols == alternate_protocol_map_.end())
|
| + return false;
|
| + for (AlternateProtocols::const_iterator alternate_protocol =
|
| + alternate_protocols->second.begin();
|
| + alternate_protocol != alternate_protocols->second.end();
|
| + alternate_protocol++) {
|
| + if (alternate_protocol->probability >=
|
| + alternate_protocol_probability_threshold_) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| }
|
|
|
| std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
|
| @@ -246,8 +264,7 @@ std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
|
| return std::string();
|
| }
|
|
|
| -AlternateProtocolInfo
|
| -HttpServerPropertiesImpl::GetAlternateProtocol(
|
| +const AlternateProtocols& HttpServerPropertiesImpl::GetAlternateProtocols(
|
| const HostPortPair& server) {
|
| DCHECK(HasAlternateProtocol(server));
|
|
|
| @@ -257,40 +274,50 @@ HttpServerPropertiesImpl::GetAlternateProtocol(
|
| return it->second;
|
|
|
| // We must be forcing an alternate.
|
| - DCHECK(g_forced_alternate_protocol);
|
| + DCHECK(!g_forced_alternate_protocol->empty());
|
| return *g_forced_alternate_protocol;
|
| }
|
|
|
| -void HttpServerPropertiesImpl::SetAlternateProtocol(
|
| +void HttpServerPropertiesImpl::AddAlternateProtocol(
|
| const HostPortPair& server,
|
| uint16 alternate_port,
|
| AlternateProtocol alternate_protocol,
|
| double alternate_probability) {
|
| -
|
| + if (!IsAlternateProtocolValid(alternate_protocol))
|
| + return;
|
| AlternateProtocolInfo alternate(alternate_port,
|
| alternate_protocol,
|
| alternate_probability);
|
| - AlternateProtocolMap::const_iterator it =
|
| + AlternateProtocolMap::const_iterator map_it =
|
| GetAlternateProtocolIterator(server);
|
| - if (it != alternate_protocol_map_.end()) {
|
| - const AlternateProtocolInfo existing_alternate = it->second;
|
| -
|
| - if (existing_alternate.is_broken) {
|
| - DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
|
| - return;
|
| + if (map_it != alternate_protocol_map_.end()) {
|
| + AlternateProtocols existing_alternates = map_it->second;
|
| + AlternateProtocols::iterator it;
|
| + for (it = existing_alternates.begin(); it != existing_alternates.end();
|
| + ++it) {
|
| + if (it->EqualsModuloProbability(alternate)) {
|
| + break;
|
| + }
|
| }
|
|
|
| - if (!existing_alternate.Equals(alternate)) {
|
| - LOG(WARNING) << "Changing the alternate protocol for: "
|
| - << server.ToString()
|
| - << " from [Port: " << existing_alternate.port
|
| - << ", Protocol: " << existing_alternate.protocol
|
| - << ", Probability: " << existing_alternate.probability
|
| - << "] to [Port: " << alternate_port
|
| - << ", Protocol: " << alternate_protocol
|
| - << ", Probability: " << alternate_probability
|
| - << "].";
|
| + if (it != existing_alternates.end()) {
|
| + if (it->is_broken) {
|
| + DVLOG(1) << "Ignore alternate protocol since it's known to be broken.";
|
| + return;
|
| + }
|
| + if (it->probability != alternate_probability) {
|
| + LOG(WARNING) << "Changing the probability of alternate protocol for: "
|
| + << server.ToString() << " Port: " << it->port
|
| + << ", Protocol: " << it->protocol
|
| + << ", Probability from: " << it->probability
|
| + << " to: " << alternate_probability << ".";
|
| + it->probability = alternate_probability;
|
| + }
|
| + } else {
|
| + existing_alternates.push_back(alternate);
|
| }
|
| +
|
| + alternate_protocol_map_.Put(server, existing_alternates);
|
| } else {
|
| if (alternate_probability >= alternate_protocol_probability_threshold_) {
|
| // TODO(rch): Consider the case where multiple requests are started
|
| @@ -298,10 +325,10 @@ void HttpServerPropertiesImpl::SetAlternateProtocol(
|
| // would reach this code, whereas all of them should should have.
|
| HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
|
| }
|
| + alternate_protocol_map_.Put(server,
|
| + AlternateProtocols(/*size=*/1, 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 < canonical_suffixes_.size(); ++i) {
|
| @@ -315,25 +342,34 @@ void HttpServerPropertiesImpl::SetAlternateProtocol(
|
| }
|
|
|
| void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
|
| - const HostPortPair& server) {
|
| - AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
|
| - if (it == alternate_protocol_map_.end()) {
|
| - if (!HasAlternateProtocol(server)) {
|
| - LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
|
| - return;
|
| + const HostPortPair& server,
|
| + const AlternateProtocolInfo& broken_alternate_protocol) {
|
| + if (!IsAlternateProtocolValid(broken_alternate_protocol.protocol))
|
| + return;
|
| + AddAlternateProtocol(server, broken_alternate_protocol.port,
|
| + broken_alternate_protocol.protocol,
|
| + broken_alternate_protocol.probability);
|
| + AlternateProtocolMap::iterator alternate_protocols =
|
| + alternate_protocol_map_.Get(server);
|
| + DCHECK(alternate_protocols != alternate_protocol_map_.end());
|
| + AlternateProtocols::iterator it;
|
| + for (it = alternate_protocols->second.begin();
|
| + it != alternate_protocols->second.end(); ++it) {
|
| + if (it->Equals(broken_alternate_protocol)) {
|
| + it->is_broken = true;
|
| + break;
|
| }
|
| - // This server's alternate protocol information is coming from a canonical
|
| - // server. Add an entry in the map for this server explicitly so that
|
| - // it can be marked as broken.
|
| - it = alternate_protocol_map_.Put(server, GetAlternateProtocol(server));
|
| }
|
| - it->second.is_broken = true;
|
| - int count = ++broken_alternate_protocol_map_[server];
|
| + DCHECK(it != alternate_protocols->second.end());
|
| +
|
| + const AlternativeService altsvc(broken_alternate_protocol.protocol,
|
| + server.host(),
|
| + broken_alternate_protocol.port);
|
| + int count = ++broken_alternate_protocol_map_[altsvc];
|
| base::TimeDelta delay =
|
| base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
|
| - BrokenAlternateProtocolEntry entry;
|
| - entry.server = server;
|
| - entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
|
| + base::TimeTicks when = base::TimeTicks::Now() + delay * (1 << (count - 1));
|
| + const BrokenAlternateProtocolEntry entry(altsvc, when);
|
| broken_alternate_protocol_list_.push_back(entry);
|
|
|
| // Do not leave this host as canonical so that we don't infer the other
|
| @@ -341,21 +377,26 @@ void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
|
| RemoveCanonicalHost(server);
|
|
|
| // If this is the only entry in the list, schedule an expiration task.
|
| - // Otherwse it will be rescheduled automatically when the pending
|
| - // task runs.
|
| + // Otherwise 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);
|
| + const HostPortPair& server,
|
| + const AlternateProtocolInfo& alternate_protocol) {
|
| + const AlternativeService altsvc(alternate_protocol.protocol, server.host(),
|
| + alternate_protocol.port);
|
| + return ContainsKey(broken_alternate_protocol_map_, altsvc);
|
| }
|
|
|
| void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
|
| - const HostPortPair& server) {
|
| - broken_alternate_protocol_map_.erase(server);
|
| + const HostPortPair& server,
|
| + const AlternateProtocolInfo& alternate_protocol) {
|
| + const AlternativeService altsvc(alternate_protocol.protocol, server.host(),
|
| + alternate_protocol.port);
|
| + broken_alternate_protocol_map_.erase(altsvc);
|
| }
|
|
|
| void HttpServerPropertiesImpl::ClearAlternateProtocol(
|
| @@ -367,6 +408,48 @@ void HttpServerPropertiesImpl::ClearAlternateProtocol(
|
| RemoveCanonicalHost(server);
|
| }
|
|
|
| +void HttpServerPropertiesImpl::ClearNonBrokenAlternateProtocols(
|
| + const HostPortPair& server) {
|
| + AlternateProtocolMap::iterator alternate_protocols =
|
| + alternate_protocol_map_.Peek(server);
|
| + if (alternate_protocols == alternate_protocol_map_.end()) {
|
| + return;
|
| + }
|
| + for (AlternateProtocols::iterator it = alternate_protocols->second.begin();
|
| + it != alternate_protocols->second.end();) {
|
| + if (!it->is_broken) {
|
| + it = alternate_protocols->second.erase(it);
|
| + } else {
|
| + ++it;
|
| + }
|
| + }
|
| + if (alternate_protocols->second.size() == 0) {
|
| + alternate_protocol_map_.Erase(alternate_protocols);
|
| + RemoveCanonicalHost(server);
|
| + }
|
| +}
|
| +
|
| +void HttpServerPropertiesImpl::RemoveAlternateProtocol(
|
| + const HostPortPair& server,
|
| + const AlternateProtocolInfo& alternate_protocol) {
|
| + AlternateProtocolMap::iterator alternate_protocols =
|
| + alternate_protocol_map_.Peek(server);
|
| + if (alternate_protocols == alternate_protocol_map_.end()) {
|
| + return;
|
| + }
|
| + for (AlternateProtocols::iterator it = alternate_protocols->second.begin();
|
| + it != alternate_protocols->second.end(); ++it) {
|
| + if (it->EqualsModuloProbability(alternate_protocol)) {
|
| + alternate_protocols->second.erase(it);
|
| + break;
|
| + }
|
| + }
|
| + if (alternate_protocols->second.size() == 0) {
|
| + alternate_protocol_map_.Erase(alternate_protocols);
|
| + RemoveCanonicalHost(server);
|
| + }
|
| +}
|
| +
|
| const AlternateProtocolMap&
|
| HttpServerPropertiesImpl::alternate_protocol_map() const {
|
| return alternate_protocol_map_;
|
| @@ -515,7 +598,10 @@ void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
|
| break;
|
| }
|
|
|
| - ClearAlternateProtocol(entry.server);
|
| + const HostPortPair server(entry.altsvc.host, entry.altsvc.port);
|
| + const AlternateProtocolInfo alternate_protocol(entry.altsvc.port,
|
| + entry.altsvc.protocol, 1.0);
|
| + RemoveAlternateProtocol(server, alternate_protocol);
|
| broken_alternate_protocol_list_.pop_front();
|
| }
|
| ScheduleBrokenAlternateProtocolMappingsExpiration();
|
|
|