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..15871b530866b780a6d9914b9272aa86fb83e98d 100644 |
--- a/net/http/http_server_properties_impl.cc |
+++ b/net/http/http_server_properties_impl.cc |
@@ -4,6 +4,8 @@ |
#include "net/http/http_server_properties_impl.h" |
+#include <algorithm> |
+ |
#include "base/bind.h" |
#include "base/location.h" |
#include "base/logging.h" |
@@ -53,25 +55,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 +190,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,66 +267,103 @@ 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(); |
+ return AlternativeServiceVector(); |
} |
- 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(); |
- } |
- 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( |
+bool HttpServerPropertiesImpl::SetAlternativeService( |
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() && |
- alternative_probability >= alternative_service_probability_threshold_) { |
+ return SetAlternativeServices( |
+ origin, AlternativeServiceInfoVector( |
+ /*size=*/1, AlternativeServiceInfo(alternative_service, |
+ alternative_probability))); |
+} |
+ |
+bool HttpServerPropertiesImpl::SetAlternativeServices( |
+ const HostPortPair& origin, |
+ const AlternativeServiceInfoVector& alternative_service_info_vector) { |
+ AlternativeServiceMap::iterator it = alternative_service_map_.Peek(origin); |
+ |
+ if (alternative_service_info_vector.empty()) { |
+ if (it == alternative_service_map_.end()) { |
+ return false; |
+ } |
+ ClearAlternativeServices(origin); |
+ return true; |
+ } |
+ |
+ bool changed = true; |
+ if (it != alternative_service_map_.end()) { |
+ DCHECK(!it->second.empty()); |
+ if (it->second.size() == alternative_service_info_vector.size()) { |
+ changed = !std::equal(it->second.begin(), it->second.end(), |
+ alternative_service_info_vector.begin()); |
+ } |
+ } |
+ |
+ const bool previously_no_alternative_services = |
+ (GetAlternateProtocolIterator(origin) == alternative_service_map_.end()); |
+ |
+ alternative_service_map_.Put(origin, alternative_service_info_vector); |
+ |
+ if (previously_no_alternative_services && |
+ !GetAlternativeServices(origin).empty()) { |
// 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); |
} |
- alternative_service_map_.Put(origin, alternative_service_info); |
- |
// 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) { |
@@ -306,6 +374,8 @@ void HttpServerPropertiesImpl::SetAlternativeService( |
break; |
} |
} |
+ |
+ return changed; |
} |
void HttpServerPropertiesImpl::MarkAlternativeServiceBroken( |
@@ -363,7 +433,7 @@ void HttpServerPropertiesImpl::ConfirmAlternativeService( |
recently_broken_alternative_services_.erase(alternative_service); |
} |
-void HttpServerPropertiesImpl::ClearAlternativeService( |
+void HttpServerPropertiesImpl::ClearAlternativeServices( |
const HostPortPair& origin) { |
RemoveCanonicalHost(origin); |
@@ -382,24 +452,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_service", |
+ scoped_ptr<base::Value>(alternative_service_list.Pass())); |
dict_list->Append(dict.Pass()); |
} |
return dict_list.Pass(); |
@@ -515,11 +592,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 +644,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(); |