|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/http/http_server_properties.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/metrics/histogram_macros.h" | 
|  | #include "base/strings/stringprintf.h" | 
|  | #include "net/http/http_network_session.h" | 
|  | #include "net/socket/ssl_client_socket.h" | 
|  | #include "net/ssl/ssl_config.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | enum AlternativeProxyUsage { | 
|  | // Alternative Proxy was used without racing a normal connection. | 
|  | ALTERNATIVE_PROXY_USAGE_NO_RACE = 0, | 
|  | // Alternative Proxy was used by winning a race with a normal connection. | 
|  | ALTERNATIVE_PROXY_USAGE_WON_RACE = 1, | 
|  | // Alternative Proxy was not used by losing a race with a normal connection. | 
|  | ALTERNATIVE_PROXY_USAGE_LOST_RACE = 2, | 
|  | // Maximum value for the enum. | 
|  | ALTERNATIVE_PROXY_USAGE_MAX, | 
|  | }; | 
|  |  | 
|  | AlternativeProxyUsage ConvertProtocolUsageToProxyUsage( | 
|  | AlternateProtocolUsage usage) { | 
|  | switch (usage) { | 
|  | case ALTERNATE_PROTOCOL_USAGE_NO_RACE: | 
|  | return ALTERNATIVE_PROXY_USAGE_NO_RACE; | 
|  | case ALTERNATE_PROTOCOL_USAGE_WON_RACE: | 
|  | return ALTERNATIVE_PROXY_USAGE_WON_RACE; | 
|  | case ALTERNATE_PROTOCOL_USAGE_LOST_RACE: | 
|  | return ALTERNATIVE_PROXY_USAGE_LOST_RACE; | 
|  | default: | 
|  | NOTREACHED(); | 
|  | return ALTERNATIVE_PROXY_USAGE_MAX; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // anonymous namespace | 
|  |  | 
|  | const char kAlternativeServiceHeader[] = "Alt-Svc"; | 
|  |  | 
|  | void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage, | 
|  | bool proxy_server_used) { | 
|  | if (proxy_server_used) { | 
|  | DCHECK_LE(usage, ALTERNATE_PROTOCOL_USAGE_LOST_RACE); | 
|  | UMA_HISTOGRAM_ENUMERATION("Net.QuicAlternativeProxy.Usage", | 
|  | ConvertProtocolUsageToProxyUsage(usage), | 
|  | ALTERNATIVE_PROXY_USAGE_MAX); | 
|  | } else { | 
|  | UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage, | 
|  | ALTERNATE_PROTOCOL_USAGE_MAX); | 
|  | } | 
|  | } | 
|  |  | 
|  | void HistogramBrokenAlternateProtocolLocation( | 
|  | BrokenAlternateProtocolLocation location){ | 
|  | UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolBrokenLocation", location, | 
|  | BROKEN_ALTERNATE_PROTOCOL_LOCATION_MAX); | 
|  | } | 
|  |  | 
|  | bool IsAlternateProtocolValid(NextProto protocol) { | 
|  | switch (protocol) { | 
|  | case kProtoUnknown: | 
|  | return false; | 
|  | case kProtoHTTP11: | 
|  | return false; | 
|  | case kProtoHTTP2: | 
|  | return true; | 
|  | case kProtoQUIC: | 
|  | return true; | 
|  | } | 
|  | NOTREACHED(); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // static | 
|  | AlternativeServiceInfo | 
|  | AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo( | 
|  | const AlternativeService& alternative_service, | 
|  | base::Time expiration) { | 
|  | DCHECK_EQ(alternative_service.protocol, kProtoHTTP2); | 
|  | return AlternativeServiceInfo(alternative_service, expiration, | 
|  | quic::QuicTransportVersionVector()); | 
|  | } | 
|  |  | 
|  | // static | 
|  | AlternativeServiceInfo AlternativeServiceInfo::CreateQuicAlternativeServiceInfo( | 
|  | const AlternativeService& alternative_service, | 
|  | base::Time expiration, | 
|  | const quic::QuicTransportVersionVector& advertised_versions) { | 
|  | DCHECK_EQ(alternative_service.protocol, kProtoQUIC); | 
|  | return AlternativeServiceInfo(alternative_service, expiration, | 
|  | advertised_versions); | 
|  | } | 
|  |  | 
|  | AlternativeServiceInfo::AlternativeServiceInfo() : alternative_service_() {} | 
|  |  | 
|  | AlternativeServiceInfo::~AlternativeServiceInfo() = default; | 
|  |  | 
|  | AlternativeServiceInfo::AlternativeServiceInfo( | 
|  | const AlternativeService& alternative_service, | 
|  | base::Time expiration, | 
|  | const quic::QuicTransportVersionVector& advertised_versions) | 
|  | : alternative_service_(alternative_service), expiration_(expiration) { | 
|  | if (alternative_service_.protocol == kProtoQUIC) { | 
|  | advertised_versions_ = advertised_versions; | 
|  | std::sort(advertised_versions_.begin(), advertised_versions_.end()); | 
|  | } | 
|  | } | 
|  |  | 
|  | AlternativeServiceInfo::AlternativeServiceInfo( | 
|  | const AlternativeServiceInfo& alternative_service_info) = default; | 
|  |  | 
|  | AlternativeServiceInfo& AlternativeServiceInfo::operator=( | 
|  | const AlternativeServiceInfo& alternative_service_info) = default; | 
|  |  | 
|  | std::string AlternativeService::ToString() const { | 
|  | return base::StringPrintf("%s %s:%d", NextProtoToString(protocol), | 
|  | host.c_str(), port); | 
|  | } | 
|  |  | 
|  | std::string AlternativeServiceInfo::ToString() const { | 
|  | base::Time::Exploded exploded; | 
|  | expiration_.LocalExplode(&exploded); | 
|  | return base::StringPrintf( | 
|  | "%s, expires %04d-%02d-%02d %02d:%02d:%02d", | 
|  | alternative_service_.ToString().c_str(), exploded.year, exploded.month, | 
|  | exploded.day_of_month, exploded.hour, exploded.minute, exploded.second); | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, | 
|  | const AlternativeService& alternative_service) { | 
|  | os << alternative_service.ToString(); | 
|  | return os; | 
|  | } | 
|  |  | 
|  | // static | 
|  | void HttpServerProperties::ForceHTTP11(SSLConfig* ssl_config) { | 
|  | ssl_config->alpn_protos.clear(); | 
|  | ssl_config->alpn_protos.push_back(kProtoHTTP11); | 
|  | } | 
|  |  | 
|  | }  // namespace net |