| // 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 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); |
| } 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 |