xref: /aosp_15_r20/external/cronet/net/socket/client_socket_pool_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_manager.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <utility>
10 
11 #include "base/check_op.h"
12 #include "base/metrics/field_trial_params.h"
13 #include "base/strings/string_piece.h"
14 #include "build/build_config.h"
15 #include "net/base/features.h"
16 #include "net/base/load_flags.h"
17 #include "net/base/proxy_chain.h"
18 #include "net/base/proxy_server.h"
19 #include "net/dns/public/secure_dns_policy.h"
20 #include "net/http/http_stream_factory.h"
21 #include "net/proxy_resolution/proxy_info.h"
22 #include "net/socket/client_socket_handle.h"
23 #include "net/socket/client_socket_pool.h"
24 #include "net/socket/connect_job.h"
25 #include "net/ssl/ssl_config.h"
26 #include "url/gurl.h"
27 #include "url/scheme_host_port.h"
28 #include "url/url_constants.h"
29 
30 namespace net {
31 
32 namespace {
33 
34 // Limit of sockets of each socket pool.
35 int g_max_sockets_per_pool[] = {
36   256,  // NORMAL_SOCKET_POOL
37   256   // WEBSOCKET_SOCKET_POOL
38 };
39 
40 static_assert(std::size(g_max_sockets_per_pool) ==
41                   HttpNetworkSession::NUM_SOCKET_POOL_TYPES,
42               "max sockets per pool length mismatch");
43 
44 // Default to allow up to 6 connections per host. Experiment and tuning may
45 // try other values (greater than 0).  Too large may cause many problems, such
46 // as home routers blocking the connections!?!?  See http://crbug.com/12066.
47 //
48 // WebSocket connections are long-lived, and should be treated differently
49 // than normal other connections. Use a limit of 255, so the limit for wss will
50 // be the same as the limit for ws. Also note that Firefox uses a limit of 200.
51 // See http://crbug.com/486800
52 int g_max_sockets_per_group[] = {
53     6,   // NORMAL_SOCKET_POOL
54     255  // WEBSOCKET_SOCKET_POOL
55 };
56 
57 static_assert(std::size(g_max_sockets_per_group) ==
58                   HttpNetworkSession::NUM_SOCKET_POOL_TYPES,
59               "max sockets per group length mismatch");
60 
61 // The max number of sockets to allow per proxy chain.  This applies both to
62 // http and SOCKS proxies.  See http://crbug.com/12066 and
63 // http://crbug.com/44501 for details about proxy chain connection limits.
64 int g_max_sockets_per_proxy_chain[] = {
65     kDefaultMaxSocketsPerProxyChain,  // NORMAL_SOCKET_POOL
66     kDefaultMaxSocketsPerProxyChain   // WEBSOCKET_SOCKET_POOL
67 };
68 
69 static_assert(std::size(g_max_sockets_per_proxy_chain) ==
70                   HttpNetworkSession::NUM_SOCKET_POOL_TYPES,
71               "max sockets per proxy chain length mismatch");
72 
73 // TODO(https://crbug.com/921369) In order to resolve longstanding issues
74 // related to pooling distinguishable sockets together, get rid of SocketParams
75 // entirely.
CreateSocketParams(const ClientSocketPool::GroupId & group_id,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs)76 scoped_refptr<ClientSocketPool::SocketParams> CreateSocketParams(
77     const ClientSocketPool::GroupId& group_id,
78     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs) {
79   bool using_ssl = GURL::SchemeIsCryptographic(group_id.destination().scheme());
80   return base::MakeRefCounted<ClientSocketPool::SocketParams>(
81       using_ssl ? allowed_bad_certs : std::vector<SSLConfig::CertAndStatus>());
82 }
83 
InitSocketPoolHelper(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy,const SocketTag & socket_tag,const NetLogWithSource & net_log,int num_preconnect_streams,ClientSocketHandle * socket_handle,HttpNetworkSession::SocketPoolType socket_pool_type,CompletionOnceCallback callback,const ClientSocketPool::ProxyAuthCallback & proxy_auth_callback)84 int InitSocketPoolHelper(
85     url::SchemeHostPort endpoint,
86     int request_load_flags,
87     RequestPriority request_priority,
88     HttpNetworkSession* session,
89     const ProxyInfo& proxy_info,
90     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
91     PrivacyMode privacy_mode,
92     NetworkAnonymizationKey network_anonymization_key,
93     SecureDnsPolicy secure_dns_policy,
94     const SocketTag& socket_tag,
95     const NetLogWithSource& net_log,
96     int num_preconnect_streams,
97     ClientSocketHandle* socket_handle,
98     HttpNetworkSession::SocketPoolType socket_pool_type,
99     CompletionOnceCallback callback,
100     const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
101   DCHECK(endpoint.IsValid());
102 
103   bool using_ssl = GURL::SchemeIsCryptographic(endpoint.scheme());
104   if (!using_ssl && session->params().testing_fixed_http_port != 0) {
105     endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
106                                    session->params().testing_fixed_http_port);
107   } else if (using_ssl && session->params().testing_fixed_https_port != 0) {
108     endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
109                                    session->params().testing_fixed_https_port);
110   }
111 
112   bool disable_cert_network_fetches =
113       !!(request_load_flags & LOAD_DISABLE_CERT_NETWORK_FETCHES);
114   ClientSocketPool::GroupId connection_group(
115       std::move(endpoint), privacy_mode, std::move(network_anonymization_key),
116       secure_dns_policy, disable_cert_network_fetches);
117   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
118       CreateSocketParams(connection_group, allowed_bad_certs);
119 
120   ClientSocketPool* pool =
121       session->GetSocketPool(socket_pool_type, proxy_info.proxy_chain());
122   ClientSocketPool::RespectLimits respect_limits =
123       ClientSocketPool::RespectLimits::ENABLED;
124   if ((request_load_flags & LOAD_IGNORE_LIMITS) != 0)
125     respect_limits = ClientSocketPool::RespectLimits::DISABLED;
126 
127   std::optional<NetworkTrafficAnnotationTag> proxy_annotation =
128       proxy_info.is_direct() ? std::nullopt
129                              : std::optional<NetworkTrafficAnnotationTag>(
130                                    proxy_info.traffic_annotation());
131   if (num_preconnect_streams) {
132     return pool->RequestSockets(connection_group, std::move(socket_params),
133                                 proxy_annotation, num_preconnect_streams,
134                                 std::move(callback), net_log);
135   }
136 
137   return socket_handle->Init(connection_group, std::move(socket_params),
138                              proxy_annotation, request_priority, socket_tag,
139                              respect_limits, std::move(callback),
140                              proxy_auth_callback, pool, net_log);
141 }
142 
143 }  // namespace
144 
145 ClientSocketPoolManager::ClientSocketPoolManager() = default;
146 ClientSocketPoolManager::~ClientSocketPoolManager() = default;
147 
148 // static
max_sockets_per_pool(HttpNetworkSession::SocketPoolType pool_type)149 int ClientSocketPoolManager::max_sockets_per_pool(
150     HttpNetworkSession::SocketPoolType pool_type) {
151   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
152   return g_max_sockets_per_pool[pool_type];
153 }
154 
155 // static
set_max_sockets_per_pool(HttpNetworkSession::SocketPoolType pool_type,int socket_count)156 void ClientSocketPoolManager::set_max_sockets_per_pool(
157     HttpNetworkSession::SocketPoolType pool_type,
158     int socket_count) {
159   DCHECK_LT(0, socket_count);
160   DCHECK_GT(1000, socket_count);  // Sanity check.
161   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
162   g_max_sockets_per_pool[pool_type] = socket_count;
163   DCHECK_GE(g_max_sockets_per_pool[pool_type],
164             g_max_sockets_per_group[pool_type]);
165 }
166 
167 // static
max_sockets_per_group(HttpNetworkSession::SocketPoolType pool_type)168 int ClientSocketPoolManager::max_sockets_per_group(
169     HttpNetworkSession::SocketPoolType pool_type) {
170   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
171   return g_max_sockets_per_group[pool_type];
172 }
173 
174 // static
set_max_sockets_per_group(HttpNetworkSession::SocketPoolType pool_type,int socket_count)175 void ClientSocketPoolManager::set_max_sockets_per_group(
176     HttpNetworkSession::SocketPoolType pool_type,
177     int socket_count) {
178   DCHECK_LT(0, socket_count);
179   // The following is a sanity check... but we should NEVER be near this value.
180   DCHECK_GT(100, socket_count);
181   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
182   g_max_sockets_per_group[pool_type] = socket_count;
183 
184   DCHECK_GE(g_max_sockets_per_pool[pool_type],
185             g_max_sockets_per_group[pool_type]);
186   DCHECK_GE(g_max_sockets_per_proxy_chain[pool_type],
187             g_max_sockets_per_group[pool_type]);
188 }
189 
190 // static
max_sockets_per_proxy_chain(HttpNetworkSession::SocketPoolType pool_type)191 int ClientSocketPoolManager::max_sockets_per_proxy_chain(
192     HttpNetworkSession::SocketPoolType pool_type) {
193   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
194   return g_max_sockets_per_proxy_chain[pool_type];
195 }
196 
197 // static
set_max_sockets_per_proxy_chain(HttpNetworkSession::SocketPoolType pool_type,int socket_count)198 void ClientSocketPoolManager::set_max_sockets_per_proxy_chain(
199     HttpNetworkSession::SocketPoolType pool_type,
200     int socket_count) {
201   DCHECK_LT(0, socket_count);
202   DCHECK_GT(100, socket_count);  // Sanity check.
203   DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
204   // Assert this case early on. The max number of sockets per group cannot
205   // exceed the max number of sockets per proxy chain.
206   DCHECK_LE(g_max_sockets_per_group[pool_type], socket_count);
207   g_max_sockets_per_proxy_chain[pool_type] = socket_count;
208 }
209 
210 // static
unused_idle_socket_timeout(HttpNetworkSession::SocketPoolType pool_type)211 base::TimeDelta ClientSocketPoolManager::unused_idle_socket_timeout(
212     HttpNetworkSession::SocketPoolType pool_type) {
213   return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
214       net::features::kNetUnusedIdleSocketTimeout,
215       "unused_idle_socket_timeout_seconds", 60));
216 }
217 
InitSocketHandleForHttpRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy,const SocketTag & socket_tag,const NetLogWithSource & net_log,ClientSocketHandle * socket_handle,CompletionOnceCallback callback,const ClientSocketPool::ProxyAuthCallback & proxy_auth_callback)218 int InitSocketHandleForHttpRequest(
219     url::SchemeHostPort endpoint,
220     int request_load_flags,
221     RequestPriority request_priority,
222     HttpNetworkSession* session,
223     const ProxyInfo& proxy_info,
224     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
225     PrivacyMode privacy_mode,
226     NetworkAnonymizationKey network_anonymization_key,
227     SecureDnsPolicy secure_dns_policy,
228     const SocketTag& socket_tag,
229     const NetLogWithSource& net_log,
230     ClientSocketHandle* socket_handle,
231     CompletionOnceCallback callback,
232     const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
233   DCHECK(socket_handle);
234   return InitSocketPoolHelper(
235       std::move(endpoint), request_load_flags, request_priority, session,
236       proxy_info, allowed_bad_certs, privacy_mode,
237       std::move(network_anonymization_key), secure_dns_policy, socket_tag,
238       net_log, 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL,
239       std::move(callback), proxy_auth_callback);
240 }
241 
InitSocketHandleForWebSocketRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,const NetLogWithSource & net_log,ClientSocketHandle * socket_handle,CompletionOnceCallback callback,const ClientSocketPool::ProxyAuthCallback & proxy_auth_callback)242 int InitSocketHandleForWebSocketRequest(
243     url::SchemeHostPort endpoint,
244     int request_load_flags,
245     RequestPriority request_priority,
246     HttpNetworkSession* session,
247     const ProxyInfo& proxy_info,
248     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
249     PrivacyMode privacy_mode,
250     NetworkAnonymizationKey network_anonymization_key,
251     const NetLogWithSource& net_log,
252     ClientSocketHandle* socket_handle,
253     CompletionOnceCallback callback,
254     const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
255   DCHECK(socket_handle);
256 
257   // QUIC proxies are currently not supported through this method.
258   DCHECK(proxy_info.is_direct() || !proxy_info.proxy_chain().Last().is_quic());
259 
260   // Expect websocket schemes (ws and wss) to be converted to the http(s)
261   // equivalent.
262   DCHECK(endpoint.scheme() == url::kHttpScheme ||
263          endpoint.scheme() == url::kHttpsScheme);
264 
265   return InitSocketPoolHelper(
266       std::move(endpoint), request_load_flags, request_priority, session,
267       proxy_info, allowed_bad_certs, privacy_mode,
268       std::move(network_anonymization_key), SecureDnsPolicy::kAllow,
269       SocketTag(), net_log, 0, socket_handle,
270       HttpNetworkSession::WEBSOCKET_SOCKET_POOL, std::move(callback),
271       proxy_auth_callback);
272 }
273 
PreconnectSocketsForHttpRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const std::vector<SSLConfig::CertAndStatus> & allowed_bad_certs,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy,const NetLogWithSource & net_log,int num_preconnect_streams,CompletionOnceCallback callback)274 int PreconnectSocketsForHttpRequest(
275     url::SchemeHostPort endpoint,
276     int request_load_flags,
277     RequestPriority request_priority,
278     HttpNetworkSession* session,
279     const ProxyInfo& proxy_info,
280     const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
281     PrivacyMode privacy_mode,
282     NetworkAnonymizationKey network_anonymization_key,
283     SecureDnsPolicy secure_dns_policy,
284     const NetLogWithSource& net_log,
285     int num_preconnect_streams,
286     CompletionOnceCallback callback) {
287   // Expect websocket schemes (ws and wss) to be converted to the http(s)
288   // equivalent.
289   DCHECK(endpoint.scheme() == url::kHttpScheme ||
290          endpoint.scheme() == url::kHttpsScheme);
291 
292   return InitSocketPoolHelper(
293       std::move(endpoint), request_load_flags, request_priority, session,
294       proxy_info, allowed_bad_certs, privacy_mode,
295       std::move(network_anonymization_key), secure_dns_policy, SocketTag(),
296       net_log, num_preconnect_streams, nullptr,
297       HttpNetworkSession::NORMAL_SOCKET_POOL, std::move(callback),
298       ClientSocketPool::ProxyAuthCallback());
299 }
300 
301 }  // namespace net
302