• 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/http_stream_factory.h"
6 
7 #include <cstddef>
8 #include <tuple>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/check.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/notreached.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/time/time.h"
19 #include "net/base/host_mapping_rules.h"
20 #include "net/base/host_port_pair.h"
21 #include "net/base/load_flags.h"
22 #include "net/base/network_anonymization_key.h"
23 #include "net/base/network_isolation_key.h"
24 #include "net/base/parse_number.h"
25 #include "net/base/port_util.h"
26 #include "net/base/privacy_mode.h"
27 #include "net/base/upload_data_stream.h"
28 #include "net/dns/public/secure_dns_policy.h"
29 #include "net/http/http_network_session.h"
30 #include "net/http/http_response_headers.h"
31 #include "net/http/http_server_properties.h"
32 #include "net/http/http_stream_factory_job.h"
33 #include "net/http/http_stream_factory_job_controller.h"
34 #include "net/http/transport_security_state.h"
35 #include "net/quic/quic_http_utils.h"
36 #include "net/socket/socket_tag.h"
37 #include "net/spdy/bidirectional_stream_spdy_impl.h"
38 #include "net/spdy/spdy_http_stream.h"
39 #include "net/ssl/ssl_config.h"
40 #include "net/third_party/quiche/src/quiche/http2/core/spdy_alt_svc_wire_format.h"
41 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
42 #include "net/third_party/quiche/src/quiche/quic/core/quic_server_id.h"
43 #include "url/gurl.h"
44 #include "url/scheme_host_port.h"
45 #include "url/url_constants.h"
46 
47 namespace net {
48 
49 namespace {
50 const char kAlternativeServiceHeader[] = "Alt-Svc";
51 
52 }  // namespace
53 
54 // static
GetSpdySessionKey(const ProxyChain & proxy_chain,const GURL & origin_url,const StreamRequestInfo & request_info)55 SpdySessionKey HttpStreamFactory::GetSpdySessionKey(
56     const ProxyChain& proxy_chain,
57     const GURL& origin_url,
58     const StreamRequestInfo& request_info) {
59   // In the case that we'll be sending a GET request to the proxy, look for an
60   // HTTP/2 proxy session *to* the proxy, instead of to the origin server. The
61   // way HTTP over HTTPS proxies work is that the ConnectJob makes a SpdyProxy,
62   // and then the HttpStreamFactory detects it when it's added to the
63   // SpdySession pool, and uses it directly (completely ignoring the result of
64   // the ConnectJob, and in fact cancelling it). So we need to create the same
65   // key used by the HttpProxyConnectJob for the last proxy in the chain.
66   if (IsGetToProxy(proxy_chain, origin_url)) {
67     // For this to work as expected, the whole chain should be HTTPS.
68     for (const auto& proxy_server : proxy_chain.proxy_servers()) {
69       CHECK(proxy_server.is_https());
70     }
71     auto [last_proxy_partial_chain, last_proxy_server] =
72         proxy_chain.SplitLast();
73     const auto& last_proxy_host_port_pair = last_proxy_server.host_port_pair();
74     // Note that `disable_cert_network_fetches` must be true for proxies to
75     // avoid deadlock. See comment on
76     // `SSLConfig::disable_cert_verification_network_fetches`.
77     return SpdySessionKey(
78         last_proxy_host_port_pair, PRIVACY_MODE_DISABLED,
79         last_proxy_partial_chain, SessionUsage::kProxy, request_info.socket_tag,
80         request_info.network_anonymization_key, request_info.secure_dns_policy,
81         /*disable_cert_network_fetches=*/true);
82   }
83   return SpdySessionKey(
84       HostPortPair::FromURL(origin_url), request_info.privacy_mode, proxy_chain,
85       SessionUsage::kDestination, request_info.socket_tag,
86       request_info.network_anonymization_key, request_info.secure_dns_policy,
87       request_info.load_flags & LOAD_DISABLE_CERT_NETWORK_FETCHES);
88 }
89 
90 // static
IsGetToProxy(const ProxyChain & proxy_chain,const GURL & origin_url)91 bool HttpStreamFactory::IsGetToProxy(const ProxyChain& proxy_chain,
92                                      const GURL& origin_url) {
93   // Sending proxied GET requests to the last proxy server in the chain is no
94   // longer supported for QUIC.
95   return proxy_chain.is_get_to_proxy_allowed() &&
96          proxy_chain.Last().is_https() && origin_url.SchemeIs(url::kHttpScheme);
97 }
98 
99 HttpStreamFactory::StreamRequestInfo::StreamRequestInfo() = default;
100 
StreamRequestInfo(const HttpRequestInfo & http_request_info)101 HttpStreamFactory::StreamRequestInfo::StreamRequestInfo(
102     const HttpRequestInfo& http_request_info)
103     : method(http_request_info.method),
104       network_anonymization_key(http_request_info.network_anonymization_key),
105       is_http1_allowed(!http_request_info.upload_data_stream ||
106                        http_request_info.upload_data_stream->AllowHTTP1()),
107       load_flags(http_request_info.load_flags),
108       privacy_mode(http_request_info.privacy_mode),
109       secure_dns_policy(http_request_info.secure_dns_policy),
110       socket_tag(http_request_info.socket_tag) {}
111 
112 HttpStreamFactory::StreamRequestInfo::StreamRequestInfo(
113     const StreamRequestInfo& other) = default;
114 HttpStreamFactory::StreamRequestInfo&
115 HttpStreamFactory::StreamRequestInfo::operator=(
116     const StreamRequestInfo& other) = default;
117 HttpStreamFactory::StreamRequestInfo::StreamRequestInfo(
118     StreamRequestInfo&& other) = default;
119 HttpStreamFactory::StreamRequestInfo&
120 HttpStreamFactory::StreamRequestInfo::operator=(StreamRequestInfo&& other) =
121     default;
122 
123 HttpStreamFactory::StreamRequestInfo::~StreamRequestInfo() = default;
124 
HttpStreamFactory(HttpNetworkSession * session)125 HttpStreamFactory::HttpStreamFactory(HttpNetworkSession* session)
126     : session_(session), job_factory_(std::make_unique<JobFactory>()) {}
127 
128 HttpStreamFactory::~HttpStreamFactory() = default;
129 
ProcessAlternativeServices(HttpNetworkSession * session,const NetworkAnonymizationKey & network_anonymization_key,const HttpResponseHeaders * headers,const url::SchemeHostPort & http_server)130 void HttpStreamFactory::ProcessAlternativeServices(
131     HttpNetworkSession* session,
132     const NetworkAnonymizationKey& network_anonymization_key,
133     const HttpResponseHeaders* headers,
134     const url::SchemeHostPort& http_server) {
135   if (!headers->HasHeader(kAlternativeServiceHeader))
136     return;
137 
138   std::string alternative_service_str =
139       headers->GetNormalizedHeader(kAlternativeServiceHeader)
140           .value_or(std::string());
141   spdy::SpdyAltSvcWireFormat::AlternativeServiceVector
142       alternative_service_vector;
143   if (!spdy::SpdyAltSvcWireFormat::ParseHeaderFieldValue(
144           alternative_service_str, &alternative_service_vector)) {
145     return;
146   }
147 
148   session->http_server_properties()->SetAlternativeServices(
149       RewriteHost(http_server), network_anonymization_key,
150       net::ProcessAlternativeServices(
151           alternative_service_vector, session->params().enable_http2,
152           session->params().enable_quic,
153           session->context().quic_context->params()->supported_versions));
154 }
155 
RewriteHost(const url::SchemeHostPort & server)156 url::SchemeHostPort HttpStreamFactory::RewriteHost(
157     const url::SchemeHostPort& server) {
158   HostPortPair host_port_pair(server.host(), server.port());
159   const HostMappingRules* mapping_rules = GetHostMappingRules();
160   if (mapping_rules)
161     mapping_rules->RewriteHost(&host_port_pair);
162   return url::SchemeHostPort(server.scheme(), host_port_pair.host(),
163                              host_port_pair.port());
164 }
165 
RequestStream(const HttpRequestInfo & request_info,RequestPriority priority,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,HttpStreamRequest::Delegate * delegate,bool enable_ip_based_pooling,bool enable_alternative_services,const NetLogWithSource & net_log)166 std::unique_ptr<HttpStreamRequest> HttpStreamFactory::RequestStream(
167     const HttpRequestInfo& request_info,
168     RequestPriority priority,
169     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
170     HttpStreamRequest::Delegate* delegate,
171     bool enable_ip_based_pooling,
172     bool enable_alternative_services,
173     const NetLogWithSource& net_log) {
174   return RequestStreamInternal(request_info, priority, allowed_bad_certs,
175                                delegate, nullptr,
176                                HttpStreamRequest::HTTP_STREAM,
177                                /*is_websocket=*/false, enable_ip_based_pooling,
178                                enable_alternative_services, net_log);
179 }
180 
181 std::unique_ptr<HttpStreamRequest>
RequestWebSocketHandshakeStream(const HttpRequestInfo & request_info,RequestPriority priority,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,HttpStreamRequest::Delegate * delegate,WebSocketHandshakeStreamBase::CreateHelper * create_helper,bool enable_ip_based_pooling,bool enable_alternative_services,const NetLogWithSource & net_log)182 HttpStreamFactory::RequestWebSocketHandshakeStream(
183     const HttpRequestInfo& request_info,
184     RequestPriority priority,
185     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
186     HttpStreamRequest::Delegate* delegate,
187     WebSocketHandshakeStreamBase::CreateHelper* create_helper,
188     bool enable_ip_based_pooling,
189     bool enable_alternative_services,
190     const NetLogWithSource& net_log) {
191   DCHECK(create_helper);
192   return RequestStreamInternal(request_info, priority, allowed_bad_certs,
193                                delegate, create_helper,
194                                HttpStreamRequest::HTTP_STREAM,
195                                /*is_websocket=*/true, enable_ip_based_pooling,
196                                enable_alternative_services, net_log);
197 }
198 
199 std::unique_ptr<HttpStreamRequest>
RequestBidirectionalStreamImpl(const HttpRequestInfo & request_info,RequestPriority priority,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,HttpStreamRequest::Delegate * delegate,bool enable_ip_based_pooling,bool enable_alternative_services,const NetLogWithSource & net_log)200 HttpStreamFactory::RequestBidirectionalStreamImpl(
201     const HttpRequestInfo& request_info,
202     RequestPriority priority,
203     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
204     HttpStreamRequest::Delegate* delegate,
205     bool enable_ip_based_pooling,
206     bool enable_alternative_services,
207     const NetLogWithSource& net_log) {
208   DCHECK(request_info.url.SchemeIs(url::kHttpsScheme));
209 
210   return RequestStreamInternal(request_info, priority, allowed_bad_certs,
211                                delegate, nullptr,
212                                HttpStreamRequest::BIDIRECTIONAL_STREAM,
213                                /*is_websocket=*/false, enable_ip_based_pooling,
214                                enable_alternative_services, net_log);
215 }
216 
RequestStreamInternal(const HttpRequestInfo & request_info,RequestPriority priority,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,HttpStreamRequest::Delegate * delegate,WebSocketHandshakeStreamBase::CreateHelper * websocket_handshake_stream_create_helper,HttpStreamRequest::StreamType stream_type,bool is_websocket,bool enable_ip_based_pooling,bool enable_alternative_services,const NetLogWithSource & net_log)217 std::unique_ptr<HttpStreamRequest> HttpStreamFactory::RequestStreamInternal(
218     const HttpRequestInfo& request_info,
219     RequestPriority priority,
220     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
221     HttpStreamRequest::Delegate* delegate,
222     WebSocketHandshakeStreamBase::CreateHelper*
223         websocket_handshake_stream_create_helper,
224     HttpStreamRequest::StreamType stream_type,
225     bool is_websocket,
226     bool enable_ip_based_pooling,
227     bool enable_alternative_services,
228     const NetLogWithSource& net_log) {
229   // This is only needed in the non-preconnect path, as preconnects do not
230   // require a NetworkIsolationKey.
231   DCHECK(request_info.IsConsistent());
232 
233   auto job_controller = std::make_unique<JobController>(
234       this, delegate, session_, job_factory_.get(), request_info,
235       /* is_preconnect = */ false, is_websocket, enable_ip_based_pooling,
236       enable_alternative_services,
237       session_->context()
238           .quic_context->params()
239           ->delay_main_job_with_available_spdy_session,
240       allowed_bad_certs);
241   JobController* job_controller_raw_ptr = job_controller.get();
242   job_controller_set_.insert(std::move(job_controller));
243   return job_controller_raw_ptr->Start(delegate,
244                                        websocket_handshake_stream_create_helper,
245                                        net_log, stream_type, priority);
246 }
247 
PreconnectStreams(int num_streams,HttpRequestInfo & request_info)248 void HttpStreamFactory::PreconnectStreams(int num_streams,
249                                           HttpRequestInfo& request_info) {
250   // Ignore invalid URLs. This matches the behavior of
251   // URLRequestJobFactory::CreateJob(). Passing very long valid GURLs over Mojo
252   // can result in invalid URLs, so can't rely on callers sending only valid
253   // URLs.
254   if (!request_info.url.is_valid()) {
255     OnPreconnectsCompleteInternal();
256     return;
257   }
258 
259   auto job_controller = std::make_unique<JobController>(
260       this, nullptr, session_, job_factory_.get(), request_info,
261       /*is_preconnect=*/true,
262       /*is_websocket=*/false,
263       /*enable_ip_based_pooling=*/true,
264       /*enable_alternative_services=*/true,
265       session_->context()
266           .quic_context->params()
267           ->delay_main_job_with_available_spdy_session,
268       /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
269   JobController* job_controller_raw_ptr = job_controller.get();
270   job_controller_set_.insert(std::move(job_controller));
271   job_controller_raw_ptr->Preconnect(num_streams);
272 }
273 
GetHostMappingRules() const274 const HostMappingRules* HttpStreamFactory::GetHostMappingRules() const {
275   return &session_->params().host_mapping_rules;
276 }
277 
OnJobControllerComplete(JobController * controller)278 void HttpStreamFactory::OnJobControllerComplete(JobController* controller) {
279   auto it = job_controller_set_.find(controller);
280   if (it != job_controller_set_.end()) {
281     job_controller_set_.erase(it);
282   } else {
283     NOTREACHED();
284   }
285 }
286 
287 }  // namespace net
288