1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 <string> 8 9 #include "base/basictypes.h" 10 #include "base/logging.h" 11 #include "base/strings/stringprintf.h" 12 #include "net/base/load_flags.h" 13 #include "net/http/http_proxy_client_socket_pool.h" 14 #include "net/http/http_request_info.h" 15 #include "net/http/http_stream_factory.h" 16 #include "net/proxy/proxy_info.h" 17 #include "net/socket/client_socket_handle.h" 18 #include "net/socket/socks_client_socket_pool.h" 19 #include "net/socket/ssl_client_socket_pool.h" 20 #include "net/socket/transport_client_socket_pool.h" 21 22 namespace net { 23 24 namespace { 25 26 // Limit of sockets of each socket pool. 27 int g_max_sockets_per_pool[] = { 28 256, // NORMAL_SOCKET_POOL 29 256 // WEBSOCKET_SOCKET_POOL 30 }; 31 32 COMPILE_ASSERT(arraysize(g_max_sockets_per_pool) == 33 HttpNetworkSession::NUM_SOCKET_POOL_TYPES, 34 max_sockets_per_pool_length_mismatch); 35 36 // Default to allow up to 6 connections per host. Experiment and tuning may 37 // try other values (greater than 0). Too large may cause many problems, such 38 // as home routers blocking the connections!?!? See http://crbug.com/12066. 39 // 40 // WebSocket connections are long-lived, and should be treated differently 41 // than normal other connections. 6 connections per group sounded too small 42 // for such use, thus we use a larger limit which was determined somewhat 43 // arbitrarily. 44 // TODO(yutak): Look at the usage and determine the right value after 45 // WebSocket protocol stack starts to work. 46 int g_max_sockets_per_group[] = { 47 6, // NORMAL_SOCKET_POOL 48 30 // WEBSOCKET_SOCKET_POOL 49 }; 50 51 COMPILE_ASSERT(arraysize(g_max_sockets_per_group) == 52 HttpNetworkSession::NUM_SOCKET_POOL_TYPES, 53 max_sockets_per_group_length_mismatch); 54 55 // The max number of sockets to allow per proxy server. This applies both to 56 // http and SOCKS proxies. See http://crbug.com/12066 and 57 // http://crbug.com/44501 for details about proxy server connection limits. 58 int g_max_sockets_per_proxy_server[] = { 59 kDefaultMaxSocketsPerProxyServer, // NORMAL_SOCKET_POOL 60 kDefaultMaxSocketsPerProxyServer // WEBSOCKET_SOCKET_POOL 61 }; 62 63 COMPILE_ASSERT(arraysize(g_max_sockets_per_proxy_server) == 64 HttpNetworkSession::NUM_SOCKET_POOL_TYPES, 65 max_sockets_per_proxy_server_length_mismatch); 66 67 // The meat of the implementation for the InitSocketHandleForHttpRequest, 68 // InitSocketHandleForRawConnect and PreconnectSocketsForHttpRequest methods. 69 int InitSocketPoolHelper(const GURL& request_url, 70 const HttpRequestHeaders& request_extra_headers, 71 int request_load_flags, 72 RequestPriority request_priority, 73 HttpNetworkSession* session, 74 const ProxyInfo& proxy_info, 75 bool force_spdy_over_ssl, 76 bool want_spdy_over_npn, 77 const SSLConfig& ssl_config_for_origin, 78 const SSLConfig& ssl_config_for_proxy, 79 bool force_tunnel, 80 PrivacyMode privacy_mode, 81 const BoundNetLog& net_log, 82 int num_preconnect_streams, 83 ClientSocketHandle* socket_handle, 84 HttpNetworkSession::SocketPoolType socket_pool_type, 85 const OnHostResolutionCallback& resolution_callback, 86 const CompletionCallback& callback) { 87 scoped_refptr<HttpProxySocketParams> http_proxy_params; 88 scoped_refptr<SOCKSSocketParams> socks_params; 89 scoped_ptr<HostPortPair> proxy_host_port; 90 91 bool using_ssl = request_url.SchemeIs("https") || 92 request_url.SchemeIs("wss") || force_spdy_over_ssl; 93 94 HostPortPair origin_host_port = 95 HostPortPair(request_url.HostNoBrackets(), 96 request_url.EffectiveIntPort()); 97 98 if (!using_ssl && session->params().testing_fixed_http_port != 0) { 99 origin_host_port.set_port(session->params().testing_fixed_http_port); 100 } else if (using_ssl && session->params().testing_fixed_https_port != 0) { 101 origin_host_port.set_port(session->params().testing_fixed_https_port); 102 } 103 104 bool disable_resolver_cache = 105 request_load_flags & LOAD_BYPASS_CACHE || 106 request_load_flags & LOAD_VALIDATE_CACHE || 107 request_load_flags & LOAD_DISABLE_CACHE; 108 109 int load_flags = request_load_flags; 110 if (session->params().ignore_certificate_errors) 111 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; 112 113 // Build the string used to uniquely identify connections of this type. 114 // Determine the host and port to connect to. 115 std::string connection_group = origin_host_port.ToString(); 116 DCHECK(!connection_group.empty()); 117 if (request_url.SchemeIs("ftp")) { 118 // Combining FTP with forced SPDY over SSL would be a "path to madness". 119 // Make sure we never do that. 120 DCHECK(!using_ssl); 121 connection_group = "ftp/" + connection_group; 122 } 123 if (using_ssl) { 124 // All connections in a group should use the same SSLConfig settings. 125 // Encode version_max in the connection group's name, unless it's the 126 // default version_max. (We want the common case to use the shortest 127 // encoding). A version_max of TLS 1.1 is encoded as "ssl(max:3.2)/" 128 // rather than "tlsv1.1/" because the actual protocol version, which 129 // is selected by the server, may not be TLS 1.1. Do not encode 130 // version_min in the connection group's name because version_min 131 // should be the same for all connections, whereas version_max may 132 // change for version fallbacks. 133 std::string prefix = "ssl/"; 134 if (ssl_config_for_origin.version_max != kDefaultSSLVersionMax) { 135 switch (ssl_config_for_origin.version_max) { 136 case SSL_PROTOCOL_VERSION_TLS1_2: 137 prefix = "ssl(max:3.3)/"; 138 break; 139 case SSL_PROTOCOL_VERSION_TLS1_1: 140 prefix = "ssl(max:3.2)/"; 141 break; 142 case SSL_PROTOCOL_VERSION_TLS1: 143 prefix = "ssl(max:3.1)/"; 144 break; 145 case SSL_PROTOCOL_VERSION_SSL3: 146 prefix = "sslv3/"; 147 break; 148 default: 149 CHECK(false); 150 break; 151 } 152 } 153 connection_group = prefix + connection_group; 154 } 155 156 bool ignore_limits = (request_load_flags & LOAD_IGNORE_LIMITS) != 0; 157 if (!proxy_info.is_direct()) { 158 ProxyServer proxy_server = proxy_info.proxy_server(); 159 proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair())); 160 scoped_refptr<TransportSocketParams> proxy_tcp_params( 161 new TransportSocketParams( 162 *proxy_host_port, 163 disable_resolver_cache, 164 ignore_limits, 165 resolution_callback, 166 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); 167 168 if (proxy_info.is_http() || proxy_info.is_https()) { 169 std::string user_agent; 170 request_extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, 171 &user_agent); 172 scoped_refptr<SSLSocketParams> ssl_params; 173 if (proxy_info.is_https()) { 174 // Combine connect and write for SSL sockets in TCP FastOpen 175 // field trial. 176 TransportSocketParams::CombineConnectAndWritePolicy 177 combine_connect_and_write = 178 session->params().enable_tcp_fast_open_for_ssl ? 179 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DESIRED : 180 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT; 181 proxy_tcp_params = new TransportSocketParams(*proxy_host_port, 182 disable_resolver_cache, 183 ignore_limits, 184 resolution_callback, 185 combine_connect_and_write); 186 // Set ssl_params, and unset proxy_tcp_params 187 ssl_params = new SSLSocketParams(proxy_tcp_params, 188 NULL, 189 NULL, 190 *proxy_host_port.get(), 191 ssl_config_for_proxy, 192 PRIVACY_MODE_DISABLED, 193 load_flags, 194 force_spdy_over_ssl, 195 want_spdy_over_npn); 196 proxy_tcp_params = NULL; 197 } 198 199 http_proxy_params = 200 new HttpProxySocketParams(proxy_tcp_params, 201 ssl_params, 202 request_url, 203 user_agent, 204 origin_host_port, 205 session->http_auth_cache(), 206 session->http_auth_handler_factory(), 207 session->spdy_session_pool(), 208 force_tunnel || using_ssl, 209 session->params().proxy_delegate); 210 } else { 211 DCHECK(proxy_info.is_socks()); 212 char socks_version; 213 if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5) 214 socks_version = '5'; 215 else 216 socks_version = '4'; 217 connection_group = base::StringPrintf( 218 "socks%c/%s", socks_version, connection_group.c_str()); 219 220 socks_params = new SOCKSSocketParams(proxy_tcp_params, 221 socks_version == '5', 222 origin_host_port); 223 } 224 } 225 226 // Change group name if privacy mode is enabled. 227 if (privacy_mode == PRIVACY_MODE_ENABLED) 228 connection_group = "pm/" + connection_group; 229 230 // Deal with SSL - which layers on top of any given proxy. 231 if (using_ssl) { 232 scoped_refptr<TransportSocketParams> ssl_tcp_params; 233 if (proxy_info.is_direct()) { 234 // Setup TCP params if non-proxied SSL connection. 235 // Combine connect and write for SSL sockets in TCP FastOpen field trial. 236 TransportSocketParams::CombineConnectAndWritePolicy 237 combine_connect_and_write = 238 session->params().enable_tcp_fast_open_for_ssl ? 239 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DESIRED : 240 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT; 241 ssl_tcp_params = new TransportSocketParams(origin_host_port, 242 disable_resolver_cache, 243 ignore_limits, 244 resolution_callback, 245 combine_connect_and_write); 246 } 247 scoped_refptr<SSLSocketParams> ssl_params = 248 new SSLSocketParams(ssl_tcp_params, 249 socks_params, 250 http_proxy_params, 251 origin_host_port, 252 ssl_config_for_origin, 253 privacy_mode, 254 load_flags, 255 force_spdy_over_ssl, 256 want_spdy_over_npn); 257 SSLClientSocketPool* ssl_pool = NULL; 258 if (proxy_info.is_direct()) { 259 ssl_pool = session->GetSSLSocketPool(socket_pool_type); 260 } else { 261 ssl_pool = session->GetSocketPoolForSSLWithProxy(socket_pool_type, 262 *proxy_host_port); 263 } 264 265 if (num_preconnect_streams) { 266 RequestSocketsForPool(ssl_pool, connection_group, ssl_params, 267 num_preconnect_streams, net_log); 268 return OK; 269 } 270 271 return socket_handle->Init(connection_group, ssl_params, 272 request_priority, callback, ssl_pool, 273 net_log); 274 } 275 276 // Finally, get the connection started. 277 278 if (proxy_info.is_http() || proxy_info.is_https()) { 279 HttpProxyClientSocketPool* pool = 280 session->GetSocketPoolForHTTPProxy(socket_pool_type, *proxy_host_port); 281 if (num_preconnect_streams) { 282 RequestSocketsForPool(pool, connection_group, http_proxy_params, 283 num_preconnect_streams, net_log); 284 return OK; 285 } 286 287 return socket_handle->Init(connection_group, http_proxy_params, 288 request_priority, callback, 289 pool, net_log); 290 } 291 292 if (proxy_info.is_socks()) { 293 SOCKSClientSocketPool* pool = 294 session->GetSocketPoolForSOCKSProxy(socket_pool_type, *proxy_host_port); 295 if (num_preconnect_streams) { 296 RequestSocketsForPool(pool, connection_group, socks_params, 297 num_preconnect_streams, net_log); 298 return OK; 299 } 300 301 return socket_handle->Init(connection_group, socks_params, 302 request_priority, callback, pool, 303 net_log); 304 } 305 306 DCHECK(proxy_info.is_direct()); 307 scoped_refptr<TransportSocketParams> tcp_params = 308 new TransportSocketParams( 309 origin_host_port, 310 disable_resolver_cache, 311 ignore_limits, 312 resolution_callback, 313 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT); 314 TransportClientSocketPool* pool = 315 session->GetTransportSocketPool(socket_pool_type); 316 if (num_preconnect_streams) { 317 RequestSocketsForPool(pool, connection_group, tcp_params, 318 num_preconnect_streams, net_log); 319 return OK; 320 } 321 322 return socket_handle->Init(connection_group, tcp_params, 323 request_priority, callback, 324 pool, net_log); 325 } 326 327 } // namespace 328 329 ClientSocketPoolManager::ClientSocketPoolManager() {} 330 ClientSocketPoolManager::~ClientSocketPoolManager() {} 331 332 // static 333 int ClientSocketPoolManager::max_sockets_per_pool( 334 HttpNetworkSession::SocketPoolType pool_type) { 335 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 336 return g_max_sockets_per_pool[pool_type]; 337 } 338 339 // static 340 void ClientSocketPoolManager::set_max_sockets_per_pool( 341 HttpNetworkSession::SocketPoolType pool_type, 342 int socket_count) { 343 DCHECK_LT(0, socket_count); 344 DCHECK_GT(1000, socket_count); // Sanity check. 345 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 346 g_max_sockets_per_pool[pool_type] = socket_count; 347 DCHECK_GE(g_max_sockets_per_pool[pool_type], 348 g_max_sockets_per_group[pool_type]); 349 } 350 351 // static 352 int ClientSocketPoolManager::max_sockets_per_group( 353 HttpNetworkSession::SocketPoolType pool_type) { 354 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 355 return g_max_sockets_per_group[pool_type]; 356 } 357 358 // static 359 void ClientSocketPoolManager::set_max_sockets_per_group( 360 HttpNetworkSession::SocketPoolType pool_type, 361 int socket_count) { 362 DCHECK_LT(0, socket_count); 363 // The following is a sanity check... but we should NEVER be near this value. 364 DCHECK_GT(100, socket_count); 365 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 366 g_max_sockets_per_group[pool_type] = socket_count; 367 368 DCHECK_GE(g_max_sockets_per_pool[pool_type], 369 g_max_sockets_per_group[pool_type]); 370 DCHECK_GE(g_max_sockets_per_proxy_server[pool_type], 371 g_max_sockets_per_group[pool_type]); 372 } 373 374 // static 375 int ClientSocketPoolManager::max_sockets_per_proxy_server( 376 HttpNetworkSession::SocketPoolType pool_type) { 377 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 378 return g_max_sockets_per_proxy_server[pool_type]; 379 } 380 381 // static 382 void ClientSocketPoolManager::set_max_sockets_per_proxy_server( 383 HttpNetworkSession::SocketPoolType pool_type, 384 int socket_count) { 385 DCHECK_LT(0, socket_count); 386 DCHECK_GT(100, socket_count); // Sanity check. 387 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 388 // Assert this case early on. The max number of sockets per group cannot 389 // exceed the max number of sockets per proxy server. 390 DCHECK_LE(g_max_sockets_per_group[pool_type], socket_count); 391 g_max_sockets_per_proxy_server[pool_type] = socket_count; 392 } 393 394 int InitSocketHandleForHttpRequest( 395 const GURL& request_url, 396 const HttpRequestHeaders& request_extra_headers, 397 int request_load_flags, 398 RequestPriority request_priority, 399 HttpNetworkSession* session, 400 const ProxyInfo& proxy_info, 401 bool force_spdy_over_ssl, 402 bool want_spdy_over_npn, 403 const SSLConfig& ssl_config_for_origin, 404 const SSLConfig& ssl_config_for_proxy, 405 PrivacyMode privacy_mode, 406 const BoundNetLog& net_log, 407 ClientSocketHandle* socket_handle, 408 const OnHostResolutionCallback& resolution_callback, 409 const CompletionCallback& callback) { 410 DCHECK(socket_handle); 411 return InitSocketPoolHelper( 412 request_url, request_extra_headers, request_load_flags, request_priority, 413 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 414 ssl_config_for_origin, ssl_config_for_proxy, false, privacy_mode, net_log, 415 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, 416 resolution_callback, callback); 417 } 418 419 int InitSocketHandleForWebSocketRequest( 420 const GURL& request_url, 421 const HttpRequestHeaders& request_extra_headers, 422 int request_load_flags, 423 RequestPriority request_priority, 424 HttpNetworkSession* session, 425 const ProxyInfo& proxy_info, 426 bool force_spdy_over_ssl, 427 bool want_spdy_over_npn, 428 const SSLConfig& ssl_config_for_origin, 429 const SSLConfig& ssl_config_for_proxy, 430 PrivacyMode privacy_mode, 431 const BoundNetLog& net_log, 432 ClientSocketHandle* socket_handle, 433 const OnHostResolutionCallback& resolution_callback, 434 const CompletionCallback& callback) { 435 DCHECK(socket_handle); 436 return InitSocketPoolHelper( 437 request_url, request_extra_headers, request_load_flags, request_priority, 438 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 439 ssl_config_for_origin, ssl_config_for_proxy, true, privacy_mode, net_log, 440 0, socket_handle, HttpNetworkSession::WEBSOCKET_SOCKET_POOL, 441 resolution_callback, callback); 442 } 443 444 int InitSocketHandleForRawConnect( 445 const HostPortPair& host_port_pair, 446 HttpNetworkSession* session, 447 const ProxyInfo& proxy_info, 448 const SSLConfig& ssl_config_for_origin, 449 const SSLConfig& ssl_config_for_proxy, 450 PrivacyMode privacy_mode, 451 const BoundNetLog& net_log, 452 ClientSocketHandle* socket_handle, 453 const CompletionCallback& callback) { 454 DCHECK(socket_handle); 455 // Synthesize an HttpRequestInfo. 456 GURL request_url = GURL("http://" + host_port_pair.ToString()); 457 HttpRequestHeaders request_extra_headers; 458 int request_load_flags = 0; 459 RequestPriority request_priority = MEDIUM; 460 461 return InitSocketPoolHelper( 462 request_url, request_extra_headers, request_load_flags, request_priority, 463 session, proxy_info, false, false, ssl_config_for_origin, 464 ssl_config_for_proxy, true, privacy_mode, net_log, 0, socket_handle, 465 HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), 466 callback); 467 } 468 469 int InitSocketHandleForTlsConnect( 470 const HostPortPair& host_port_pair, 471 HttpNetworkSession* session, 472 const ProxyInfo& proxy_info, 473 const SSLConfig& ssl_config_for_origin, 474 const SSLConfig& ssl_config_for_proxy, 475 PrivacyMode privacy_mode, 476 const BoundNetLog& net_log, 477 ClientSocketHandle* socket_handle, 478 const CompletionCallback& callback) { 479 DCHECK(socket_handle); 480 // Synthesize an HttpRequestInfo. 481 GURL request_url = GURL("https://" + host_port_pair.ToString()); 482 HttpRequestHeaders request_extra_headers; 483 int request_load_flags = 0; 484 RequestPriority request_priority = MEDIUM; 485 486 return InitSocketPoolHelper( 487 request_url, request_extra_headers, request_load_flags, request_priority, 488 session, proxy_info, false, false, ssl_config_for_origin, 489 ssl_config_for_proxy, true, privacy_mode, net_log, 0, socket_handle, 490 HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), 491 callback); 492 } 493 494 int PreconnectSocketsForHttpRequest( 495 const GURL& request_url, 496 const HttpRequestHeaders& request_extra_headers, 497 int request_load_flags, 498 RequestPriority request_priority, 499 HttpNetworkSession* session, 500 const ProxyInfo& proxy_info, 501 bool force_spdy_over_ssl, 502 bool want_spdy_over_npn, 503 const SSLConfig& ssl_config_for_origin, 504 const SSLConfig& ssl_config_for_proxy, 505 PrivacyMode privacy_mode, 506 const BoundNetLog& net_log, 507 int num_preconnect_streams) { 508 return InitSocketPoolHelper( 509 request_url, request_extra_headers, request_load_flags, request_priority, 510 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 511 ssl_config_for_origin, ssl_config_for_proxy, false, privacy_mode, net_log, 512 num_preconnect_streams, NULL, HttpNetworkSession::NORMAL_SOCKET_POOL, 513 OnHostResolutionCallback(), CompletionCallback()); 514 } 515 516 } // namespace net 517