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/ssl_client_socket_pool.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/metrics/field_trial.h"
10#include "base/metrics/histogram.h"
11#include "base/metrics/sparse_histogram.h"
12#include "base/values.h"
13#include "net/base/host_port_pair.h"
14#include "net/base/net_errors.h"
15#include "net/http/http_proxy_client_socket.h"
16#include "net/http/http_proxy_client_socket_pool.h"
17#include "net/socket/client_socket_factory.h"
18#include "net/socket/client_socket_handle.h"
19#include "net/socket/socks_client_socket_pool.h"
20#include "net/socket/ssl_client_socket.h"
21#include "net/socket/transport_client_socket_pool.h"
22#include "net/ssl/ssl_cert_request_info.h"
23#include "net/ssl/ssl_connection_status_flags.h"
24#include "net/ssl/ssl_info.h"
25
26namespace net {
27
28SSLSocketParams::SSLSocketParams(
29    const scoped_refptr<TransportSocketParams>& transport_params,
30    const scoped_refptr<SOCKSSocketParams>& socks_params,
31    const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
32    ProxyServer::Scheme proxy,
33    const HostPortPair& host_and_port,
34    const SSLConfig& ssl_config,
35    PrivacyMode privacy_mode,
36    int load_flags,
37    bool force_spdy_over_ssl,
38    bool want_spdy_over_npn)
39    : transport_params_(transport_params),
40      http_proxy_params_(http_proxy_params),
41      socks_params_(socks_params),
42      proxy_(proxy),
43      host_and_port_(host_and_port),
44      ssl_config_(ssl_config),
45      privacy_mode_(privacy_mode),
46      load_flags_(load_flags),
47      force_spdy_over_ssl_(force_spdy_over_ssl),
48      want_spdy_over_npn_(want_spdy_over_npn),
49      ignore_limits_(false) {
50  switch (proxy_) {
51    case ProxyServer::SCHEME_DIRECT:
52      DCHECK(transport_params_.get() != NULL);
53      DCHECK(http_proxy_params_.get() == NULL);
54      DCHECK(socks_params_.get() == NULL);
55      ignore_limits_ = transport_params_->ignore_limits();
56      break;
57    case ProxyServer::SCHEME_HTTP:
58    case ProxyServer::SCHEME_HTTPS:
59      DCHECK(transport_params_.get() == NULL);
60      DCHECK(http_proxy_params_.get() != NULL);
61      DCHECK(socks_params_.get() == NULL);
62      ignore_limits_ = http_proxy_params_->ignore_limits();
63      break;
64    case ProxyServer::SCHEME_SOCKS4:
65    case ProxyServer::SCHEME_SOCKS5:
66      DCHECK(transport_params_.get() == NULL);
67      DCHECK(http_proxy_params_.get() == NULL);
68      DCHECK(socks_params_.get() != NULL);
69      ignore_limits_ = socks_params_->ignore_limits();
70      break;
71    default:
72      LOG(DFATAL) << "unknown proxy type";
73      break;
74  }
75}
76
77SSLSocketParams::~SSLSocketParams() {}
78
79// Timeout for the SSL handshake portion of the connect.
80static const int kSSLHandshakeTimeoutInSeconds = 30;
81
82SSLConnectJob::SSLConnectJob(const std::string& group_name,
83                             const scoped_refptr<SSLSocketParams>& params,
84                             const base::TimeDelta& timeout_duration,
85                             TransportClientSocketPool* transport_pool,
86                             SOCKSClientSocketPool* socks_pool,
87                             HttpProxyClientSocketPool* http_proxy_pool,
88                             ClientSocketFactory* client_socket_factory,
89                             HostResolver* host_resolver,
90                             const SSLClientSocketContext& context,
91                             Delegate* delegate,
92                             NetLog* net_log)
93    : ConnectJob(group_name,
94                 timeout_duration,
95                 delegate,
96                 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
97      params_(params),
98      transport_pool_(transport_pool),
99      socks_pool_(socks_pool),
100      http_proxy_pool_(http_proxy_pool),
101      client_socket_factory_(client_socket_factory),
102      host_resolver_(host_resolver),
103      context_(context.cert_verifier,
104               context.server_bound_cert_service,
105               context.transport_security_state,
106               (params->privacy_mode() == kPrivacyModeEnabled
107                    ? "pm/" + context.ssl_session_cache_shard
108                    : context.ssl_session_cache_shard)),
109      callback_(base::Bind(&SSLConnectJob::OnIOComplete,
110                           base::Unretained(this))) {}
111
112SSLConnectJob::~SSLConnectJob() {}
113
114LoadState SSLConnectJob::GetLoadState() const {
115  switch (next_state_) {
116    case STATE_TUNNEL_CONNECT_COMPLETE:
117      if (transport_socket_handle_->socket())
118        return LOAD_STATE_ESTABLISHING_PROXY_TUNNEL;
119      // else, fall through.
120    case STATE_TRANSPORT_CONNECT:
121    case STATE_TRANSPORT_CONNECT_COMPLETE:
122    case STATE_SOCKS_CONNECT:
123    case STATE_SOCKS_CONNECT_COMPLETE:
124    case STATE_TUNNEL_CONNECT:
125      return transport_socket_handle_->GetLoadState();
126    case STATE_SSL_CONNECT:
127    case STATE_SSL_CONNECT_COMPLETE:
128      return LOAD_STATE_SSL_HANDSHAKE;
129    default:
130      NOTREACHED();
131      return LOAD_STATE_IDLE;
132  }
133}
134
135void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle* handle) {
136  // Headers in |error_response_info_| indicate a proxy tunnel setup
137  // problem. See DoTunnelConnectComplete.
138  if (error_response_info_.headers.get()) {
139    handle->set_pending_http_proxy_connection(
140        transport_socket_handle_.release());
141  }
142  handle->set_ssl_error_response_info(error_response_info_);
143  if (!connect_timing_.ssl_start.is_null())
144    handle->set_is_ssl_error(true);
145}
146
147void SSLConnectJob::OnIOComplete(int result) {
148  int rv = DoLoop(result);
149  if (rv != ERR_IO_PENDING)
150    NotifyDelegateOfCompletion(rv);  // Deletes |this|.
151}
152
153int SSLConnectJob::DoLoop(int result) {
154  DCHECK_NE(next_state_, STATE_NONE);
155
156  int rv = result;
157  do {
158    State state = next_state_;
159    next_state_ = STATE_NONE;
160    switch (state) {
161      case STATE_TRANSPORT_CONNECT:
162        DCHECK_EQ(OK, rv);
163        rv = DoTransportConnect();
164        break;
165      case STATE_TRANSPORT_CONNECT_COMPLETE:
166        rv = DoTransportConnectComplete(rv);
167        break;
168      case STATE_SOCKS_CONNECT:
169        DCHECK_EQ(OK, rv);
170        rv = DoSOCKSConnect();
171        break;
172      case STATE_SOCKS_CONNECT_COMPLETE:
173        rv = DoSOCKSConnectComplete(rv);
174        break;
175      case STATE_TUNNEL_CONNECT:
176        DCHECK_EQ(OK, rv);
177        rv = DoTunnelConnect();
178        break;
179      case STATE_TUNNEL_CONNECT_COMPLETE:
180        rv = DoTunnelConnectComplete(rv);
181        break;
182      case STATE_SSL_CONNECT:
183        DCHECK_EQ(OK, rv);
184        rv = DoSSLConnect();
185        break;
186      case STATE_SSL_CONNECT_COMPLETE:
187        rv = DoSSLConnectComplete(rv);
188        break;
189      default:
190        NOTREACHED() << "bad state";
191        rv = ERR_FAILED;
192        break;
193    }
194  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
195
196  return rv;
197}
198
199int SSLConnectJob::DoTransportConnect() {
200  DCHECK(transport_pool_);
201
202  next_state_ = STATE_TRANSPORT_CONNECT_COMPLETE;
203  transport_socket_handle_.reset(new ClientSocketHandle());
204  scoped_refptr<TransportSocketParams> transport_params =
205      params_->transport_params();
206  return transport_socket_handle_->Init(
207      group_name(), transport_params,
208      transport_params->destination().priority(), callback_, transport_pool_,
209      net_log());
210}
211
212int SSLConnectJob::DoTransportConnectComplete(int result) {
213  if (result == OK)
214    next_state_ = STATE_SSL_CONNECT;
215
216  return result;
217}
218
219int SSLConnectJob::DoSOCKSConnect() {
220  DCHECK(socks_pool_);
221  next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
222  transport_socket_handle_.reset(new ClientSocketHandle());
223  scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params();
224  return transport_socket_handle_->Init(
225      group_name(), socks_params, socks_params->destination().priority(),
226      callback_, socks_pool_, net_log());
227}
228
229int SSLConnectJob::DoSOCKSConnectComplete(int result) {
230  if (result == OK)
231    next_state_ = STATE_SSL_CONNECT;
232
233  return result;
234}
235
236int SSLConnectJob::DoTunnelConnect() {
237  DCHECK(http_proxy_pool_);
238  next_state_ = STATE_TUNNEL_CONNECT_COMPLETE;
239
240  transport_socket_handle_.reset(new ClientSocketHandle());
241  scoped_refptr<HttpProxySocketParams> http_proxy_params =
242      params_->http_proxy_params();
243  return transport_socket_handle_->Init(
244      group_name(), http_proxy_params,
245      http_proxy_params->destination().priority(), callback_, http_proxy_pool_,
246      net_log());
247}
248
249int SSLConnectJob::DoTunnelConnectComplete(int result) {
250  // Extract the information needed to prompt for appropriate proxy
251  // authentication so that when ClientSocketPoolBaseHelper calls
252  // |GetAdditionalErrorState|, we can easily set the state.
253  if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
254    error_response_info_ = transport_socket_handle_->ssl_error_response_info();
255  } else if (result == ERR_PROXY_AUTH_REQUESTED ||
256             result == ERR_HTTPS_PROXY_TUNNEL_RESPONSE) {
257    StreamSocket* socket = transport_socket_handle_->socket();
258    HttpProxyClientSocket* tunnel_socket =
259        static_cast<HttpProxyClientSocket*>(socket);
260    error_response_info_ = *tunnel_socket->GetConnectResponseInfo();
261  }
262  if (result < 0)
263    return result;
264
265  next_state_ = STATE_SSL_CONNECT;
266  return result;
267}
268
269int SSLConnectJob::DoSSLConnect() {
270  next_state_ = STATE_SSL_CONNECT_COMPLETE;
271  // Reset the timeout to just the time allowed for the SSL handshake.
272  ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds));
273
274  // If the handle has a fresh socket, get its connect start and DNS times.
275  // This should always be the case.
276  const LoadTimingInfo::ConnectTiming& socket_connect_timing =
277      transport_socket_handle_->connect_timing();
278  if (!transport_socket_handle_->is_reused() &&
279      !socket_connect_timing.connect_start.is_null()) {
280    // Overwriting |connect_start| serves two purposes - it adjusts timing so
281    // |connect_start| doesn't include dns times, and it adjusts the time so
282    // as not to include time spent waiting for an idle socket.
283    connect_timing_.connect_start = socket_connect_timing.connect_start;
284    connect_timing_.dns_start = socket_connect_timing.dns_start;
285    connect_timing_.dns_end = socket_connect_timing.dns_end;
286  }
287
288  connect_timing_.ssl_start = base::TimeTicks::Now();
289
290  ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket(
291      transport_socket_handle_.release(),
292      params_->host_and_port(),
293      params_->ssl_config(),
294      context_));
295  return ssl_socket_->Connect(callback_);
296}
297
298int SSLConnectJob::DoSSLConnectComplete(int result) {
299  connect_timing_.ssl_end = base::TimeTicks::Now();
300
301  SSLClientSocket::NextProtoStatus status =
302      SSLClientSocket::kNextProtoUnsupported;
303  std::string proto;
304  std::string server_protos;
305  // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket
306  // that hasn't had SSL_ImportFD called on it. If we get a certificate error
307  // here, then we know that we called SSL_ImportFD.
308  if (result == OK || IsCertificateError(result))
309    status = ssl_socket_->GetNextProto(&proto, &server_protos);
310
311  // If we want spdy over npn, make sure it succeeded.
312  if (status == SSLClientSocket::kNextProtoNegotiated) {
313    ssl_socket_->set_was_npn_negotiated(true);
314    NextProto protocol_negotiated =
315        SSLClientSocket::NextProtoFromString(proto);
316    ssl_socket_->set_protocol_negotiated(protocol_negotiated);
317    // If we negotiated a SPDY version, it must have been present in
318    // SSLConfig::next_protos.
319    // TODO(mbelshe): Verify this.
320    if (protocol_negotiated >= kProtoSPDYMinimumVersion &&
321        protocol_negotiated <= kProtoSPDYMaximumVersion) {
322      ssl_socket_->set_was_spdy_negotiated(true);
323    }
324  }
325  if (params_->want_spdy_over_npn() && !ssl_socket_->was_spdy_negotiated())
326    return ERR_NPN_NEGOTIATION_FAILED;
327
328  // Spdy might be turned on by default, or it might be over npn.
329  bool using_spdy = params_->force_spdy_over_ssl() ||
330      params_->want_spdy_over_npn();
331
332  if (result == OK ||
333      ssl_socket_->IgnoreCertError(result, params_->load_flags())) {
334    DCHECK(!connect_timing_.ssl_start.is_null());
335    base::TimeDelta connect_duration =
336        connect_timing_.ssl_end - connect_timing_.ssl_start;
337    if (using_spdy) {
338      UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency_2",
339                                 connect_duration,
340                                 base::TimeDelta::FromMilliseconds(1),
341                                 base::TimeDelta::FromMinutes(1),
342                                 100);
343    }
344#if defined(SPDY_PROXY_AUTH_ORIGIN)
345    bool using_data_reduction_proxy = params_->host_and_port().Equals(
346        HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
347    if (using_data_reduction_proxy) {
348      UMA_HISTOGRAM_CUSTOM_TIMES(
349          "Net.SSL_Connection_Latency_DataReductionProxy",
350          connect_duration,
351          base::TimeDelta::FromMilliseconds(1),
352          base::TimeDelta::FromMinutes(1),
353          100);
354    }
355#endif
356
357    UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_2",
358                               connect_duration,
359                               base::TimeDelta::FromMilliseconds(1),
360                               base::TimeDelta::FromMinutes(1),
361                               100);
362
363    SSLInfo ssl_info;
364    ssl_socket_->GetSSLInfo(&ssl_info);
365
366    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSL_CipherSuite",
367                                SSLConnectionStatusToCipherSuite(
368                                    ssl_info.connection_status));
369
370    if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME) {
371      UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Resume_Handshake",
372                                 connect_duration,
373                                 base::TimeDelta::FromMilliseconds(1),
374                                 base::TimeDelta::FromMinutes(1),
375                                 100);
376    } else if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_FULL) {
377      UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Full_Handshake",
378                                 connect_duration,
379                                 base::TimeDelta::FromMilliseconds(1),
380                                 base::TimeDelta::FromMinutes(1),
381                                 100);
382    }
383
384    const std::string& host = params_->host_and_port().host();
385    bool is_google = host == "google.com" ||
386                     (host.size() > 11 &&
387                      host.rfind(".google.com") == host.size() - 11);
388    if (is_google) {
389      UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google2",
390                                 connect_duration,
391                                 base::TimeDelta::FromMilliseconds(1),
392                                 base::TimeDelta::FromMinutes(1),
393                                 100);
394      if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_RESUME) {
395        UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google_"
396                                       "Resume_Handshake",
397                                   connect_duration,
398                                   base::TimeDelta::FromMilliseconds(1),
399                                   base::TimeDelta::FromMinutes(1),
400                                   100);
401      } else if (ssl_info.handshake_type == SSLInfo::HANDSHAKE_FULL) {
402        UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google_"
403                                       "Full_Handshake",
404                                   connect_duration,
405                                   base::TimeDelta::FromMilliseconds(1),
406                                   base::TimeDelta::FromMinutes(1),
407                                   100);
408      }
409    }
410  }
411
412  if (result == OK || IsCertificateError(result)) {
413    set_socket(ssl_socket_.release());
414  } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
415    error_response_info_.cert_request_info = new SSLCertRequestInfo;
416    ssl_socket_->GetSSLCertRequestInfo(
417        error_response_info_.cert_request_info.get());
418  }
419
420  return result;
421}
422
423int SSLConnectJob::ConnectInternal() {
424  switch (params_->proxy()) {
425    case ProxyServer::SCHEME_DIRECT:
426      next_state_ = STATE_TRANSPORT_CONNECT;
427      break;
428    case ProxyServer::SCHEME_HTTP:
429    case ProxyServer::SCHEME_HTTPS:
430      next_state_ = STATE_TUNNEL_CONNECT;
431      break;
432    case ProxyServer::SCHEME_SOCKS4:
433    case ProxyServer::SCHEME_SOCKS5:
434      next_state_ = STATE_SOCKS_CONNECT;
435      break;
436    default:
437      NOTREACHED() << "unknown proxy type";
438      break;
439  }
440  return DoLoop(OK);
441}
442
443SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
444    TransportClientSocketPool* transport_pool,
445    SOCKSClientSocketPool* socks_pool,
446    HttpProxyClientSocketPool* http_proxy_pool,
447    ClientSocketFactory* client_socket_factory,
448    HostResolver* host_resolver,
449    const SSLClientSocketContext& context,
450    NetLog* net_log)
451    : transport_pool_(transport_pool),
452      socks_pool_(socks_pool),
453      http_proxy_pool_(http_proxy_pool),
454      client_socket_factory_(client_socket_factory),
455      host_resolver_(host_resolver),
456      context_(context),
457      net_log_(net_log) {
458  base::TimeDelta max_transport_timeout = base::TimeDelta();
459  base::TimeDelta pool_timeout;
460  if (transport_pool_)
461    max_transport_timeout = transport_pool_->ConnectionTimeout();
462  if (socks_pool_) {
463    pool_timeout = socks_pool_->ConnectionTimeout();
464    if (pool_timeout > max_transport_timeout)
465      max_transport_timeout = pool_timeout;
466  }
467  if (http_proxy_pool_) {
468    pool_timeout = http_proxy_pool_->ConnectionTimeout();
469    if (pool_timeout > max_transport_timeout)
470      max_transport_timeout = pool_timeout;
471  }
472  timeout_ = max_transport_timeout +
473      base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds);
474}
475
476SSLClientSocketPool::SSLClientSocketPool(
477    int max_sockets,
478    int max_sockets_per_group,
479    ClientSocketPoolHistograms* histograms,
480    HostResolver* host_resolver,
481    CertVerifier* cert_verifier,
482    ServerBoundCertService* server_bound_cert_service,
483    TransportSecurityState* transport_security_state,
484    const std::string& ssl_session_cache_shard,
485    ClientSocketFactory* client_socket_factory,
486    TransportClientSocketPool* transport_pool,
487    SOCKSClientSocketPool* socks_pool,
488    HttpProxyClientSocketPool* http_proxy_pool,
489    SSLConfigService* ssl_config_service,
490    NetLog* net_log)
491    : transport_pool_(transport_pool),
492      socks_pool_(socks_pool),
493      http_proxy_pool_(http_proxy_pool),
494      base_(max_sockets, max_sockets_per_group, histograms,
495            ClientSocketPool::unused_idle_socket_timeout(),
496            ClientSocketPool::used_idle_socket_timeout(),
497            new SSLConnectJobFactory(transport_pool,
498                                     socks_pool,
499                                     http_proxy_pool,
500                                     client_socket_factory,
501                                     host_resolver,
502                                     SSLClientSocketContext(
503                                         cert_verifier,
504                                         server_bound_cert_service,
505                                         transport_security_state,
506                                         ssl_session_cache_shard),
507                                     net_log)),
508      ssl_config_service_(ssl_config_service) {
509  if (ssl_config_service_.get())
510    ssl_config_service_->AddObserver(this);
511  if (transport_pool_)
512    transport_pool_->AddLayeredPool(this);
513  if (socks_pool_)
514    socks_pool_->AddLayeredPool(this);
515  if (http_proxy_pool_)
516    http_proxy_pool_->AddLayeredPool(this);
517}
518
519SSLClientSocketPool::~SSLClientSocketPool() {
520  if (http_proxy_pool_)
521    http_proxy_pool_->RemoveLayeredPool(this);
522  if (socks_pool_)
523    socks_pool_->RemoveLayeredPool(this);
524  if (transport_pool_)
525    transport_pool_->RemoveLayeredPool(this);
526  if (ssl_config_service_.get())
527    ssl_config_service_->RemoveObserver(this);
528}
529
530ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob(
531    const std::string& group_name,
532    const PoolBase::Request& request,
533    ConnectJob::Delegate* delegate) const {
534  return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(),
535                           transport_pool_, socks_pool_, http_proxy_pool_,
536                           client_socket_factory_, host_resolver_,
537                           context_, delegate, net_log_);
538}
539
540base::TimeDelta
541SSLClientSocketPool::SSLConnectJobFactory::ConnectionTimeout() const {
542  return timeout_;
543}
544
545int SSLClientSocketPool::RequestSocket(const std::string& group_name,
546                                       const void* socket_params,
547                                       RequestPriority priority,
548                                       ClientSocketHandle* handle,
549                                       const CompletionCallback& callback,
550                                       const BoundNetLog& net_log) {
551  const scoped_refptr<SSLSocketParams>* casted_socket_params =
552      static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params);
553
554  return base_.RequestSocket(group_name, *casted_socket_params, priority,
555                             handle, callback, net_log);
556}
557
558void SSLClientSocketPool::RequestSockets(
559    const std::string& group_name,
560    const void* params,
561    int num_sockets,
562    const BoundNetLog& net_log) {
563  const scoped_refptr<SSLSocketParams>* casted_params =
564      static_cast<const scoped_refptr<SSLSocketParams>*>(params);
565
566  base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
567}
568
569void SSLClientSocketPool::CancelRequest(const std::string& group_name,
570                                        ClientSocketHandle* handle) {
571  base_.CancelRequest(group_name, handle);
572}
573
574void SSLClientSocketPool::ReleaseSocket(const std::string& group_name,
575                                        StreamSocket* socket, int id) {
576  base_.ReleaseSocket(group_name, socket, id);
577}
578
579void SSLClientSocketPool::FlushWithError(int error) {
580  base_.FlushWithError(error);
581}
582
583bool SSLClientSocketPool::IsStalled() const {
584  return base_.IsStalled() ||
585      (transport_pool_ && transport_pool_->IsStalled()) ||
586      (socks_pool_ && socks_pool_->IsStalled()) ||
587      (http_proxy_pool_ && http_proxy_pool_->IsStalled());
588}
589
590void SSLClientSocketPool::CloseIdleSockets() {
591  base_.CloseIdleSockets();
592}
593
594int SSLClientSocketPool::IdleSocketCount() const {
595  return base_.idle_socket_count();
596}
597
598int SSLClientSocketPool::IdleSocketCountInGroup(
599    const std::string& group_name) const {
600  return base_.IdleSocketCountInGroup(group_name);
601}
602
603LoadState SSLClientSocketPool::GetLoadState(
604    const std::string& group_name, const ClientSocketHandle* handle) const {
605  return base_.GetLoadState(group_name, handle);
606}
607
608void SSLClientSocketPool::AddLayeredPool(LayeredPool* layered_pool) {
609  base_.AddLayeredPool(layered_pool);
610}
611
612void SSLClientSocketPool::RemoveLayeredPool(LayeredPool* layered_pool) {
613  base_.RemoveLayeredPool(layered_pool);
614}
615
616base::DictionaryValue* SSLClientSocketPool::GetInfoAsValue(
617    const std::string& name,
618    const std::string& type,
619    bool include_nested_pools) const {
620  base::DictionaryValue* dict = base_.GetInfoAsValue(name, type);
621  if (include_nested_pools) {
622    base::ListValue* list = new base::ListValue();
623    if (transport_pool_) {
624      list->Append(transport_pool_->GetInfoAsValue("transport_socket_pool",
625                                                   "transport_socket_pool",
626                                                   false));
627    }
628    if (socks_pool_) {
629      list->Append(socks_pool_->GetInfoAsValue("socks_pool",
630                                               "socks_pool",
631                                               true));
632    }
633    if (http_proxy_pool_) {
634      list->Append(http_proxy_pool_->GetInfoAsValue("http_proxy_pool",
635                                                    "http_proxy_pool",
636                                                    true));
637    }
638    dict->Set("nested_pools", list);
639  }
640  return dict;
641}
642
643base::TimeDelta SSLClientSocketPool::ConnectionTimeout() const {
644  return base_.ConnectionTimeout();
645}
646
647ClientSocketPoolHistograms* SSLClientSocketPool::histograms() const {
648  return base_.histograms();
649}
650
651void SSLClientSocketPool::OnSSLConfigChanged() {
652  FlushWithError(ERR_NETWORK_CHANGED);
653}
654
655bool SSLClientSocketPool::CloseOneIdleConnection() {
656  if (base_.CloseOneIdleSocket())
657    return true;
658  return base_.CloseOneIdleConnectionInLayeredPool();
659}
660
661}  // namespace net
662