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<TransportSocketParams> tcp_params; 88 scoped_refptr<HttpProxySocketParams> http_proxy_params; 89 scoped_refptr<SOCKSSocketParams> socks_params; 90 scoped_ptr<HostPortPair> proxy_host_port; 91 92 bool using_ssl = request_url.SchemeIs("https") || 93 request_url.SchemeIs("wss") || force_spdy_over_ssl; 94 95 HostPortPair origin_host_port = 96 HostPortPair(request_url.HostNoBrackets(), 97 request_url.EffectiveIntPort()); 98 99 if (!using_ssl && session->params().testing_fixed_http_port != 0) { 100 origin_host_port.set_port(session->params().testing_fixed_http_port); 101 } else if (using_ssl && session->params().testing_fixed_https_port != 0) { 102 origin_host_port.set_port(session->params().testing_fixed_https_port); 103 } 104 105 bool disable_resolver_cache = 106 request_load_flags & LOAD_BYPASS_CACHE || 107 request_load_flags & LOAD_VALIDATE_CACHE || 108 request_load_flags & LOAD_DISABLE_CACHE; 109 110 int load_flags = request_load_flags; 111 if (session->params().ignore_certificate_errors) 112 load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; 113 114 // Build the string used to uniquely identify connections of this type. 115 // Determine the host and port to connect to. 116 std::string connection_group = origin_host_port.ToString(); 117 DCHECK(!connection_group.empty()); 118 if (request_url.SchemeIs("ftp")) { 119 // Combining FTP with forced SPDY over SSL would be a "path to madness". 120 // Make sure we never do that. 121 DCHECK(!using_ssl); 122 connection_group = "ftp/" + connection_group; 123 } 124 if (using_ssl) { 125 // All connections in a group should use the same SSLConfig settings. 126 // Encode version_max in the connection group's name, unless it's the 127 // default version_max. (We want the common case to use the shortest 128 // encoding). A version_max of TLS 1.1 is encoded as "ssl(max:3.2)/" 129 // rather than "tlsv1.1/" because the actual protocol version, which 130 // is selected by the server, may not be TLS 1.1. Do not encode 131 // version_min in the connection group's name because version_min 132 // should be the same for all connections, whereas version_max may 133 // change for version fallbacks. 134 std::string prefix = "ssl/"; 135 if (ssl_config_for_origin.version_max != net::kDefaultSSLVersionMax) { 136 switch (ssl_config_for_origin.version_max) { 137 case SSL_PROTOCOL_VERSION_TLS1_2: 138 prefix = "ssl(max:3.3)/"; 139 break; 140 case SSL_PROTOCOL_VERSION_TLS1_1: 141 prefix = "ssl(max:3.2)/"; 142 break; 143 case SSL_PROTOCOL_VERSION_TLS1: 144 prefix = "ssl(max:3.1)/"; 145 break; 146 case SSL_PROTOCOL_VERSION_SSL3: 147 prefix = "sslv3/"; 148 break; 149 default: 150 CHECK(false); 151 break; 152 } 153 } 154 connection_group = prefix + connection_group; 155 } 156 157 bool ignore_limits = (request_load_flags & LOAD_IGNORE_LIMITS) != 0; 158 if (proxy_info.is_direct()) { 159 tcp_params = new TransportSocketParams(origin_host_port, 160 disable_resolver_cache, 161 ignore_limits, 162 resolution_callback); 163 } else { 164 ProxyServer proxy_server = proxy_info.proxy_server(); 165 proxy_host_port.reset(new HostPortPair(proxy_server.host_port_pair())); 166 scoped_refptr<TransportSocketParams> proxy_tcp_params( 167 new TransportSocketParams(*proxy_host_port, 168 disable_resolver_cache, 169 ignore_limits, 170 resolution_callback)); 171 172 if (proxy_info.is_http() || proxy_info.is_https()) { 173 std::string user_agent; 174 request_extra_headers.GetHeader(HttpRequestHeaders::kUserAgent, 175 &user_agent); 176 scoped_refptr<SSLSocketParams> ssl_params; 177 if (proxy_info.is_https()) { 178 // Set ssl_params, and unset proxy_tcp_params 179 ssl_params = new SSLSocketParams(proxy_tcp_params, 180 NULL, 181 NULL, 182 *proxy_host_port.get(), 183 ssl_config_for_proxy, 184 PRIVACY_MODE_DISABLED, 185 load_flags, 186 force_spdy_over_ssl, 187 want_spdy_over_npn); 188 proxy_tcp_params = NULL; 189 } 190 191 http_proxy_params = 192 new HttpProxySocketParams(proxy_tcp_params, 193 ssl_params, 194 request_url, 195 user_agent, 196 origin_host_port, 197 session->http_auth_cache(), 198 session->http_auth_handler_factory(), 199 session->spdy_session_pool(), 200 force_tunnel || using_ssl); 201 } else { 202 DCHECK(proxy_info.is_socks()); 203 char socks_version; 204 if (proxy_server.scheme() == ProxyServer::SCHEME_SOCKS5) 205 socks_version = '5'; 206 else 207 socks_version = '4'; 208 connection_group = base::StringPrintf( 209 "socks%c/%s", socks_version, connection_group.c_str()); 210 211 socks_params = new SOCKSSocketParams(proxy_tcp_params, 212 socks_version == '5', 213 origin_host_port); 214 } 215 } 216 217 // Change group name if privacy mode is enabled. 218 if (privacy_mode == PRIVACY_MODE_ENABLED) 219 connection_group = "pm/" + connection_group; 220 221 // Deal with SSL - which layers on top of any given proxy. 222 if (using_ssl) { 223 scoped_refptr<SSLSocketParams> ssl_params = 224 new SSLSocketParams(tcp_params, 225 socks_params, 226 http_proxy_params, 227 origin_host_port, 228 ssl_config_for_origin, 229 privacy_mode, 230 load_flags, 231 force_spdy_over_ssl, 232 want_spdy_over_npn); 233 SSLClientSocketPool* ssl_pool = NULL; 234 if (proxy_info.is_direct()) { 235 ssl_pool = session->GetSSLSocketPool(socket_pool_type); 236 } else { 237 ssl_pool = session->GetSocketPoolForSSLWithProxy(socket_pool_type, 238 *proxy_host_port); 239 } 240 241 if (num_preconnect_streams) { 242 RequestSocketsForPool(ssl_pool, connection_group, ssl_params, 243 num_preconnect_streams, net_log); 244 return OK; 245 } 246 247 return socket_handle->Init(connection_group, ssl_params, 248 request_priority, callback, ssl_pool, 249 net_log); 250 } 251 252 // Finally, get the connection started. 253 254 if (proxy_info.is_http() || proxy_info.is_https()) { 255 HttpProxyClientSocketPool* pool = 256 session->GetSocketPoolForHTTPProxy(socket_pool_type, *proxy_host_port); 257 if (num_preconnect_streams) { 258 RequestSocketsForPool(pool, connection_group, http_proxy_params, 259 num_preconnect_streams, net_log); 260 return OK; 261 } 262 263 return socket_handle->Init(connection_group, http_proxy_params, 264 request_priority, callback, 265 pool, net_log); 266 } 267 268 if (proxy_info.is_socks()) { 269 SOCKSClientSocketPool* pool = 270 session->GetSocketPoolForSOCKSProxy(socket_pool_type, *proxy_host_port); 271 if (num_preconnect_streams) { 272 RequestSocketsForPool(pool, connection_group, socks_params, 273 num_preconnect_streams, net_log); 274 return OK; 275 } 276 277 return socket_handle->Init(connection_group, socks_params, 278 request_priority, callback, pool, 279 net_log); 280 } 281 282 DCHECK(proxy_info.is_direct()); 283 284 TransportClientSocketPool* pool = 285 session->GetTransportSocketPool(socket_pool_type); 286 if (num_preconnect_streams) { 287 RequestSocketsForPool(pool, connection_group, tcp_params, 288 num_preconnect_streams, net_log); 289 return OK; 290 } 291 292 return socket_handle->Init(connection_group, tcp_params, 293 request_priority, callback, 294 pool, net_log); 295 } 296 297 } // namespace 298 299 ClientSocketPoolManager::ClientSocketPoolManager() {} 300 ClientSocketPoolManager::~ClientSocketPoolManager() {} 301 302 // static 303 int ClientSocketPoolManager::max_sockets_per_pool( 304 HttpNetworkSession::SocketPoolType pool_type) { 305 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 306 return g_max_sockets_per_pool[pool_type]; 307 } 308 309 // static 310 void ClientSocketPoolManager::set_max_sockets_per_pool( 311 HttpNetworkSession::SocketPoolType pool_type, 312 int socket_count) { 313 DCHECK_LT(0, socket_count); 314 DCHECK_GT(1000, socket_count); // Sanity check. 315 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 316 g_max_sockets_per_pool[pool_type] = socket_count; 317 DCHECK_GE(g_max_sockets_per_pool[pool_type], 318 g_max_sockets_per_group[pool_type]); 319 } 320 321 // static 322 int ClientSocketPoolManager::max_sockets_per_group( 323 HttpNetworkSession::SocketPoolType pool_type) { 324 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 325 return g_max_sockets_per_group[pool_type]; 326 } 327 328 // static 329 void ClientSocketPoolManager::set_max_sockets_per_group( 330 HttpNetworkSession::SocketPoolType pool_type, 331 int socket_count) { 332 DCHECK_LT(0, socket_count); 333 // The following is a sanity check... but we should NEVER be near this value. 334 DCHECK_GT(100, socket_count); 335 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 336 g_max_sockets_per_group[pool_type] = socket_count; 337 338 DCHECK_GE(g_max_sockets_per_pool[pool_type], 339 g_max_sockets_per_group[pool_type]); 340 DCHECK_GE(g_max_sockets_per_proxy_server[pool_type], 341 g_max_sockets_per_group[pool_type]); 342 } 343 344 // static 345 int ClientSocketPoolManager::max_sockets_per_proxy_server( 346 HttpNetworkSession::SocketPoolType pool_type) { 347 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 348 return g_max_sockets_per_proxy_server[pool_type]; 349 } 350 351 // static 352 void ClientSocketPoolManager::set_max_sockets_per_proxy_server( 353 HttpNetworkSession::SocketPoolType pool_type, 354 int socket_count) { 355 DCHECK_LT(0, socket_count); 356 DCHECK_GT(100, socket_count); // Sanity check. 357 DCHECK_LT(pool_type, HttpNetworkSession::NUM_SOCKET_POOL_TYPES); 358 // Assert this case early on. The max number of sockets per group cannot 359 // exceed the max number of sockets per proxy server. 360 DCHECK_LE(g_max_sockets_per_group[pool_type], socket_count); 361 g_max_sockets_per_proxy_server[pool_type] = socket_count; 362 } 363 364 int InitSocketHandleForHttpRequest( 365 const GURL& request_url, 366 const HttpRequestHeaders& request_extra_headers, 367 int request_load_flags, 368 RequestPriority request_priority, 369 HttpNetworkSession* session, 370 const ProxyInfo& proxy_info, 371 bool force_spdy_over_ssl, 372 bool want_spdy_over_npn, 373 const SSLConfig& ssl_config_for_origin, 374 const SSLConfig& ssl_config_for_proxy, 375 PrivacyMode privacy_mode, 376 const BoundNetLog& net_log, 377 ClientSocketHandle* socket_handle, 378 const OnHostResolutionCallback& resolution_callback, 379 const CompletionCallback& callback) { 380 DCHECK(socket_handle); 381 return InitSocketPoolHelper( 382 request_url, request_extra_headers, request_load_flags, request_priority, 383 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 384 ssl_config_for_origin, ssl_config_for_proxy, false, privacy_mode, net_log, 385 0, socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL, 386 resolution_callback, callback); 387 } 388 389 int InitSocketHandleForWebSocketRequest( 390 const GURL& request_url, 391 const HttpRequestHeaders& request_extra_headers, 392 int request_load_flags, 393 RequestPriority request_priority, 394 HttpNetworkSession* session, 395 const ProxyInfo& proxy_info, 396 bool force_spdy_over_ssl, 397 bool want_spdy_over_npn, 398 const SSLConfig& ssl_config_for_origin, 399 const SSLConfig& ssl_config_for_proxy, 400 PrivacyMode privacy_mode, 401 const BoundNetLog& net_log, 402 ClientSocketHandle* socket_handle, 403 const OnHostResolutionCallback& resolution_callback, 404 const CompletionCallback& callback) { 405 DCHECK(socket_handle); 406 return InitSocketPoolHelper( 407 request_url, request_extra_headers, request_load_flags, request_priority, 408 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 409 ssl_config_for_origin, ssl_config_for_proxy, true, privacy_mode, net_log, 410 0, socket_handle, HttpNetworkSession::WEBSOCKET_SOCKET_POOL, 411 resolution_callback, callback); 412 } 413 414 int InitSocketHandleForRawConnect( 415 const HostPortPair& host_port_pair, 416 HttpNetworkSession* session, 417 const ProxyInfo& proxy_info, 418 const SSLConfig& ssl_config_for_origin, 419 const SSLConfig& ssl_config_for_proxy, 420 PrivacyMode privacy_mode, 421 const BoundNetLog& net_log, 422 ClientSocketHandle* socket_handle, 423 const CompletionCallback& callback) { 424 DCHECK(socket_handle); 425 // Synthesize an HttpRequestInfo. 426 GURL request_url = GURL("http://" + host_port_pair.ToString()); 427 HttpRequestHeaders request_extra_headers; 428 int request_load_flags = 0; 429 RequestPriority request_priority = MEDIUM; 430 431 return InitSocketPoolHelper( 432 request_url, request_extra_headers, request_load_flags, request_priority, 433 session, proxy_info, false, false, ssl_config_for_origin, 434 ssl_config_for_proxy, true, privacy_mode, net_log, 0, socket_handle, 435 HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), 436 callback); 437 } 438 439 int InitSocketHandleForTlsConnect( 440 const HostPortPair& host_port_pair, 441 HttpNetworkSession* session, 442 const ProxyInfo& proxy_info, 443 const SSLConfig& ssl_config_for_origin, 444 const SSLConfig& ssl_config_for_proxy, 445 PrivacyMode privacy_mode, 446 const BoundNetLog& net_log, 447 ClientSocketHandle* socket_handle, 448 const CompletionCallback& callback) { 449 DCHECK(socket_handle); 450 // Synthesize an HttpRequestInfo. 451 GURL request_url = GURL("https://" + host_port_pair.ToString()); 452 HttpRequestHeaders request_extra_headers; 453 int request_load_flags = 0; 454 RequestPriority request_priority = MEDIUM; 455 456 return InitSocketPoolHelper( 457 request_url, request_extra_headers, request_load_flags, request_priority, 458 session, proxy_info, false, false, ssl_config_for_origin, 459 ssl_config_for_proxy, true, privacy_mode, net_log, 0, socket_handle, 460 HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(), 461 callback); 462 } 463 464 int PreconnectSocketsForHttpRequest( 465 const GURL& request_url, 466 const HttpRequestHeaders& request_extra_headers, 467 int request_load_flags, 468 RequestPriority request_priority, 469 HttpNetworkSession* session, 470 const ProxyInfo& proxy_info, 471 bool force_spdy_over_ssl, 472 bool want_spdy_over_npn, 473 const SSLConfig& ssl_config_for_origin, 474 const SSLConfig& ssl_config_for_proxy, 475 PrivacyMode privacy_mode, 476 const BoundNetLog& net_log, 477 int num_preconnect_streams) { 478 return InitSocketPoolHelper( 479 request_url, request_extra_headers, request_load_flags, request_priority, 480 session, proxy_info, force_spdy_over_ssl, want_spdy_over_npn, 481 ssl_config_for_origin, ssl_config_for_proxy, false, privacy_mode, net_log, 482 num_preconnect_streams, NULL, HttpNetworkSession::NORMAL_SOCKET_POOL, 483 OnHostResolutionCallback(), CompletionCallback()); 484 } 485 486 } // namespace net 487