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