1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/socket/client_socket_pool.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <memory>
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker #include <vector>
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/base/host_port_pair.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/base/proxy_chain.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/base/session_usage.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/dns/public/secure_dns_policy.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/http/http_proxy_connect_job.h"
22*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
23*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_with_source.h"
24*6777b538SAndroid Build Coastguard Worker #include "net/socket/connect_job.h"
25*6777b538SAndroid Build Coastguard Worker #include "net/socket/connect_job_factory.h"
26*6777b538SAndroid Build Coastguard Worker #include "net/socket/socks_connect_job.h"
27*6777b538SAndroid Build Coastguard Worker #include "net/socket/ssl_connect_job.h"
28*6777b538SAndroid Build Coastguard Worker #include "net/socket/stream_socket.h"
29*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_session.h"
30*6777b538SAndroid Build Coastguard Worker #include "net/spdy/spdy_session_pool.h"
31*6777b538SAndroid Build Coastguard Worker #include "net/ssl/ssl_config.h"
32*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
33*6777b538SAndroid Build Coastguard Worker #include "url/scheme_host_port.h"
34*6777b538SAndroid Build Coastguard Worker #include "url/url_constants.h"
35*6777b538SAndroid Build Coastguard Worker
36*6777b538SAndroid Build Coastguard Worker namespace net {
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker namespace {
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker // The maximum duration, in seconds, to keep used idle persistent sockets alive.
41*6777b538SAndroid Build Coastguard Worker int64_t g_used_idle_socket_timeout_s = 300; // 5 minutes
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker // Invoked by the transport socket pool after host resolution is complete
44*6777b538SAndroid Build Coastguard Worker // to allow the connection to be aborted, if a matching SPDY session can
45*6777b538SAndroid Build Coastguard Worker // be found. Returns OnHostResolutionCallbackResult::kMayBeDeletedAsync if such
46*6777b538SAndroid Build Coastguard Worker // a session is found, as it will post a task that may delete the calling
47*6777b538SAndroid Build Coastguard Worker // ConnectJob. Also returns kMayBeDeletedAsync if there may already be such
48*6777b538SAndroid Build Coastguard Worker // 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)49*6777b538SAndroid Build Coastguard Worker OnHostResolutionCallbackResult OnHostResolution(
50*6777b538SAndroid Build Coastguard Worker SpdySessionPool* spdy_session_pool,
51*6777b538SAndroid Build Coastguard Worker const SpdySessionKey& spdy_session_key,
52*6777b538SAndroid Build Coastguard Worker bool is_for_websockets,
53*6777b538SAndroid Build Coastguard Worker const HostPortPair& host_port_pair,
54*6777b538SAndroid Build Coastguard Worker const std::vector<HostResolverEndpointResult>& endpoint_results,
55*6777b538SAndroid Build Coastguard Worker const std::set<std::string>& aliases) {
56*6777b538SAndroid Build Coastguard Worker DCHECK(host_port_pair == spdy_session_key.host_port_pair());
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker // It is OK to dereference spdy_session_pool, because the
59*6777b538SAndroid Build Coastguard Worker // ClientSocketPoolManager will be destroyed in the same callback that
60*6777b538SAndroid Build Coastguard Worker // destroys the SpdySessionPool.
61*6777b538SAndroid Build Coastguard Worker return spdy_session_pool->OnHostResolutionComplete(
62*6777b538SAndroid Build Coastguard Worker spdy_session_key, is_for_websockets, endpoint_results, aliases);
63*6777b538SAndroid Build Coastguard Worker }
64*6777b538SAndroid Build Coastguard Worker
GetPrivacyModeGroupIdPrefix(PrivacyMode privacy_mode)65*6777b538SAndroid Build Coastguard Worker std::string_view GetPrivacyModeGroupIdPrefix(PrivacyMode privacy_mode) {
66*6777b538SAndroid Build Coastguard Worker switch (privacy_mode) {
67*6777b538SAndroid Build Coastguard Worker case PrivacyMode::PRIVACY_MODE_DISABLED:
68*6777b538SAndroid Build Coastguard Worker return "";
69*6777b538SAndroid Build Coastguard Worker case PrivacyMode::PRIVACY_MODE_ENABLED:
70*6777b538SAndroid Build Coastguard Worker return "pm/";
71*6777b538SAndroid Build Coastguard Worker case PrivacyMode::PRIVACY_MODE_ENABLED_WITHOUT_CLIENT_CERTS:
72*6777b538SAndroid Build Coastguard Worker return "pmwocc/";
73*6777b538SAndroid Build Coastguard Worker case PrivacyMode::PRIVACY_MODE_ENABLED_PARTITIONED_STATE_ALLOWED:
74*6777b538SAndroid Build Coastguard Worker return "pmpsa/";
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker
GetSecureDnsPolicyGroupIdPrefix(SecureDnsPolicy secure_dns_policy)78*6777b538SAndroid Build Coastguard Worker std::string_view GetSecureDnsPolicyGroupIdPrefix(
79*6777b538SAndroid Build Coastguard Worker SecureDnsPolicy secure_dns_policy) {
80*6777b538SAndroid Build Coastguard Worker switch (secure_dns_policy) {
81*6777b538SAndroid Build Coastguard Worker case SecureDnsPolicy::kAllow:
82*6777b538SAndroid Build Coastguard Worker return "";
83*6777b538SAndroid Build Coastguard Worker case SecureDnsPolicy::kDisable:
84*6777b538SAndroid Build Coastguard Worker return "dsd/";
85*6777b538SAndroid Build Coastguard Worker case SecureDnsPolicy::kBootstrap:
86*6777b538SAndroid Build Coastguard Worker return "dns_bootstrap/";
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker } // namespace
91*6777b538SAndroid Build Coastguard Worker
SocketParams(const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs)92*6777b538SAndroid Build Coastguard Worker ClientSocketPool::SocketParams::SocketParams(
93*6777b538SAndroid Build Coastguard Worker const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs)
94*6777b538SAndroid Build Coastguard Worker : allowed_bad_certs_(allowed_bad_certs) {}
95*6777b538SAndroid Build Coastguard Worker
96*6777b538SAndroid Build Coastguard Worker ClientSocketPool::SocketParams::~SocketParams() = default;
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker scoped_refptr<ClientSocketPool::SocketParams>
CreateForHttpForTesting()99*6777b538SAndroid Build Coastguard Worker ClientSocketPool::SocketParams::CreateForHttpForTesting() {
100*6777b538SAndroid Build Coastguard Worker return base::MakeRefCounted<SocketParams>(
101*6777b538SAndroid Build Coastguard Worker /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
102*6777b538SAndroid Build Coastguard Worker }
103*6777b538SAndroid Build Coastguard Worker
GroupId()104*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId::GroupId()
105*6777b538SAndroid Build Coastguard Worker : privacy_mode_(PrivacyMode::PRIVACY_MODE_DISABLED) {}
106*6777b538SAndroid Build Coastguard Worker
GroupId(url::SchemeHostPort destination,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy,bool disable_cert_network_fetches)107*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId::GroupId(
108*6777b538SAndroid Build Coastguard Worker url::SchemeHostPort destination,
109*6777b538SAndroid Build Coastguard Worker PrivacyMode privacy_mode,
110*6777b538SAndroid Build Coastguard Worker NetworkAnonymizationKey network_anonymization_key,
111*6777b538SAndroid Build Coastguard Worker SecureDnsPolicy secure_dns_policy,
112*6777b538SAndroid Build Coastguard Worker bool disable_cert_network_fetches)
113*6777b538SAndroid Build Coastguard Worker : destination_(std::move(destination)),
114*6777b538SAndroid Build Coastguard Worker privacy_mode_(privacy_mode),
115*6777b538SAndroid Build Coastguard Worker network_anonymization_key_(
116*6777b538SAndroid Build Coastguard Worker NetworkAnonymizationKey::IsPartitioningEnabled()
117*6777b538SAndroid Build Coastguard Worker ? std::move(network_anonymization_key)
118*6777b538SAndroid Build Coastguard Worker : NetworkAnonymizationKey()),
119*6777b538SAndroid Build Coastguard Worker secure_dns_policy_(secure_dns_policy),
120*6777b538SAndroid Build Coastguard Worker disable_cert_network_fetches_(disable_cert_network_fetches) {
121*6777b538SAndroid Build Coastguard Worker DCHECK(destination_.IsValid());
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker // ClientSocketPool only expected to be used for HTTP/HTTPS/WS/WSS cases, and
124*6777b538SAndroid Build Coastguard Worker // "ws"/"wss" schemes should be converted to "http"/"https" equivalent first.
125*6777b538SAndroid Build Coastguard Worker DCHECK(destination_.scheme() == url::kHttpScheme ||
126*6777b538SAndroid Build Coastguard Worker destination_.scheme() == url::kHttpsScheme);
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker
129*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId::GroupId(const GroupId& group_id) = default;
130*6777b538SAndroid Build Coastguard Worker
131*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId::~GroupId() = default;
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId& ClientSocketPool::GroupId::operator=(
134*6777b538SAndroid Build Coastguard Worker const GroupId& group_id) = default;
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker ClientSocketPool::GroupId& ClientSocketPool::GroupId::operator=(
137*6777b538SAndroid Build Coastguard Worker GroupId&& group_id) = default;
138*6777b538SAndroid Build Coastguard Worker
ToString() const139*6777b538SAndroid Build Coastguard Worker std::string ClientSocketPool::GroupId::ToString() const {
140*6777b538SAndroid Build Coastguard Worker return base::StrCat(
141*6777b538SAndroid Build Coastguard Worker {disable_cert_network_fetches_ ? "disable_cert_network_fetches/" : "",
142*6777b538SAndroid Build Coastguard Worker GetSecureDnsPolicyGroupIdPrefix(secure_dns_policy_),
143*6777b538SAndroid Build Coastguard Worker GetPrivacyModeGroupIdPrefix(privacy_mode_), destination_.Serialize(),
144*6777b538SAndroid Build Coastguard Worker NetworkAnonymizationKey::IsPartitioningEnabled()
145*6777b538SAndroid Build Coastguard Worker ? base::StrCat(
146*6777b538SAndroid Build Coastguard Worker {" <", network_anonymization_key_.ToDebugString(), ">"})
147*6777b538SAndroid Build Coastguard Worker : ""});
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Worker ClientSocketPool::~ClientSocketPool() = default;
151*6777b538SAndroid Build Coastguard Worker
152*6777b538SAndroid Build Coastguard Worker // static
used_idle_socket_timeout()153*6777b538SAndroid Build Coastguard Worker base::TimeDelta ClientSocketPool::used_idle_socket_timeout() {
154*6777b538SAndroid Build Coastguard Worker return base::Seconds(g_used_idle_socket_timeout_s);
155*6777b538SAndroid Build Coastguard Worker }
156*6777b538SAndroid Build Coastguard Worker
157*6777b538SAndroid Build Coastguard Worker // static
set_used_idle_socket_timeout(base::TimeDelta timeout)158*6777b538SAndroid Build Coastguard Worker void ClientSocketPool::set_used_idle_socket_timeout(base::TimeDelta timeout) {
159*6777b538SAndroid Build Coastguard Worker DCHECK_GT(timeout.InSeconds(), 0);
160*6777b538SAndroid Build Coastguard Worker g_used_idle_socket_timeout_s = timeout.InSeconds();
161*6777b538SAndroid Build Coastguard Worker }
162*6777b538SAndroid Build Coastguard Worker
ClientSocketPool(bool is_for_websockets,const CommonConnectJobParams * common_connect_job_params,std::unique_ptr<ConnectJobFactory> connect_job_factory)163*6777b538SAndroid Build Coastguard Worker ClientSocketPool::ClientSocketPool(
164*6777b538SAndroid Build Coastguard Worker bool is_for_websockets,
165*6777b538SAndroid Build Coastguard Worker const CommonConnectJobParams* common_connect_job_params,
166*6777b538SAndroid Build Coastguard Worker std::unique_ptr<ConnectJobFactory> connect_job_factory)
167*6777b538SAndroid Build Coastguard Worker : is_for_websockets_(is_for_websockets),
168*6777b538SAndroid Build Coastguard Worker common_connect_job_params_(common_connect_job_params),
169*6777b538SAndroid Build Coastguard Worker connect_job_factory_(std::move(connect_job_factory)) {}
170*6777b538SAndroid Build Coastguard Worker
NetLogTcpClientSocketPoolRequestedSocket(const NetLogWithSource & net_log,const GroupId & group_id)171*6777b538SAndroid Build Coastguard Worker void ClientSocketPool::NetLogTcpClientSocketPoolRequestedSocket(
172*6777b538SAndroid Build Coastguard Worker const NetLogWithSource& net_log,
173*6777b538SAndroid Build Coastguard Worker const GroupId& group_id) {
174*6777b538SAndroid Build Coastguard Worker // TODO(eroman): Split out the host and port parameters.
175*6777b538SAndroid Build Coastguard Worker net_log.AddEvent(NetLogEventType::TCP_CLIENT_SOCKET_POOL_REQUESTED_SOCKET,
176*6777b538SAndroid Build Coastguard Worker [&] { return NetLogGroupIdParams(group_id); });
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker
NetLogGroupIdParams(const GroupId & group_id)179*6777b538SAndroid Build Coastguard Worker base::Value::Dict ClientSocketPool::NetLogGroupIdParams(
180*6777b538SAndroid Build Coastguard Worker const GroupId& group_id) {
181*6777b538SAndroid Build Coastguard Worker return base::Value::Dict().Set("group_id", group_id.ToString());
182*6777b538SAndroid Build Coastguard Worker }
183*6777b538SAndroid Build Coastguard Worker
CreateConnectJob(GroupId group_id,scoped_refptr<SocketParams> socket_params,const ProxyChain & proxy_chain,const std::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,RequestPriority request_priority,SocketTag socket_tag,ConnectJob::Delegate * delegate)184*6777b538SAndroid Build Coastguard Worker std::unique_ptr<ConnectJob> ClientSocketPool::CreateConnectJob(
185*6777b538SAndroid Build Coastguard Worker GroupId group_id,
186*6777b538SAndroid Build Coastguard Worker scoped_refptr<SocketParams> socket_params,
187*6777b538SAndroid Build Coastguard Worker const ProxyChain& proxy_chain,
188*6777b538SAndroid Build Coastguard Worker const std::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
189*6777b538SAndroid Build Coastguard Worker RequestPriority request_priority,
190*6777b538SAndroid Build Coastguard Worker SocketTag socket_tag,
191*6777b538SAndroid Build Coastguard Worker ConnectJob::Delegate* delegate) {
192*6777b538SAndroid Build Coastguard Worker bool using_ssl = GURL::SchemeIsCryptographic(group_id.destination().scheme());
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker // If applicable, set up a callback to handle checking for H2 IP pooling
195*6777b538SAndroid Build Coastguard Worker // opportunities. We don't perform H2 IP pooling to or through proxy servers,
196*6777b538SAndroid Build Coastguard Worker // so ignore those cases.
197*6777b538SAndroid Build Coastguard Worker OnHostResolutionCallback resolution_callback;
198*6777b538SAndroid Build Coastguard Worker if (using_ssl && proxy_chain.is_direct()) {
199*6777b538SAndroid Build Coastguard Worker resolution_callback = base::BindRepeating(
200*6777b538SAndroid Build Coastguard Worker &OnHostResolution, common_connect_job_params_->spdy_session_pool,
201*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1206799): Pass along as SchemeHostPort.
202*6777b538SAndroid Build Coastguard Worker SpdySessionKey(HostPortPair::FromSchemeHostPort(group_id.destination()),
203*6777b538SAndroid Build Coastguard Worker group_id.privacy_mode(), proxy_chain,
204*6777b538SAndroid Build Coastguard Worker SessionUsage::kDestination, socket_tag,
205*6777b538SAndroid Build Coastguard Worker group_id.network_anonymization_key(),
206*6777b538SAndroid Build Coastguard Worker group_id.secure_dns_policy(),
207*6777b538SAndroid Build Coastguard Worker group_id.disable_cert_network_fetches()),
208*6777b538SAndroid Build Coastguard Worker is_for_websockets_);
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker // Force a CONNECT tunnel for websockets. If this is false, the connect job
212*6777b538SAndroid Build Coastguard Worker // may still use a tunnel for other reasons.
213*6777b538SAndroid Build Coastguard Worker bool force_tunnel = is_for_websockets_;
214*6777b538SAndroid Build Coastguard Worker
215*6777b538SAndroid Build Coastguard Worker // Only offer HTTP/1.1 for WebSockets. Although RFC 8441 defines WebSockets
216*6777b538SAndroid Build Coastguard Worker // over HTTP/2, a single WSS/HTTPS origin may support HTTP over HTTP/2
217*6777b538SAndroid Build Coastguard Worker // without supporting WebSockets over HTTP/2. Offering HTTP/2 for a fresh
218*6777b538SAndroid Build Coastguard Worker // connection would break such origins.
219*6777b538SAndroid Build Coastguard Worker //
220*6777b538SAndroid Build Coastguard Worker // However, still offer HTTP/1.1 rather than skipping ALPN entirely. While
221*6777b538SAndroid Build Coastguard Worker // this will not change the application protocol (HTTP/1.1 is default), it
222*6777b538SAndroid Build Coastguard Worker // provides hardening against cross-protocol attacks and allows for the False
223*6777b538SAndroid Build Coastguard Worker // Start (RFC 7918) optimization.
224*6777b538SAndroid Build Coastguard Worker ConnectJobFactory::AlpnMode alpn_mode =
225*6777b538SAndroid Build Coastguard Worker is_for_websockets_ ? ConnectJobFactory::AlpnMode::kHttp11Only
226*6777b538SAndroid Build Coastguard Worker : ConnectJobFactory::AlpnMode::kHttpAll;
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker return connect_job_factory_->CreateConnectJob(
229*6777b538SAndroid Build Coastguard Worker group_id.destination(), proxy_chain, proxy_annotation_tag,
230*6777b538SAndroid Build Coastguard Worker socket_params->allowed_bad_certs(), alpn_mode, force_tunnel,
231*6777b538SAndroid Build Coastguard Worker group_id.privacy_mode(), resolution_callback, request_priority,
232*6777b538SAndroid Build Coastguard Worker socket_tag, group_id.network_anonymization_key(),
233*6777b538SAndroid Build Coastguard Worker group_id.secure_dns_policy(), group_id.disable_cert_network_fetches(),
234*6777b538SAndroid Build Coastguard Worker common_connect_job_params_, delegate);
235*6777b538SAndroid Build Coastguard Worker }
236*6777b538SAndroid Build Coastguard Worker
237*6777b538SAndroid Build Coastguard Worker } // namespace net
238