1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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_job.h"
6 
7 #include <algorithm>
8 #include <string>
9 
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/check_op.h"
13 #include "base/feature_list.h"
14 #include "base/location.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "base/metrics/sparse_histogram.h"
17 #include "base/notreached.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_number_conversions.h"
21 #include "base/strings/string_util.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "base/trace_event/trace_event.h"
24 #include "base/values.h"
25 #include "build/build_config.h"
26 #include "net/base/port_util.h"
27 #include "net/base/proxy_delegate.h"
28 #include "net/base/trace_constants.h"
29 #include "net/cert/cert_verifier.h"
30 #include "net/http/bidirectional_stream_impl.h"
31 #include "net/http/http_basic_stream.h"
32 #include "net/http/http_network_session.h"
33 #include "net/http/http_proxy_client_socket.h"
34 #include "net/http/http_request_info.h"
35 #include "net/http/http_server_properties.h"
36 #include "net/http/http_stream_factory.h"
37 #include "net/http/proxy_fallback.h"
38 #include "net/log/net_log.h"
39 #include "net/log/net_log_capture_mode.h"
40 #include "net/log/net_log_event_type.h"
41 #include "net/log/net_log_source.h"
42 #include "net/log/net_log_source_type.h"
43 #include "net/quic/bidirectional_stream_quic_impl.h"
44 #include "net/quic/quic_http_stream.h"
45 #include "net/socket/client_socket_handle.h"
46 #include "net/socket/client_socket_pool_manager.h"
47 #include "net/socket/connect_job.h"
48 #include "net/socket/ssl_client_socket.h"
49 #include "net/socket/stream_socket.h"
50 #include "net/spdy/bidirectional_stream_spdy_impl.h"
51 #include "net/spdy/http2_push_promise_index.h"
52 #include "net/spdy/spdy_http_stream.h"
53 #include "net/spdy/spdy_session.h"
54 #include "net/ssl/ssl_cert_request_info.h"
55 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
56 #include "url/url_constants.h"
57 
58 namespace net {
59 
60 namespace {
61 
62 // Experiment to preconnect only one connection if HttpServerProperties is
63 // not supported or initialized.
64 const base::Feature kLimitEarlyPreconnectsExperiment{
65     "LimitEarlyPreconnects", base::FEATURE_ENABLED_BY_DEFAULT};
66 
67 }  // namespace
68 
69 // Returns parameters associated with the start of a HTTP stream job.
NetLogHttpStreamJobParams(const NetLogSource & source,const GURL & original_url,const GURL & url,bool expect_spdy,bool using_quic,RequestPriority priority)70 base::Value NetLogHttpStreamJobParams(const NetLogSource& source,
71                                       const GURL& original_url,
72                                       const GURL& url,
73                                       bool expect_spdy,
74                                       bool using_quic,
75                                       RequestPriority priority) {
76   base::Value dict(base::Value::Type::DICTIONARY);
77   if (source.IsValid())
78     source.AddToEventParameters(&dict);
79   dict.SetStringKey("original_url", original_url.GetOrigin().spec());
80   dict.SetStringKey("url", url.GetOrigin().spec());
81   dict.SetBoolKey("expect_spdy", expect_spdy);
82   dict.SetBoolKey("using_quic", using_quic);
83   dict.SetStringKey("priority", RequestPriorityToString(priority));
84   return dict;
85 }
86 
87 // Returns parameters associated with the Proto (with NPN negotiation) of a HTTP
88 // stream.
NetLogHttpStreamProtoParams(NextProto negotiated_protocol)89 base::Value NetLogHttpStreamProtoParams(NextProto negotiated_protocol) {
90   base::Value dict(base::Value::Type::DICTIONARY);
91 
92   dict.SetStringKey("proto", NextProtoToString(negotiated_protocol));
93   return dict;
94 }
95 
Job(Delegate * delegate,JobType job_type,HttpNetworkSession * session,const HttpRequestInfo & request_info,RequestPriority priority,const ProxyInfo & proxy_info,const SSLConfig & server_ssl_config,const SSLConfig & proxy_ssl_config,HostPortPair destination,GURL origin_url,NextProto alternative_protocol,quic::ParsedQuicVersion quic_version,bool is_websocket,bool enable_ip_based_pooling,NetLog * net_log)96 HttpStreamFactory::Job::Job(Delegate* delegate,
97                             JobType job_type,
98                             HttpNetworkSession* session,
99                             const HttpRequestInfo& request_info,
100                             RequestPriority priority,
101                             const ProxyInfo& proxy_info,
102                             const SSLConfig& server_ssl_config,
103                             const SSLConfig& proxy_ssl_config,
104                             HostPortPair destination,
105                             GURL origin_url,
106                             NextProto alternative_protocol,
107                             quic::ParsedQuicVersion quic_version,
108                             bool is_websocket,
109                             bool enable_ip_based_pooling,
110                             NetLog* net_log)
111     : request_info_(request_info),
112       priority_(priority),
113       proxy_info_(proxy_info),
114       server_ssl_config_(server_ssl_config),
115       proxy_ssl_config_(proxy_ssl_config),
116       net_log_(
117           NetLogWithSource::Make(net_log, NetLogSourceType::HTTP_STREAM_JOB)),
118       io_callback_(
119           base::BindRepeating(&Job::OnIOComplete, base::Unretained(this))),
120       connection_(new ClientSocketHandle),
121       session_(session),
122       next_state_(STATE_NONE),
123       destination_(destination),
124       origin_url_(origin_url),
125       is_websocket_(is_websocket),
126       try_websocket_over_http2_(is_websocket_ &&
127                                 origin_url_.SchemeIs(url::kWssScheme) &&
128                                 proxy_info_.is_direct() &&
129                                 session_->params().enable_websocket_over_http2),
130       // Don't use IP connection pooling for HTTP over HTTPS proxies. It doesn't
131       // get us much, and testing it is more effort than its worth.
132       enable_ip_based_pooling_(
133           enable_ip_based_pooling &&
134           !(proxy_info_.proxy_server().is_secure_http_like() &&
135             origin_url_.SchemeIs(url::kHttpScheme))),
136       delegate_(delegate),
137       job_type_(job_type),
138       using_ssl_(origin_url_.SchemeIs(url::kHttpsScheme) ||
139                  origin_url_.SchemeIs(url::kWssScheme)),
140       using_quic_(alternative_protocol == kProtoQUIC ||
141                   (ShouldForceQuic(session,
142                                    destination,
143                                    origin_url,
144                                    proxy_info,
145                                    using_ssl_))),
146       quic_version_(quic_version),
147       expect_spdy_(alternative_protocol == kProtoHTTP2 && !using_quic_),
148       using_spdy_(false),
149       should_reconsider_proxy_(false),
150       quic_request_(session_->quic_stream_factory()),
151       expect_on_quic_host_resolution_(false),
152       using_existing_quic_session_(false),
153       establishing_tunnel_(false),
154       was_alpn_negotiated_(false),
155       negotiated_protocol_(kProtoUnknown),
156       num_streams_(0),
157       pushed_stream_id_(kNoPushedStreamFound),
158       spdy_session_direct_(
159           !(proxy_info.is_https() && origin_url_.SchemeIs(url::kHttpScheme))),
160       spdy_session_key_(
161           using_quic_ ? SpdySessionKey()
162                       : GetSpdySessionKey(spdy_session_direct_,
163                                           proxy_info_.proxy_server(),
164                                           origin_url_,
165                                           request_info_.privacy_mode,
166                                           request_info_.socket_tag,
167                                           request_info_.network_isolation_key,
168                                           request_info_.disable_secure_dns)),
169       stream_type_(HttpStreamRequest::BIDIRECTIONAL_STREAM),
170       init_connection_already_resumed_(false) {
171   // QUIC can only be spoken to servers, never to proxies.
172   if (alternative_protocol == kProtoQUIC)
173     DCHECK(proxy_info_.is_direct());
174 
175   // The Job is forced to use QUIC without a designated version, try the
176   // preferred QUIC version that is supported by default.
177   if (quic_version_ == quic::ParsedQuicVersion::Unsupported() &&
178       ShouldForceQuic(session, destination, origin_url, proxy_info,
179                       using_ssl_)) {
180     quic_version_ =
181         session->context().quic_context->params()->supported_versions[0];
182   }
183 
184   if (using_quic_)
185     DCHECK_NE(quic_version_, quic::ParsedQuicVersion::Unsupported());
186 
187   DCHECK(session);
188   if (alternative_protocol != kProtoUnknown) {
189     // If the alternative service protocol is specified, then the job type must
190     // be either ALTERNATIVE or PRECONNECT.
191     DCHECK(job_type_ == ALTERNATIVE || job_type_ == PRECONNECT);
192   }
193 
194   if (expect_spdy_) {
195     DCHECK(origin_url_.SchemeIs(url::kHttpsScheme));
196   }
197   if (using_quic_) {
198     DCHECK(session_->IsQuicEnabled());
199   }
200   if (job_type_ == PRECONNECT || is_websocket_) {
201     DCHECK(request_info_.socket_tag == SocketTag());
202   }
203   if (is_websocket_) {
204     DCHECK(origin_url_.SchemeIsWSOrWSS());
205   } else {
206     DCHECK(!origin_url_.SchemeIsWSOrWSS());
207   }
208 }
209 
~Job()210 HttpStreamFactory::Job::~Job() {
211   net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB);
212 
213   // When we're in a partially constructed state, waiting for the user to
214   // provide certificate handling information or authentication, we can't reuse
215   // this stream at all.
216   if (next_state_ == STATE_WAITING_USER_ACTION) {
217     connection_->socket()->Disconnect();
218     connection_.reset();
219   }
220 
221   // The stream could be in a partial state.  It is not reusable.
222   if (stream_.get() && next_state_ != STATE_DONE)
223     stream_->Close(true /* not reusable */);
224 }
225 
Start(HttpStreamRequest::StreamType stream_type)226 void HttpStreamFactory::Job::Start(HttpStreamRequest::StreamType stream_type) {
227   stream_type_ = stream_type;
228   StartInternal();
229 }
230 
Preconnect(int num_streams)231 int HttpStreamFactory::Job::Preconnect(int num_streams) {
232   DCHECK_GT(num_streams, 0);
233   HttpServerProperties* http_server_properties =
234       session_->http_server_properties();
235   DCHECK(http_server_properties);
236   // Preconnect one connection if either of the following is true:
237   //   (1) kLimitEarlyPreconnectsStreamExperiment is turned on,
238   //   HttpServerProperties is not initialized, and url scheme is cryptographic.
239   //   (2) The server supports H2 or QUIC.
240   bool connect_one_stream =
241       base::FeatureList::IsEnabled(kLimitEarlyPreconnectsExperiment) &&
242       !http_server_properties->IsInitialized() &&
243       request_info_.url.SchemeIsCryptographic();
244   if (connect_one_stream || http_server_properties->SupportsRequestPriority(
245                                 url::SchemeHostPort(request_info_.url),
246                                 request_info_.network_isolation_key)) {
247     num_streams_ = 1;
248   } else {
249     num_streams_ = num_streams;
250   }
251   return StartInternal();
252 }
253 
RestartTunnelWithProxyAuth()254 int HttpStreamFactory::Job::RestartTunnelWithProxyAuth() {
255   DCHECK(establishing_tunnel_);
256   DCHECK(restart_with_auth_callback_);
257 
258   std::move(restart_with_auth_callback_).Run();
259   return ERR_IO_PENDING;
260 }
261 
GetLoadState() const262 LoadState HttpStreamFactory::Job::GetLoadState() const {
263   switch (next_state_) {
264     case STATE_INIT_CONNECTION_COMPLETE:
265     case STATE_CREATE_STREAM_COMPLETE:
266       return using_quic_ ? LOAD_STATE_CONNECTING : connection_->GetLoadState();
267     default:
268       return LOAD_STATE_IDLE;
269   }
270 }
271 
Resume()272 void HttpStreamFactory::Job::Resume() {
273   DCHECK_EQ(job_type_, MAIN);
274   DCHECK_EQ(next_state_, STATE_WAIT_COMPLETE);
275   OnIOComplete(OK);
276 }
277 
Orphan()278 void HttpStreamFactory::Job::Orphan() {
279   DCHECK_EQ(job_type_, ALTERNATIVE);
280   net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_ORPHANED);
281 
282   // Watching for SPDY sessions isn't supported on orphaned jobs.
283   // TODO(mmenke): Fix that.
284   spdy_session_request_.reset();
285 }
286 
SetPriority(RequestPriority priority)287 void HttpStreamFactory::Job::SetPriority(RequestPriority priority) {
288   priority_ = priority;
289   // Ownership of |connection_| is passed to the newly created stream
290   // or H2 session in DoCreateStream(), and the consumer is not
291   // notified immediately, so this call may occur when |connection_|
292   // is null.
293   //
294   // Note that streams are created without a priority associated with them,
295   // and it is up to the consumer to set their priority via
296   // HttpStream::InitializeStream().  So there is no need for this code
297   // to propagate priority changes to the newly created stream.
298   if (connection_ && connection_->is_initialized())
299     connection_->SetPriority(priority);
300   // TODO(akalin): Maybe Propagate this to the preconnect state.
301 }
302 
was_alpn_negotiated() const303 bool HttpStreamFactory::Job::was_alpn_negotiated() const {
304   return was_alpn_negotiated_;
305 }
306 
negotiated_protocol() const307 NextProto HttpStreamFactory::Job::negotiated_protocol() const {
308   return negotiated_protocol_;
309 }
310 
using_spdy() const311 bool HttpStreamFactory::Job::using_spdy() const {
312   return using_spdy_;
313 }
314 
EstimateMemoryUsage() const315 size_t HttpStreamFactory::Job::EstimateMemoryUsage() const {
316   StreamSocket::SocketMemoryStats stats;
317   if (connection_)
318     connection_->DumpMemoryStats(&stats);
319   return stats.total_size;
320 }
321 
server_ssl_config() const322 const SSLConfig& HttpStreamFactory::Job::server_ssl_config() const {
323   return server_ssl_config_;
324 }
325 
proxy_ssl_config() const326 const SSLConfig& HttpStreamFactory::Job::proxy_ssl_config() const {
327   return proxy_ssl_config_;
328 }
329 
proxy_info() const330 const ProxyInfo& HttpStreamFactory::Job::proxy_info() const {
331   return proxy_info_;
332 }
333 
resolve_error_info() const334 ResolveErrorInfo HttpStreamFactory::Job::resolve_error_info() const {
335   return resolve_error_info_;
336 }
337 
GetSSLInfo(SSLInfo * ssl_info)338 void HttpStreamFactory::Job::GetSSLInfo(SSLInfo* ssl_info) {
339   DCHECK(using_ssl_);
340   DCHECK(!establishing_tunnel_);
341   DCHECK(connection_.get() && connection_->socket());
342   connection_->socket()->GetSSLInfo(ssl_info);
343 }
344 
345 // static
ShouldForceQuic(HttpNetworkSession * session,const HostPortPair & destination,const GURL & origin_url,const ProxyInfo & proxy_info,bool using_ssl)346 bool HttpStreamFactory::Job::ShouldForceQuic(HttpNetworkSession* session,
347                                              const HostPortPair& destination,
348                                              const GURL& origin_url,
349                                              const ProxyInfo& proxy_info,
350                                              bool using_ssl) {
351   if (!session->IsQuicEnabled())
352     return false;
353   // If this is going through a QUIC proxy, only force QUIC for insecure
354   // requests. If the request is secure, a tunnel will be needed, and those are
355   // handled by the socket pools, using an HttpProxyConnectJob.
356   if (proxy_info.is_quic())
357     return !using_ssl;
358   const QuicParams* quic_params = session->context().quic_context->params();
359   return (base::Contains(quic_params->origins_to_force_quic_on,
360                          HostPortPair()) ||
361           base::Contains(quic_params->origins_to_force_quic_on, destination)) &&
362          proxy_info.is_direct() && origin_url.SchemeIs(url::kHttpsScheme);
363 }
364 
365 // static
GetSpdySessionKey(bool spdy_session_direct,const ProxyServer & proxy_server,const GURL & origin_url,PrivacyMode privacy_mode,const SocketTag & socket_tag,const NetworkIsolationKey & network_isolation_key,bool disable_secure_dns)366 SpdySessionKey HttpStreamFactory::Job::GetSpdySessionKey(
367     bool spdy_session_direct,
368     const ProxyServer& proxy_server,
369     const GURL& origin_url,
370     PrivacyMode privacy_mode,
371     const SocketTag& socket_tag,
372     const NetworkIsolationKey& network_isolation_key,
373     bool disable_secure_dns) {
374   // In the case that we're using an HTTPS proxy for an HTTP url, look for a
375   // HTTP/2 proxy session *to* the proxy, instead of to the  origin server.
376   if (!spdy_session_direct) {
377     return SpdySessionKey(proxy_server.host_port_pair(), ProxyServer::Direct(),
378                           PRIVACY_MODE_DISABLED,
379                           SpdySessionKey::IsProxySession::kTrue, socket_tag,
380                           network_isolation_key, disable_secure_dns);
381   }
382   return SpdySessionKey(HostPortPair::FromURL(origin_url), proxy_server,
383                         privacy_mode, SpdySessionKey::IsProxySession::kFalse,
384                         socket_tag, network_isolation_key, disable_secure_dns);
385 }
386 
CanUseExistingSpdySession() const387 bool HttpStreamFactory::Job::CanUseExistingSpdySession() const {
388   DCHECK(!using_quic_);
389 
390   if (proxy_info_.is_direct() &&
391       session_->http_server_properties()->RequiresHTTP11(
392           url::SchemeHostPort(request_info_.url),
393           request_info_.network_isolation_key)) {
394     return false;
395   }
396 
397   if (is_websocket_)
398     return try_websocket_over_http2_;
399 
400   DCHECK(origin_url_.SchemeIsHTTPOrHTTPS());
401 
402   // We need to make sure that if a HTTP/2 session was created for
403   // https://somehost/ then we do not use that session for http://somehost:443/.
404   // The only time we can use an existing session is if the request URL is
405   // https (the normal case) or if we are connecting to a HTTP/2 proxy.
406   // https://crbug.com/133176
407   return origin_url_.SchemeIs(url::kHttpsScheme) ||
408          proxy_info_.proxy_server().is_https();
409 }
410 
OnStreamReadyCallback()411 void HttpStreamFactory::Job::OnStreamReadyCallback() {
412   DCHECK(stream_.get());
413   DCHECK_NE(job_type_, PRECONNECT);
414   DCHECK(!is_websocket_ || try_websocket_over_http2_);
415 
416   MaybeCopyConnectionAttemptsFromSocketOrHandle();
417 
418   delegate_->OnStreamReady(this, server_ssl_config_);
419   // |this| may be deleted after this call.
420 }
421 
OnWebSocketHandshakeStreamReadyCallback()422 void HttpStreamFactory::Job::OnWebSocketHandshakeStreamReadyCallback() {
423   DCHECK(websocket_stream_);
424   DCHECK_NE(job_type_, PRECONNECT);
425   DCHECK(is_websocket_);
426 
427   MaybeCopyConnectionAttemptsFromSocketOrHandle();
428 
429   delegate_->OnWebSocketHandshakeStreamReady(
430       this, server_ssl_config_, proxy_info_, std::move(websocket_stream_));
431   // |this| may be deleted after this call.
432 }
433 
OnBidirectionalStreamImplReadyCallback()434 void HttpStreamFactory::Job::OnBidirectionalStreamImplReadyCallback() {
435   DCHECK(bidirectional_stream_impl_);
436 
437   MaybeCopyConnectionAttemptsFromSocketOrHandle();
438 
439   delegate_->OnBidirectionalStreamImplReady(this, server_ssl_config_,
440                                             proxy_info_);
441   // |this| may be deleted after this call.
442 }
443 
OnStreamFailedCallback(int result)444 void HttpStreamFactory::Job::OnStreamFailedCallback(int result) {
445   DCHECK_NE(job_type_, PRECONNECT);
446 
447   MaybeCopyConnectionAttemptsFromSocketOrHandle();
448 
449   delegate_->OnStreamFailed(this, result, server_ssl_config_);
450   // |this| may be deleted after this call.
451 }
452 
OnCertificateErrorCallback(int result,const SSLInfo & ssl_info)453 void HttpStreamFactory::Job::OnCertificateErrorCallback(
454     int result,
455     const SSLInfo& ssl_info) {
456   DCHECK_NE(job_type_, PRECONNECT);
457   DCHECK(!spdy_session_request_);
458 
459   MaybeCopyConnectionAttemptsFromSocketOrHandle();
460 
461   delegate_->OnCertificateError(this, result, server_ssl_config_, ssl_info);
462   // |this| may be deleted after this call.
463 }
464 
OnNeedsProxyAuthCallback(const HttpResponseInfo & response,HttpAuthController * auth_controller,base::OnceClosure restart_with_auth_callback)465 void HttpStreamFactory::Job::OnNeedsProxyAuthCallback(
466     const HttpResponseInfo& response,
467     HttpAuthController* auth_controller,
468     base::OnceClosure restart_with_auth_callback) {
469   DCHECK_NE(job_type_, PRECONNECT);
470   DCHECK(establishing_tunnel_);
471   DCHECK(!restart_with_auth_callback_);
472 
473   restart_with_auth_callback_ = std::move(restart_with_auth_callback);
474 
475   // This is called out of band, so need to abort the SpdySessionRequest to
476   // prevent being passed a new session while waiting on proxy auth credentials.
477   spdy_session_request_.reset();
478 
479   delegate_->OnNeedsProxyAuth(this, response, server_ssl_config_, proxy_info_,
480                               auth_controller);
481   // |this| may be deleted after this call.
482 }
483 
OnNeedsClientAuthCallback(SSLCertRequestInfo * cert_info)484 void HttpStreamFactory::Job::OnNeedsClientAuthCallback(
485     SSLCertRequestInfo* cert_info) {
486   DCHECK_NE(job_type_, PRECONNECT);
487   DCHECK(!spdy_session_request_);
488 
489   delegate_->OnNeedsClientAuth(this, server_ssl_config_, cert_info);
490   // |this| may be deleted after this call.
491 }
492 
OnPreconnectsComplete()493 void HttpStreamFactory::Job::OnPreconnectsComplete() {
494   delegate_->OnPreconnectsComplete(this);
495   // |this| may be deleted after this call.
496 }
497 
OnIOComplete(int result)498 void HttpStreamFactory::Job::OnIOComplete(int result) {
499   TRACE_EVENT0(NetTracingCategory(), "HttpStreamFactory::Job::OnIOComplete");
500   RunLoop(result);
501 }
502 
RunLoop(int result)503 void HttpStreamFactory::Job::RunLoop(int result) {
504   TRACE_EVENT0(NetTracingCategory(), "HttpStreamFactory::Job::RunLoop");
505   result = DoLoop(result);
506 
507   if (result == ERR_IO_PENDING)
508     return;
509 
510   // Stop watching for new SpdySessions, to avoid receiving a new SPDY session
511   // while doing anything other than waiting to establish a connection.
512   spdy_session_request_.reset();
513 
514   if (job_type_ == PRECONNECT) {
515     base::ThreadTaskRunnerHandle::Get()->PostTask(
516         FROM_HERE,
517         base::BindOnce(&HttpStreamFactory::Job::OnPreconnectsComplete,
518                        ptr_factory_.GetWeakPtr()));
519     return;
520   }
521 
522   if (IsCertificateError(result)) {
523     // Retrieve SSL information from the socket.
524     SSLInfo ssl_info;
525     GetSSLInfo(&ssl_info);
526 
527     next_state_ = STATE_WAITING_USER_ACTION;
528     base::ThreadTaskRunnerHandle::Get()->PostTask(
529         FROM_HERE,
530         base::BindOnce(&HttpStreamFactory::Job::OnCertificateErrorCallback,
531                        ptr_factory_.GetWeakPtr(), result, ssl_info));
532     return;
533   }
534 
535   switch (result) {
536     case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
537       base::ThreadTaskRunnerHandle::Get()->PostTask(
538           FROM_HERE,
539           base::BindOnce(
540               &Job::OnNeedsClientAuthCallback, ptr_factory_.GetWeakPtr(),
541               base::RetainedRef(connection_->ssl_cert_request_info())));
542       return;
543 
544     case OK:
545       next_state_ = STATE_DONE;
546       if (is_websocket_) {
547         DCHECK(websocket_stream_);
548         base::ThreadTaskRunnerHandle::Get()->PostTask(
549             FROM_HERE,
550             base::BindOnce(&Job::OnWebSocketHandshakeStreamReadyCallback,
551                            ptr_factory_.GetWeakPtr()));
552       } else if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
553         if (!bidirectional_stream_impl_) {
554           base::ThreadTaskRunnerHandle::Get()->PostTask(
555               FROM_HERE, base::BindOnce(&Job::OnStreamFailedCallback,
556                                         ptr_factory_.GetWeakPtr(), ERR_FAILED));
557         } else {
558           base::ThreadTaskRunnerHandle::Get()->PostTask(
559               FROM_HERE,
560               base::BindOnce(&Job::OnBidirectionalStreamImplReadyCallback,
561                              ptr_factory_.GetWeakPtr()));
562         }
563       } else {
564         DCHECK(stream_.get());
565         base::ThreadTaskRunnerHandle::Get()->PostTask(
566             FROM_HERE, base::BindOnce(&Job::OnStreamReadyCallback,
567                                       ptr_factory_.GetWeakPtr()));
568       }
569       return;
570 
571     default:
572       base::ThreadTaskRunnerHandle::Get()->PostTask(
573           FROM_HERE, base::BindOnce(&Job::OnStreamFailedCallback,
574                                     ptr_factory_.GetWeakPtr(), result));
575       return;
576   }
577 }
578 
DoLoop(int result)579 int HttpStreamFactory::Job::DoLoop(int result) {
580   DCHECK_NE(next_state_, STATE_NONE);
581   int rv = result;
582   do {
583     State state = next_state_;
584     next_state_ = STATE_NONE;
585     switch (state) {
586       case STATE_START:
587         DCHECK_EQ(OK, rv);
588         rv = DoStart();
589         break;
590       case STATE_WAIT:
591         DCHECK_EQ(OK, rv);
592         rv = DoWait();
593         break;
594       case STATE_WAIT_COMPLETE:
595         rv = DoWaitComplete(rv);
596         break;
597       case STATE_INIT_CONNECTION:
598         DCHECK_EQ(OK, rv);
599         rv = DoInitConnection();
600         break;
601       case STATE_INIT_CONNECTION_COMPLETE:
602         rv = DoInitConnectionComplete(rv);
603         break;
604       case STATE_WAITING_USER_ACTION:
605         rv = DoWaitingUserAction(rv);
606         break;
607       case STATE_CREATE_STREAM:
608         DCHECK_EQ(OK, rv);
609         rv = DoCreateStream();
610         break;
611       case STATE_CREATE_STREAM_COMPLETE:
612         rv = DoCreateStreamComplete(rv);
613         break;
614       default:
615         NOTREACHED() << "bad state";
616         rv = ERR_FAILED;
617         break;
618     }
619   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
620   return rv;
621 }
622 
StartInternal()623 int HttpStreamFactory::Job::StartInternal() {
624   CHECK_EQ(STATE_NONE, next_state_);
625   next_state_ = STATE_START;
626   RunLoop(OK);
627   return ERR_IO_PENDING;
628 }
629 
DoStart()630 int HttpStreamFactory::Job::DoStart() {
631   const NetLogWithSource* net_log = delegate_->GetNetLog();
632 
633   if (net_log) {
634     net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_JOB, [&] {
635       return NetLogHttpStreamJobParams(net_log->source(), request_info_.url,
636                                        origin_url_, expect_spdy_, using_quic_,
637                                        priority_);
638     });
639     net_log->AddEventReferencingSource(
640         NetLogEventType::HTTP_STREAM_REQUEST_STARTED_JOB, net_log_.source());
641   }
642 
643   // Don't connect to restricted ports.
644   if (!IsPortAllowedForScheme(destination_.port(),
645                               request_info_.url.scheme_piece())) {
646     return ERR_UNSAFE_PORT;
647   }
648 
649   if (!session_->params().enable_quic_proxies_for_https_urls &&
650       proxy_info_.is_quic() && request_info_.url.SchemeIsCryptographic()) {
651     return ERR_NOT_IMPLEMENTED;
652   }
653 
654   next_state_ = STATE_WAIT;
655   return OK;
656 }
657 
DoWait()658 int HttpStreamFactory::Job::DoWait() {
659   next_state_ = STATE_WAIT_COMPLETE;
660   bool should_wait = delegate_->ShouldWait(this);
661   net_log_.AddEntryWithBoolParams(NetLogEventType::HTTP_STREAM_JOB_WAITING,
662                                   NetLogEventPhase::BEGIN, "should_wait",
663                                   should_wait);
664   if (should_wait)
665     return ERR_IO_PENDING;
666 
667   return OK;
668 }
669 
DoWaitComplete(int result)670 int HttpStreamFactory::Job::DoWaitComplete(int result) {
671   net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_WAITING);
672   DCHECK_EQ(OK, result);
673   next_state_ = STATE_INIT_CONNECTION;
674   return OK;
675 }
676 
ResumeInitConnection()677 void HttpStreamFactory::Job::ResumeInitConnection() {
678   if (init_connection_already_resumed_)
679     return;
680   DCHECK_EQ(next_state_, STATE_INIT_CONNECTION);
681   net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_RESUME_INIT_CONNECTION);
682   init_connection_already_resumed_ = true;
683   OnIOComplete(OK);
684 }
685 
DoInitConnection()686 int HttpStreamFactory::Job::DoInitConnection() {
687   net_log_.BeginEvent(NetLogEventType::HTTP_STREAM_JOB_INIT_CONNECTION);
688   int result = DoInitConnectionImpl();
689   if (!expect_on_quic_host_resolution_) {
690     delegate_->OnConnectionInitialized(this, result);
691   }
692   return result;
693 }
694 
DoInitConnectionImpl()695 int HttpStreamFactory::Job::DoInitConnectionImpl() {
696   DCHECK(!connection_->is_initialized());
697 
698   if (using_quic_ && !proxy_info_.is_quic() && !proxy_info_.is_direct()) {
699     // QUIC can not be spoken to non-QUIC proxies.  This error should not be
700     // user visible, because the non-alternative Job should be resumed.
701     return ERR_NO_SUPPORTED_PROXIES;
702   }
703 
704   DCHECK(proxy_info_.proxy_server().is_valid());
705   next_state_ = STATE_INIT_CONNECTION_COMPLETE;
706 
707   if (proxy_info_.is_secure_http_like()) {
708     // Disable network fetches for HTTPS proxies, since the network requests
709     // are probably going to need to go through the proxy too.
710     proxy_ssl_config_.disable_cert_verification_network_fetches = true;
711   }
712   if (using_ssl_) {
713     // Prior to HTTP/2 and SPDY, some servers use TLS renegotiation to request
714     // TLS client authentication after the HTTP request was sent. Allow
715     // renegotiation for only those connections.
716     //
717     // Note that this does NOT implement the provision in
718     // https://http2.github.io/http2-spec/#rfc.section.9.2.1 which allows the
719     // server to request a renegotiation immediately before sending the
720     // connection preface as waiting for the preface would cost the round trip
721     // that False Start otherwise saves.
722     server_ssl_config_.renego_allowed_default = true;
723     server_ssl_config_.renego_allowed_for_protos.push_back(kProtoHTTP11);
724   }
725 
726   if (using_quic_)
727     return DoInitConnectionImplQuic();
728 
729   // Check first if there is a pushed stream matching the request, or an HTTP/2
730   // connection this request can pool to.  If so, then go straight to using
731   // that.
732   if (CanUseExistingSpdySession()) {
733     if (!is_websocket_) {
734       session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream(
735           spdy_session_key_, origin_url_, request_info_,
736           &existing_spdy_session_, &pushed_stream_id_);
737     }
738     if (!existing_spdy_session_) {
739       if (!spdy_session_request_) {
740         // If not currently watching for an H2 session, use
741         // SpdySessionPool::RequestSession() to check for a session, and start
742         // watching for one.
743         bool should_throttle_connect = ShouldThrottleConnectForSpdy();
744         base::RepeatingClosure resume_callback =
745             should_throttle_connect
746                 ? base::BindRepeating(
747                       &HttpStreamFactory::Job::ResumeInitConnection,
748                       ptr_factory_.GetWeakPtr())
749                 : base::RepeatingClosure();
750 
751         bool is_blocking_request_for_session;
752         existing_spdy_session_ = session_->spdy_session_pool()->RequestSession(
753             spdy_session_key_, enable_ip_based_pooling_, is_websocket_,
754             net_log_, resume_callback, this, &spdy_session_request_,
755             &is_blocking_request_for_session);
756         if (!existing_spdy_session_ && should_throttle_connect &&
757             !is_blocking_request_for_session) {
758           net_log_.AddEvent(NetLogEventType::HTTP_STREAM_JOB_THROTTLED);
759           next_state_ = STATE_INIT_CONNECTION;
760           base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
761               FROM_HERE, resume_callback,
762               base::TimeDelta::FromMilliseconds(kHTTP2ThrottleMs));
763           return ERR_IO_PENDING;
764         }
765       } else if (enable_ip_based_pooling_) {
766         // If already watching for an H2 session, still need to check for an
767         // existing connection that can be reused through IP pooling, as those
768         // don't post session available notifications.
769         //
770         // TODO(mmenke):  Make sessions created through IP pooling invoke the
771         // callback.
772         existing_spdy_session_ =
773             session_->spdy_session_pool()->FindAvailableSession(
774                 spdy_session_key_, enable_ip_based_pooling_, is_websocket_,
775                 net_log_);
776       }
777     }
778     if (existing_spdy_session_) {
779       // Stop watching for SpdySessions.
780       spdy_session_request_.reset();
781 
782       // If we're preconnecting, but we already have a SpdySession, we don't
783       // actually need to preconnect any sockets, so we're done.
784       if (job_type_ == PRECONNECT)
785         return OK;
786       using_spdy_ = true;
787       next_state_ = STATE_CREATE_STREAM;
788       return OK;
789     }
790   }
791 
792   if (proxy_info_.is_http_like())
793     establishing_tunnel_ = using_ssl_;
794 
795   HttpServerProperties* http_server_properties =
796       session_->http_server_properties();
797   if (http_server_properties) {
798     http_server_properties->MaybeForceHTTP11(
799         url::SchemeHostPort(request_info_.url),
800         request_info_.network_isolation_key, &server_ssl_config_);
801     if (proxy_info_.is_https()) {
802       http_server_properties->MaybeForceHTTP11(
803           url::SchemeHostPort(
804               url::kHttpsScheme,
805               proxy_info_.proxy_server().host_port_pair().host(),
806               proxy_info_.proxy_server().host_port_pair().port()),
807           request_info_.network_isolation_key, &proxy_ssl_config_);
808     }
809   }
810 
811   if (job_type_ == PRECONNECT) {
812     DCHECK(!is_websocket_);
813     DCHECK(request_info_.socket_tag == SocketTag());
814     return PreconnectSocketsForHttpRequest(
815         GetSocketGroup(), destination_, request_info_.load_flags, priority_,
816         session_, proxy_info_, server_ssl_config_, proxy_ssl_config_,
817         request_info_.privacy_mode, request_info_.network_isolation_key,
818         request_info_.disable_secure_dns, net_log_, num_streams_);
819   }
820 
821   ClientSocketPool::ProxyAuthCallback proxy_auth_callback =
822       base::BindRepeating(&HttpStreamFactory::Job::OnNeedsProxyAuthCallback,
823                           base::Unretained(this));
824   if (is_websocket_) {
825     DCHECK(request_info_.socket_tag == SocketTag());
826     DCHECK(!request_info_.disable_secure_dns);
827     SSLConfig websocket_server_ssl_config = server_ssl_config_;
828     websocket_server_ssl_config.alpn_protos.clear();
829     return InitSocketHandleForWebSocketRequest(
830         GetSocketGroup(), destination_, request_info_.load_flags, priority_,
831         session_, proxy_info_, websocket_server_ssl_config, proxy_ssl_config_,
832         request_info_.privacy_mode, request_info_.network_isolation_key,
833         net_log_, connection_.get(), io_callback_, proxy_auth_callback);
834   }
835 
836   return InitSocketHandleForHttpRequest(
837       GetSocketGroup(), destination_, request_info_.load_flags, priority_,
838       session_, proxy_info_, server_ssl_config_, proxy_ssl_config_,
839       request_info_.privacy_mode, request_info_.network_isolation_key,
840       request_info_.disable_secure_dns, request_info_.socket_tag, net_log_,
841       connection_.get(), io_callback_, proxy_auth_callback);
842 }
843 
DoInitConnectionImplQuic()844 int HttpStreamFactory::Job::DoInitConnectionImplQuic() {
845   HostPortPair destination;
846   SSLConfig* ssl_config;
847   GURL url(request_info_.url);
848   if (proxy_info_.is_quic()) {
849     // A proxy's certificate is expected to be valid for the proxy hostname.
850     destination = proxy_info_.proxy_server().host_port_pair();
851     ssl_config = &proxy_ssl_config_;
852     GURL::Replacements replacements;
853     replacements.SetSchemeStr(url::kHttpsScheme);
854     replacements.SetHostStr(destination.host());
855     const std::string new_port = base::NumberToString(destination.port());
856     replacements.SetPortStr(new_port);
857     replacements.ClearUsername();
858     replacements.ClearPassword();
859     replacements.ClearPath();
860     replacements.ClearQuery();
861     replacements.ClearRef();
862     url = url.ReplaceComponents(replacements);
863   } else {
864     DCHECK(using_ssl_);
865     // The certificate of a QUIC alternative server is expected to be valid
866     // for the origin of the request (in addition to being valid for the
867     // server itself).
868     destination = destination_;
869     ssl_config = &server_ssl_config_;
870   }
871   int rv = quic_request_.Request(
872       destination, quic_version_, request_info_.privacy_mode, priority_,
873       request_info_.socket_tag, request_info_.network_isolation_key,
874       request_info_.disable_secure_dns, ssl_config->GetCertVerifyFlags(), url,
875       net_log_, &net_error_details_,
876       base::BindOnce(&Job::OnFailedOnDefaultNetwork, ptr_factory_.GetWeakPtr()),
877       io_callback_);
878   if (rv == OK) {
879     using_existing_quic_session_ = true;
880   } else if (rv == ERR_IO_PENDING) {
881     // There's no available QUIC session. Inform the delegate how long to
882     // delay the main job.
883     delegate_->MaybeSetWaitTimeForMainJob(
884         quic_request_.GetTimeDelayForWaitingJob());
885     expect_on_quic_host_resolution_ = quic_request_.WaitForHostResolution(
886         base::BindOnce(&Job::OnQuicHostResolution, base::Unretained(this)));
887   }
888   return rv;
889 }
890 
OnQuicHostResolution(int result)891 void HttpStreamFactory::Job::OnQuicHostResolution(int result) {
892   DCHECK(expect_on_quic_host_resolution_);
893   expect_on_quic_host_resolution_ = false;
894   delegate_->OnConnectionInitialized(this, result);
895 }
896 
OnFailedOnDefaultNetwork(int result)897 void HttpStreamFactory::Job::OnFailedOnDefaultNetwork(int result) {
898   DCHECK_EQ(job_type_, ALTERNATIVE);
899   DCHECK(using_quic_);
900   delegate_->OnFailedOnDefaultNetwork(this);
901 }
902 
DoInitConnectionComplete(int result)903 int HttpStreamFactory::Job::DoInitConnectionComplete(int result) {
904   net_log_.EndEvent(NetLogEventType::HTTP_STREAM_JOB_INIT_CONNECTION);
905 
906   // No need to continue waiting for a session, once a connection is
907   // established.
908   spdy_session_request_.reset();
909 
910   if (job_type_ == PRECONNECT) {
911     if (using_quic_)
912       return result;
913     DCHECK_EQ(OK, result);
914     return OK;
915   }
916 
917   resolve_error_info_ = connection_->resolve_error_info();
918 
919   // |result| may be the result of any of the stacked pools. The following
920   // logic is used when determining how to interpret an error.
921   // If |result| < 0:
922   //   and connection_->socket() != NULL, then the SSL handshake ran and it
923   //     is a potentially recoverable error.
924   //   and connection_->socket == NULL and connection_->is_ssl_error() is true,
925   //     then the SSL handshake ran with an unrecoverable error.
926   //   otherwise, the error came from one of the other pools.
927   bool ssl_started = using_ssl_ && (result == OK || connection_->socket() ||
928                                     connection_->is_ssl_error());
929 
930   if (ssl_started && result == OK) {
931     if (using_quic_) {
932       was_alpn_negotiated_ = true;
933       negotiated_protocol_ = kProtoQUIC;
934     } else {
935       if (connection_->socket()->WasAlpnNegotiated()) {
936         was_alpn_negotiated_ = true;
937         negotiated_protocol_ = connection_->socket()->GetNegotiatedProtocol();
938         net_log_.AddEvent(NetLogEventType::HTTP_STREAM_REQUEST_PROTO, [&] {
939           return NetLogHttpStreamProtoParams(negotiated_protocol_);
940         });
941         if (negotiated_protocol_ == kProtoHTTP2) {
942           if (is_websocket_) {
943             // WebSocket is not supported over a fresh HTTP/2 connection.
944             return ERR_NOT_IMPLEMENTED;
945           }
946 
947           using_spdy_ = true;
948         }
949       }
950     }
951   } else if (proxy_info_.is_secure_http_like() && connection_->socket() &&
952              result == OK) {
953     ProxyClientSocket* proxy_socket =
954         static_cast<ProxyClientSocket*>(connection_->socket());
955     // http://crbug.com/642354
956     if (!proxy_socket->IsConnected())
957       return ERR_CONNECTION_CLOSED;
958     if (proxy_socket->IsUsingSpdy()) {
959       was_alpn_negotiated_ = true;
960       negotiated_protocol_ = proxy_socket->GetProxyNegotiatedProtocol();
961       using_spdy_ = true;
962 
963       // Using unencrypted websockets over an H2 proxy is not currently
964       // supported.
965       // TODO(mmenke): Should this case be treated like
966       // |try_websocket_over_http2_|, or should we force HTTP/1.1?
967       if (is_websocket_ && !try_websocket_over_http2_)
968         return ERR_NOT_IMPLEMENTED;
969     }
970   }
971 
972   if (proxy_info_.is_quic() && using_quic_ && result < 0)
973     return ReconsiderProxyAfterError(result);
974 
975   if (expect_spdy_ && !using_spdy_)
976     return ERR_ALPN_NEGOTIATION_FAILED;
977 
978   if (!ssl_started && result < 0 && (expect_spdy_ || using_quic_))
979     return result;
980 
981   if (using_quic_) {
982     if (result < 0)
983       return result;
984 
985     if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
986       std::unique_ptr<QuicChromiumClientSession::Handle> session =
987           quic_request_.ReleaseSessionHandle();
988       if (!session) {
989         // Quic session is closed before stream can be created.
990         return ERR_CONNECTION_CLOSED;
991       }
992       bidirectional_stream_impl_.reset(
993           new BidirectionalStreamQuicImpl(std::move(session)));
994     } else {
995       std::unique_ptr<QuicChromiumClientSession::Handle> session =
996           quic_request_.ReleaseSessionHandle();
997       if (!session) {
998         // Quic session is closed before stream can be created.
999         return ERR_CONNECTION_CLOSED;
1000       }
1001       stream_ = std::make_unique<QuicHttpStream>(std::move(session));
1002     }
1003     next_state_ = STATE_NONE;
1004     return OK;
1005   }
1006 
1007   if (result < 0 && !ssl_started)
1008     return ReconsiderProxyAfterError(result);
1009 
1010   establishing_tunnel_ = false;
1011 
1012   // Handle SSL errors below.
1013   if (using_ssl_) {
1014     DCHECK(ssl_started);
1015     if (IsCertificateError(result)) {
1016       SSLInfo ssl_info;
1017       GetSSLInfo(&ssl_info);
1018       if (ssl_info.cert) {
1019         // Add the bad certificate to the set of allowed certificates in the
1020         // SSL config object. This data structure will be consulted after
1021         // calling RestartIgnoringLastError(). And the user will be asked
1022         // interactively before RestartIgnoringLastError() is ever called.
1023         server_ssl_config_.allowed_bad_certs.emplace_back(ssl_info.cert,
1024                                                           ssl_info.cert_status);
1025       }
1026     }
1027     if (result < 0)
1028       return result;
1029   }
1030 
1031   next_state_ = STATE_CREATE_STREAM;
1032   return OK;
1033 }
1034 
DoWaitingUserAction(int result)1035 int HttpStreamFactory::Job::DoWaitingUserAction(int result) {
1036   // This state indicates that the stream request is in a partially
1037   // completed state, and we've called back to the delegate for more
1038   // information.
1039 
1040   // We're always waiting here for the delegate to call us back.
1041   return ERR_IO_PENDING;
1042 }
1043 
SetSpdyHttpStreamOrBidirectionalStreamImpl(base::WeakPtr<SpdySession> session)1044 int HttpStreamFactory::Job::SetSpdyHttpStreamOrBidirectionalStreamImpl(
1045     base::WeakPtr<SpdySession> session) {
1046   DCHECK(using_spdy_);
1047 
1048   if (is_websocket_) {
1049     DCHECK_NE(job_type_, PRECONNECT);
1050     DCHECK(delegate_->websocket_handshake_stream_create_helper());
1051 
1052     if (!try_websocket_over_http2_) {
1053       // Plaintext WebSocket is not supported over HTTP/2 proxy,
1054       // see https://crbug.com/684681.
1055       return ERR_NOT_IMPLEMENTED;
1056     }
1057 
1058     websocket_stream_ = delegate_->websocket_handshake_stream_create_helper()
1059                             ->CreateHttp2Stream(session);
1060     return OK;
1061   }
1062   if (stream_type_ == HttpStreamRequest::BIDIRECTIONAL_STREAM) {
1063     bidirectional_stream_impl_ = std::make_unique<BidirectionalStreamSpdyImpl>(
1064         session, net_log_.source());
1065     return OK;
1066   }
1067 
1068   // TODO(willchan): Delete this code, because eventually, the HttpStreamFactory
1069   // will be creating all the SpdyHttpStreams, since it will know when
1070   // SpdySessions become available.
1071 
1072   stream_ = std::make_unique<SpdyHttpStream>(session, pushed_stream_id_,
1073                                              net_log_.source());
1074   return OK;
1075 }
1076 
DoCreateStream()1077 int HttpStreamFactory::Job::DoCreateStream() {
1078   DCHECK(connection_->socket() || existing_spdy_session_.get());
1079   DCHECK(!using_quic_);
1080 
1081   next_state_ = STATE_CREATE_STREAM_COMPLETE;
1082 
1083   if (!using_spdy_) {
1084     DCHECK(!expect_spdy_);
1085     bool using_proxy = (proxy_info_.is_http_like()) &&
1086                        request_info_.url.SchemeIs(url::kHttpScheme);
1087     if (is_websocket_) {
1088       DCHECK_NE(job_type_, PRECONNECT);
1089       DCHECK(delegate_->websocket_handshake_stream_create_helper());
1090       websocket_stream_ =
1091           delegate_->websocket_handshake_stream_create_helper()
1092               ->CreateBasicStream(std::move(connection_), using_proxy,
1093                                   session_->websocket_endpoint_lock_manager());
1094     } else {
1095       if (request_info_.upload_data_stream &&
1096           !request_info_.upload_data_stream->AllowHTTP1()) {
1097         return ERR_H2_OR_QUIC_REQUIRED;
1098       }
1099       stream_ = std::make_unique<HttpBasicStream>(std::move(connection_),
1100                                                   using_proxy);
1101     }
1102     return OK;
1103   }
1104 
1105   CHECK(!stream_.get());
1106 
1107   // It is possible that a pushed stream has been opened by a server since last
1108   // time Job checked above.
1109   if (!existing_spdy_session_) {
1110     // WebSocket over HTTP/2 is only allowed to use existing HTTP/2 connections.
1111     // Therefore |using_spdy_| could not have been set unless a connection had
1112     // already been found.
1113     DCHECK(!is_websocket_);
1114 
1115     session_->spdy_session_pool()->push_promise_index()->ClaimPushedStream(
1116         spdy_session_key_, origin_url_, request_info_, &existing_spdy_session_,
1117         &pushed_stream_id_);
1118     // It is also possible that an HTTP/2 connection has been established since
1119     // last time Job checked above.
1120     if (!existing_spdy_session_) {
1121       existing_spdy_session_ =
1122           session_->spdy_session_pool()->FindAvailableSession(
1123               spdy_session_key_, enable_ip_based_pooling_,
1124               /* is_websocket = */ false, net_log_);
1125     }
1126   }
1127   if (existing_spdy_session_) {
1128     // We picked up an existing session, so we don't need our socket.
1129     if (connection_->socket())
1130       connection_->socket()->Disconnect();
1131     connection_->Reset();
1132 
1133     int set_result =
1134         SetSpdyHttpStreamOrBidirectionalStreamImpl(existing_spdy_session_);
1135     existing_spdy_session_.reset();
1136     return set_result;
1137   }
1138 
1139   // Close idle sockets in this group, since subsequent requests will go over
1140   // |spdy_session|.
1141   if (connection_->socket()->IsConnected())
1142     connection_->CloseIdleSocketsInGroup("Switching to HTTP2 session");
1143 
1144   // If |spdy_session_direct_| is false, then |proxy_info_| is guaranteed to
1145   // have a non-empty proxy list.
1146   bool is_trusted_proxy =
1147       !spdy_session_direct_ && proxy_info_.proxy_server().is_trusted_proxy();
1148 
1149   base::WeakPtr<SpdySession> spdy_session =
1150       session_->spdy_session_pool()->CreateAvailableSessionFromSocketHandle(
1151           spdy_session_key_, is_trusted_proxy, std::move(connection_),
1152           net_log_);
1153 
1154   if (!spdy_session->HasAcceptableTransportSecurity()) {
1155     spdy_session->CloseSessionOnError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY,
1156                                       "");
1157     return ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY;
1158   }
1159 
1160   url::SchemeHostPort scheme_host_port(
1161       using_ssl_ ? url::kHttpsScheme : url::kHttpScheme,
1162       spdy_session_key_.host_port_pair().host(),
1163       spdy_session_key_.host_port_pair().port());
1164 
1165   HttpServerProperties* http_server_properties =
1166       session_->http_server_properties();
1167   if (http_server_properties) {
1168     http_server_properties->SetSupportsSpdy(scheme_host_port,
1169                                             request_info_.network_isolation_key,
1170                                             true /* supports_spdy */);
1171   }
1172 
1173   // Create a SpdyHttpStream or a BidirectionalStreamImpl attached to the
1174   // session.
1175   return SetSpdyHttpStreamOrBidirectionalStreamImpl(spdy_session);
1176 }
1177 
DoCreateStreamComplete(int result)1178 int HttpStreamFactory::Job::DoCreateStreamComplete(int result) {
1179   if (result < 0)
1180     return result;
1181 
1182   session_->proxy_resolution_service()->ReportSuccess(proxy_info_);
1183   next_state_ = STATE_NONE;
1184   return OK;
1185 }
1186 
OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session)1187 void HttpStreamFactory::Job::OnSpdySessionAvailable(
1188     base::WeakPtr<SpdySession> spdy_session) {
1189   DCHECK(spdy_session);
1190 
1191   // No need for the connection any more, since |spdy_session| can be used
1192   // instead, and there's no benefit from keeping the old ConnectJob in the
1193   // socket pool.
1194   if (connection_)
1195     connection_->ResetAndCloseSocket();
1196 
1197   // Once a connection is initialized, or if there's any out-of-band callback,
1198   // like proxy auth challenge, the SpdySessionRequest is cancelled.
1199   DCHECK(next_state_ == STATE_INIT_CONNECTION ||
1200          next_state_ == STATE_INIT_CONNECTION_COMPLETE);
1201 
1202   // Ignore calls to ResumeInitConnection() from either the timer or the
1203   // SpdySessionPool.
1204   init_connection_already_resumed_ = true;
1205 
1206   // If this is a preconnect, nothing left do to.
1207   if (job_type_ == PRECONNECT) {
1208     OnPreconnectsComplete();
1209     return;
1210   }
1211 
1212   using_spdy_ = true;
1213   existing_spdy_session_ = spdy_session;
1214   next_state_ = STATE_CREATE_STREAM;
1215 
1216   // This will synchronously close |connection_|, so no need to worry about it
1217   // calling back into |this|.
1218   RunLoop(net::OK);
1219 }
1220 
ReconsiderProxyAfterError(int error)1221 int HttpStreamFactory::Job::ReconsiderProxyAfterError(int error) {
1222   // Check if the error was a proxy failure.
1223   if (!CanFalloverToNextProxy(proxy_info_.proxy_server(), error, &error))
1224     return error;
1225 
1226   should_reconsider_proxy_ = true;
1227   return error;
1228 }
1229 
1230 ClientSocketPoolManager::SocketGroupType
GetSocketGroup() const1231 HttpStreamFactory::Job::GetSocketGroup() const {
1232   std::string scheme = origin_url_.scheme();
1233 
1234   if (scheme == url::kHttpsScheme || scheme == url::kWssScheme)
1235     return ClientSocketPoolManager::SSL_GROUP;
1236 
1237   DCHECK(scheme == url::kHttpScheme || scheme == url::kWsScheme);
1238   return ClientSocketPoolManager::NORMAL_GROUP;
1239 }
1240 
1241 // If the connection succeeds, failed connection attempts leading up to the
1242 // success will be returned via the successfully connected socket. If the
1243 // connection fails, failed connection attempts will be returned via the
1244 // ClientSocketHandle. Check whether a socket was returned and copy the
1245 // connection attempts from the proper place.
MaybeCopyConnectionAttemptsFromSocketOrHandle()1246 void HttpStreamFactory::Job::MaybeCopyConnectionAttemptsFromSocketOrHandle() {
1247   if (!connection_)
1248     return;
1249 
1250   ConnectionAttempts socket_attempts = connection_->connection_attempts();
1251   if (connection_->socket()) {
1252     connection_->socket()->GetConnectionAttempts(&socket_attempts);
1253   }
1254 
1255   delegate_->AddConnectionAttemptsToRequest(this, socket_attempts);
1256 }
1257 
1258 HttpStreamFactory::JobFactory::JobFactory() = default;
1259 
1260 HttpStreamFactory::JobFactory::~JobFactory() = default;
1261 
1262 std::unique_ptr<HttpStreamFactory::Job>
CreateMainJob(HttpStreamFactory::Job::Delegate * delegate,HttpStreamFactory::JobType job_type,HttpNetworkSession * session,const HttpRequestInfo & request_info,RequestPriority priority,const ProxyInfo & proxy_info,const SSLConfig & server_ssl_config,const SSLConfig & proxy_ssl_config,HostPortPair destination,GURL origin_url,bool is_websocket,bool enable_ip_based_pooling,NetLog * net_log)1263 HttpStreamFactory::JobFactory::CreateMainJob(
1264     HttpStreamFactory::Job::Delegate* delegate,
1265     HttpStreamFactory::JobType job_type,
1266     HttpNetworkSession* session,
1267     const HttpRequestInfo& request_info,
1268     RequestPriority priority,
1269     const ProxyInfo& proxy_info,
1270     const SSLConfig& server_ssl_config,
1271     const SSLConfig& proxy_ssl_config,
1272     HostPortPair destination,
1273     GURL origin_url,
1274     bool is_websocket,
1275     bool enable_ip_based_pooling,
1276     NetLog* net_log) {
1277   return std::make_unique<HttpStreamFactory::Job>(
1278       delegate, job_type, session, request_info, priority, proxy_info,
1279       server_ssl_config, proxy_ssl_config, destination, origin_url,
1280       kProtoUnknown, quic::ParsedQuicVersion::Unsupported(), is_websocket,
1281       enable_ip_based_pooling, net_log);
1282 }
1283 
1284 std::unique_ptr<HttpStreamFactory::Job>
CreateAltSvcJob(HttpStreamFactory::Job::Delegate * delegate,HttpStreamFactory::JobType job_type,HttpNetworkSession * session,const HttpRequestInfo & request_info,RequestPriority priority,const ProxyInfo & proxy_info,const SSLConfig & server_ssl_config,const SSLConfig & proxy_ssl_config,HostPortPair destination,GURL origin_url,NextProto alternative_protocol,quic::ParsedQuicVersion quic_version,bool is_websocket,bool enable_ip_based_pooling,NetLog * net_log)1285 HttpStreamFactory::JobFactory::CreateAltSvcJob(
1286     HttpStreamFactory::Job::Delegate* delegate,
1287     HttpStreamFactory::JobType job_type,
1288     HttpNetworkSession* session,
1289     const HttpRequestInfo& request_info,
1290     RequestPriority priority,
1291     const ProxyInfo& proxy_info,
1292     const SSLConfig& server_ssl_config,
1293     const SSLConfig& proxy_ssl_config,
1294     HostPortPair destination,
1295     GURL origin_url,
1296     NextProto alternative_protocol,
1297     quic::ParsedQuicVersion quic_version,
1298     bool is_websocket,
1299     bool enable_ip_based_pooling,
1300     NetLog* net_log) {
1301   return std::make_unique<HttpStreamFactory::Job>(
1302       delegate, job_type, session, request_info, priority, proxy_info,
1303       server_ssl_config, proxy_ssl_config, destination, origin_url,
1304       alternative_protocol, quic_version, is_websocket, enable_ip_based_pooling,
1305       net_log);
1306 }
1307 
ShouldThrottleConnectForSpdy() const1308 bool HttpStreamFactory::Job::ShouldThrottleConnectForSpdy() const {
1309   DCHECK(!using_quic_);
1310   DCHECK(!spdy_session_request_);
1311 
1312   // If the job has previously been throttled, don't throttle it again.
1313   if (init_connection_already_resumed_)
1314     return false;
1315 
1316   url::SchemeHostPort scheme_host_port(
1317       using_ssl_ ? url::kHttpsScheme : url::kHttpScheme,
1318       spdy_session_key_.host_port_pair().host(),
1319       spdy_session_key_.host_port_pair().port());
1320   // Only throttle the request if the server is believed to support H2.
1321   return session_->http_server_properties()->GetSupportsSpdy(
1322       scheme_host_port, request_info_.network_isolation_key);
1323 }
1324 
1325 }  // namespace net
1326