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 535c915477358ae03584c23ef39b8c33f9ef5548..9bfb9cbb5871379e451d636224044f7c676fbd07 100644 |
--- a/net/http/http_server_properties_impl.cc |
+++ b/net/http/http_server_properties_impl.cc |
@@ -53,25 +53,48 @@ void HttpServerPropertiesImpl::InitializeSpdyServers( |
void HttpServerPropertiesImpl::InitializeAlternativeServiceServers( |
AlternativeServiceMap* alternative_service_map) { |
- // Keep all the broken ones since those don't get persisted. |
- for (AlternativeServiceMap::iterator it = alternative_service_map_.begin(); |
- it != alternative_service_map_.end();) { |
- AlternativeService alternative_service(it->second.alternative_service); |
- if (alternative_service.host.empty()) { |
- alternative_service.host = it->first.host(); |
+ for (AlternativeServiceMap::iterator map_it = |
+ alternative_service_map_.begin(); |
+ map_it != alternative_service_map_.end();) { |
+ for (AlternativeServiceInfoVector::iterator it = map_it->second.begin(); |
+ it != map_it->second.end();) { |
+ // Keep all the broken ones since those do not get persisted. |
+ AlternativeService alternative_service(it->alternative_service); |
+ if (alternative_service.host.empty()) { |
+ alternative_service.host = map_it->first.host(); |
+ } |
+ if (IsAlternativeServiceBroken(alternative_service)) { |
+ ++it; |
+ continue; |
+ } |
+ it = map_it->second.erase(it); |
} |
- if (IsAlternativeServiceBroken(alternative_service)) { |
- ++it; |
- } else { |
- it = alternative_service_map_.Erase(it); |
+ if (map_it->second.empty()) { |
+ RemoveCanonicalHost(map_it->first); |
+ map_it = alternative_service_map_.Erase(map_it); |
+ continue; |
} |
+ ++map_it; |
} |
// Add the entries from persisted data. |
- for (AlternativeServiceMap::reverse_iterator it = |
+ for (AlternativeServiceMap::reverse_iterator input_it = |
alternative_service_map->rbegin(); |
- it != alternative_service_map->rend(); ++it) { |
- alternative_service_map_.Put(it->first, it->second); |
+ input_it != alternative_service_map->rend(); ++input_it) { |
+ AlternativeServiceMap::iterator output_it = |
+ alternative_service_map_.Peek(input_it->first); |
+ if (output_it == alternative_service_map_.end()) { |
+ // There is no value in alternative_service_map_ for input_it->first: |
+ // inserting in AlternativeServiceVectorInfo. |
+ alternative_service_map_.Put(input_it->first, input_it->second); |
+ continue; |
+ } |
+ // There are some broken alternative services in alternative_service_map_ |
+ // for input_it->first: appending AlternativeServiceInfo one by one. |
+ for (const AlternativeServiceInfo& alternative_service_info : |
+ input_it->second) { |
+ output_it->second.push_back(alternative_service_info); |
+ } |
} |
// Attempt to find canonical servers. |
@@ -165,9 +188,15 @@ bool HttpServerPropertiesImpl::SupportsRequestPriority( |
if (GetSupportsSpdy(host_port_pair)) |
return true; |
- const AlternativeService alternative_service = |
- GetAlternativeService(host_port_pair); |
- return alternative_service.protocol == QUIC; |
+ const AlternativeServiceVector alternative_service_vector = |
+ GetAlternativeServices(host_port_pair); |
+ for (const AlternativeService& alternative_service : |
+ alternative_service_vector) { |
+ if (alternative_service.protocol == QUIC) { |
+ return true; |
+ } |
+ } |
+ return false; |
} |
bool HttpServerPropertiesImpl::GetSupportsSpdy( |
@@ -236,57 +265,65 @@ std::string HttpServerPropertiesImpl::GetCanonicalSuffix( |
return std::string(); |
} |
-AlternativeService HttpServerPropertiesImpl::GetAlternativeService( |
+AlternativeServiceVector HttpServerPropertiesImpl::GetAlternativeServices( |
const HostPortPair& origin) { |
+ // Copy alternative services with probability greater than or equal to the |
+ // threshold into |alternative_services_above_threshold|. |
+ AlternativeServiceVector alternative_services_above_threshold; |
AlternativeServiceMap::const_iterator it = |
alternative_service_map_.Get(origin); |
if (it != alternative_service_map_.end()) { |
- if (it->second.probability < alternative_service_probability_threshold_) { |
- return AlternativeService(); |
- } |
- AlternativeService alternative_service(it->second.alternative_service); |
- if (alternative_service.host.empty()) { |
- alternative_service.host = origin.host(); |
+ for (const AlternativeServiceInfo& alternative_service_info : it->second) { |
+ if (alternative_service_info.probability < |
+ alternative_service_probability_threshold_) { |
+ continue; |
+ } |
+ AlternativeService alternative_service( |
+ alternative_service_info.alternative_service); |
+ if (alternative_service.host.empty()) { |
+ alternative_service.host = origin.host(); |
+ } |
+ alternative_services_above_threshold.push_back(alternative_service); |
} |
- return alternative_service; |
+ return alternative_services_above_threshold; |
} |
CanonicalHostMap::const_iterator canonical = GetCanonicalHost(origin); |
if (canonical == canonical_host_to_origin_map_.end()) { |
- return AlternativeService(); |
+ return AlternativeServiceVector(); |
} |
it = alternative_service_map_.Get(canonical->second); |
if (it == alternative_service_map_.end()) { |
- return AlternativeService(); |
- } |
- if (it->second.probability < alternative_service_probability_threshold_) { |
- return AlternativeService(); |
- } |
- AlternativeService alternative_service(it->second.alternative_service); |
- if (alternative_service.host.empty()) { |
- alternative_service.host = canonical->second.host(); |
+ return AlternativeServiceVector(); |
} |
- if (IsAlternativeServiceBroken(alternative_service)) { |
- RemoveCanonicalHost(canonical->second); |
- return AlternativeService(); |
- } |
- // Empty hostname: if alternative service for with hostname of canonical host |
- // is not broken, then return alternative service with hostname of origin. |
- if (it->second.alternative_service.host.empty()) { |
- alternative_service.host = origin.host(); |
+ for (const AlternativeServiceInfo& alternative_service_info : it->second) { |
+ if (alternative_service_info.probability < |
+ alternative_service_probability_threshold_) { |
+ continue; |
+ } |
+ AlternativeService alternative_service( |
+ alternative_service_info.alternative_service); |
+ if (alternative_service.host.empty()) { |
+ alternative_service.host = canonical->second.host(); |
+ if (IsAlternativeServiceBroken(alternative_service)) { |
+ continue; |
+ } |
+ alternative_service.host = origin.host(); |
+ } else if (IsAlternativeServiceBroken(alternative_service)) { |
+ continue; |
+ } |
+ alternative_services_above_threshold.push_back(alternative_service); |
} |
- return alternative_service; |
+ return alternative_services_above_threshold; |
} |
-void HttpServerPropertiesImpl::SetAlternativeService( |
+void HttpServerPropertiesImpl::AddAlternativeService( |
const HostPortPair& origin, |
const AlternativeService& alternative_service, |
double alternative_probability) { |
- const AlternativeServiceInfo alternative_service_info( |
- alternative_service, alternative_probability); |
- AlternativeServiceMap::const_iterator it = |
- GetAlternateProtocolIterator(origin); |
- if (it == alternative_service_map_.end() && |
+ DCHECK(IsAlternateProtocolValid(alternative_service.protocol)); |
+ |
+ if (GetAlternateProtocolIterator(origin) == alternative_service_map_.end() && |
alternative_probability >= alternative_service_probability_threshold_) { |
// TODO(rch): Consider the case where multiple requests are started |
// before the first completes. In this case, only one of the jobs |
@@ -294,7 +331,35 @@ void HttpServerPropertiesImpl::SetAlternativeService( |
HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING); |
} |
- alternative_service_map_.Put(origin, alternative_service_info); |
+ const AlternativeServiceInfo alternative_service_info( |
+ alternative_service, alternative_probability); |
+ AlternativeServiceMap::iterator map_it = alternative_service_map_.Get(origin); |
+ if (map_it == alternative_service_map_.end()) { |
+ alternative_service_map_.Put( |
+ origin, |
+ AlternativeServiceInfoVector(/*size=*/1, alternative_service_info)); |
+ } else { |
+ AlternativeServiceInfoVector& existing_alternative_service_info_vector = |
+ map_it->second; |
+ AlternativeServiceInfoVector::iterator it; |
+ for (it = existing_alternative_service_info_vector.begin(); |
+ it != existing_alternative_service_info_vector.end(); ++it) { |
+ if (*it == alternative_service_info) { |
+ // Alternative service info is identical to an existing one. |
+ return; |
+ } |
+ if (it->alternative_service == alternative_service) { |
+ // Different info (for example, probability) for existing alternative |
+ // service: change alternative_service_info. |
+ *it = alternative_service_info; |
+ break; |
+ } |
+ } |
+ if (it == existing_alternative_service_info_vector.end()) { |
+ existing_alternative_service_info_vector.push_back( |
+ alternative_service_info); |
+ } |
+ } |
// If this host ends with a canonical suffix, then set it as the |
// canonical host. |
@@ -363,7 +428,7 @@ void HttpServerPropertiesImpl::ConfirmAlternativeService( |
recently_broken_alternative_services_.erase(alternative_service); |
} |
-void HttpServerPropertiesImpl::ClearAlternativeService( |
+void HttpServerPropertiesImpl::ClearAlternativeServices( |
const HostPortPair& origin) { |
RemoveCanonicalHost(origin); |
@@ -382,24 +447,31 @@ const AlternativeServiceMap& HttpServerPropertiesImpl::alternative_service_map() |
scoped_ptr<base::Value> |
HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue() |
const { |
- scoped_ptr<base::ListValue> dict_list(new base::ListValue()); |
+ scoped_ptr<base::ListValue> dict_list(new base::ListValue); |
for (const auto& alternative_service_map_item : alternative_service_map_) { |
+ scoped_ptr<base::ListValue> alternative_service_list(new base::ListValue); |
const HostPortPair& host_port_pair = alternative_service_map_item.first; |
- const AlternativeServiceInfo& alternative_service_info = |
- alternative_service_map_item.second; |
- std::string alternative_service_string(alternative_service_info.ToString()); |
- AlternativeService alternative_service( |
- alternative_service_info.alternative_service); |
- if (alternative_service.host.empty()) { |
- alternative_service.host = host_port_pair.host(); |
- } |
- if (IsAlternativeServiceBroken(alternative_service)) { |
- alternative_service_string.append(" (broken)"); |
+ for (const AlternativeServiceInfo& alternative_service_info : |
+ alternative_service_map_item.second) { |
+ std::string alternative_service_string( |
+ alternative_service_info.ToString()); |
+ AlternativeService alternative_service( |
+ alternative_service_info.alternative_service); |
+ if (alternative_service.host.empty()) { |
+ alternative_service.host = host_port_pair.host(); |
+ } |
+ if (IsAlternativeServiceBroken(alternative_service)) { |
+ alternative_service_string.append(" (broken)"); |
+ } |
+ alternative_service_list->Append( |
+ new base::StringValue(alternative_service_string)); |
} |
- |
+ if (alternative_service_list->empty()) |
+ continue; |
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
dict->SetString("host_port_pair", host_port_pair.ToString()); |
- dict->SetString("alternative_service", alternative_service_string); |
+ dict->Set("alternative_services", |
+ scoped_ptr<base::Value>(alternative_service_list.Pass())); |
dict_list->Append(dict.Pass()); |
} |
return dict_list.Pass(); |
@@ -515,11 +587,15 @@ HttpServerPropertiesImpl::GetAlternateProtocolIterator( |
return alternative_service_map_.end(); |
} |
- const AlternativeService alternative_service( |
- it->second.alternative_service.protocol, canonical_host_port.host(), |
- it->second.alternative_service.port); |
- if (!IsAlternativeServiceBroken(alternative_service)) { |
- return it; |
+ for (const AlternativeServiceInfo& alternative_service_info : it->second) { |
+ AlternativeService alternative_service( |
+ alternative_service_info.alternative_service); |
+ if (alternative_service.host.empty()) { |
+ alternative_service.host = canonical_host_port.host(); |
+ } |
+ if (!IsAlternativeServiceBroken(alternative_service)) { |
+ return it; |
+ } |
} |
RemoveCanonicalHost(canonical_host_port); |
@@ -563,7 +639,7 @@ void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() { |
const AlternativeService alternative_service = it->first; |
broken_alternative_services_.erase(it); |
// TODO(bnc): Make sure broken alternative services are not in the mapping. |
- ClearAlternativeService( |
+ ClearAlternativeServices( |
HostPortPair(alternative_service.host, alternative_service.port)); |
} |
ScheduleBrokenAlternateProtocolMappingsExpiration(); |