Chromium Code Reviews| Index: net/socket_stream/socket_stream.cc |
| diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc |
| index 74eabecdfbbf201c92824e27f60c6f00ee3b80c4..c2ecfdf3c2f375998f7cd6b4fe6e736dce21265b 100644 |
| --- a/net/socket_stream/socket_stream.cc |
| +++ b/net/socket_stream/socket_stream.cc |
| @@ -304,6 +304,49 @@ void SocketStream::Finish(int result) { |
| Release(); |
| } |
| +int SocketStream::DidEstablishSSL(int result) { |
| + if (IsCertificateError(result)) { |
| + if (socket_->IsConnectedAndIdle()) { |
| + result = HandleCertificateError(result); |
| + } else { |
| + // SSLClientSocket for Mac will report socket is not connected, |
| + // if it returns cert verification error. It didn't perform |
| + // SSLHandshake yet. |
| + // So, we should restart establishing connection with the |
| + // certificate in allowed bad certificates in |ssl_config_|. |
| + // See also net/http/http_network_transaction.cc |
| + // HandleCertificateError() and RestartIgnoringLastError(). |
| + SSLClientSocket* ssl_socket = |
| + reinterpret_cast<SSLClientSocket*>(socket_.get()); |
| + SSLInfo ssl_info; |
| + ssl_socket->GetSSLInfo(&ssl_info); |
| + if (ssl_info.cert == NULL || |
| + ssl_config_.IsAllowedBadCert(ssl_info.cert, NULL)) { |
| + // If we already have the certificate in the set of allowed bad |
| + // certificates, we did try it and failed again, so we should not |
| + // retry again: the connection should fail at last. |
| + next_state_ = STATE_CLOSE; |
| + return result; |
| + } |
| + // Add the bad certificate to the set of allowed certificates in the |
| + // SSL config object. |
| + SSLConfig::CertAndStatus bad_cert; |
| + if (!ssl_info.cert->GetDEREncoded(&bad_cert.der_cert)) { |
| + next_state_ = STATE_CLOSE; |
| + return result; |
| + } |
| + bad_cert.cert_status = ssl_info.cert_status; |
| + ssl_config_.allowed_bad_certs.push_back(bad_cert); |
| + // Restart connection ignoring the bad certificate. |
| + socket_->Disconnect(); |
| + socket_.reset(); |
| + next_state_ = STATE_TCP_CONNECT; |
| + return OK; |
| + } |
| + } |
| + return result; |
| +} |
| + |
| int SocketStream::DidEstablishConnection() { |
| if (!socket_.get() || !socket_->IsConnected()) { |
| next_state_ = STATE_CLOSE; |
| @@ -440,6 +483,13 @@ void SocketStream::DoLoop(int result) { |
| case STATE_SOCKS_CONNECT_COMPLETE: |
| result = DoSOCKSConnectComplete(result); |
| break; |
| + case STATE_SECURE_PROXY_CONNECT: |
| + DCHECK_EQ(OK, result); |
| + result = DoSecureProxyConnect(); |
| + break; |
| + case STATE_SECURE_PROXY_CONNECT_COMPLETE: |
| + result = DoSecureProxyConnectComplete(result); |
| + break; |
| case STATE_SSL_CONNECT: |
| DCHECK_EQ(OK, result); |
| result = DoSSLConnect(); |
| @@ -469,7 +519,7 @@ void SocketStream::DoLoop(int result) { |
| // If the connection is not established yet and had actual errors, |
| // close the connection. |
| if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) { |
| - DCHECK_EQ(next_state_, STATE_CLOSE); |
| + next_state_ = STATE_CLOSE; |
|
ukai
2011/07/25 12:33:14
hmm, we might not need this.
If Do* method returns
Yuta Kitamura
2011/07/25 12:39:47
I think that's better.
|
| net_log_.EndEventWithNetErrorCode( |
| NetLog::TYPE_SOCKET_STREAM_CONNECT, result); |
| } |
| @@ -616,11 +666,14 @@ int SocketStream::DoTcpConnectComplete(int result) { |
| return result; |
| } |
| - if (proxy_mode_ == kTunnelProxy) |
| - next_state_ = STATE_WRITE_TUNNEL_HEADERS; |
| - else if (proxy_mode_ == kSOCKSProxy) |
| + if (proxy_mode_ == kTunnelProxy) { |
| + if (proxy_info_.is_https()) |
| + next_state_ = STATE_SECURE_PROXY_CONNECT; |
| + else |
| + next_state_ = STATE_WRITE_TUNNEL_HEADERS; |
| + } else if (proxy_mode_ == kSOCKSProxy) { |
| next_state_ = STATE_SOCKS_CONNECT; |
| - else if (is_secure()) { |
| + } else if (is_secure()) { |
| next_state_ = STATE_SSL_CONNECT; |
| } else { |
| result = DidEstablishConnection(); |
| @@ -850,6 +903,35 @@ int SocketStream::DoSOCKSConnectComplete(int result) { |
| return result; |
| } |
| +int SocketStream::DoSecureProxyConnect() { |
| + DCHECK(factory_); |
| + SSLClientSocketContext ssl_context; |
| + ssl_context.cert_verifier = cert_verifier_; |
| + ssl_context.origin_bound_cert_service = origin_bound_cert_service_; |
| + // TODO(agl): look into plumbing SSLHostInfo here. |
| + socket_.reset(factory_->CreateSSLClientSocket( |
| + socket_.release(), |
| + proxy_info_.proxy_server().host_port_pair(), |
| + ssl_config_, |
| + NULL /* ssl_host_info */, |
| + ssl_context)); |
| + next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE; |
| + metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION); |
| + return socket_->Connect(&io_callback_); |
|
Yuta Kitamura
2011/07/25 10:24:44
Can't you set STATE_CLOSE to next_state_ if Connec
ukai
2011/07/25 10:29:59
It's possible, but other methods (Read, Write, ...
Yuta Kitamura
2011/07/25 10:44:48
Um... if I read DoReadWrite() correctly, it always
ukai
2011/07/25 11:49:04
not only DoReadWrite().
We had a potential bug whe
|
| +} |
| + |
| +int SocketStream::DoSecureProxyConnectComplete(int result) { |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| + result = DidEstablishSSL(result); |
| + if (next_state_ != STATE_NONE) |
| + return result; |
| + if (result == OK) |
| + next_state_ = STATE_WRITE_TUNNEL_HEADERS; |
| + else |
| + next_state_ = STATE_CLOSE; |
| + return result; |
| +} |
| + |
| int SocketStream::DoSSLConnect() { |
| DCHECK(factory_); |
| SSLClientSocketContext ssl_context; |
| @@ -867,46 +949,10 @@ int SocketStream::DoSSLConnect() { |
| } |
| int SocketStream::DoSSLConnectComplete(int result) { |
| - if (IsCertificateError(result)) { |
| - if (socket_->IsConnectedAndIdle()) { |
| - result = HandleCertificateError(result); |
| - } else { |
| - // SSLClientSocket for Mac will report socket is not connected, |
| - // if it returns cert verification error. It didn't perform |
| - // SSLHandshake yet. |
| - // So, we should restart establishing connection with the |
| - // certificate in allowed bad certificates in |ssl_config_|. |
| - // See also net/http/http_network_transaction.cc |
| - // HandleCertificateError() and RestartIgnoringLastError(). |
| - SSLClientSocket* ssl_socket = |
| - reinterpret_cast<SSLClientSocket*>(socket_.get()); |
| - SSLInfo ssl_info; |
| - ssl_socket->GetSSLInfo(&ssl_info); |
| - if (ssl_info.cert == NULL || |
| - ssl_config_.IsAllowedBadCert(ssl_info.cert, NULL)) { |
| - // If we already have the certificate in the set of allowed bad |
| - // certificates, we did try it and failed again, so we should not |
| - // retry again: the connection should fail at last. |
| - next_state_ = STATE_CLOSE; |
| - return result; |
| - } |
| - // Add the bad certificate to the set of allowed certificates in the |
| - // SSL config object. |
| - SSLConfig::CertAndStatus bad_cert; |
| - if (!ssl_info.cert->GetDEREncoded(&bad_cert.der_cert)) { |
| - next_state_ = STATE_CLOSE; |
| - return result; |
| - } |
| - bad_cert.cert_status = ssl_info.cert_status; |
| - ssl_config_.allowed_bad_certs.push_back(bad_cert); |
| - // Restart connection ignoring the bad certificate. |
| - socket_->Disconnect(); |
| - socket_.reset(); |
| - next_state_ = STATE_TCP_CONNECT; |
| - return OK; |
| - } |
| - } |
| - |
| + DCHECK_EQ(STATE_NONE, next_state_); |
| + result = DidEstablishSSL(result); |
| + if (next_state_ != STATE_NONE) |
| + return result; |
| // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible. |
| // If we use HTTPS and this is the first connection to the SPDY server, |
| // we should take care of TLS NPN extension here. |