Chromium Code Reviews| 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 |
| index 2c704658820bc06a8404679c2f796be269657387..c424767e82decd0a8efeec2df529b97c2761d7f9 100644 |
| --- a/net/socket/ssl_client_socket_pool.cc |
| +++ b/net/socket/ssl_client_socket_pool.cc |
| @@ -94,6 +94,57 @@ SSLSocketParams::GetHttpProxyConnectionParams() const { |
| return http_proxy_params_; |
| } |
| +bool SSLConnectJobMessenger::CanProceed(SSLClientSocket* ssl_socket) { |
| + // If the session is in the session cache, or there are no connecting |
| + // sockets allow the connection to proceed. |
| + if (ssl_socket->InSessionCache() || connecting_sockets_.empty()) { |
| + return true; |
| + } |
| + return false; |
|
wtc
2014/07/11 00:48:55
You can just say
return ssl_socket->InSessionCac
mshelley
2014/07/11 23:26:27
Done.
|
| +} |
| + |
| +void SSLConnectJobMessenger::MonitorConnectionResult( |
| + SSLClientSocket* ssl_socket) { |
| + connecting_sockets_.push_back(ssl_socket); |
| + ssl_socket->SetIsLeader(); |
| + ssl_socket->SetSocketFailureCallback( |
| + base::Bind(&SSLConnectJobMessenger::OnJobFailed, base::Unretained(this))); |
| + ssl_socket->WatchSessionForCompletion(base::Bind( |
| + &SSLConnectJobMessenger::OnJobSucceeded, base::Unretained(this))); |
|
wtc
2014/07/11 00:48:54
IMPORTANT: we need to convince ourselves that we d
|
| +} |
| + |
| +void SSLConnectJobMessenger::AddPendingSocket(SSLClientSocket* socket, |
| + const base::Closure& callback) { |
| + pending_sockets_and_callbacks_.push_back(SocketAndCallback(socket, callback)); |
| +} |
| + |
| +void SSLConnectJobMessenger::OnJobSucceeded() { |
| + SSLPendingSocketsAndCallbacks temp_list = pending_sockets_and_callbacks_; |
| + pending_sockets_and_callbacks_.clear(); |
| + connecting_sockets_.clear(); |
| + RunAllJobs(temp_list); |
| +} |
| + |
| +void SSLConnectJobMessenger::OnJobFailed() { |
| + if (pending_sockets_and_callbacks_.empty()) |
| + return; |
| + base::Closure callback = pending_sockets_and_callbacks_[0].callback; |
| + connecting_sockets_.erase(connecting_sockets_.begin()); |
| + SSLClientSocket* ssl_socket = pending_sockets_and_callbacks_[0].socket; |
| + pending_sockets_and_callbacks_.erase(pending_sockets_and_callbacks_.begin()); |
| + MonitorConnectionResult(ssl_socket); |
| + callback.Run(); |
| +} |
| + |
| +void SSLConnectJobMessenger::RunAllJobs( |
| + std::vector<SocketAndCallback>& pending_sockets_and_callbacks) { |
| + for (std::vector<SocketAndCallback>::const_iterator it = |
| + pending_sockets_and_callbacks.begin(); |
| + it != pending_sockets_and_callbacks.end(); |
| + ++it) |
| + it->callback.Run(); |
| +} |
| + |
| // Timeout for the SSL handshake portion of the connect. |
| static const int kSSLHandshakeTimeoutInSeconds = 30; |
| @@ -107,6 +158,7 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name, |
| ClientSocketFactory* client_socket_factory, |
| HostResolver* host_resolver, |
| const SSLClientSocketContext& context, |
| + SSLConnectJobMessenger* messenger, |
| Delegate* delegate, |
| NetLog* net_log) |
| : ConnectJob(group_name, |
| @@ -127,8 +179,11 @@ SSLConnectJob::SSLConnectJob(const std::string& group_name, |
| (params->privacy_mode() == PRIVACY_MODE_ENABLED |
| ? "pm/" + context.ssl_session_cache_shard |
| : context.ssl_session_cache_shard)), |
| - callback_(base::Bind(&SSLConnectJob::OnIOComplete, |
| - base::Unretained(this))) {} |
| + io_callback_( |
| + base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))), |
| + messenger_(messenger), |
| + weak_factory_(this) { |
| +} |
| SSLConnectJob::~SSLConnectJob() {} |
|
wtc
2014/07/11 00:48:54
IMPORTANT: we should remove the SSLClientSocket of
mshelley
2014/07/11 23:26:27
Done.
|
| @@ -144,6 +199,8 @@ LoadState SSLConnectJob::GetLoadState() const { |
| case STATE_SOCKS_CONNECT_COMPLETE: |
| case STATE_TUNNEL_CONNECT: |
| return transport_socket_handle_->GetLoadState(); |
| + case STATE_CREATE_SSL_SOCKET: |
| + case STATE_CHECK_FOR_RESUME: |
| case STATE_SSL_CONNECT: |
| case STATE_SSL_CONNECT_COMPLETE: |
| return LOAD_STATE_SSL_HANDSHAKE; |
| @@ -200,6 +257,12 @@ int SSLConnectJob::DoLoop(int result) { |
| case STATE_TUNNEL_CONNECT_COMPLETE: |
| rv = DoTunnelConnectComplete(rv); |
| break; |
| + case STATE_CREATE_SSL_SOCKET: |
| + rv = DoCreateSSLSocket(); |
| + break; |
| + case STATE_CHECK_FOR_RESUME: |
| + rv = DoCheckForResume(); |
| + break; |
| case STATE_SSL_CONNECT: |
| DCHECK_EQ(OK, rv); |
| rv = DoSSLConnect(); |
| @@ -227,14 +290,16 @@ int SSLConnectJob::DoTransportConnect() { |
| return transport_socket_handle_->Init(group_name(), |
| direct_params, |
| priority(), |
| - callback_, |
| + io_callback_, |
| transport_pool_, |
| net_log()); |
| } |
| int SSLConnectJob::DoTransportConnectComplete(int result) { |
| - if (result == OK) |
| - next_state_ = STATE_SSL_CONNECT; |
| + if (result != OK) |
| + return result; |
| + |
| + next_state_ = STATE_CREATE_SSL_SOCKET; |
| return result; |
| } |
| @@ -248,14 +313,16 @@ int SSLConnectJob::DoSOCKSConnect() { |
| return transport_socket_handle_->Init(group_name(), |
| socks_proxy_params, |
| priority(), |
| - callback_, |
| + io_callback_, |
| socks_pool_, |
| net_log()); |
| } |
| int SSLConnectJob::DoSOCKSConnectComplete(int result) { |
| - if (result == OK) |
| - next_state_ = STATE_SSL_CONNECT; |
| + if (result != OK) |
| + return result; |
| + |
| + next_state_ = STATE_CREATE_SSL_SOCKET; |
| return result; |
| } |
| @@ -270,7 +337,7 @@ int SSLConnectJob::DoTunnelConnect() { |
| return transport_socket_handle_->Init(group_name(), |
| http_proxy_params, |
| priority(), |
| - callback_, |
| + io_callback_, |
| http_proxy_pool_, |
| net_log()); |
| } |
| @@ -291,12 +358,15 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) { |
| if (result < 0) |
| return result; |
| - next_state_ = STATE_SSL_CONNECT; |
| + next_state_ = STATE_CREATE_SSL_SOCKET; |
| return result; |
| } |
| -int SSLConnectJob::DoSSLConnect() { |
| - next_state_ = STATE_SSL_CONNECT_COMPLETE; |
| +int SSLConnectJob::DoCreateSSLSocket() { |
| + if (SSLClientSocketPool::GetEnableConnectJobWaiting()) |
|
wtc
2014/07/11 00:48:55
You can just test |messenger_|.
mshelley
2014/07/11 23:26:27
Done.
|
| + next_state_ = STATE_CHECK_FOR_RESUME; |
| + else |
| + next_state_ = STATE_SSL_CONNECT; |
| // Reset the timeout to just the time allowed for the SSL handshake. |
| ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds)); |
| @@ -314,19 +384,43 @@ int SSLConnectJob::DoSSLConnect() { |
| connect_timing_.dns_end = socket_connect_timing.dns_end; |
| } |
| - connect_timing_.ssl_start = base::TimeTicks::Now(); |
| - |
| ssl_socket_ = client_socket_factory_->CreateSSLClientSocket( |
| transport_socket_handle_.Pass(), |
| params_->host_and_port(), |
| params_->ssl_config(), |
| context_); |
| - return ssl_socket_->Connect(callback_); |
| + return OK; |
| +} |
| + |
| +int SSLConnectJob::DoCheckForResume() { |
| + next_state_ = STATE_SSL_CONNECT; |
| + if (messenger_->CanProceed(ssl_socket_.get())) { |
| + if (ssl_socket_->InSessionCache()) |
|
wtc
2014/07/11 00:48:55
Doing it this way means we are calling ssl_socket_
mshelley
2014/07/11 23:26:27
Acknowledged.
|
| + return OK; |
| + messenger_->MonitorConnectionResult(ssl_socket_.get()); |
| + return OK; |
| + } |
| + messenger_->AddPendingSocket( |
| + ssl_socket_.get(), |
| + base::Bind(&net::SSLConnectJob::ResumeSSLConnection, |
| + weak_factory_.GetWeakPtr())); |
|
wtc
2014/07/11 00:48:55
IMPORTANT: this weak pointer only protects the job
mshelley
2014/07/11 23:26:27
Done.
|
| + return ERR_IO_PENDING; |
| +} |
| + |
| +int SSLConnectJob::DoSSLConnect() { |
| + next_state_ = STATE_SSL_CONNECT_COMPLETE; |
| + |
| + connect_timing_.ssl_start = base::TimeTicks::Now(); |
| + |
| + return ssl_socket_->Connect(io_callback_); |
| } |
| int SSLConnectJob::DoSSLConnectComplete(int result) { |
| connect_timing_.ssl_end = base::TimeTicks::Now(); |
| + if (result != OK && SSLClientSocketPool::GetEnableConnectJobWaiting()) |
|
wtc
2014/07/11 00:48:54
1. BUG? : messenger_->OnJobFailed() will be invoke
mshelley
2014/07/11 23:26:27
Done.
|
| + messenger_->OnJobFailed(); |
| + |
| SSLClientSocket::NextProtoStatus status = |
| SSLClientSocket::kNextProtoUnsupported; |
| std::string proto; |
| @@ -411,9 +505,9 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { |
| } |
| const std::string& host = params_->host_and_port().host(); |
| - bool is_google = host == "google.com" || |
| - (host.size() > 11 && |
| - host.rfind(".google.com") == host.size() - 11); |
| + bool is_google = |
| + host == "google.com" || |
| + (host.size() > 11 && host.rfind(".google.com") == host.size() - 11); |
| if (is_google) { |
| UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency_Google2", |
| connect_duration, |
| @@ -449,6 +543,11 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { |
| return result; |
| } |
| +void SSLConnectJob::ResumeSSLConnection() { |
| + DCHECK_EQ(next_state_, STATE_SSL_CONNECT); |
| + OnIOComplete(OK); |
| +} |
| + |
| SSLConnectJob::State SSLConnectJob::GetInitialState( |
| SSLSocketParams::ConnectionType connection_type) { |
| switch (connection_type) { |
| @@ -482,7 +581,8 @@ SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory( |
| client_socket_factory_(client_socket_factory), |
| host_resolver_(host_resolver), |
| context_(context), |
| - net_log_(net_log) { |
| + net_log_(net_log), |
| + messenger_map_(new MessengerMap) { |
| base::TimeDelta max_transport_timeout = base::TimeDelta(); |
| base::TimeDelta pool_timeout; |
| if (transport_pool_) |
| @@ -520,21 +620,24 @@ SSLClientSocketPool::SSLClientSocketPool( |
| : transport_pool_(transport_pool), |
| socks_pool_(socks_pool), |
| http_proxy_pool_(http_proxy_pool), |
| - base_(this, max_sockets, max_sockets_per_group, histograms, |
| + base_(this, |
| + max_sockets, |
| + max_sockets_per_group, |
| + histograms, |
| ClientSocketPool::unused_idle_socket_timeout(), |
| ClientSocketPool::used_idle_socket_timeout(), |
| - new SSLConnectJobFactory(transport_pool, |
| - socks_pool, |
| - http_proxy_pool, |
| - client_socket_factory, |
| - host_resolver, |
| - SSLClientSocketContext( |
| - cert_verifier, |
| - server_bound_cert_service, |
| - transport_security_state, |
| - cert_transparency_verifier, |
| - ssl_session_cache_shard), |
| - net_log)), |
| + new SSLConnectJobFactory( |
| + transport_pool, |
| + socks_pool, |
| + http_proxy_pool, |
| + client_socket_factory, |
| + host_resolver, |
| + SSLClientSocketContext(cert_verifier, |
| + server_bound_cert_service, |
| + transport_security_state, |
| + cert_transparency_verifier, |
| + ssl_session_cache_shard), |
| + net_log)), |
| ssl_config_service_(ssl_config_service) { |
| if (ssl_config_service_.get()) |
| ssl_config_service_->AddObserver(this); |
| @@ -556,11 +659,35 @@ SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob( |
| const std::string& group_name, |
| const PoolBase::Request& request, |
| ConnectJob::Delegate* delegate) const { |
| - return scoped_ptr<ConnectJob>( |
| - new SSLConnectJob(group_name, request.priority(), request.params(), |
| - ConnectionTimeout(), transport_pool_, socks_pool_, |
| - http_proxy_pool_, client_socket_factory_, |
| - host_resolver_, context_, delegate, net_log_)); |
| + SSLConnectJobMessenger* messenger; |
| + std::string cache_key = SSLClientSocket::FormatSessionCacheKey( |
| + request.params()->host_and_port().ToString(), |
| + context_.ssl_session_cache_shard); |
|
wtc
2014/07/11 00:48:55
Move the |cache_key| declaration into the if state
mshelley
2014/07/11 23:26:27
Done.
|
| + if (SSLClientSocketPool::GetEnableConnectJobWaiting()) { |
| + MessengerMap::const_iterator it = messenger_map_->find(cache_key); |
| + if (it == messenger_map_->end()) { |
| + std::pair<MessengerMap::iterator, bool> iter = messenger_map_->insert( |
| + MessengerMap::value_type(cache_key, new SSLConnectJobMessenger())); |
| + it = iter.first; |
| + } |
| + messenger = it->second; |
| + } else { |
| + messenger = NULL; |
|
wtc
2014/07/11 00:48:54
Nit: you can initialize |messager| to NULL on line
mshelley
2014/07/11 23:26:27
Done.
|
| + } |
| + |
| + return scoped_ptr<ConnectJob>(new SSLConnectJob(group_name, |
| + request.priority(), |
| + request.params(), |
| + ConnectionTimeout(), |
| + transport_pool_, |
| + socks_pool_, |
| + http_proxy_pool_, |
| + client_socket_factory_, |
| + host_resolver_, |
| + context_, |
| + messenger, |
| + delegate, |
| + net_log_)); |
| } |
| base::TimeDelta |
| @@ -679,6 +806,19 @@ bool SSLClientSocketPool::CloseOneIdleConnection() { |
| return base_.CloseOneIdleConnectionInHigherLayeredPool(); |
| } |
| +// static |
| +bool SSLClientSocketPool::enable_connect_job_waiting_ = false; |
|
wtc
2014/07/11 00:48:55
We usually initialize static data members before t
mshelley
2014/07/11 23:26:27
Done.
|
| + |
| +// static |
| +void SSLClientSocketPool::EnableConnectJobWaiting(bool enable) { |
| + enable_connect_job_waiting_ = enable; |
| +} |
| + |
| +// static |
| +bool SSLClientSocketPool::GetEnableConnectJobWaiting() { |
| + return enable_connect_job_waiting_; |
| +} |
| + |
| void SSLClientSocketPool::OnSSLConfigChanged() { |
| FlushWithError(ERR_NETWORK_CHANGED); |
| } |