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