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.
5 #include "net/socket/ssl_client_socket_pool.h"
8 #include "base/bind_helpers.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h"
11 #include "base/values.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/net_errors.h"
14 #include "net/http/http_proxy_client_socket.h"
15 #include "net/http/http_proxy_client_socket_pool.h"
16 #include "net/socket/client_socket_factory.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.h"
20 #include "net/socket/transport_client_socket_pool.h"
21 #include "net/ssl/ssl_cert_request_info.h"
25 SSLSocketParams::SSLSocketParams(
26 const scoped_refptr
<TransportSocketParams
>& transport_params
,
27 const scoped_refptr
<SOCKSSocketParams
>& socks_params
,
28 const scoped_refptr
<HttpProxySocketParams
>& http_proxy_params
,
29 ProxyServer::Scheme proxy
,
30 const HostPortPair
& host_and_port
,
31 const SSLConfig
& ssl_config
,
33 bool force_spdy_over_ssl
,
34 bool want_spdy_over_npn
)
35 : transport_params_(transport_params
),
36 http_proxy_params_(http_proxy_params
),
37 socks_params_(socks_params
),
39 host_and_port_(host_and_port
),
40 ssl_config_(ssl_config
),
41 load_flags_(load_flags
),
42 force_spdy_over_ssl_(force_spdy_over_ssl
),
43 want_spdy_over_npn_(want_spdy_over_npn
),
44 ignore_limits_(false) {
46 case ProxyServer::SCHEME_DIRECT
:
47 DCHECK(transport_params_
.get() != NULL
);
48 DCHECK(http_proxy_params_
.get() == NULL
);
49 DCHECK(socks_params_
.get() == NULL
);
50 ignore_limits_
= transport_params_
->ignore_limits();
52 case ProxyServer::SCHEME_HTTP
:
53 case ProxyServer::SCHEME_HTTPS
:
54 DCHECK(transport_params_
.get() == NULL
);
55 DCHECK(http_proxy_params_
.get() != NULL
);
56 DCHECK(socks_params_
.get() == NULL
);
57 ignore_limits_
= http_proxy_params_
->ignore_limits();
59 case ProxyServer::SCHEME_SOCKS4
:
60 case ProxyServer::SCHEME_SOCKS5
:
61 DCHECK(transport_params_
.get() == NULL
);
62 DCHECK(http_proxy_params_
.get() == NULL
);
63 DCHECK(socks_params_
.get() != NULL
);
64 ignore_limits_
= socks_params_
->ignore_limits();
67 LOG(DFATAL
) << "unknown proxy type";
72 SSLSocketParams::~SSLSocketParams() {}
74 // Timeout for the SSL handshake portion of the connect.
75 static const int kSSLHandshakeTimeoutInSeconds
= 30;
77 SSLConnectJob::SSLConnectJob(const std::string
& group_name
,
78 const scoped_refptr
<SSLSocketParams
>& params
,
79 const base::TimeDelta
& timeout_duration
,
80 TransportClientSocketPool
* transport_pool
,
81 SOCKSClientSocketPool
* socks_pool
,
82 HttpProxyClientSocketPool
* http_proxy_pool
,
83 ClientSocketFactory
* client_socket_factory
,
84 HostResolver
* host_resolver
,
85 const SSLClientSocketContext
& context
,
88 : ConnectJob(group_name
, timeout_duration
, delegate
,
89 BoundNetLog::Make(net_log
, NetLog::SOURCE_CONNECT_JOB
)),
91 transport_pool_(transport_pool
),
92 socks_pool_(socks_pool
),
93 http_proxy_pool_(http_proxy_pool
),
94 client_socket_factory_(client_socket_factory
),
95 host_resolver_(host_resolver
),
97 ALLOW_THIS_IN_INITIALIZER_LIST(
98 callback_(base::Bind(&SSLConnectJob::OnIOComplete
,
99 base::Unretained(this)))) {}
101 SSLConnectJob::~SSLConnectJob() {}
103 LoadState
SSLConnectJob::GetLoadState() const {
104 switch (next_state_
) {
105 case STATE_TUNNEL_CONNECT_COMPLETE
:
106 if (transport_socket_handle_
->socket())
107 return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL
;
108 // else, fall through.
109 case STATE_TRANSPORT_CONNECT
:
110 case STATE_TRANSPORT_CONNECT_COMPLETE
:
111 case STATE_SOCKS_CONNECT
:
112 case STATE_SOCKS_CONNECT_COMPLETE
:
113 case STATE_TUNNEL_CONNECT
:
114 return transport_socket_handle_
->GetLoadState();
115 case STATE_SSL_CONNECT
:
116 case STATE_SSL_CONNECT_COMPLETE
:
117 return LOAD_STATE_SSL_HANDSHAKE
;
120 return LOAD_STATE_IDLE
;
124 void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle
* handle
) {
125 // Headers in |error_response_info_| indicate a proxy tunnel setup
126 // problem. See DoTunnelConnectComplete.
127 if (error_response_info_
.headers
) {
128 handle
->set_pending_http_proxy_connection(
129 transport_socket_handle_
.release());
131 handle
->set_ssl_error_response_info(error_response_info_
);
132 if (!connect_timing_
.ssl_start
.is_null())
133 handle
->set_is_ssl_error(true);
136 void SSLConnectJob::OnIOComplete(int result
) {
137 int rv
= DoLoop(result
);
138 if (rv
!= ERR_IO_PENDING
)
139 NotifyDelegateOfCompletion(rv
); // Deletes |this|.
142 int SSLConnectJob::DoLoop(int result
) {
143 DCHECK_NE(next_state_
, STATE_NONE
);
147 State state
= next_state_
;
148 next_state_
= STATE_NONE
;
150 case STATE_TRANSPORT_CONNECT
:
152 rv
= DoTransportConnect();
154 case STATE_TRANSPORT_CONNECT_COMPLETE
:
155 rv
= DoTransportConnectComplete(rv
);
157 case STATE_SOCKS_CONNECT
:
159 rv
= DoSOCKSConnect();
161 case STATE_SOCKS_CONNECT_COMPLETE
:
162 rv
= DoSOCKSConnectComplete(rv
);
164 case STATE_TUNNEL_CONNECT
:
166 rv
= DoTunnelConnect();
168 case STATE_TUNNEL_CONNECT_COMPLETE
:
169 rv
= DoTunnelConnectComplete(rv
);
171 case STATE_SSL_CONNECT
:
175 case STATE_SSL_CONNECT_COMPLETE
:
176 rv
= DoSSLConnectComplete(rv
);
179 NOTREACHED() << "bad state";
183 } while (rv
!= ERR_IO_PENDING
&& next_state_
!= STATE_NONE
);
188 int SSLConnectJob::DoTransportConnect() {
189 DCHECK(transport_pool_
);
191 next_state_
= STATE_TRANSPORT_CONNECT_COMPLETE
;
192 transport_socket_handle_
.reset(new ClientSocketHandle());
193 scoped_refptr
<TransportSocketParams
> transport_params
=
194 params_
->transport_params();
195 return transport_socket_handle_
->Init(
196 group_name(), transport_params
,
197 transport_params
->destination().priority(), callback_
, transport_pool_
,
201 int SSLConnectJob::DoTransportConnectComplete(int result
) {
203 next_state_
= STATE_SSL_CONNECT
;
208 int SSLConnectJob::DoSOCKSConnect() {
210 next_state_
= STATE_SOCKS_CONNECT_COMPLETE
;
211 transport_socket_handle_
.reset(new ClientSocketHandle());
212 scoped_refptr
<SOCKSSocketParams
> socks_params
= params_
->socks_params();
213 return transport_socket_handle_
->Init(
214 group_name(), socks_params
, socks_params
->destination().priority(),
215 callback_
, socks_pool_
, net_log());
218 int SSLConnectJob::DoSOCKSConnectComplete(int result
) {
220 next_state_
= STATE_SSL_CONNECT
;
225 int SSLConnectJob::DoTunnelConnect() {
226 DCHECK(http_proxy_pool_
);
227 next_state_
= STATE_TUNNEL_CONNECT_COMPLETE
;
229 transport_socket_handle_
.reset(new ClientSocketHandle());
230 scoped_refptr
<HttpProxySocketParams
> http_proxy_params
=
231 params_
->http_proxy_params();
232 return transport_socket_handle_
->Init(
233 group_name(), http_proxy_params
,
234 http_proxy_params
->destination().priority(), callback_
, http_proxy_pool_
,
238 int SSLConnectJob::DoTunnelConnectComplete(int result
) {
239 // Extract the information needed to prompt for appropriate proxy
240 // authentication so that when ClientSocketPoolBaseHelper calls
241 // |GetAdditionalErrorState|, we can easily set the state.
242 if (result
== ERR_SSL_CLIENT_AUTH_CERT_NEEDED
) {
243 error_response_info_
= transport_socket_handle_
->ssl_error_response_info();
244 } else if (result
== ERR_PROXY_AUTH_REQUESTED
||
245 result
== ERR_HTTPS_PROXY_TUNNEL_RESPONSE
) {
246 StreamSocket
* socket
= transport_socket_handle_
->socket();
247 HttpProxyClientSocket
* tunnel_socket
=
248 static_cast<HttpProxyClientSocket
*>(socket
);
249 error_response_info_
= *tunnel_socket
->GetConnectResponseInfo();
254 next_state_
= STATE_SSL_CONNECT
;
258 int SSLConnectJob::DoSSLConnect() {
259 next_state_
= STATE_SSL_CONNECT_COMPLETE
;
260 // Reset the timeout to just the time allowed for the SSL handshake.
261 ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds
));
263 // If the handle has a fresh socket, get its connect start and DNS times.
264 // This should always be the case.
265 const LoadTimingInfo::ConnectTiming
& socket_connect_timing
=
266 transport_socket_handle_
->connect_timing();
267 if (!transport_socket_handle_
->is_reused() &&
268 !socket_connect_timing
.connect_start
.is_null()) {
269 // Overwriting |connect_start| serves two purposes - it adjusts timing so
270 // |connect_start| doesn't include dns times, and it adjusts the time so
271 // as not to include time spent waiting for an idle socket.
272 connect_timing_
.connect_start
= socket_connect_timing
.connect_start
;
273 connect_timing_
.dns_start
= socket_connect_timing
.dns_start
;
274 connect_timing_
.dns_end
= socket_connect_timing
.dns_end
;
277 connect_timing_
.ssl_start
= base::TimeTicks::Now();
279 ssl_socket_
.reset(client_socket_factory_
->CreateSSLClientSocket(
280 transport_socket_handle_
.release(), params_
->host_and_port(),
281 params_
->ssl_config(), context_
));
282 return ssl_socket_
->Connect(callback_
);
285 int SSLConnectJob::DoSSLConnectComplete(int result
) {
286 connect_timing_
.ssl_end
= base::TimeTicks::Now();
288 SSLClientSocket::NextProtoStatus status
=
289 SSLClientSocket::kNextProtoUnsupported
;
291 std::string server_protos
;
292 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
293 // that hasn't had SSL_ImportFD called on it. If we get a certificate error
294 // here, then we know that we called SSL_ImportFD.
295 if (result
== OK
|| IsCertificateError(result
))
296 status
= ssl_socket_
->GetNextProto(&proto
, &server_protos
);
298 // If we want spdy over npn, make sure it succeeded.
299 if (status
== SSLClientSocket::kNextProtoNegotiated
) {
300 ssl_socket_
->set_was_npn_negotiated(true);
301 NextProto protocol_negotiated
=
302 SSLClientSocket::NextProtoFromString(proto
);
303 ssl_socket_
->set_protocol_negotiated(protocol_negotiated
);
304 // If we negotiated a SPDY version, it must have been present in
305 // SSLConfig::next_protos.
306 // TODO(mbelshe): Verify this.
307 if (protocol_negotiated
>= kProtoSPDYMinimumVersion
&&
308 protocol_negotiated
<= kProtoSPDYMaximumVersion
) {
309 ssl_socket_
->set_was_spdy_negotiated(true);
312 if (params_
->want_spdy_over_npn() && !ssl_socket_
->was_spdy_negotiated())
313 return ERR_NPN_NEGOTIATION_FAILED
;
315 // Spdy might be turned on by default, or it might be over npn.
316 bool using_spdy
= params_
->force_spdy_over_ssl() ||
317 params_
->want_spdy_over_npn();
320 ssl_socket_
->IgnoreCertError(result
, params_
->load_flags())) {
321 DCHECK(!connect_timing_
.ssl_start
.is_null());
322 base::TimeDelta connect_duration
=
323 connect_timing_
.ssl_end
- connect_timing_
.ssl_start
;
325 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency_2",
327 base::TimeDelta::FromMilliseconds(1),
328 base::TimeDelta::FromMinutes(1),
332 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_2",
334 base::TimeDelta::FromMilliseconds(1),
335 base::TimeDelta::FromMinutes(1),
339 ssl_socket_
->GetSSLInfo(&ssl_info
);
341 if (ssl_info
.handshake_type
== SSLInfo::HANDSHAKE_RESUME
) {
342 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Resume_Handshake",
344 base::TimeDelta::FromMilliseconds(1),
345 base::TimeDelta::FromMinutes(1),
347 } else if (ssl_info
.handshake_type
== SSLInfo::HANDSHAKE_FULL
) {
348 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Full_Handshake",
350 base::TimeDelta::FromMilliseconds(1),
351 base::TimeDelta::FromMinutes(1),
355 const std::string
& host
= params_
->host_and_port().host();
356 bool is_google
= host
== "google.com" ||
358 host
.rfind(".google.com") == host
.size() - 11);
360 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google2",
362 base::TimeDelta::FromMilliseconds(1),
363 base::TimeDelta::FromMinutes(1),
365 if (ssl_info
.handshake_type
== SSLInfo::HANDSHAKE_RESUME
) {
366 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google_"
369 base::TimeDelta::FromMilliseconds(1),
370 base::TimeDelta::FromMinutes(1),
372 } else if (ssl_info
.handshake_type
== SSLInfo::HANDSHAKE_FULL
) {
373 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google_"
376 base::TimeDelta::FromMilliseconds(1),
377 base::TimeDelta::FromMinutes(1),
383 if (result
== OK
|| IsCertificateError(result
)) {
384 set_socket(ssl_socket_
.release());
385 } else if (result
== ERR_SSL_CLIENT_AUTH_CERT_NEEDED
) {
386 error_response_info_
.cert_request_info
= new SSLCertRequestInfo
;
387 ssl_socket_
->GetSSLCertRequestInfo(error_response_info_
.cert_request_info
);
393 int SSLConnectJob::ConnectInternal() {
394 switch (params_
->proxy()) {
395 case ProxyServer::SCHEME_DIRECT
:
396 next_state_
= STATE_TRANSPORT_CONNECT
;
398 case ProxyServer::SCHEME_HTTP
:
399 case ProxyServer::SCHEME_HTTPS
:
400 next_state_
= STATE_TUNNEL_CONNECT
;
402 case ProxyServer::SCHEME_SOCKS4
:
403 case ProxyServer::SCHEME_SOCKS5
:
404 next_state_
= STATE_SOCKS_CONNECT
;
407 NOTREACHED() << "unknown proxy type";
413 SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
414 TransportClientSocketPool
* transport_pool
,
415 SOCKSClientSocketPool
* socks_pool
,
416 HttpProxyClientSocketPool
* http_proxy_pool
,
417 ClientSocketFactory
* client_socket_factory
,
418 HostResolver
* host_resolver
,
419 const SSLClientSocketContext
& context
,
421 : transport_pool_(transport_pool
),
422 socks_pool_(socks_pool
),
423 http_proxy_pool_(http_proxy_pool
),
424 client_socket_factory_(client_socket_factory
),
425 host_resolver_(host_resolver
),
428 base::TimeDelta max_transport_timeout
= base::TimeDelta();
429 base::TimeDelta pool_timeout
;
431 max_transport_timeout
= transport_pool_
->ConnectionTimeout();
433 pool_timeout
= socks_pool_
->ConnectionTimeout();
434 if (pool_timeout
> max_transport_timeout
)
435 max_transport_timeout
= pool_timeout
;
437 if (http_proxy_pool_
) {
438 pool_timeout
= http_proxy_pool_
->ConnectionTimeout();
439 if (pool_timeout
> max_transport_timeout
)
440 max_transport_timeout
= pool_timeout
;
442 timeout_
= max_transport_timeout
+
443 base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds
);
446 SSLClientSocketPool::SSLClientSocketPool(
448 int max_sockets_per_group
,
449 ClientSocketPoolHistograms
* histograms
,
450 HostResolver
* host_resolver
,
451 CertVerifier
* cert_verifier
,
452 ServerBoundCertService
* server_bound_cert_service
,
453 TransportSecurityState
* transport_security_state
,
454 const std::string
& ssl_session_cache_shard
,
455 ClientSocketFactory
* client_socket_factory
,
456 TransportClientSocketPool
* transport_pool
,
457 SOCKSClientSocketPool
* socks_pool
,
458 HttpProxyClientSocketPool
* http_proxy_pool
,
459 SSLConfigService
* ssl_config_service
,
461 : transport_pool_(transport_pool
),
462 socks_pool_(socks_pool
),
463 http_proxy_pool_(http_proxy_pool
),
464 base_(max_sockets
, max_sockets_per_group
, histograms
,
465 ClientSocketPool::unused_idle_socket_timeout(),
466 ClientSocketPool::used_idle_socket_timeout(),
467 new SSLConnectJobFactory(transport_pool
,
470 client_socket_factory
,
472 SSLClientSocketContext(
474 server_bound_cert_service
,
475 transport_security_state
,
476 ssl_session_cache_shard
),
478 ssl_config_service_(ssl_config_service
) {
479 if (ssl_config_service_
)
480 ssl_config_service_
->AddObserver(this);
482 transport_pool_
->AddLayeredPool(this);
484 socks_pool_
->AddLayeredPool(this);
485 if (http_proxy_pool_
)
486 http_proxy_pool_
->AddLayeredPool(this);
489 SSLClientSocketPool::~SSLClientSocketPool() {
490 if (http_proxy_pool_
)
491 http_proxy_pool_
->RemoveLayeredPool(this);
493 socks_pool_
->RemoveLayeredPool(this);
495 transport_pool_
->RemoveLayeredPool(this);
496 if (ssl_config_service_
)
497 ssl_config_service_
->RemoveObserver(this);
500 ConnectJob
* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
501 const std::string
& group_name
,
502 const PoolBase::Request
& request
,
503 ConnectJob::Delegate
* delegate
) const {
504 return new SSLConnectJob(group_name
, request
.params(), ConnectionTimeout(),
505 transport_pool_
, socks_pool_
, http_proxy_pool_
,
506 client_socket_factory_
, host_resolver_
,
507 context_
, delegate
, net_log_
);
511 SSLClientSocketPool::SSLConnectJobFactory::ConnectionTimeout() const {
515 int SSLClientSocketPool::RequestSocket(const std::string
& group_name
,
516 const void* socket_params
,
517 RequestPriority priority
,
518 ClientSocketHandle
* handle
,
519 const CompletionCallback
& callback
,
520 const BoundNetLog
& net_log
) {
521 const scoped_refptr
<SSLSocketParams
>* casted_socket_params
=
522 static_cast<const scoped_refptr
<SSLSocketParams
>*>(socket_params
);
524 return base_
.RequestSocket(group_name
, *casted_socket_params
, priority
,
525 handle
, callback
, net_log
);
528 void SSLClientSocketPool::RequestSockets(
529 const std::string
& group_name
,
532 const BoundNetLog
& net_log
) {
533 const scoped_refptr
<SSLSocketParams
>* casted_params
=
534 static_cast<const scoped_refptr
<SSLSocketParams
>*>(params
);
536 base_
.RequestSockets(group_name
, *casted_params
, num_sockets
, net_log
);
539 void SSLClientSocketPool::CancelRequest(const std::string
& group_name
,
540 ClientSocketHandle
* handle
) {
541 base_
.CancelRequest(group_name
, handle
);
544 void SSLClientSocketPool::ReleaseSocket(const std::string
& group_name
,
545 StreamSocket
* socket
, int id
) {
546 base_
.ReleaseSocket(group_name
, socket
, id
);
549 void SSLClientSocketPool::FlushWithError(int error
) {
550 base_
.FlushWithError(error
);
553 bool SSLClientSocketPool::IsStalled() const {
554 return base_
.IsStalled() ||
555 (transport_pool_
&& transport_pool_
->IsStalled()) ||
556 (socks_pool_
&& socks_pool_
->IsStalled()) ||
557 (http_proxy_pool_
&& http_proxy_pool_
->IsStalled());
560 void SSLClientSocketPool::CloseIdleSockets() {
561 base_
.CloseIdleSockets();
564 int SSLClientSocketPool::IdleSocketCount() const {
565 return base_
.idle_socket_count();
568 int SSLClientSocketPool::IdleSocketCountInGroup(
569 const std::string
& group_name
) const {
570 return base_
.IdleSocketCountInGroup(group_name
);
573 LoadState
SSLClientSocketPool::GetLoadState(
574 const std::string
& group_name
, const ClientSocketHandle
* handle
) const {
575 return base_
.GetLoadState(group_name
, handle
);
578 void SSLClientSocketPool::AddLayeredPool(LayeredPool
* layered_pool
) {
579 base_
.AddLayeredPool(layered_pool
);
582 void SSLClientSocketPool::RemoveLayeredPool(LayeredPool
* layered_pool
) {
583 base_
.RemoveLayeredPool(layered_pool
);
586 DictionaryValue
* SSLClientSocketPool::GetInfoAsValue(
587 const std::string
& name
,
588 const std::string
& type
,
589 bool include_nested_pools
) const {
590 DictionaryValue
* dict
= base_
.GetInfoAsValue(name
, type
);
591 if (include_nested_pools
) {
592 ListValue
* list
= new ListValue();
593 if (transport_pool_
) {
594 list
->Append(transport_pool_
->GetInfoAsValue("transport_socket_pool",
595 "transport_socket_pool",
599 list
->Append(socks_pool_
->GetInfoAsValue("socks_pool",
603 if (http_proxy_pool_
) {
604 list
->Append(http_proxy_pool_
->GetInfoAsValue("http_proxy_pool",
608 dict
->Set("nested_pools", list
);
613 base::TimeDelta
SSLClientSocketPool::ConnectionTimeout() const {
614 return base_
.ConnectionTimeout();
617 ClientSocketPoolHistograms
* SSLClientSocketPool::histograms() const {
618 return base_
.histograms();
621 void SSLClientSocketPool::OnSSLConfigChanged() {
622 FlushWithError(ERR_NETWORK_CHANGED
);
625 bool SSLClientSocketPool::CloseOneIdleConnection() {
626 if (base_
.CloseOneIdleSocket())
628 return base_
.CloseOneIdleConnectionInLayeredPool();