Index: net/socket/ssl_client_socket_pool.cc |
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fedb3ca9a9ac0d8d9911a4cee7491794803a2e34 |
--- /dev/null |
+++ b/net/socket/ssl_client_socket_pool.cc |
@@ -0,0 +1,424 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "net/socket/ssl_client_socket_pool.h" |
+ |
+#include "net/base/net_errors.h" |
+#include "net/socket/client_socket_factory.h" |
+#include "net/socket/client_socket_handle.h" |
+ |
+namespace net { |
+ |
+SSLSocketParams::SSLSocketParams( |
+ const scoped_refptr<TCPSocketParams>& tcp_params, |
+ const scoped_refptr<HttpProxySocketParams>& http_proxy_params, |
+ const scoped_refptr<SOCKSSocketParams>& socks_params, |
+ ProxyServer::Scheme proxy, |
+ const std::string& hostname, |
+ const SSLConfig& ssl_config, |
+ int load_flags, |
+ bool want_spdy) |
+ : tcp_params_(tcp_params), |
+ http_proxy_params_(http_proxy_params), |
+ socks_params_(socks_params), |
+ proxy_(proxy), |
+ hostname_(hostname), |
+ ssl_config_(ssl_config), |
+ load_flags_(load_flags), |
+ want_spdy_(want_spdy) { |
+ switch (proxy_) { |
+ case ProxyServer::SCHEME_DIRECT: |
+ DCHECK(tcp_params_.get() != NULL); |
+ DCHECK(http_proxy_params_.get() == NULL); |
+ DCHECK(socks_params_.get() == NULL); |
+ break; |
+ case ProxyServer::SCHEME_HTTP: |
+ DCHECK(tcp_params_.get() == NULL); |
+ DCHECK(http_proxy_params_.get() != NULL); |
+ DCHECK(socks_params_.get() == NULL); |
+ break; |
+ case ProxyServer::SCHEME_SOCKS4: |
+ case ProxyServer::SCHEME_SOCKS5: |
+ DCHECK(tcp_params_.get() == NULL); |
+ DCHECK(http_proxy_params_.get() == NULL); |
+ DCHECK(socks_params_.get() != NULL); |
+ break; |
+ default: |
+ LOG(DFATAL) << "unknown proxy type"; |
+ break; |
+ } |
+} |
+ |
+SSLSocketParams::~SSLSocketParams() {} |
+ |
+// Timeout for the SSL handshake portion of the connect. |
+static const int kSSLHandshakeTimeoutInSeconds = 30; |
+ |
+SSLConnectJob::SSLConnectJob( |
+ const std::string& group_name, |
+ const scoped_refptr<SSLSocketParams>& params, |
+ const base::TimeDelta& timeout_duration, |
+ const scoped_refptr<TCPClientSocketPool>& tcp_pool, |
+ const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, |
+ const scoped_refptr<SOCKSClientSocketPool>& socks_pool, |
+ ClientSocketFactory* client_socket_factory, |
+ const scoped_refptr<HostResolver>& host_resolver, |
+ Delegate* delegate, |
+ NetLog* net_log) |
+ : ConnectJob(group_name, timeout_duration, delegate, |
+ BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), |
+ params_(params), |
+ tcp_pool_(tcp_pool), |
+ http_proxy_pool_(http_proxy_pool), |
+ socks_pool_(socks_pool), |
+ client_socket_factory_(client_socket_factory), |
+ resolver_(host_resolver), |
Nico
2015/03/08 02:31:18
This constructor sets all fields except next_state
wrong vandebo
2015/03/08 03:57:15
Looks like it could have been set to STATE_NONE
|
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ callback_(this, &SSLConnectJob::OnIOComplete)) {} |
+ |
+SSLConnectJob::~SSLConnectJob() {} |
+ |
+LoadState SSLConnectJob::GetLoadState() const { |
+ switch (next_state_) { |
+ case STATE_TCP_CONNECT: |
+ case STATE_TCP_CONNECT_COMPLETE: |
+ case STATE_SOCKS_CONNECT: |
+ case STATE_SOCKS_CONNECT_COMPLETE: |
+ case STATE_TUNNEL_CONNECT: |
+ case STATE_TUNNEL_CONNECT_COMPLETE: |
+ return transport_socket_handle_->GetLoadState(); |
+ case STATE_SSL_CONNECT: |
+ case STATE_SSL_CONNECT_COMPLETE: |
+ return LOAD_STATE_SSL_HANDSHAKE; |
+ default: |
+ NOTREACHED(); |
+ return LOAD_STATE_IDLE; |
+ } |
+} |
+ |
+int SSLConnectJob::ConnectInternal() { |
+ DetermineFirstState(); |
+ return DoLoop(OK); |
+} |
+ |
+void SSLConnectJob::DetermineFirstState() { |
+ switch (params_->proxy()) { |
+ case ProxyServer::SCHEME_DIRECT: |
+ next_state_ = STATE_TCP_CONNECT; |
+ break; |
+ case ProxyServer::SCHEME_HTTP: |
+ next_state_ = STATE_TUNNEL_CONNECT; |
+ break; |
+ case ProxyServer::SCHEME_SOCKS4: |
+ case ProxyServer::SCHEME_SOCKS5: |
+ next_state_ = STATE_SOCKS_CONNECT; |
+ break; |
+ default: |
+ NOTREACHED() << "unknown proxy type"; |
+ break; |
+ } |
+} |
+ |
+void SSLConnectJob::OnIOComplete(int result) { |
+ int rv = DoLoop(result); |
+ if (rv != ERR_IO_PENDING) |
+ NotifyDelegateOfCompletion(rv); // Deletes |this|. |
+} |
+ |
+int SSLConnectJob::DoLoop(int result) { |
+ DCHECK_NE(next_state_, STATE_NONE); |
+ |
+ int rv = result; |
+ do { |
+ State state = next_state_; |
+ next_state_ = STATE_NONE; |
+ switch (state) { |
+ case STATE_TCP_CONNECT: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoTCPConnect(); |
+ break; |
+ case STATE_TCP_CONNECT_COMPLETE: |
+ rv = DoTCPConnectComplete(rv); |
+ break; |
+ case STATE_SOCKS_CONNECT: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoSOCKSConnect(); |
+ break; |
+ case STATE_SOCKS_CONNECT_COMPLETE: |
+ rv = DoSOCKSConnectComplete(rv); |
+ break; |
+ case STATE_TUNNEL_CONNECT: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoTunnelConnect(); |
+ break; |
+ case STATE_TUNNEL_CONNECT_COMPLETE: |
+ rv = DoTunnelConnectComplete(rv); |
+ break; |
+ case STATE_SSL_CONNECT: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoSSLConnect(); |
+ break; |
+ case STATE_SSL_CONNECT_COMPLETE: |
+ rv = DoSSLConnectComplete(rv); |
+ break; |
+ default: |
+ NOTREACHED() << "bad state"; |
+ rv = ERR_FAILED; |
+ break; |
+ } |
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
+ |
+ return rv; |
+} |
+ |
+int SSLConnectJob::DoTCPConnect() { |
+ DCHECK(tcp_pool_.get()); |
+ next_state_ = STATE_TCP_CONNECT_COMPLETE; |
+ transport_socket_handle_.reset(new ClientSocketHandle()); |
+ scoped_refptr<TCPSocketParams> tcp_params = params_->tcp_params(); |
+ return transport_socket_handle_->Init(group_name(), tcp_params, |
+ tcp_params->destination().priority(), |
+ &callback_, tcp_pool_, net_log()); |
+} |
+ |
+int SSLConnectJob::DoTCPConnectComplete(int result) { |
+ if (result == OK) |
+ next_state_ = STATE_SSL_CONNECT; |
+ |
+ return result; |
+} |
+ |
+int SSLConnectJob::DoSOCKSConnect() { |
+ DCHECK(socks_pool_.get()); |
+ next_state_ = STATE_SOCKS_CONNECT_COMPLETE; |
+ transport_socket_handle_.reset(new ClientSocketHandle()); |
+ scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params(); |
+ return transport_socket_handle_->Init(group_name(), socks_params, |
+ socks_params->destination().priority(), |
+ &callback_, socks_pool_, net_log()); |
+} |
+ |
+int SSLConnectJob::DoSOCKSConnectComplete(int result) { |
+ if (result == OK) |
+ next_state_ = STATE_SSL_CONNECT; |
+ |
+ return result; |
+} |
+ |
+int SSLConnectJob::DoTunnelConnect() { |
+ DCHECK(http_proxy_pool_.get()); |
+ next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; |
+ transport_socket_handle_.reset(new ClientSocketHandle()); |
+ scoped_refptr<HttpProxySocketParams> http_proxy_params = |
+ params_->http_proxy_params(); |
+ return transport_socket_handle_->Init( |
+ group_name(), http_proxy_params, |
+ http_proxy_params->tcp_params()->destination().priority(), &callback_, |
+ http_proxy_pool_, net_log()); |
+} |
+ |
+int SSLConnectJob::DoTunnelConnectComplete(int result) { |
+ ClientSocket* socket = transport_socket_handle_->socket(); |
+ HttpProxyClientSocket* tunnel_socket = |
+ static_cast<HttpProxyClientSocket*>(socket); |
+ |
+ if (result == ERR_RETRY_CONNECTION) { |
+ DetermineFirstState(); |
+ transport_socket_handle_->socket()->Disconnect(); |
+ return OK; |
+ } |
+ |
+ if (result == ERR_PROXY_AUTH_REQUESTED) { |
+ // Extract the information needed to prompt for the proxy authentication. |
+ // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|, |
+ // we can easily set the state. |
+ const HttpResponseInfo* tunnel_response = tunnel_socket->GetResponseInfo(); |
+ |
+ http_auth_response_headers_ = tunnel_response->headers; |
+ http_auth_auth_challenge_ = tunnel_response->auth_challenge; |
+ } |
+ |
+ if (result < 0) |
+ return result; |
+ |
+ if (tunnel_socket->NeedsRestartWithAuth()) { |
+ // We must have gotten an 'idle' tunnel socket that is waiting for auth. |
+ // The HttpAuthController should have new credentials, we just need |
+ // to retry. |
+ next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; |
+ return tunnel_socket->RestartWithAuth(&callback_); |
+ } |
+ |
+ next_state_ = STATE_SSL_CONNECT; |
+ return result; |
+} |
+ |
+void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) { |
+ if (http_auth_response_headers_.get() != NULL) |
+ handle->set_tunnel_auth_response_info(http_auth_response_headers_, |
+ http_auth_auth_challenge_); |
+ if (!ssl_connect_start_time_.is_null()) |
+ handle->set_is_ssl_error(true); |
+} |
+ |
+int SSLConnectJob::DoSSLConnect() { |
+ next_state_ = STATE_SSL_CONNECT_COMPLETE; |
+ // Reset the timeout to just the time allowed for the SSL handshake. |
+ ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds)); |
+ ssl_connect_start_time_ = base::TimeTicks::Now(); |
+ |
+ ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket( |
+ transport_socket_handle_.release(), params_->hostname(), |
+ params_->ssl_config())); |
+ return ssl_socket_->Connect(&callback_); |
+} |
+ |
+int SSLConnectJob::DoSSLConnectComplete(int result) { |
+ SSLClientSocket::NextProtoStatus status = |
+ SSLClientSocket::kNextProtoUnsupported; |
+ std::string proto; |
+ // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket |
+ // that hasn't had SSL_ImportFD called on it. If we get a certificate error |
+ // here, then we know that we called SSL_ImportFD. |
+ if (result == OK || IsCertificateError(result)) |
+ status = ssl_socket_->GetNextProto(&proto); |
+ |
+ bool using_spdy = false; |
+ if (status == SSLClientSocket::kNextProtoNegotiated) { |
+ ssl_socket_->setWasNpnNegotiated(true); |
+ if (SSLClientSocket::NextProtoFromString(proto) == |
+ SSLClientSocket::kProtoSPDY1) { |
+ using_spdy = true; |
+ } |
+ } |
+ if (params_->want_spdy() && !using_spdy) |
+ return ERR_NPN_NEGOTIATION_FAILED; |
+ |
+ if (result == OK || |
+ ssl_socket_->IgnoreCertError(result, params_->load_flags())) { |
+ DCHECK(ssl_connect_start_time_ != base::TimeTicks()); |
+ base::TimeDelta connect_duration = |
+ base::TimeTicks::Now() - ssl_connect_start_time_; |
+ if (using_spdy) |
+ UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency", |
+ connect_duration, |
+ base::TimeDelta::FromMilliseconds(1), |
+ base::TimeDelta::FromMinutes(10), |
+ 100); |
+ else |
+ UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency", |
+ connect_duration, |
+ base::TimeDelta::FromMilliseconds(1), |
+ base::TimeDelta::FromMinutes(10), |
+ 100); |
+ } |
+ if (result == OK || IsCertificateError(result)) |
+ set_socket(ssl_socket_.release()); |
+ |
+ return result; |
+} |
+ |
+ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob( |
+ const std::string& group_name, |
+ const PoolBase::Request& request, |
+ ConnectJob::Delegate* delegate) const { |
+ return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(), |
+ tcp_pool_, http_proxy_pool_, socks_pool_, |
+ client_socket_factory_, host_resolver_, delegate, |
+ net_log_); |
+} |
+ |
+SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory( |
+ const scoped_refptr<TCPClientSocketPool>& tcp_pool, |
+ const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, |
+ const scoped_refptr<SOCKSClientSocketPool>& socks_pool, |
+ ClientSocketFactory* client_socket_factory, |
+ HostResolver* host_resolver, |
+ NetLog* net_log) |
+ : tcp_pool_(tcp_pool), |
+ http_proxy_pool_(http_proxy_pool), |
+ socks_pool_(socks_pool), |
+ client_socket_factory_(client_socket_factory), |
+ host_resolver_(host_resolver), |
+ net_log_(net_log) { |
+ base::TimeDelta max_transport_timeout = base::TimeDelta(); |
+ base::TimeDelta pool_timeout; |
+ if (tcp_pool_) |
+ max_transport_timeout = tcp_pool_->ConnectionTimeout(); |
+ if (socks_pool_) { |
+ pool_timeout = socks_pool_->ConnectionTimeout(); |
+ if (pool_timeout > max_transport_timeout) |
+ max_transport_timeout = pool_timeout; |
+ } |
+ if (http_proxy_pool_) { |
+ pool_timeout = http_proxy_pool_->ConnectionTimeout(); |
+ if (pool_timeout > max_transport_timeout) |
+ max_transport_timeout = pool_timeout; |
+ } |
+ timeout_ = max_transport_timeout + |
+ base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds); |
+} |
+ |
+SSLClientSocketPool::SSLClientSocketPool( |
+ int max_sockets, |
+ int max_sockets_per_group, |
+ const scoped_refptr<ClientSocketPoolHistograms>& histograms, |
+ const scoped_refptr<HostResolver>& host_resolver, |
+ ClientSocketFactory* client_socket_factory, |
+ const scoped_refptr<TCPClientSocketPool>& tcp_pool, |
+ const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, |
+ const scoped_refptr<SOCKSClientSocketPool>& socks_pool, |
+ NetLog* net_log) |
+ : base_(max_sockets, max_sockets_per_group, histograms, |
+ base::TimeDelta::FromSeconds( |
+ ClientSocketPool::unused_idle_socket_timeout()), |
+ base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout), |
+ new SSLConnectJobFactory(tcp_pool, http_proxy_pool, socks_pool, |
+ client_socket_factory, host_resolver, |
+ net_log)) {} |
+ |
+SSLClientSocketPool::~SSLClientSocketPool() {} |
+ |
+int SSLClientSocketPool::RequestSocket(const std::string& group_name, |
+ const void* socket_params, |
+ RequestPriority priority, |
+ ClientSocketHandle* handle, |
+ CompletionCallback* callback, |
+ const BoundNetLog& net_log) { |
+ const scoped_refptr<SSLSocketParams>* casted_socket_params = |
+ static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params); |
+ |
+ return base_.RequestSocket(group_name, *casted_socket_params, priority, |
+ handle, callback, net_log); |
+} |
+ |
+void SSLClientSocketPool::CancelRequest(const std::string& group_name, |
+ const ClientSocketHandle* handle) { |
+ base_.CancelRequest(group_name, handle); |
+} |
+ |
+void SSLClientSocketPool::ReleaseSocket(const std::string& group_name, |
+ ClientSocket* socket, int id) { |
+ base_.ReleaseSocket(group_name, socket, id); |
+} |
+ |
+void SSLClientSocketPool::Flush() { |
+ base_.Flush(); |
+} |
+ |
+void SSLClientSocketPool::CloseIdleSockets() { |
+ base_.CloseIdleSockets(); |
+} |
+ |
+int SSLClientSocketPool::IdleSocketCountInGroup( |
+ const std::string& group_name) const { |
+ return base_.IdleSocketCountInGroup(group_name); |
+} |
+ |
+LoadState SSLClientSocketPool::GetLoadState( |
+ const std::string& group_name, const ClientSocketHandle* handle) const { |
+ return base_.GetLoadState(group_name, handle); |
+} |
+ |
+} // namespace net |