// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_HTTP_HTTP_PROXY_CONNECT_JOB_H_ #define NET_HTTP_HTTP_PROXY_CONNECT_JOB_H_ #include #include #include #include "base/functional/callback_forward.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "net/base/host_port_pair.h" #include "net/base/net_export.h" #include "net/base/network_anonymization_key.h" #include "net/base/proxy_chain.h" #include "net/base/request_priority.h" #include "net/dns/public/resolve_error_info.h" #include "net/dns/public/secure_dns_policy.h" #include "net/http/http_auth.h" #include "net/quic/quic_chromium_client_session.h" #include "net/socket/connect_job.h" #include "net/socket/connect_job_params.h" #include "net/socket/ssl_client_socket.h" #include "net/spdy/spdy_session_key.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace net { class HttpAuthController; class HttpResponseInfo; class NetworkQualityEstimator; class SocketTag; class ProxyClientSocket; class SpdyStreamRequest; class SSLSocketParams; class TransportSocketParams; class QuicSessionRequest; // HttpProxySocketParams only needs the socket params for one of the proxy // types. The other param must be NULL. When using an HTTP proxy, // `transport_params` must be set. When using an HTTPS proxy, `ssl_params` must // be set. When using a QUIC proxy, both must be `nullptr` but `quic_ssl_config` // must be set. class NET_EXPORT_PRIVATE HttpProxySocketParams : public base::RefCounted { public: // Construct an `HttpProxyConnectJob` over a transport or SSL connection // defined by the `ConnectJobParams`. HttpProxySocketParams( ConnectJobParams nested_params, const HostPortPair& endpoint, const ProxyChain& proxy_chain, size_t proxy_chain_index, bool tunnel, const NetworkTrafficAnnotationTag traffic_annotation, const NetworkAnonymizationKey& network_anonymization_key, SecureDnsPolicy secure_dns_policy); // Construct an `HttpProxyConnectJob` over a QUIC connection using the given // SSL config. HttpProxySocketParams( SSLConfig quic_ssl_config, const HostPortPair& endpoint, const ProxyChain& proxy_chain, size_t proxy_chain_index, bool tunnel, const NetworkTrafficAnnotationTag traffic_annotation, const NetworkAnonymizationKey& network_anonymization_key, SecureDnsPolicy secure_dns_policy); HttpProxySocketParams(const HttpProxySocketParams&) = delete; HttpProxySocketParams& operator=(const HttpProxySocketParams&) = delete; bool is_over_transport() const { return nested_params_ && nested_params_->is_transport(); } bool is_over_ssl() const { return nested_params_ && nested_params_->is_ssl(); } bool is_over_quic() const { return quic_ssl_config_.has_value(); } // Get the nested transport params, or fail if not `is_over_transport()`. const scoped_refptr& transport_params() const { return nested_params_->transport(); } // Get the nested SSL params, or fail if not `is_over_ssl()`. const scoped_refptr& ssl_params() const { return nested_params_->ssl(); } // Get the QUIC ssl config, or fail if not `is_over_quic()`. const std::optional& quic_ssl_config() const { return quic_ssl_config_; } const HostPortPair& endpoint() const { return endpoint_; } const ProxyChain& proxy_chain() const { return proxy_chain_; } const ProxyServer& proxy_server() const { return proxy_chain_.GetProxyServer(proxy_chain_index_); } size_t proxy_chain_index() const { return proxy_chain_index_; } bool tunnel() const { return tunnel_; } const NetworkAnonymizationKey& network_anonymization_key() const { return network_anonymization_key_; } const NetworkTrafficAnnotationTag traffic_annotation() const { return traffic_annotation_; } SecureDnsPolicy secure_dns_policy() { return secure_dns_policy_; } private: friend class base::RefCounted; HttpProxySocketParams( std::optional nested_params, std::optional quic_ssl_config, const HostPortPair& endpoint, const ProxyChain& proxy_chain, size_t proxy_chain_index, bool tunnel, const NetworkTrafficAnnotationTag traffic_annotation, const NetworkAnonymizationKey& network_anonymization_key, SecureDnsPolicy secure_dns_policy); ~HttpProxySocketParams(); const std::optional nested_params_; const std::optional quic_ssl_config_; const HostPortPair endpoint_; const ProxyChain proxy_chain_; const size_t proxy_chain_index_; const bool tunnel_; const NetworkAnonymizationKey network_anonymization_key_; const NetworkTrafficAnnotationTag traffic_annotation_; const SecureDnsPolicy secure_dns_policy_; }; // HttpProxyConnectJob optionally establishes a tunnel through the proxy // server after connecting the underlying transport socket. class NET_EXPORT_PRIVATE HttpProxyConnectJob : public ConnectJob, public ConnectJob::Delegate { public: class NET_EXPORT_PRIVATE Factory { public: Factory() = default; virtual ~Factory() = default; virtual std::unique_ptr Create( RequestPriority priority, const SocketTag& socket_tag, const CommonConnectJobParams* common_connect_job_params, scoped_refptr params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log); }; HttpProxyConnectJob(RequestPriority priority, const SocketTag& socket_tag, const CommonConnectJobParams* common_connect_job_params, scoped_refptr params, ConnectJob::Delegate* delegate, const NetLogWithSource* net_log); HttpProxyConnectJob(const HttpProxyConnectJob&) = delete; HttpProxyConnectJob& operator=(const HttpProxyConnectJob&) = delete; ~HttpProxyConnectJob() override; // A single priority is used for tunnels over H2 and QUIC, which can be shared // by multiple requests of different priorities either in series (tunnels for // HTTP/1.x requests) or simultaneously (tunnels for H2 requests). Changing // the priority of the tunnel based on the current request also potentially // leaks private data to the proxy. static const RequestPriority kH2QuicTunnelPriority; // ConnectJob methods. LoadState GetLoadState() const override; bool HasEstablishedConnection() const override; ResolveErrorInfo GetResolveErrorInfo() const override; bool IsSSLError() const override; scoped_refptr GetCertRequestInfo() override; // ConnectJob::Delegate implementation. void OnConnectJobComplete(int result, ConnectJob* job) override; void OnNeedsProxyAuth(const HttpResponseInfo& response, HttpAuthController* auth_controller, base::OnceClosure restart_with_auth_callback, ConnectJob* job) override; // In some cases, a timeout that's stricter than the TCP (+SSL, if applicable) // is used for HTTP proxies during connection establishment and SSL // negotiation for the connection to the proxy itself. In those cases, returns // the connection timeout that will be used by a HttpProxyConnectJob created // with the specified parameters, given current network conditions. Otherwise, // returns base::TimeDelta(). static base::TimeDelta AlternateNestedConnectionTimeout( const HttpProxySocketParams& params, const NetworkQualityEstimator* network_quality_estimator); // Returns the timeout for establishing a tunnel after a connection has been // established. static base::TimeDelta TunnelTimeoutForTesting(); // Updates the field trial parameters used in calculating timeouts. static void UpdateFieldTrialParametersForTesting(); private: enum State { STATE_BEGIN_CONNECT, STATE_TRANSPORT_CONNECT, STATE_TRANSPORT_CONNECT_COMPLETE, STATE_HTTP_PROXY_CONNECT, STATE_HTTP_PROXY_CONNECT_COMPLETE, STATE_SPDY_PROXY_CREATE_STREAM, STATE_SPDY_PROXY_CREATE_STREAM_COMPLETE, STATE_QUIC_PROXY_CREATE_SESSION, STATE_QUIC_PROXY_CREATE_STREAM, STATE_QUIC_PROXY_CREATE_STREAM_COMPLETE, STATE_RESTART_WITH_AUTH, STATE_RESTART_WITH_AUTH_COMPLETE, STATE_NONE, }; // Begins the tcp connection and the optional Http proxy tunnel. If the // request is not immediately serviceable (likely), the request will return // ERR_IO_PENDING. An OK return from this function or the callback means // that the connection is established; ERR_PROXY_AUTH_REQUESTED means // that the tunnel needs authentication credentials, the socket will be // returned in this case, and must be released back to the pool; or // a standard net error code will be returned. int ConnectInternal() override; ProxyServer::Scheme GetProxyServerScheme() const; void OnIOComplete(int result); void RestartWithAuthCredentials(); // Runs the state transition loop. int DoLoop(int result); // Determine if need to go through TCP or SSL path. int DoBeginConnect(); // Connecting to HTTP or HTTPS Proxy int DoTransportConnect(); int DoTransportConnectComplete(int result); int DoHttpProxyConnect(); int DoHttpProxyConnectComplete(int result); int DoSpdyProxyCreateStream(); int DoSpdyProxyCreateStreamComplete(int result); int DoQuicProxyCreateSession(); int DoQuicProxyCreateStream(int result); int DoQuicProxyCreateStreamComplete(int result); int DoRestartWithAuth(); int DoRestartWithAuthComplete(int result); // ConnectJob implementation. void ChangePriorityInternal(RequestPriority priority) override; void OnTimedOutInternal() override; void OnAuthChallenge(); const HostPortPair& GetDestination() const; std::string GetUserAgent() const; SpdySessionKey CreateSpdySessionKey() const; scoped_refptr params_; scoped_refptr ssl_cert_request_info_; State next_state_ = STATE_NONE; bool has_restarted_ = false; // Set to true once a connection has been successfully established. Remains // true even if a new socket is being connected to retry with auth. bool has_established_connection_ = false; ResolveErrorInfo resolve_error_info_; std::unique_ptr nested_connect_job_; std::unique_ptr transport_socket_; std::unique_ptr spdy_stream_request_; std::unique_ptr quic_session_request_; std::unique_ptr quic_session_; scoped_refptr http_auth_controller_; NetErrorDetails quic_net_error_details_; // Time when the connection to the proxy was started. base::TimeTicks connect_start_time_; base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace net #endif // NET_HTTP_HTTP_PROXY_CONNECT_JOB_H_