• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "net/socket/client_socket_pool.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/check_op.h"
11 #include "base/feature_list.h"
12 #include "base/functional/bind.h"
13 #include "net/base/features.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/proxy_server.h"
16 #include "net/dns/public/secure_dns_policy.h"
17 #include "net/http/http_proxy_connect_job.h"
18 #include "net/log/net_log_event_type.h"
19 #include "net/log/net_log_with_source.h"
20 #include "net/socket/connect_job.h"
21 #include "net/socket/connect_job_factory.h"
22 #include "net/socket/socks_connect_job.h"
23 #include "net/socket/ssl_connect_job.h"
24 #include "net/socket/stream_socket.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/spdy/spdy_session_pool.h"
27 #include "url/gurl.h"
28 #include "url/scheme_host_port.h"
29 #include "url/url_constants.h"
30 
31 namespace net {
32 
33 namespace {
34 
35 // The maximum duration, in seconds, to keep used idle persistent sockets alive.
36 int64_t g_used_idle_socket_timeout_s = 300;  // 5 minutes
37 
38 // Invoked by the transport socket pool after host resolution is complete
39 // to allow the connection to be aborted, if a matching SPDY session can
40 // be found. Returns OnHostResolutionCallbackResult::kMayBeDeletedAsync if such
41 // a session is found, as it will post a task that may delete the calling
42 // ConnectJob. Also returns kMayBeDeletedAsync if there may already be such
43 // a task posted.
OnHostResolution(SpdySessionPool * spdy_session_pool,const SpdySessionKey & spdy_session_key,bool is_for_websockets,const HostPortPair & host_port_pair,const std::vector<HostResolverEndpointResult> & endpoint_results,const std::set<std::string> & aliases)44 OnHostResolutionCallbackResult OnHostResolution(
45     SpdySessionPool* spdy_session_pool,
46     const SpdySessionKey& spdy_session_key,
47     bool is_for_websockets,
48     const HostPortPair& host_port_pair,
49     const std::vector<HostResolverEndpointResult>& endpoint_results,
50     const std::set<std::string>& aliases) {
51   DCHECK(host_port_pair == spdy_session_key.host_port_pair());
52 
53   // It is OK to dereference spdy_session_pool, because the
54   // ClientSocketPoolManager will be destroyed in the same callback that
55   // destroys the SpdySessionPool.
56   return spdy_session_pool->OnHostResolutionComplete(
57       spdy_session_key, is_for_websockets, endpoint_results, aliases);
58 }
59 
60 }  // namespace
61 
SocketParams(std::unique_ptr<SSLConfig> ssl_config_for_origin,std::unique_ptr<SSLConfig> ssl_config_for_proxy)62 ClientSocketPool::SocketParams::SocketParams(
63     std::unique_ptr<SSLConfig> ssl_config_for_origin,
64     std::unique_ptr<SSLConfig> ssl_config_for_proxy)
65     : ssl_config_for_origin_(std::move(ssl_config_for_origin)),
66       ssl_config_for_proxy_(std::move(ssl_config_for_proxy)) {}
67 
68 ClientSocketPool::SocketParams::~SocketParams() = default;
69 
70 scoped_refptr<ClientSocketPool::SocketParams>
CreateForHttpForTesting()71 ClientSocketPool::SocketParams::CreateForHttpForTesting() {
72   return base::MakeRefCounted<SocketParams>(nullptr /* ssl_config_for_origin */,
73                                             nullptr /* ssl_config_for_proxy */);
74 }
75 
GroupId()76 ClientSocketPool::GroupId::GroupId()
77     : privacy_mode_(PrivacyMode::PRIVACY_MODE_DISABLED) {}
78 
GroupId(url::SchemeHostPort destination,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy)79 ClientSocketPool::GroupId::GroupId(
80     url::SchemeHostPort destination,
81     PrivacyMode privacy_mode,
82     NetworkAnonymizationKey network_anonymization_key,
83     SecureDnsPolicy secure_dns_policy)
84     : destination_(std::move(destination)),
85       privacy_mode_(privacy_mode),
86       network_anonymization_key_(
87           NetworkAnonymizationKey::IsPartitioningEnabled()
88               ? std::move(network_anonymization_key)
89               : NetworkAnonymizationKey()),
90       secure_dns_policy_(secure_dns_policy) {
91   DCHECK(destination_.IsValid());
92 
93   // ClientSocketPool only expected to be used for HTTP/HTTPS/WS/WSS cases, and
94   // "ws"/"wss" schemes should be converted to "http"/"https" equivalent first.
95   DCHECK(destination_.scheme() == url::kHttpScheme ||
96          destination_.scheme() == url::kHttpsScheme);
97 }
98 
99 ClientSocketPool::GroupId::GroupId(const GroupId& group_id) = default;
100 
101 ClientSocketPool::GroupId::~GroupId() = default;
102 
103 ClientSocketPool::GroupId& ClientSocketPool::GroupId::operator=(
104     const GroupId& group_id) = default;
105 
106 ClientSocketPool::GroupId& ClientSocketPool::GroupId::operator=(
107     GroupId&& group_id) = default;
108 
ToString() const109 std::string ClientSocketPool::GroupId::ToString() const {
110   std::string result = destination_.Serialize();
111 
112   if (privacy_mode_)
113     result = "pm/" + result;
114 
115   if (NetworkAnonymizationKey::IsPartitioningEnabled()) {
116     result += " <";
117     result += network_anonymization_key_.ToDebugString();
118     result += ">";
119   }
120 
121   switch (secure_dns_policy_) {
122     case SecureDnsPolicy::kAllow:
123       break;
124     case SecureDnsPolicy::kDisable:
125       result = "dsd/" + result;
126       break;
127     case SecureDnsPolicy::kBootstrap:
128       result = "dns_bootstrap/" + result;
129       break;
130   }
131 
132   return result;
133 }
134 
135 ClientSocketPool::~ClientSocketPool() = default;
136 
137 // static
used_idle_socket_timeout()138 base::TimeDelta ClientSocketPool::used_idle_socket_timeout() {
139   return base::Seconds(g_used_idle_socket_timeout_s);
140 }
141 
142 // static
set_used_idle_socket_timeout(base::TimeDelta timeout)143 void ClientSocketPool::set_used_idle_socket_timeout(base::TimeDelta timeout) {
144   DCHECK_GT(timeout.InSeconds(), 0);
145   g_used_idle_socket_timeout_s = timeout.InSeconds();
146 }
147 
ClientSocketPool(bool is_for_websockets,const CommonConnectJobParams * common_connect_job_params,std::unique_ptr<ConnectJobFactory> connect_job_factory)148 ClientSocketPool::ClientSocketPool(
149     bool is_for_websockets,
150     const CommonConnectJobParams* common_connect_job_params,
151     std::unique_ptr<ConnectJobFactory> connect_job_factory)
152     : is_for_websockets_(is_for_websockets),
153       common_connect_job_params_(common_connect_job_params),
154       connect_job_factory_(std::move(connect_job_factory)) {}
155 
NetLogTcpClientSocketPoolRequestedSocket(const NetLogWithSource & net_log,const GroupId & group_id)156 void ClientSocketPool::NetLogTcpClientSocketPoolRequestedSocket(
157     const NetLogWithSource& net_log,
158     const GroupId& group_id) {
159   // TODO(eroman): Split out the host and port parameters.
160   net_log.AddEvent(NetLogEventType::TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
161                    [&] { return NetLogGroupIdParams(group_id); });
162 }
163 
NetLogGroupIdParams(const GroupId & group_id)164 base::Value::Dict ClientSocketPool::NetLogGroupIdParams(
165     const GroupId& group_id) {
166   base::Value::Dict event_params;
167   event_params.Set("group_id", group_id.ToString());
168   return event_params;
169 }
170 
CreateConnectJob(GroupId group_id,scoped_refptr<SocketParams> socket_params,const ProxyServer & proxy_server,const absl::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,RequestPriority request_priority,SocketTag socket_tag,ConnectJob::Delegate * delegate)171 std::unique_ptr<ConnectJob> ClientSocketPool::CreateConnectJob(
172     GroupId group_id,
173     scoped_refptr<SocketParams> socket_params,
174     const ProxyServer& proxy_server,
175     const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
176     RequestPriority request_priority,
177     SocketTag socket_tag,
178     ConnectJob::Delegate* delegate) {
179   bool using_ssl = GURL::SchemeIsCryptographic(group_id.destination().scheme());
180 
181   // If applicable, set up a callback to handle checking for H2 IP pooling
182   // opportunities.
183   OnHostResolutionCallback resolution_callback;
184   if (using_ssl && proxy_server.is_direct()) {
185     resolution_callback = base::BindRepeating(
186         &OnHostResolution, common_connect_job_params_->spdy_session_pool,
187         // TODO(crbug.com/1206799): Pass along as SchemeHostPort.
188         SpdySessionKey(HostPortPair::FromSchemeHostPort(group_id.destination()),
189                        proxy_server, group_id.privacy_mode(),
190                        SpdySessionKey::IsProxySession::kFalse, socket_tag,
191                        group_id.network_anonymization_key(),
192                        group_id.secure_dns_policy()),
193         is_for_websockets_);
194   } else if (proxy_server.is_https()) {
195     resolution_callback = base::BindRepeating(
196         &OnHostResolution, common_connect_job_params_->spdy_session_pool,
197         SpdySessionKey(proxy_server.host_port_pair(), ProxyServer::Direct(),
198                        group_id.privacy_mode(),
199                        SpdySessionKey::IsProxySession::kTrue, socket_tag,
200                        group_id.network_anonymization_key(),
201                        group_id.secure_dns_policy()),
202         is_for_websockets_);
203   }
204 
205   return connect_job_factory_->CreateConnectJob(
206       group_id.destination(), proxy_server, proxy_annotation_tag,
207       socket_params->ssl_config_for_origin(),
208       socket_params->ssl_config_for_proxy(), is_for_websockets_,
209       group_id.privacy_mode(), resolution_callback, request_priority,
210       socket_tag, group_id.network_anonymization_key(),
211       group_id.secure_dns_policy(), common_connect_job_params_, delegate);
212 }
213 
214 }  // namespace net
215