blob: c176371fbc63c4d5504ccf7cb0807a3c6838a421 [file] [log] [blame]
// 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 <memory>
#include <optional>
#include <string>
#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<HttpProxySocketParams> {
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<TransportSocketParams>& transport_params() const {
return nested_params_->transport();
}
// Get the nested SSL params, or fail if not `is_over_ssl()`.
const scoped_refptr<SSLSocketParams>& ssl_params() const {
return nested_params_->ssl();
}
// Get the QUIC ssl config, or fail if not `is_over_quic()`.
const std::optional<SSLConfig>& 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>;
HttpProxySocketParams(
std::optional<ConnectJobParams> nested_params,
std::optional<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 std::optional<ConnectJobParams> nested_params_;
const std::optional<SSLConfig> 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<HttpProxyConnectJob> Create(
RequestPriority priority,
const SocketTag& socket_tag,
const CommonConnectJobParams* common_connect_job_params,
scoped_refptr<HttpProxySocketParams> params,
ConnectJob::Delegate* delegate,
const NetLogWithSource* net_log);
};
HttpProxyConnectJob(RequestPriority priority,
const SocketTag& socket_tag,
const CommonConnectJobParams* common_connect_job_params,
scoped_refptr<HttpProxySocketParams> 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<SSLCertRequestInfo> 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<HttpProxySocketParams> params_;
scoped_refptr<SSLCertRequestInfo> 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<ConnectJob> nested_connect_job_;
std::unique_ptr<ProxyClientSocket> transport_socket_;
std::unique_ptr<SpdyStreamRequest> spdy_stream_request_;
std::unique_ptr<QuicSessionRequest> quic_session_request_;
std::unique_ptr<QuicChromiumClientSession::Handle> quic_session_;
scoped_refptr<HttpAuthController> http_auth_controller_;
NetErrorDetails quic_net_error_details_;
// Time when the connection to the proxy was started.
base::TimeTicks connect_start_time_;
base::WeakPtrFactory<HttpProxyConnectJob> weak_ptr_factory_{this};
};
} // namespace net
#endif // NET_HTTP_HTTP_PROXY_CONNECT_JOB_H_