blob: 871d0f5bcbdf58f6fc20c0cb9784f8368b643f63 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/socket/connect_job.h"
#include <utility>
#include "base/trace_event/trace_event.h"
#include "net/base/net_errors.h"
#include "net/base/trace_constants.h"
#include "net/http/http_auth_controller.h"
#include "net/http/http_proxy_connect_job.h"
#include "net/log/net_log.h"
#include "net/log/net_log_event_type.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/socket_tag.h"
#include "net/socket/socks_connect_job.h"
#include "net/socket/ssl_connect_job.h"
#include "net/socket/stream_socket.h"
#include "net/socket/transport_connect_job.h"
#include "net/ssl/ssl_config.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace net {
CommonConnectJobParams::CommonConnectJobParams(
ClientSocketFactory* client_socket_factory,
HostResolver* host_resolver,
HttpAuthCache* http_auth_cache,
HttpAuthHandlerFactory* http_auth_handler_factory,
SpdySessionPool* spdy_session_pool,
const quic::ParsedQuicVersionVector* quic_supported_versions,
QuicStreamFactory* quic_stream_factory,
ProxyDelegate* proxy_delegate,
const HttpUserAgentSettings* http_user_agent_settings,
const SSLClientSocketContext& ssl_client_socket_context,
const SSLClientSocketContext& ssl_client_socket_context_privacy_mode,
SocketPerformanceWatcherFactory* socket_performance_watcher_factory,
NetworkQualityEstimator* network_quality_estimator,
NetLog* net_log,
WebSocketEndpointLockManager* websocket_endpoint_lock_manager)
: client_socket_factory(client_socket_factory),
host_resolver(host_resolver),
http_auth_cache(http_auth_cache),
http_auth_handler_factory(http_auth_handler_factory),
spdy_session_pool(spdy_session_pool),
quic_supported_versions(quic_supported_versions),
quic_stream_factory(quic_stream_factory),
proxy_delegate(proxy_delegate),
http_user_agent_settings(http_user_agent_settings),
ssl_client_socket_context(ssl_client_socket_context),
ssl_client_socket_context_privacy_mode(
ssl_client_socket_context_privacy_mode),
socket_performance_watcher_factory(socket_performance_watcher_factory),
network_quality_estimator(network_quality_estimator),
net_log(net_log),
websocket_endpoint_lock_manager(websocket_endpoint_lock_manager) {}
CommonConnectJobParams::CommonConnectJobParams(
const CommonConnectJobParams& other) = default;
CommonConnectJobParams::~CommonConnectJobParams() = default;
CommonConnectJobParams& CommonConnectJobParams::operator=(
const CommonConnectJobParams& other) = default;
ConnectJob::ConnectJob(RequestPriority priority,
const SocketTag& socket_tag,
base::TimeDelta timeout_duration,
const CommonConnectJobParams* common_connect_job_params,
Delegate* delegate,
const NetLogWithSource* net_log,
NetLogSourceType net_log_source_type,
NetLogEventType net_log_connect_event_type)
: timeout_duration_(timeout_duration),
priority_(priority),
socket_tag_(socket_tag),
common_connect_job_params_(common_connect_job_params),
delegate_(delegate),
top_level_job_(net_log == nullptr),
net_log_(net_log
? *net_log
: NetLogWithSource::Make(common_connect_job_params->net_log,
net_log_source_type)),
net_log_connect_event_type_(net_log_connect_event_type) {
DCHECK(delegate);
if (top_level_job_)
net_log_.BeginEvent(NetLogEventType::CONNECT_JOB);
}
ConnectJob::~ConnectJob() {
// Log end of Connect event if ConnectJob was still in-progress when
// destroyed.
if (delegate_)
LogConnectCompletion(ERR_ABORTED);
if (top_level_job_)
net_log().EndEvent(NetLogEventType::CONNECT_JOB);
}
std::unique_ptr<ConnectJob> ConnectJob::CreateConnectJob(
bool using_ssl,
const HostPortPair& endpoint,
const ProxyServer& proxy_server,
const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
const SSLConfig* ssl_config_for_origin,
const SSLConfig* ssl_config_for_proxy,
bool force_tunnel,
PrivacyMode privacy_mode,
const OnHostResolutionCallback& resolution_callback,
RequestPriority request_priority,
SocketTag socket_tag,
const NetworkIsolationKey& network_isolation_key,
const CommonConnectJobParams* common_connect_job_params,
ConnectJob::Delegate* delegate) {
scoped_refptr<HttpProxySocketParams> http_proxy_params;
scoped_refptr<SOCKSSocketParams> socks_params;
if (!proxy_server.is_direct()) {
auto proxy_tcp_params = base::MakeRefCounted<TransportSocketParams>(
proxy_server.host_port_pair(), resolution_callback);
if (proxy_server.is_http() || proxy_server.is_https() ||
proxy_server.is_quic()) {
scoped_refptr<SSLSocketParams> ssl_params;
if (!proxy_server.is_http()) {
DCHECK(ssl_config_for_proxy);
// Set ssl_params, and unset proxy_tcp_params
ssl_params = base::MakeRefCounted<SSLSocketParams>(
std::move(proxy_tcp_params), nullptr, nullptr,
proxy_server.host_port_pair(), *ssl_config_for_proxy,
PRIVACY_MODE_DISABLED);
proxy_tcp_params = nullptr;
}
http_proxy_params = base::MakeRefCounted<HttpProxySocketParams>(
std::move(proxy_tcp_params), std::move(ssl_params),
proxy_server.is_quic(), endpoint, proxy_server.is_trusted_proxy(),
force_tunnel || using_ssl, *proxy_annotation_tag,
network_isolation_key);
} else {
DCHECK(proxy_server.is_socks());
socks_params = base::MakeRefCounted<SOCKSSocketParams>(
std::move(proxy_tcp_params),
proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5, endpoint,
*proxy_annotation_tag);
}
}
// Deal with SSL - which layers on top of any given proxy.
if (using_ssl) {
DCHECK(ssl_config_for_origin);
scoped_refptr<TransportSocketParams> ssl_tcp_params;
if (proxy_server.is_direct()) {
ssl_tcp_params = base::MakeRefCounted<TransportSocketParams>(
endpoint, resolution_callback);
}
auto ssl_params = base::MakeRefCounted<SSLSocketParams>(
std::move(ssl_tcp_params), std::move(socks_params),
std::move(http_proxy_params), endpoint, *ssl_config_for_origin,
privacy_mode);
return std::make_unique<SSLConnectJob>(
request_priority, socket_tag, common_connect_job_params,
std::move(ssl_params), delegate, nullptr /* net_log */);
}
if (proxy_server.is_http() || proxy_server.is_https()) {
return std::make_unique<HttpProxyConnectJob>(
request_priority, socket_tag, common_connect_job_params,
std::move(http_proxy_params), delegate, nullptr /* net_log */);
}
if (proxy_server.is_socks()) {
return std::make_unique<SOCKSConnectJob>(
request_priority, socket_tag, common_connect_job_params,
std::move(socks_params), delegate, nullptr /* net_log */);
}
DCHECK(proxy_server.is_direct());
auto tcp_params = base::MakeRefCounted<TransportSocketParams>(
endpoint, resolution_callback);
return TransportConnectJob::CreateTransportConnectJob(
std::move(tcp_params), request_priority, socket_tag,
common_connect_job_params, delegate, nullptr /* net_log */);
}
std::unique_ptr<StreamSocket> ConnectJob::PassSocket() {
return std::move(socket_);
}
void ConnectJob::ChangePriority(RequestPriority priority) {
priority_ = priority;
ChangePriorityInternal(priority);
}
int ConnectJob::Connect() {
if (!timeout_duration_.is_zero())
timer_.Start(FROM_HERE, timeout_duration_, this, &ConnectJob::OnTimeout);
LogConnectStart();
int rv = ConnectInternal();
if (rv != ERR_IO_PENDING) {
LogConnectCompletion(rv);
delegate_ = nullptr;
}
return rv;
}
ConnectionAttempts ConnectJob::GetConnectionAttempts() const {
// Return empty list by default - used by proxy classes.
return ConnectionAttempts();
}
bool ConnectJob::IsSSLError() const {
return false;
}
scoped_refptr<SSLCertRequestInfo> ConnectJob::GetCertRequestInfo() {
return nullptr;
}
void ConnectJob::SetSocket(std::unique_ptr<StreamSocket> socket) {
if (socket)
net_log().AddEvent(NetLogEventType::CONNECT_JOB_SET_SOCKET);
socket_ = std::move(socket);
}
void ConnectJob::NotifyDelegateOfCompletion(int rv) {
TRACE_EVENT0(NetTracingCategory(), "ConnectJob::NotifyDelegateOfCompletion");
// The delegate will own |this|.
Delegate* delegate = delegate_;
delegate_ = nullptr;
LogConnectCompletion(rv);
delegate->OnConnectJobComplete(rv, this);
}
void ConnectJob::NotifyDelegateOfProxyAuth(
const HttpResponseInfo& response,
HttpAuthController* auth_controller,
base::OnceClosure restart_with_auth_callback) {
delegate_->OnNeedsProxyAuth(response, auth_controller,
std::move(restart_with_auth_callback), this);
}
void ConnectJob::ResetTimer(base::TimeDelta remaining_time) {
timer_.Stop();
if (!remaining_time.is_zero())
timer_.Start(FROM_HERE, remaining_time, this, &ConnectJob::OnTimeout);
}
bool ConnectJob::TimerIsRunning() const {
return timer_.IsRunning();
}
void ConnectJob::LogConnectStart() {
connect_timing_.connect_start = base::TimeTicks::Now();
net_log().BeginEvent(net_log_connect_event_type_);
}
void ConnectJob::LogConnectCompletion(int net_error) {
connect_timing_.connect_end = base::TimeTicks::Now();
net_log().EndEventWithNetErrorCode(net_log_connect_event_type_, net_error);
}
void ConnectJob::OnTimeout() {
// Make sure the socket is NULL before calling into |delegate|.
SetSocket(nullptr);
OnTimedOutInternal();
net_log_.AddEvent(NetLogEventType::CONNECT_JOB_TIMED_OUT);
NotifyDelegateOfCompletion(ERR_TIMED_OUT);
}
void ConnectJob::OnTimedOutInternal() {}
} // namespace net