1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/http/alternative_service.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros_local.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
12*6777b538SAndroid Build Coastguard Worker #include "net/base/port_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "net/third_party/quiche/src/quiche/quic/core/http/spdy_utils.h"
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker namespace net {
16*6777b538SAndroid Build Coastguard Worker
HistogramAlternateProtocolUsage(AlternateProtocolUsage usage,bool is_google_host)17*6777b538SAndroid Build Coastguard Worker void HistogramAlternateProtocolUsage(AlternateProtocolUsage usage,
18*6777b538SAndroid Build Coastguard Worker bool is_google_host) {
19*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsage", usage,
20*6777b538SAndroid Build Coastguard Worker ALTERNATE_PROTOCOL_USAGE_MAX);
21*6777b538SAndroid Build Coastguard Worker if (is_google_host) {
22*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolUsageGoogle", usage,
23*6777b538SAndroid Build Coastguard Worker ALTERNATE_PROTOCOL_USAGE_MAX);
24*6777b538SAndroid Build Coastguard Worker }
25*6777b538SAndroid Build Coastguard Worker }
26*6777b538SAndroid Build Coastguard Worker
HistogramBrokenAlternateProtocolLocation(BrokenAlternateProtocolLocation location)27*6777b538SAndroid Build Coastguard Worker void HistogramBrokenAlternateProtocolLocation(
28*6777b538SAndroid Build Coastguard Worker BrokenAlternateProtocolLocation location) {
29*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_ENUMERATION("Net.AlternateProtocolBrokenLocation", location,
30*6777b538SAndroid Build Coastguard Worker BROKEN_ALTERNATE_PROTOCOL_LOCATION_MAX);
31*6777b538SAndroid Build Coastguard Worker }
32*6777b538SAndroid Build Coastguard Worker
IsAlternateProtocolValid(NextProto protocol)33*6777b538SAndroid Build Coastguard Worker bool IsAlternateProtocolValid(NextProto protocol) {
34*6777b538SAndroid Build Coastguard Worker switch (protocol) {
35*6777b538SAndroid Build Coastguard Worker case kProtoUnknown:
36*6777b538SAndroid Build Coastguard Worker return false;
37*6777b538SAndroid Build Coastguard Worker case kProtoHTTP11:
38*6777b538SAndroid Build Coastguard Worker return false;
39*6777b538SAndroid Build Coastguard Worker case kProtoHTTP2:
40*6777b538SAndroid Build Coastguard Worker return true;
41*6777b538SAndroid Build Coastguard Worker case kProtoQUIC:
42*6777b538SAndroid Build Coastguard Worker return true;
43*6777b538SAndroid Build Coastguard Worker }
44*6777b538SAndroid Build Coastguard Worker NOTREACHED();
45*6777b538SAndroid Build Coastguard Worker return false;
46*6777b538SAndroid Build Coastguard Worker }
47*6777b538SAndroid Build Coastguard Worker
IsProtocolEnabled(NextProto protocol,bool is_http2_enabled,bool is_quic_enabled)48*6777b538SAndroid Build Coastguard Worker bool IsProtocolEnabled(NextProto protocol,
49*6777b538SAndroid Build Coastguard Worker bool is_http2_enabled,
50*6777b538SAndroid Build Coastguard Worker bool is_quic_enabled) {
51*6777b538SAndroid Build Coastguard Worker switch (protocol) {
52*6777b538SAndroid Build Coastguard Worker case kProtoUnknown:
53*6777b538SAndroid Build Coastguard Worker NOTREACHED();
54*6777b538SAndroid Build Coastguard Worker return false;
55*6777b538SAndroid Build Coastguard Worker case kProtoHTTP11:
56*6777b538SAndroid Build Coastguard Worker return true;
57*6777b538SAndroid Build Coastguard Worker case kProtoHTTP2:
58*6777b538SAndroid Build Coastguard Worker return is_http2_enabled;
59*6777b538SAndroid Build Coastguard Worker case kProtoQUIC:
60*6777b538SAndroid Build Coastguard Worker return is_quic_enabled;
61*6777b538SAndroid Build Coastguard Worker }
62*6777b538SAndroid Build Coastguard Worker NOTREACHED();
63*6777b538SAndroid Build Coastguard Worker return false;
64*6777b538SAndroid Build Coastguard Worker }
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker // static
67*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo
CreateHttp2AlternativeServiceInfo(const AlternativeService & alternative_service,base::Time expiration)68*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
69*6777b538SAndroid Build Coastguard Worker const AlternativeService& alternative_service,
70*6777b538SAndroid Build Coastguard Worker base::Time expiration) {
71*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(alternative_service.protocol, kProtoHTTP2);
72*6777b538SAndroid Build Coastguard Worker return AlternativeServiceInfo(alternative_service, expiration,
73*6777b538SAndroid Build Coastguard Worker quic::ParsedQuicVersionVector());
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker // static
CreateQuicAlternativeServiceInfo(const AlternativeService & alternative_service,base::Time expiration,const quic::ParsedQuicVersionVector & advertised_versions)77*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
78*6777b538SAndroid Build Coastguard Worker const AlternativeService& alternative_service,
79*6777b538SAndroid Build Coastguard Worker base::Time expiration,
80*6777b538SAndroid Build Coastguard Worker const quic::ParsedQuicVersionVector& advertised_versions) {
81*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(alternative_service.protocol, kProtoQUIC);
82*6777b538SAndroid Build Coastguard Worker return AlternativeServiceInfo(alternative_service, expiration,
83*6777b538SAndroid Build Coastguard Worker advertised_versions);
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
AlternativeServiceInfo()86*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::AlternativeServiceInfo() : alternative_service_() {}
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::~AlternativeServiceInfo() = default;
89*6777b538SAndroid Build Coastguard Worker
AlternativeServiceInfo(const AlternativeService & alternative_service,base::Time expiration,const quic::ParsedQuicVersionVector & advertised_versions)90*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::AlternativeServiceInfo(
91*6777b538SAndroid Build Coastguard Worker const AlternativeService& alternative_service,
92*6777b538SAndroid Build Coastguard Worker base::Time expiration,
93*6777b538SAndroid Build Coastguard Worker const quic::ParsedQuicVersionVector& advertised_versions)
94*6777b538SAndroid Build Coastguard Worker : alternative_service_(alternative_service), expiration_(expiration) {
95*6777b538SAndroid Build Coastguard Worker if (alternative_service_.protocol == kProtoQUIC) {
96*6777b538SAndroid Build Coastguard Worker advertised_versions_ = advertised_versions;
97*6777b538SAndroid Build Coastguard Worker }
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::AlternativeServiceInfo(
101*6777b538SAndroid Build Coastguard Worker const AlternativeServiceInfo& alternative_service_info) = default;
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo& AlternativeServiceInfo::operator=(
104*6777b538SAndroid Build Coastguard Worker const AlternativeServiceInfo& alternative_service_info) = default;
105*6777b538SAndroid Build Coastguard Worker
ToString() const106*6777b538SAndroid Build Coastguard Worker std::string AlternativeService::ToString() const {
107*6777b538SAndroid Build Coastguard Worker return base::StringPrintf("%s %s:%d", NextProtoToString(protocol),
108*6777b538SAndroid Build Coastguard Worker host.c_str(), port);
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker
ToString() const111*6777b538SAndroid Build Coastguard Worker std::string AlternativeServiceInfo::ToString() const {
112*6777b538SAndroid Build Coastguard Worker // NOTE: Cannot use `base::UnlocalizedTimeFormatWithPattern()` since
113*6777b538SAndroid Build Coastguard Worker // `net/DEPS` disallows `base/i18n`.
114*6777b538SAndroid Build Coastguard Worker base::Time::Exploded exploded;
115*6777b538SAndroid Build Coastguard Worker expiration_.LocalExplode(&exploded);
116*6777b538SAndroid Build Coastguard Worker return base::StringPrintf(
117*6777b538SAndroid Build Coastguard Worker "%s, expires %04d-%02d-%02d %02d:%02d:%02d",
118*6777b538SAndroid Build Coastguard Worker alternative_service_.ToString().c_str(), exploded.year, exploded.month,
119*6777b538SAndroid Build Coastguard Worker exploded.day_of_month, exploded.hour, exploded.minute, exploded.second);
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker // static
TransportVersionLessThan(const quic::ParsedQuicVersion & lhs,const quic::ParsedQuicVersion & rhs)123*6777b538SAndroid Build Coastguard Worker bool AlternativeServiceInfo::TransportVersionLessThan(
124*6777b538SAndroid Build Coastguard Worker const quic::ParsedQuicVersion& lhs,
125*6777b538SAndroid Build Coastguard Worker const quic::ParsedQuicVersion& rhs) {
126*6777b538SAndroid Build Coastguard Worker return lhs.transport_version < rhs.transport_version;
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker
operator <<(std::ostream & os,const AlternativeService & alternative_service)129*6777b538SAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os,
130*6777b538SAndroid Build Coastguard Worker const AlternativeService& alternative_service) {
131*6777b538SAndroid Build Coastguard Worker os << alternative_service.ToString();
132*6777b538SAndroid Build Coastguard Worker return os;
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
ProcessAlternativeServices(const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & alternative_service_vector,bool is_http2_enabled,bool is_quic_enabled,const quic::ParsedQuicVersionVector & supported_quic_versions)135*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfoVector ProcessAlternativeServices(
136*6777b538SAndroid Build Coastguard Worker const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector&
137*6777b538SAndroid Build Coastguard Worker alternative_service_vector,
138*6777b538SAndroid Build Coastguard Worker bool is_http2_enabled,
139*6777b538SAndroid Build Coastguard Worker bool is_quic_enabled,
140*6777b538SAndroid Build Coastguard Worker const quic::ParsedQuicVersionVector& supported_quic_versions) {
141*6777b538SAndroid Build Coastguard Worker // Convert spdy::SpdyAltSvcWireFormat::AlternativeService entries
142*6777b538SAndroid Build Coastguard Worker // to net::AlternativeServiceInfo.
143*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfoVector alternative_service_info_vector;
144*6777b538SAndroid Build Coastguard Worker for (const spdy::SpdyAltSvcWireFormat::AlternativeService&
145*6777b538SAndroid Build Coastguard Worker alternative_service_entry : alternative_service_vector) {
146*6777b538SAndroid Build Coastguard Worker if (!IsPortValid(alternative_service_entry.port))
147*6777b538SAndroid Build Coastguard Worker continue;
148*6777b538SAndroid Build Coastguard Worker
149*6777b538SAndroid Build Coastguard Worker NextProto protocol =
150*6777b538SAndroid Build Coastguard Worker NextProtoFromString(alternative_service_entry.protocol_id);
151*6777b538SAndroid Build Coastguard Worker quic::ParsedQuicVersionVector advertised_versions;
152*6777b538SAndroid Build Coastguard Worker if (protocol == kProtoQUIC) {
153*6777b538SAndroid Build Coastguard Worker continue; // Ignore legacy QUIC alt-svc advertisements.
154*6777b538SAndroid Build Coastguard Worker } else if (!IsAlternateProtocolValid(protocol)) {
155*6777b538SAndroid Build Coastguard Worker quic::ParsedQuicVersion version =
156*6777b538SAndroid Build Coastguard Worker quic::SpdyUtils::ExtractQuicVersionFromAltSvcEntry(
157*6777b538SAndroid Build Coastguard Worker alternative_service_entry, supported_quic_versions);
158*6777b538SAndroid Build Coastguard Worker if (version == quic::ParsedQuicVersion::Unsupported()) {
159*6777b538SAndroid Build Coastguard Worker continue;
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker protocol = kProtoQUIC;
162*6777b538SAndroid Build Coastguard Worker advertised_versions = {version};
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker if (!IsAlternateProtocolValid(protocol) ||
165*6777b538SAndroid Build Coastguard Worker !IsProtocolEnabled(protocol, is_http2_enabled, is_quic_enabled)) {
166*6777b538SAndroid Build Coastguard Worker continue;
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker AlternativeService alternative_service(protocol,
170*6777b538SAndroid Build Coastguard Worker alternative_service_entry.host,
171*6777b538SAndroid Build Coastguard Worker alternative_service_entry.port);
172*6777b538SAndroid Build Coastguard Worker base::Time expiration =
173*6777b538SAndroid Build Coastguard Worker base::Time::Now() +
174*6777b538SAndroid Build Coastguard Worker base::Seconds(alternative_service_entry.max_age_seconds);
175*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo alternative_service_info;
176*6777b538SAndroid Build Coastguard Worker if (protocol == kProtoQUIC) {
177*6777b538SAndroid Build Coastguard Worker alternative_service_info =
178*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
179*6777b538SAndroid Build Coastguard Worker alternative_service, expiration, advertised_versions);
180*6777b538SAndroid Build Coastguard Worker } else {
181*6777b538SAndroid Build Coastguard Worker alternative_service_info =
182*6777b538SAndroid Build Coastguard Worker AlternativeServiceInfo::CreateHttp2AlternativeServiceInfo(
183*6777b538SAndroid Build Coastguard Worker alternative_service, expiration);
184*6777b538SAndroid Build Coastguard Worker }
185*6777b538SAndroid Build Coastguard Worker alternative_service_info_vector.push_back(alternative_service_info);
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker return alternative_service_info_vector;
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker } // namespace net
191