| 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();
|
|
|