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 #ifndef NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_ 6 #define NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_ 7 8 #include <memory> 9 #include <utility> 10 #include <vector> 11 12 #include "base/memory/raw_ptr.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/time/time.h" 15 #include "net/base/completion_repeating_callback.h" 16 #include "net/base/net_export.h" 17 #include "net/base/request_priority.h" 18 #include "net/dns/public/resolve_error_info.h" 19 #include "net/dns/public/secure_dns_policy.h" 20 #include "net/http/bidirectional_stream_impl.h" 21 #include "net/http/http_auth.h" 22 #include "net/http/http_auth_controller.h" 23 #include "net/http/http_stream_factory.h" 24 #include "net/http/http_stream_request.h" 25 #include "net/quic/quic_session_pool.h" 26 #include "net/socket/client_socket_handle.h" 27 #include "net/socket/client_socket_pool.h" 28 #include "net/socket/client_socket_pool_manager.h" 29 #include "net/socket/next_proto.h" 30 #include "net/socket/ssl_client_socket.h" 31 #include "net/spdy/spdy_session_key.h" 32 #include "net/spdy/spdy_session_pool.h" 33 #include "net/ssl/ssl_config.h" 34 #include "url/gurl.h" 35 #include "url/scheme_host_port.h" 36 37 namespace net { 38 39 namespace test { 40 41 class HttpStreamFactoryJobPeer; 42 43 } // namespace test 44 45 class ClientSocketHandle; 46 class HttpAuthController; 47 class HttpNetworkSession; 48 class HttpStream; 49 class SpdySessionPool; 50 class NetLog; 51 class ProxyChain; 52 struct SSLConfig; 53 54 // An HttpStreamRequest exists for each stream which is in progress of being 55 // created for the HttpStreamFactory. 56 class HttpStreamFactory::Job 57 : public SpdySessionPool::SpdySessionRequest::Delegate { 58 public: 59 // For jobs issued simultaneously to an HTTP/2 supported server, a delay is 60 // applied to avoid unnecessary socket connection establishments. 61 // https://crbug.com/718576 62 static const int kHTTP2ThrottleMs = 300; 63 64 // Returns true when QUIC is forcibly used for `destination`. 65 static bool OriginToForceQuicOn(const QuicParams& quic_params, 66 const url::SchemeHostPort& destination); 67 68 // Delegate to report Job's status to HttpStreamRequest and HttpStreamFactory. 69 class NET_EXPORT_PRIVATE Delegate { 70 public: 71 virtual ~Delegate() = default; 72 73 // Invoked when |job| has an HttpStream ready. 74 virtual void OnStreamReady(Job* job) = 0; 75 76 // Invoked when |job| has a BidirectionalStream ready. 77 virtual void OnBidirectionalStreamImplReady( 78 Job* job, 79 const ProxyInfo& used_proxy_info) = 0; 80 81 // Invoked when |job| has a WebSocketHandshakeStream ready. 82 virtual void OnWebSocketHandshakeStreamReady( 83 Job* job, 84 const ProxyInfo& used_proxy_info, 85 std::unique_ptr<WebSocketHandshakeStreamBase> stream) = 0; 86 87 // Invoked when |job| fails to create a stream. 88 virtual void OnStreamFailed(Job* job, int status) = 0; 89 90 // Invoked when |job| fails on the default network. 91 virtual void OnFailedOnDefaultNetwork(Job* job) = 0; 92 93 // Invoked when |job| has a certificate error for the HttpStreamRequest. 94 virtual void OnCertificateError(Job* job, 95 int status, 96 const SSLInfo& ssl_info) = 0; 97 98 // Invoked when |job| raises failure for SSL Client Auth. 99 virtual void OnNeedsClientAuth(Job* job, SSLCertRequestInfo* cert_info) = 0; 100 101 // Invoked when |job| needs proxy authentication. 102 virtual void OnNeedsProxyAuth(Job* job, 103 const HttpResponseInfo& proxy_response, 104 const ProxyInfo& used_proxy_info, 105 HttpAuthController* auth_controller) = 0; 106 107 // Invoked when the |job| finishes pre-connecting sockets. 108 virtual void OnPreconnectsComplete(Job* job, int result) = 0; 109 110 // Invoked to record connection attempts made by the socket layer to 111 // HttpStreamRequest if |job| is associated with HttpStreamRequest. 112 virtual void AddConnectionAttemptsToRequest( 113 Job* job, 114 const ConnectionAttempts& attempts) = 0; 115 116 // Invoked when |job| finishes initiating a connection. This may occur 117 // before the handshake is complete, and provides the delegate an 118 // early chance to handle any errors. 119 virtual void OnConnectionInitialized(Job* job, int rv) = 0; 120 121 // Return false if |job| can advance to the next state. Otherwise, |job| 122 // will wait for Job::Resume() to be called before advancing. 123 virtual bool ShouldWait(Job* job) = 0; 124 125 virtual const NetLogWithSource* GetNetLog() const = 0; 126 127 virtual WebSocketHandshakeStreamBase::CreateHelper* 128 websocket_handshake_stream_create_helper() = 0; 129 130 virtual void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) = 0; 131 }; 132 133 // Job is owned by |delegate|, hence |delegate| is valid for the lifetime of 134 // the Job. 135 // 136 // |alternative_protocol| is the protocol required by Alternative Service, if 137 // any: 138 // * |alternative_protocol == kProtoUnknown| means that the Job can pool to an 139 // existing SpdySession, or bind to a idle TCP socket that might use either 140 // HTTP/1.1 or HTTP/2. 141 // * |alternative_protocol == kProtoHTTP2| means that the Job can pool to an 142 // existing SpdySession, or bind to a idle TCP socket. In the latter case, 143 // if the socket does not use HTTP/2, then the Job fails. 144 // * |alternative_protocol == kProtoQUIC| means that the Job can pool to an 145 // existing QUIC connection or open a new one. 146 // Note that this can be overwritten by specifying a QUIC proxy in 147 // |proxy_info|, or by setting 148 // HttpNetworkSession::Params::origins_to_force_quic_on. 149 Job(Delegate* delegate, 150 JobType job_type, 151 HttpNetworkSession* session, 152 const StreamRequestInfo& request_info, 153 RequestPriority priority, 154 const ProxyInfo& proxy_info, 155 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs, 156 url::SchemeHostPort destination, 157 GURL origin_url, 158 NextProto alternative_protocol, 159 quic::ParsedQuicVersion quic_version, 160 bool is_websocket, 161 bool enable_ip_based_pooling, 162 NetLog* net_log); 163 164 Job(const Job&) = delete; 165 Job& operator=(const Job&) = delete; 166 167 ~Job() override; 168 169 // Start initiates the process of creating a new HttpStream. 170 // |delegate_| will be notified upon completion. 171 void Start(HttpStreamRequest::StreamType stream_type); 172 173 // Preconnect will attempt to request |num_streams| sockets from the 174 // appropriate ClientSocketPool. 175 int Preconnect(int num_streams); 176 177 int RestartTunnelWithProxyAuth(); 178 LoadState GetLoadState() const; 179 180 // Tells |this| that |delegate_| has determined it still needs to continue 181 // connecting. 182 virtual void Resume(); 183 184 // Called when |this| is orphaned by Delegate. This is valid for 185 // ALTERNATIVE job and DNS_ALPN_H3 job. 186 void Orphan(); 187 188 void SetPriority(RequestPriority priority); 189 190 // Returns true if the current request can be immediately sent on a existing 191 // spdy session. 192 bool HasAvailableSpdySession() const; 193 194 // Returns true if the current request can be immediately sent on a existing 195 // QUIC session. 196 bool HasAvailableQuicSession() const; 197 198 // Returns true if a connected (idle or handed out) or connecting socket 199 // exists for the job. This method is not supported for WebSocket and QUIC. 200 bool TargettedSocketGroupHasActiveSocket() const; 201 origin_url()202 const GURL& origin_url() const { return origin_url_; } priority()203 RequestPriority priority() const { return priority_; } 204 NextProto negotiated_protocol() const; net_log()205 const NetLogWithSource& net_log() const { return net_log_; } stream_type()206 HttpStreamRequest::StreamType stream_type() const { return stream_type_; } 207 ReleaseStream()208 std::unique_ptr<HttpStream> ReleaseStream() { return std::move(stream_); } 209 ReleaseBidirectionalStream()210 std::unique_ptr<BidirectionalStreamImpl> ReleaseBidirectionalStream() { 211 return std::move(bidirectional_stream_impl_); 212 } 213 is_waiting()214 bool is_waiting() const { return next_state_ == STATE_WAIT_COMPLETE; } 215 const ProxyInfo& proxy_info() const; 216 ResolveErrorInfo resolve_error_info() const; 217 job_type()218 JobType job_type() const { return job_type_; } 219 using_existing_quic_session()220 bool using_existing_quic_session() const { 221 return using_existing_quic_session_; 222 } 223 expect_on_quic_session_created()224 bool expect_on_quic_session_created() const { 225 return expect_on_quic_session_created_; 226 } 227 expect_on_quic_host_resolution_for_tests()228 bool expect_on_quic_host_resolution_for_tests() const { 229 return expect_on_quic_host_resolution_; 230 } 231 using_quic()232 bool using_quic() const { return using_quic_; } 233 should_reconsider_proxy()234 bool should_reconsider_proxy() const { return should_reconsider_proxy_; } 235 net_error_details()236 NetErrorDetails* net_error_details() { return &net_error_details_; } 237 238 private: 239 friend class test::HttpStreamFactoryJobPeer; 240 241 enum State { 242 STATE_START, 243 // The main and alternative jobs are started in parallel. The main job 244 // can wait if it's paused. The alternative job never waits. 245 // 246 // An HTTP/2 alternative job notifies the JobController in DoInitConnection 247 // unless it can pool to an existing SpdySession. JobController, in turn, 248 // resumes the main job. 249 // 250 // A QUIC alternative job notifies the JobController in DoInitConnection 251 // regardless of whether it pools to an existing QUIC session, but the main 252 // job is only resumed after some delay. 253 // 254 // If the main job is resumed, then it races the alternative job. 255 STATE_WAIT, 256 STATE_WAIT_COMPLETE, 257 258 STATE_INIT_CONNECTION, 259 STATE_INIT_CONNECTION_COMPLETE, 260 STATE_WAITING_USER_ACTION, 261 STATE_CREATE_STREAM, 262 STATE_CREATE_STREAM_COMPLETE, 263 STATE_DONE, 264 STATE_NONE, 265 }; 266 267 void OnStreamReadyCallback(); 268 void OnBidirectionalStreamImplReadyCallback(); 269 void OnWebSocketHandshakeStreamReadyCallback(); 270 // This callback function is called when a new SPDY session is created. 271 void OnNewSpdySessionReadyCallback(); 272 void OnStreamFailedCallback(int result); 273 void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info); 274 void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info, 275 HttpAuthController* auth_controller, 276 base::OnceClosure restart_with_auth_callback); 277 void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info); 278 void OnPreconnectsComplete(int result); 279 280 void OnIOComplete(int result); 281 // RunLoop() finishes asynchronously and invokes one of the On* methods (see 282 // above) when done. 283 void RunLoop(int result); 284 int DoLoop(int result); 285 int StartInternal(); 286 int DoInitConnectionImpl(); 287 // `server_cert_verifier_flags` are the cert verifier flags if connecting to a 288 // QUIC server. If making non-tunnelled requests to a QUIC proxy, they will be 289 // ignored. 290 int DoInitConnectionImplQuic(int server_cert_verifier_flags); 291 292 // If this is a QUIC alt job, then this function is called when host 293 // resolution completes. It's called with the next result after host 294 // resolution, not the result of host resolution itself. 295 void OnQuicHostResolution(int result); 296 297 // If this is a QUIC alt job, this function is called when the QUIC session is 298 // created. It's called with the result of either failed session creation or 299 // an attempted crypto connection. 300 void OnQuicSessionCreated(int result); 301 302 // Invoked when the underlying connection fails on the default network. 303 void OnFailedOnDefaultNetwork(int result); 304 305 // Each of these methods corresponds to a State value. Those with an input 306 // argument receive the result from the previous state. If a method returns 307 // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the 308 // next state method as the result arg. 309 int DoStart(); 310 int DoWait(); 311 int DoWaitComplete(int result); 312 int DoInitConnection(); 313 int DoInitConnectionComplete(int result); 314 int DoWaitingUserAction(int result); 315 int DoCreateStream(); 316 int DoCreateStreamComplete(int result); 317 318 void ResumeInitConnection(); 319 320 // Creates a SpdyHttpStream or a BidirectionalStreamImpl from the given values 321 // and sets to |stream_| or |bidirectional_stream_impl_| respectively. Does 322 // nothing if |stream_factory_| is for WebSocket. 323 int SetSpdyHttpStreamOrBidirectionalStreamImpl( 324 base::WeakPtr<SpdySession> session); 325 326 // SpdySessionPool::SpdySessionRequest::Delegate implementation: 327 void OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session) override; 328 329 // Retrieve SSLInfo from our SSL Socket. 330 // This must only be called when we are using an SSLSocket. 331 void GetSSLInfo(SSLInfo* ssl_info); 332 333 // Returns true if the resulting stream will use an HTTP GET to the final 334 // proxy in the chain, instead of a CONNECT to the endpoint. 335 bool UsingHttpProxyWithoutTunnel() const; 336 337 // Called in Job constructor: should Job be forced to use QUIC. 338 static bool ShouldForceQuic(HttpNetworkSession* session, 339 const url::SchemeHostPort& destination, 340 const ProxyInfo& proxy_info, 341 bool using_ssl, 342 bool is_websocket); 343 344 // Called in Job constructor. Use |spdy_session_key_| after construction. 345 static SpdySessionKey GetSpdySessionKey( 346 const ProxyChain& proxy_chain, 347 const GURL& origin_url, 348 const StreamRequestInfo& request_info); 349 350 // Returns whether an appropriate SPDY session would correspond to either a 351 // connection to the last proxy server in the chain (for the traditional HTTP 352 // proxying behavior of sending a GET request to the proxy server) or a 353 // connection through the entire proxy chain (for tunneled requests). Note 354 // that for QUIC proxies we no longer support the former. 355 static bool IsGetToProxy(const ProxyChain& proxy_chain, 356 const GURL& origin_url); 357 358 // Returns true if the current request can use an existing spdy session. 359 bool CanUseExistingSpdySession() const; 360 361 // Called when we encounter a network error that could be resolved by trying 362 // a new proxy configuration. If there is another proxy configuration to try 363 // then this method sets next_state_ appropriately and returns either OK or 364 // ERR_IO_PENDING depending on whether or not the new proxy configuration is 365 // available synchronously or asynchronously. Otherwise, the given error 366 // code is simply returned. 367 int ReconsiderProxyAfterError(int error); 368 369 void MaybeCopyConnectionAttemptsFromHandle(); 370 371 // Returns true if the request should be throttled to allow for only one 372 // connection attempt to be made to an H2 server at a time. 373 bool ShouldThrottleConnectForSpdy() const; 374 375 // True if Job actually uses HTTP/2. Note this describes both using HTTP/2 376 // with an HTTPS origin, and proxying a cleartext HTTP request over an HTTP/2 377 // proxy. This differs from `using_ssl_`, which only describes the origin. 378 bool using_spdy() const; 379 380 bool disable_cert_verification_network_fetches() const; 381 382 const StreamRequestInfo request_info_; 383 RequestPriority priority_; 384 const ProxyInfo proxy_info_; 385 const std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_; 386 const NetLogWithSource net_log_; 387 388 const CompletionRepeatingCallback io_callback_; 389 std::unique_ptr<ClientSocketHandle> connection_; 390 const raw_ptr<HttpNetworkSession> session_; 391 392 State next_state_ = STATE_NONE; 393 394 bool started_ = false; 395 396 // The server we are trying to reach, could be that of the origin or of the 397 // alternative service (after applying host mapping rules). The scheme of this 398 // is always HTTP or HTTPS, even for websockets requests. 399 const url::SchemeHostPort destination_; 400 401 // The origin url we're trying to reach. This url may be different from the 402 // original request when host mapping rules are set-up. It has the original 403 // scheme, so may be HTTP, HTTPS, WS, or WSS. It does not change when there's 404 // an alternate service, but it does take into account host mapping rules, 405 // unlike `request_info_.url`. 406 const GURL origin_url_; 407 408 // True if request is for Websocket. 409 const bool is_websocket_; 410 411 // True if WebSocket request is allowed to use a WebSocket-capable existing 412 // HTTP/2 connection. In this case FindAvailableSession() must be called with 413 // |enable_websocket = true|. 414 const bool try_websocket_over_http2_; 415 416 // Enable pooling to a SpdySession with matching IP and certificate 417 // even if the SpdySessionKey is different. 418 const bool enable_ip_based_pooling_; 419 420 // Unowned. |this| job is owned by |delegate_|. 421 const raw_ptr<Delegate> delegate_; 422 423 const JobType job_type_; 424 425 // True if handling a HTTPS request. Note this only describes the origin URL. 426 // If false (an HTTP request), the request may still be sent over an HTTPS 427 // proxy. This differs from `using_quic_` and `using_spdy()`, which also 428 // describe some proxy cases. 429 const bool using_ssl_; 430 431 // True if Job actually uses QUIC. Note this describes both using QUIC 432 // with an HTTPS origin, and proxying a cleartext HTTP request over an QUIC 433 // proxy. This differs from `using_ssl_`, which only describes the origin. 434 const bool using_quic_; 435 436 // quic::ParsedQuicVersion that should be used to connect to the QUIC 437 // server if Job uses QUIC. 438 quic::ParsedQuicVersion quic_version_; 439 440 // True if Alternative Service protocol field requires that HTTP/2 is used. 441 // In this case, Job fails if it cannot pool to an existing SpdySession and 442 // the server does not negotiate HTTP/2 on a new socket. 443 const bool expect_spdy_; 444 445 // True if this job might succeed with a different proxy config. 446 bool should_reconsider_proxy_ = false; 447 448 QuicSessionRequest quic_request_; 449 450 // Only valid for a QUIC job. Set when a QUIC connection is started. If true, 451 // then OnQuicHostResolution() is expected to be called in the future. 452 bool expect_on_quic_host_resolution_ = false; 453 454 // Only valid for a QUIC job. Set when a QUIC connection is started. If true, 455 // OnQuicSessionCreated() is expected to be called in the future. 456 bool expect_on_quic_session_created_ = false; 457 458 // True if this job used an existing QUIC session. 459 bool using_existing_quic_session_ = false; 460 461 // True when the tunnel is in the process of being established - we can't 462 // read from the socket until the tunnel is done. 463 bool establishing_tunnel_ = false; 464 465 std::unique_ptr<HttpStream> stream_; 466 std::unique_ptr<WebSocketHandshakeStreamBase> websocket_stream_; 467 std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_; 468 469 // Protocol negotiated with the server. 470 NextProto negotiated_protocol_ = kProtoUnknown; 471 472 // 0 if we're not preconnecting. Otherwise, the number of streams to 473 // preconnect. 474 int num_streams_ = 0; 475 476 // Initialized when we have an existing SpdySession. 477 base::WeakPtr<SpdySession> existing_spdy_session_; 478 479 // Which SpdySessions in the pool to use. Note that, if requesting an HTTP URL 480 // through an HTTPS proxy, this key corresponds to the last proxy in the proxy 481 // chain and not the origin server. 482 const SpdySessionKey spdy_session_key_; 483 484 // Type of stream that is requested. 485 HttpStreamRequest::StreamType stream_type_ = 486 HttpStreamRequest::BIDIRECTIONAL_STREAM; 487 488 // Whether Job has continued to DoInitConnection(). 489 bool init_connection_already_resumed_ = false; 490 491 base::OnceClosure restart_with_auth_callback_; 492 493 NetErrorDetails net_error_details_; 494 495 ResolveErrorInfo resolve_error_info_; 496 497 std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request_; 498 499 base::WeakPtrFactory<Job> ptr_factory_{this}; 500 }; 501 502 // Factory for creating Jobs. 503 class HttpStreamFactory::JobFactory { 504 public: 505 JobFactory(); 506 507 virtual ~JobFactory(); 508 509 virtual std::unique_ptr<HttpStreamFactory::Job> CreateJob( 510 HttpStreamFactory::Job::Delegate* delegate, 511 HttpStreamFactory::JobType job_type, 512 HttpNetworkSession* session, 513 const StreamRequestInfo& request_info, 514 RequestPriority priority, 515 const ProxyInfo& proxy_info, 516 const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs, 517 url::SchemeHostPort destination, 518 GURL origin_url, 519 bool is_websocket, 520 bool enable_ip_based_pooling, 521 NetLog* net_log, 522 NextProto alternative_protocol = kProtoUnknown, 523 quic::ParsedQuicVersion quic_version = 524 quic::ParsedQuicVersion::Unsupported()); 525 }; 526 527 } // namespace net 528 529 #endif // NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_ 530