Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2010 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 "net/base/net_errors.h" | |
| 8 #include "net/socket/client_socket_factory.h" | |
| 9 #include "net/socket/client_socket_handle.h" | |
| 10 | |
| 11 namespace net { | |
| 12 | |
| 13 SSLSocketParams::SSLSocketParams( | |
| 14 const scoped_refptr<TCPSocketParams>& tcp_params, | |
| 15 const scoped_refptr<HttpProxySocketParams>& http_proxy_params, | |
| 16 const scoped_refptr<SOCKSSocketParams>& socks_params, | |
| 17 ProxyServer::Scheme proxy, | |
| 18 const std::string& hostname, | |
| 19 const SSLConfig& ssl_config, | |
| 20 int load_flags, | |
| 21 bool want_spdy) | |
| 22 : tcp_params_(tcp_params), | |
| 23 http_proxy_params_(http_proxy_params), | |
| 24 socks_params_(socks_params), | |
| 25 proxy_(proxy), | |
| 26 hostname_(hostname), | |
| 27 ssl_config_(ssl_config), | |
| 28 load_flags_(load_flags), | |
| 29 want_spdy_(want_spdy) { | |
| 30 switch (proxy_) { | |
| 31 case ProxyServer::SCHEME_DIRECT: | |
| 32 DCHECK(tcp_params_.get() != NULL); | |
| 33 DCHECK(http_proxy_params_.get() == NULL); | |
| 34 DCHECK(socks_params_.get() == NULL); | |
| 35 break; | |
| 36 case ProxyServer::SCHEME_HTTP: | |
| 37 DCHECK(tcp_params_.get() == NULL); | |
| 38 DCHECK(http_proxy_params_.get() != NULL); | |
| 39 DCHECK(socks_params_.get() == NULL); | |
| 40 break; | |
| 41 case ProxyServer::SCHEME_SOCKS4: | |
| 42 case ProxyServer::SCHEME_SOCKS5: | |
| 43 DCHECK(tcp_params_.get() == NULL); | |
| 44 DCHECK(http_proxy_params_.get() == NULL); | |
| 45 DCHECK(socks_params_.get() != NULL); | |
| 46 break; | |
| 47 default: | |
| 48 LOG(DFATAL) << "unknown proxy type"; | |
| 49 break; | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 SSLSocketParams::~SSLSocketParams() {} | |
| 54 | |
| 55 // Timeout for the SSL handshake portion of the connect. | |
| 56 static const int kSSLHandshakeTimeoutInSeconds = 30; | |
| 57 | |
| 58 SSLConnectJob::SSLConnectJob( | |
| 59 const std::string& group_name, | |
| 60 const scoped_refptr<SSLSocketParams>& params, | |
| 61 const base::TimeDelta& timeout_duration, | |
| 62 const scoped_refptr<TCPClientSocketPool>& tcp_pool, | |
| 63 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, | |
| 64 const scoped_refptr<SOCKSClientSocketPool>& socks_pool, | |
| 65 ClientSocketFactory* client_socket_factory, | |
| 66 const scoped_refptr<HostResolver>& host_resolver, | |
| 67 Delegate* delegate, | |
| 68 NetLog* net_log) | |
| 69 : ConnectJob(group_name, timeout_duration, delegate, | |
| 70 BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), | |
| 71 params_(params), | |
| 72 tcp_pool_(tcp_pool), | |
| 73 http_proxy_pool_(http_proxy_pool), | |
| 74 socks_pool_(socks_pool), | |
| 75 client_socket_factory_(client_socket_factory), | |
| 76 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
| |
| 77 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 78 callback_(this, &SSLConnectJob::OnIOComplete)) {} | |
| 79 | |
| 80 SSLConnectJob::~SSLConnectJob() {} | |
| 81 | |
| 82 LoadState SSLConnectJob::GetLoadState() const { | |
| 83 switch (next_state_) { | |
| 84 case STATE_TCP_CONNECT: | |
| 85 case STATE_TCP_CONNECT_COMPLETE: | |
| 86 case STATE_SOCKS_CONNECT: | |
| 87 case STATE_SOCKS_CONNECT_COMPLETE: | |
| 88 case STATE_TUNNEL_CONNECT: | |
| 89 case STATE_TUNNEL_CONNECT_COMPLETE: | |
| 90 return transport_socket_handle_->GetLoadState(); | |
| 91 case STATE_SSL_CONNECT: | |
| 92 case STATE_SSL_CONNECT_COMPLETE: | |
| 93 return LOAD_STATE_SSL_HANDSHAKE; | |
| 94 default: | |
| 95 NOTREACHED(); | |
| 96 return LOAD_STATE_IDLE; | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 int SSLConnectJob::ConnectInternal() { | |
| 101 DetermineFirstState(); | |
| 102 return DoLoop(OK); | |
| 103 } | |
| 104 | |
| 105 void SSLConnectJob::DetermineFirstState() { | |
| 106 switch (params_->proxy()) { | |
| 107 case ProxyServer::SCHEME_DIRECT: | |
| 108 next_state_ = STATE_TCP_CONNECT; | |
| 109 break; | |
| 110 case ProxyServer::SCHEME_HTTP: | |
| 111 next_state_ = STATE_TUNNEL_CONNECT; | |
| 112 break; | |
| 113 case ProxyServer::SCHEME_SOCKS4: | |
| 114 case ProxyServer::SCHEME_SOCKS5: | |
| 115 next_state_ = STATE_SOCKS_CONNECT; | |
| 116 break; | |
| 117 default: | |
| 118 NOTREACHED() << "unknown proxy type"; | |
| 119 break; | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 void SSLConnectJob::OnIOComplete(int result) { | |
| 124 int rv = DoLoop(result); | |
| 125 if (rv != ERR_IO_PENDING) | |
| 126 NotifyDelegateOfCompletion(rv); // Deletes |this|. | |
| 127 } | |
| 128 | |
| 129 int SSLConnectJob::DoLoop(int result) { | |
| 130 DCHECK_NE(next_state_, STATE_NONE); | |
| 131 | |
| 132 int rv = result; | |
| 133 do { | |
| 134 State state = next_state_; | |
| 135 next_state_ = STATE_NONE; | |
| 136 switch (state) { | |
| 137 case STATE_TCP_CONNECT: | |
| 138 DCHECK_EQ(OK, rv); | |
| 139 rv = DoTCPConnect(); | |
| 140 break; | |
| 141 case STATE_TCP_CONNECT_COMPLETE: | |
| 142 rv = DoTCPConnectComplete(rv); | |
| 143 break; | |
| 144 case STATE_SOCKS_CONNECT: | |
| 145 DCHECK_EQ(OK, rv); | |
| 146 rv = DoSOCKSConnect(); | |
| 147 break; | |
| 148 case STATE_SOCKS_CONNECT_COMPLETE: | |
| 149 rv = DoSOCKSConnectComplete(rv); | |
| 150 break; | |
| 151 case STATE_TUNNEL_CONNECT: | |
| 152 DCHECK_EQ(OK, rv); | |
| 153 rv = DoTunnelConnect(); | |
| 154 break; | |
| 155 case STATE_TUNNEL_CONNECT_COMPLETE: | |
| 156 rv = DoTunnelConnectComplete(rv); | |
| 157 break; | |
| 158 case STATE_SSL_CONNECT: | |
| 159 DCHECK_EQ(OK, rv); | |
| 160 rv = DoSSLConnect(); | |
| 161 break; | |
| 162 case STATE_SSL_CONNECT_COMPLETE: | |
| 163 rv = DoSSLConnectComplete(rv); | |
| 164 break; | |
| 165 default: | |
| 166 NOTREACHED() << "bad state"; | |
| 167 rv = ERR_FAILED; | |
| 168 break; | |
| 169 } | |
| 170 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | |
| 171 | |
| 172 return rv; | |
| 173 } | |
| 174 | |
| 175 int SSLConnectJob::DoTCPConnect() { | |
| 176 DCHECK(tcp_pool_.get()); | |
| 177 next_state_ = STATE_TCP_CONNECT_COMPLETE; | |
| 178 transport_socket_handle_.reset(new ClientSocketHandle()); | |
| 179 scoped_refptr<TCPSocketParams> tcp_params = params_->tcp_params(); | |
| 180 return transport_socket_handle_->Init(group_name(), tcp_params, | |
| 181 tcp_params->destination().priority(), | |
| 182 &callback_, tcp_pool_, net_log()); | |
| 183 } | |
| 184 | |
| 185 int SSLConnectJob::DoTCPConnectComplete(int result) { | |
| 186 if (result == OK) | |
| 187 next_state_ = STATE_SSL_CONNECT; | |
| 188 | |
| 189 return result; | |
| 190 } | |
| 191 | |
| 192 int SSLConnectJob::DoSOCKSConnect() { | |
| 193 DCHECK(socks_pool_.get()); | |
| 194 next_state_ = STATE_SOCKS_CONNECT_COMPLETE; | |
| 195 transport_socket_handle_.reset(new ClientSocketHandle()); | |
| 196 scoped_refptr<SOCKSSocketParams> socks_params = params_->socks_params(); | |
| 197 return transport_socket_handle_->Init(group_name(), socks_params, | |
| 198 socks_params->destination().priority(), | |
| 199 &callback_, socks_pool_, net_log()); | |
| 200 } | |
| 201 | |
| 202 int SSLConnectJob::DoSOCKSConnectComplete(int result) { | |
| 203 if (result == OK) | |
| 204 next_state_ = STATE_SSL_CONNECT; | |
| 205 | |
| 206 return result; | |
| 207 } | |
| 208 | |
| 209 int SSLConnectJob::DoTunnelConnect() { | |
| 210 DCHECK(http_proxy_pool_.get()); | |
| 211 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; | |
| 212 transport_socket_handle_.reset(new ClientSocketHandle()); | |
| 213 scoped_refptr<HttpProxySocketParams> http_proxy_params = | |
| 214 params_->http_proxy_params(); | |
| 215 return transport_socket_handle_->Init( | |
| 216 group_name(), http_proxy_params, | |
| 217 http_proxy_params->tcp_params()->destination().priority(), &callback_, | |
| 218 http_proxy_pool_, net_log()); | |
| 219 } | |
| 220 | |
| 221 int SSLConnectJob::DoTunnelConnectComplete(int result) { | |
| 222 ClientSocket* socket = transport_socket_handle_->socket(); | |
| 223 HttpProxyClientSocket* tunnel_socket = | |
| 224 static_cast<HttpProxyClientSocket*>(socket); | |
| 225 | |
| 226 if (result == ERR_RETRY_CONNECTION) { | |
| 227 DetermineFirstState(); | |
| 228 transport_socket_handle_->socket()->Disconnect(); | |
| 229 return OK; | |
| 230 } | |
| 231 | |
| 232 if (result == ERR_PROXY_AUTH_REQUESTED) { | |
| 233 // Extract the information needed to prompt for the proxy authentication. | |
| 234 // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|, | |
| 235 // we can easily set the state. | |
| 236 const HttpResponseInfo* tunnel_response = tunnel_socket->GetResponseInfo(); | |
| 237 | |
| 238 http_auth_response_headers_ = tunnel_response->headers; | |
| 239 http_auth_auth_challenge_ = tunnel_response->auth_challenge; | |
| 240 } | |
| 241 | |
| 242 if (result < 0) | |
| 243 return result; | |
| 244 | |
| 245 if (tunnel_socket->NeedsRestartWithAuth()) { | |
| 246 // We must have gotten an 'idle' tunnel socket that is waiting for auth. | |
| 247 // The HttpAuthController should have new credentials, we just need | |
| 248 // to retry. | |
| 249 next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; | |
| 250 return tunnel_socket->RestartWithAuth(&callback_); | |
| 251 } | |
| 252 | |
| 253 next_state_ = STATE_SSL_CONNECT; | |
| 254 return result; | |
| 255 } | |
| 256 | |
| 257 void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) { | |
| 258 if (http_auth_response_headers_.get() != NULL) | |
| 259 handle->set_tunnel_auth_response_info(http_auth_response_headers_, | |
| 260 http_auth_auth_challenge_); | |
| 261 if (!ssl_connect_start_time_.is_null()) | |
| 262 handle->set_is_ssl_error(true); | |
| 263 } | |
| 264 | |
| 265 int SSLConnectJob::DoSSLConnect() { | |
| 266 next_state_ = STATE_SSL_CONNECT_COMPLETE; | |
| 267 // Reset the timeout to just the time allowed for the SSL handshake. | |
| 268 ResetTimer(base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds)); | |
| 269 ssl_connect_start_time_ = base::TimeTicks::Now(); | |
| 270 | |
| 271 ssl_socket_.reset(client_socket_factory_->CreateSSLClientSocket( | |
| 272 transport_socket_handle_.release(), params_->hostname(), | |
| 273 params_->ssl_config())); | |
| 274 return ssl_socket_->Connect(&callback_); | |
| 275 } | |
| 276 | |
| 277 int SSLConnectJob::DoSSLConnectComplete(int result) { | |
| 278 SSLClientSocket::NextProtoStatus status = | |
| 279 SSLClientSocket::kNextProtoUnsupported; | |
| 280 std::string proto; | |
| 281 // GetNextProto will fail and and trigger a NOTREACHED if we pass in a socket | |
| 282 // that hasn't had SSL_ImportFD called on it. If we get a certificate error | |
| 283 // here, then we know that we called SSL_ImportFD. | |
| 284 if (result == OK || IsCertificateError(result)) | |
| 285 status = ssl_socket_->GetNextProto(&proto); | |
| 286 | |
| 287 bool using_spdy = false; | |
| 288 if (status == SSLClientSocket::kNextProtoNegotiated) { | |
| 289 ssl_socket_->setWasNpnNegotiated(true); | |
| 290 if (SSLClientSocket::NextProtoFromString(proto) == | |
| 291 SSLClientSocket::kProtoSPDY1) { | |
| 292 using_spdy = true; | |
| 293 } | |
| 294 } | |
| 295 if (params_->want_spdy() && !using_spdy) | |
| 296 return ERR_NPN_NEGOTIATION_FAILED; | |
| 297 | |
| 298 if (result == OK || | |
| 299 ssl_socket_->IgnoreCertError(result, params_->load_flags())) { | |
| 300 DCHECK(ssl_connect_start_time_ != base::TimeTicks()); | |
| 301 base::TimeDelta connect_duration = | |
| 302 base::TimeTicks::Now() - ssl_connect_start_time_; | |
| 303 if (using_spdy) | |
| 304 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency", | |
| 305 connect_duration, | |
| 306 base::TimeDelta::FromMilliseconds(1), | |
| 307 base::TimeDelta::FromMinutes(10), | |
| 308 100); | |
| 309 else | |
| 310 UMA_HISTOGRAM_CUSTOM_TIMES("Net.SSL_Connection_Latency", | |
| 311 connect_duration, | |
| 312 base::TimeDelta::FromMilliseconds(1), | |
| 313 base::TimeDelta::FromMinutes(10), | |
| 314 100); | |
| 315 } | |
| 316 if (result == OK || IsCertificateError(result)) | |
| 317 set_socket(ssl_socket_.release()); | |
| 318 | |
| 319 return result; | |
| 320 } | |
| 321 | |
| 322 ConnectJob* SSLClientSocketPool::SSLConnectJobFactory::NewConnectJob( | |
| 323 const std::string& group_name, | |
| 324 const PoolBase::Request& request, | |
| 325 ConnectJob::Delegate* delegate) const { | |
| 326 return new SSLConnectJob(group_name, request.params(), ConnectionTimeout(), | |
| 327 tcp_pool_, http_proxy_pool_, socks_pool_, | |
| 328 client_socket_factory_, host_resolver_, delegate, | |
| 329 net_log_); | |
| 330 } | |
| 331 | |
| 332 SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory( | |
| 333 const scoped_refptr<TCPClientSocketPool>& tcp_pool, | |
| 334 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, | |
| 335 const scoped_refptr<SOCKSClientSocketPool>& socks_pool, | |
| 336 ClientSocketFactory* client_socket_factory, | |
| 337 HostResolver* host_resolver, | |
| 338 NetLog* net_log) | |
| 339 : tcp_pool_(tcp_pool), | |
| 340 http_proxy_pool_(http_proxy_pool), | |
| 341 socks_pool_(socks_pool), | |
| 342 client_socket_factory_(client_socket_factory), | |
| 343 host_resolver_(host_resolver), | |
| 344 net_log_(net_log) { | |
| 345 base::TimeDelta max_transport_timeout = base::TimeDelta(); | |
| 346 base::TimeDelta pool_timeout; | |
| 347 if (tcp_pool_) | |
| 348 max_transport_timeout = tcp_pool_->ConnectionTimeout(); | |
| 349 if (socks_pool_) { | |
| 350 pool_timeout = socks_pool_->ConnectionTimeout(); | |
| 351 if (pool_timeout > max_transport_timeout) | |
| 352 max_transport_timeout = pool_timeout; | |
| 353 } | |
| 354 if (http_proxy_pool_) { | |
| 355 pool_timeout = http_proxy_pool_->ConnectionTimeout(); | |
| 356 if (pool_timeout > max_transport_timeout) | |
| 357 max_transport_timeout = pool_timeout; | |
| 358 } | |
| 359 timeout_ = max_transport_timeout + | |
| 360 base::TimeDelta::FromSeconds(kSSLHandshakeTimeoutInSeconds); | |
| 361 } | |
| 362 | |
| 363 SSLClientSocketPool::SSLClientSocketPool( | |
| 364 int max_sockets, | |
| 365 int max_sockets_per_group, | |
| 366 const scoped_refptr<ClientSocketPoolHistograms>& histograms, | |
| 367 const scoped_refptr<HostResolver>& host_resolver, | |
| 368 ClientSocketFactory* client_socket_factory, | |
| 369 const scoped_refptr<TCPClientSocketPool>& tcp_pool, | |
| 370 const scoped_refptr<HttpProxyClientSocketPool>& http_proxy_pool, | |
| 371 const scoped_refptr<SOCKSClientSocketPool>& socks_pool, | |
| 372 NetLog* net_log) | |
| 373 : base_(max_sockets, max_sockets_per_group, histograms, | |
| 374 base::TimeDelta::FromSeconds( | |
| 375 ClientSocketPool::unused_idle_socket_timeout()), | |
| 376 base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout), | |
| 377 new SSLConnectJobFactory(tcp_pool, http_proxy_pool, socks_pool, | |
| 378 client_socket_factory, host_resolver, | |
| 379 net_log)) {} | |
| 380 | |
| 381 SSLClientSocketPool::~SSLClientSocketPool() {} | |
| 382 | |
| 383 int SSLClientSocketPool::RequestSocket(const std::string& group_name, | |
| 384 const void* socket_params, | |
| 385 RequestPriority priority, | |
| 386 ClientSocketHandle* handle, | |
| 387 CompletionCallback* callback, | |
| 388 const BoundNetLog& net_log) { | |
| 389 const scoped_refptr<SSLSocketParams>* casted_socket_params = | |
| 390 static_cast<const scoped_refptr<SSLSocketParams>*>(socket_params); | |
| 391 | |
| 392 return base_.RequestSocket(group_name, *casted_socket_params, priority, | |
| 393 handle, callback, net_log); | |
| 394 } | |
| 395 | |
| 396 void SSLClientSocketPool::CancelRequest(const std::string& group_name, | |
| 397 const ClientSocketHandle* handle) { | |
| 398 base_.CancelRequest(group_name, handle); | |
| 399 } | |
| 400 | |
| 401 void SSLClientSocketPool::ReleaseSocket(const std::string& group_name, | |
| 402 ClientSocket* socket, int id) { | |
| 403 base_.ReleaseSocket(group_name, socket, id); | |
| 404 } | |
| 405 | |
| 406 void SSLClientSocketPool::Flush() { | |
| 407 base_.Flush(); | |
| 408 } | |
| 409 | |
| 410 void SSLClientSocketPool::CloseIdleSockets() { | |
| 411 base_.CloseIdleSockets(); | |
| 412 } | |
| 413 | |
| 414 int SSLClientSocketPool::IdleSocketCountInGroup( | |
| 415 const std::string& group_name) const { | |
| 416 return base_.IdleSocketCountInGroup(group_name); | |
| 417 } | |
| 418 | |
| 419 LoadState SSLClientSocketPool::GetLoadState( | |
| 420 const std::string& group_name, const ClientSocketHandle* handle) const { | |
| 421 return base_.GetLoadState(group_name, handle); | |
| 422 } | |
| 423 | |
| 424 } // namespace net | |
| OLD | NEW |