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 <utility>
9
10 #include "base/check_op.h"
11 #include "base/metrics/field_trial_params.h"
12 #include "base/strings/string_piece.h"
13 #include "build/build_config.h"
14 #include "net/base/features.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/proxy_chain.h"
17 #include "net/base/proxy_server.h"
18 #include "net/dns/public/secure_dns_policy.h"
19 #include "net/http/http_stream_factory.h"
20 #include "net/proxy_resolution/proxy_info.h"
21 #include "net/socket/client_socket_handle.h"
22 #include "net/socket/client_socket_pool.h"
23 #include "net/socket/connect_job.h"
24 #include "net/ssl/ssl_config.h"
25 #include "third_party/abseil-cpp/absl/types/optional.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 ProxyChain & proxy_chain,const SSLConfig & ssl_config_for_origin,const SSLConfig & base_ssl_config_for_proxies)76 scoped_refptr<ClientSocketPool::SocketParams> CreateSocketParams(
77 const ClientSocketPool::GroupId& group_id,
78 const ProxyChain& proxy_chain,
79 const SSLConfig& ssl_config_for_origin,
80 const SSLConfig& base_ssl_config_for_proxies) {
81 bool using_ssl = GURL::SchemeIsCryptographic(group_id.destination().scheme());
82
83 // If there is a proxy chain and any server in that chain is using SSL,
84 // then this socket will need to use SSL.
85 bool using_proxy_ssl =
86 !proxy_chain.is_direct() &&
87 std::any_of(proxy_chain.proxy_servers().begin(),
88 proxy_chain.proxy_servers().end(),
89 [](const ProxyServer& proxy_server) {
90 return proxy_server.is_secure_http_like();
91 });
92
93 return base::MakeRefCounted<ClientSocketPool::SocketParams>(
94 using_ssl ? std::make_unique<SSLConfig>(ssl_config_for_origin) : nullptr,
95 using_proxy_ssl ? std::make_unique<SSLConfig>(base_ssl_config_for_proxies)
96 : nullptr);
97 }
98
InitSocketPoolHelper(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const SSLConfig & ssl_config_for_origin,const SSLConfig & base_ssl_config_for_proxies,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)99 int InitSocketPoolHelper(
100 url::SchemeHostPort endpoint,
101 int request_load_flags,
102 RequestPriority request_priority,
103 HttpNetworkSession* session,
104 const ProxyInfo& proxy_info,
105 const SSLConfig& ssl_config_for_origin,
106 const SSLConfig& base_ssl_config_for_proxies,
107 PrivacyMode privacy_mode,
108 NetworkAnonymizationKey network_anonymization_key,
109 SecureDnsPolicy secure_dns_policy,
110 const SocketTag& socket_tag,
111 const NetLogWithSource& net_log,
112 int num_preconnect_streams,
113 ClientSocketHandle* socket_handle,
114 HttpNetworkSession::SocketPoolType socket_pool_type,
115 CompletionOnceCallback callback,
116 const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
117 DCHECK(endpoint.IsValid());
118
119 bool using_ssl = GURL::SchemeIsCryptographic(endpoint.scheme());
120 if (!using_ssl && session->params().testing_fixed_http_port != 0) {
121 endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
122 session->params().testing_fixed_http_port);
123 } else if (using_ssl && session->params().testing_fixed_https_port != 0) {
124 endpoint = url::SchemeHostPort(endpoint.scheme(), endpoint.host(),
125 session->params().testing_fixed_https_port);
126 }
127
128 ClientSocketPool::GroupId connection_group(
129 std::move(endpoint), privacy_mode, std::move(network_anonymization_key),
130 secure_dns_policy);
131 scoped_refptr<ClientSocketPool::SocketParams> socket_params =
132 CreateSocketParams(connection_group, proxy_info.proxy_chain(),
133 ssl_config_for_origin, base_ssl_config_for_proxies);
134
135 ClientSocketPool* pool =
136 session->GetSocketPool(socket_pool_type, proxy_info.proxy_chain());
137 ClientSocketPool::RespectLimits respect_limits =
138 ClientSocketPool::RespectLimits::ENABLED;
139 if ((request_load_flags & LOAD_IGNORE_LIMITS) != 0)
140 respect_limits = ClientSocketPool::RespectLimits::DISABLED;
141
142 absl::optional<NetworkTrafficAnnotationTag> proxy_annotation =
143 proxy_info.is_direct() ? absl::nullopt
144 : absl::optional<NetworkTrafficAnnotationTag>(
145 proxy_info.traffic_annotation());
146 if (num_preconnect_streams) {
147 return pool->RequestSockets(connection_group, std::move(socket_params),
148 proxy_annotation, num_preconnect_streams,
149 std::move(callback), net_log);
150 }
151
152 return socket_handle->Init(connection_group, std::move(socket_params),
153 proxy_annotation, request_priority, socket_tag,
154 respect_limits, std::move(callback),
155 proxy_auth_callback, pool, net_log);
156 }
157
158 } // namespace
159
160 ClientSocketPoolManager::ClientSocketPoolManager() = default;
161 ClientSocketPoolManager::~ClientSocketPoolManager() = default;
162
163 // static
max_sockets_per_pool(HttpNetworkSession::SocketPoolType pool_type)164 int ClientSocketPoolManager::max_sockets_per_pool(
165 HttpNetworkSession::SocketPoolType pool_type) {
166 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
167 return g_max_sockets_per_pool[pool_type];
168 }
169
170 // static
set_max_sockets_per_pool(HttpNetworkSession::SocketPoolType pool_type,int socket_count)171 void ClientSocketPoolManager::set_max_sockets_per_pool(
172 HttpNetworkSession::SocketPoolType pool_type,
173 int socket_count) {
174 DCHECK_LT(0, socket_count);
175 DCHECK_GT(1000, socket_count); // Sanity check.
176 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
177 g_max_sockets_per_pool[pool_type] = socket_count;
178 DCHECK_GE(g_max_sockets_per_pool[pool_type],
179 g_max_sockets_per_group[pool_type]);
180 }
181
182 // static
max_sockets_per_group(HttpNetworkSession::SocketPoolType pool_type)183 int ClientSocketPoolManager::max_sockets_per_group(
184 HttpNetworkSession::SocketPoolType pool_type) {
185 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
186 return g_max_sockets_per_group[pool_type];
187 }
188
189 // static
set_max_sockets_per_group(HttpNetworkSession::SocketPoolType pool_type,int socket_count)190 void ClientSocketPoolManager::set_max_sockets_per_group(
191 HttpNetworkSession::SocketPoolType pool_type,
192 int socket_count) {
193 DCHECK_LT(0, socket_count);
194 // The following is a sanity check... but we should NEVER be near this value.
195 DCHECK_GT(100, socket_count);
196 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
197 g_max_sockets_per_group[pool_type] = socket_count;
198
199 DCHECK_GE(g_max_sockets_per_pool[pool_type],
200 g_max_sockets_per_group[pool_type]);
201 DCHECK_GE(g_max_sockets_per_proxy_chain[pool_type],
202 g_max_sockets_per_group[pool_type]);
203 }
204
205 // static
max_sockets_per_proxy_chain(HttpNetworkSession::SocketPoolType pool_type)206 int ClientSocketPoolManager::max_sockets_per_proxy_chain(
207 HttpNetworkSession::SocketPoolType pool_type) {
208 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
209 return g_max_sockets_per_proxy_chain[pool_type];
210 }
211
212 // static
set_max_sockets_per_proxy_chain(HttpNetworkSession::SocketPoolType pool_type,int socket_count)213 void ClientSocketPoolManager::set_max_sockets_per_proxy_chain(
214 HttpNetworkSession::SocketPoolType pool_type,
215 int socket_count) {
216 DCHECK_LT(0, socket_count);
217 DCHECK_GT(100, socket_count); // Sanity check.
218 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES);
219 // Assert this case early on. The max number of sockets per group cannot
220 // exceed the max number of sockets per proxy chain.
221 DCHECK_LE(g_max_sockets_per_group[pool_type], socket_count);
222 g_max_sockets_per_proxy_chain[pool_type] = socket_count;
223 }
224
225 // static
unused_idle_socket_timeout(HttpNetworkSession::SocketPoolType pool_type)226 base::TimeDelta ClientSocketPoolManager::unused_idle_socket_timeout(
227 HttpNetworkSession::SocketPoolType pool_type) {
228 return base::Seconds(base::GetFieldTrialParamByFeatureAsInt(
229 net::features::kNetUnusedIdleSocketTimeout,
230 "unused_idle_socket_timeout_seconds", 60));
231 }
232
InitSocketHandleForHttpRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const SSLConfig & ssl_config_for_origin,const SSLConfig & base_ssl_config_for_proxies,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)233 int InitSocketHandleForHttpRequest(
234 url::SchemeHostPort endpoint,
235 int request_load_flags,
236 RequestPriority request_priority,
237 HttpNetworkSession* session,
238 const ProxyInfo& proxy_info,
239 const SSLConfig& ssl_config_for_origin,
240 const SSLConfig& base_ssl_config_for_proxies,
241 PrivacyMode privacy_mode,
242 NetworkAnonymizationKey network_anonymization_key,
243 SecureDnsPolicy secure_dns_policy,
244 const SocketTag& socket_tag,
245 const NetLogWithSource& net_log,
246 ClientSocketHandle* socket_handle,
247 CompletionOnceCallback callback,
248 const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
249 DCHECK(socket_handle);
250 return InitSocketPoolHelper(
251 std::move(endpoint), request_load_flags, request_priority, session,
252 proxy_info, ssl_config_for_origin, base_ssl_config_for_proxies,
253 privacy_mode, std::move(network_anonymization_key), secure_dns_policy,
254 socket_tag, net_log, 0, socket_handle,
255 HttpNetworkSession::NORMAL_SOCKET_POOL, std::move(callback),
256 proxy_auth_callback);
257 }
258
InitSocketHandleForWebSocketRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const SSLConfig & ssl_config_for_origin,const SSLConfig & base_ssl_config_for_proxies,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,const NetLogWithSource & net_log,ClientSocketHandle * socket_handle,CompletionOnceCallback callback,const ClientSocketPool::ProxyAuthCallback & proxy_auth_callback)259 int InitSocketHandleForWebSocketRequest(
260 url::SchemeHostPort endpoint,
261 int request_load_flags,
262 RequestPriority request_priority,
263 HttpNetworkSession* session,
264 const ProxyInfo& proxy_info,
265 const SSLConfig& ssl_config_for_origin,
266 const SSLConfig& base_ssl_config_for_proxies,
267 PrivacyMode privacy_mode,
268 NetworkAnonymizationKey network_anonymization_key,
269 const NetLogWithSource& net_log,
270 ClientSocketHandle* socket_handle,
271 CompletionOnceCallback callback,
272 const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback) {
273 DCHECK(socket_handle);
274
275 // QUIC proxies are currently not supported through this method.
276 DCHECK(!proxy_info.is_quic());
277
278 // Expect websocket schemes (ws and wss) to be converted to the http(s)
279 // equivalent.
280 DCHECK(endpoint.scheme() == url::kHttpScheme ||
281 endpoint.scheme() == url::kHttpsScheme);
282
283 return InitSocketPoolHelper(
284 std::move(endpoint), request_load_flags, request_priority, session,
285 proxy_info, ssl_config_for_origin, base_ssl_config_for_proxies,
286 privacy_mode, std::move(network_anonymization_key),
287 SecureDnsPolicy::kAllow, SocketTag(), net_log, 0, socket_handle,
288 HttpNetworkSession::WEBSOCKET_SOCKET_POOL, std::move(callback),
289 proxy_auth_callback);
290 }
291
PreconnectSocketsForHttpRequest(url::SchemeHostPort endpoint,int request_load_flags,RequestPriority request_priority,HttpNetworkSession * session,const ProxyInfo & proxy_info,const SSLConfig & ssl_config_for_origin,const SSLConfig & base_ssl_config_for_proxies,PrivacyMode privacy_mode,NetworkAnonymizationKey network_anonymization_key,SecureDnsPolicy secure_dns_policy,const NetLogWithSource & net_log,int num_preconnect_streams,CompletionOnceCallback callback)292 int PreconnectSocketsForHttpRequest(
293 url::SchemeHostPort endpoint,
294 int request_load_flags,
295 RequestPriority request_priority,
296 HttpNetworkSession* session,
297 const ProxyInfo& proxy_info,
298 const SSLConfig& ssl_config_for_origin,
299 const SSLConfig& base_ssl_config_for_proxies,
300 PrivacyMode privacy_mode,
301 NetworkAnonymizationKey network_anonymization_key,
302 SecureDnsPolicy secure_dns_policy,
303 const NetLogWithSource& net_log,
304 int num_preconnect_streams,
305 CompletionOnceCallback callback) {
306 // QUIC proxies are currently not supported through this method.
307 DCHECK(!proxy_info.is_quic());
308
309 // Expect websocket schemes (ws and wss) to be converted to the http(s)
310 // equivalent.
311 DCHECK(endpoint.scheme() == url::kHttpScheme ||
312 endpoint.scheme() == url::kHttpsScheme);
313
314 return InitSocketPoolHelper(
315 std::move(endpoint), request_load_flags, request_priority, session,
316 proxy_info, ssl_config_for_origin, base_ssl_config_for_proxies,
317 privacy_mode, std::move(network_anonymization_key), secure_dns_policy,
318 SocketTag(), net_log, num_preconnect_streams, nullptr,
319 HttpNetworkSession::NORMAL_SOCKET_POOL, std::move(callback),
320 ClientSocketPool::ProxyAuthCallback());
321 }
322
323 } // namespace net
324