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