Chromium Code Reviews| 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 a8bc04a685980d1f5adb6d1ec778cdbc58f77968..75f66250acc4edb4de6366ab56bd9186b2344df8 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,11 +233,21 @@ 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 = alternate_protocol_map_.Get(server); |
| - if (it != alternate_protocol_map_.end()) |
| - return it->second.probability >= alternate_protocol_probability_threshold_; |
| + AlternateProtocolMap::const_iterator alternate_protocols = |
| + alternate_protocol_map_.Get(server); |
| + if (alternate_protocols != alternate_protocol_map_.end()) { |
| + 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; |
| + } |
| + } |
| + } |
| auto canonical = GetCanonicalHost(server); |
| if (canonical == canonical_host_to_origin_map_.end() || |
| @@ -253,8 +271,7 @@ std::string HttpServerPropertiesImpl::GetCanonicalSuffix( |
| return std::string(); |
| } |
| -AlternateProtocolInfo |
| -HttpServerPropertiesImpl::GetAlternateProtocol( |
| +const AlternateProtocols& HttpServerPropertiesImpl::GetAlternateProtocols( |
| const HostPortPair& server) { |
| DCHECK(HasAlternateProtocol(server)); |
| @@ -269,39 +286,50 @@ HttpServerPropertiesImpl::GetAlternateProtocol( |
| return alternate_protocol_map_.Get(canonical_host->second)->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) { |
| - |
| AlternateProtocolInfo alternate(alternate_port, |
| alternate_protocol, |
| alternate_probability); |
| - if (HasAlternateProtocol(server)) { |
| - const AlternateProtocolInfo existing_alternate = |
| - GetAlternateProtocol(server); |
| - |
| - if (existing_alternate.is_broken) { |
| - DVLOG(1) << "Ignore alternate protocol since it's known to be broken."; |
| - return; |
| + // Do not call HasAlternateProtocol(), because we don't care about |
| + // |g_forced_alternate_protocol|, or whether the alternate protocol |
| + // probability is higher than the threshold. |
| + AlternateProtocolMap::iterator map_it = alternate_protocol_map_.Get(server); |
| + 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->EqualsModuloProbabilityAndProtocol(alternate)) { |
|
Bence
2015/01/30 21:24:50
This needs to be EqualsModuloProbability. We coul
|
| + 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 |
| @@ -309,10 +337,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) { |
| @@ -326,19 +354,24 @@ 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) { |
| + 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; |
| + DCHECK(it != alternate_protocols->second.end()); |
| + |
| int count = ++broken_alternate_protocol_map_[server]; |
| base::TimeDelta delay = |
| base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs); |
| @@ -352,20 +385,21 @@ 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) { |
| + const HostPortPair& server, |
| + const AlternateProtocolInfo& alternate_protocol) { |
| return ContainsKey(broken_alternate_protocol_map_, server); |
| } |
| void HttpServerPropertiesImpl::ConfirmAlternateProtocol( |
| - const HostPortPair& server) { |
| + const HostPortPair& server, |
| + const AlternateProtocolInfo& alternate_protocol) { |
| broken_alternate_protocol_map_.erase(server); |
| } |
| @@ -378,6 +412,47 @@ 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()) { |
| + 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); |
| + 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->Equals(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_; |