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