| Index: net/http/http_network_transaction.cc | 
| diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc | 
| index e0967c60da61f7b86887f153e4b46433bc05d65f..328bdf777274f21afc3c5c5ef8737a2e7207d51f 100644 | 
| --- a/net/http/http_network_transaction.cc | 
| +++ b/net/http/http_network_transaction.cc | 
| @@ -17,6 +17,7 @@ | 
| #include "base/string_number_conversions.h" | 
| #include "base/string_util.h" | 
| #include "base/stringprintf.h" | 
| +#include "base/utf_string_conversions.h" | 
| #include "build/build_config.h" | 
| #include "googleurl/src/gurl.h" | 
| #include "net/base/auth.h" | 
| @@ -197,6 +198,49 @@ int HttpNetworkTransaction::RestartWithCertificate( | 
| return rv; | 
| } | 
|  | 
| +void HttpNetworkTransaction::SetTLSLoginAuthData(AuthData* auth_data) { | 
| +  DCHECK(!stream_request_.get()) << "Can't set TLS login on existing stream"; | 
| +  DCHECK(!stream_.get()); | 
| +  DCHECK_EQ(STATE_NONE, next_state_); | 
| + | 
| +  DCHECK(!auth_data->username.empty()); | 
| +  DCHECK(!auth_data->password.empty()); | 
| + | 
| +  tls_auth_data_ = auth_data; | 
| +  ssl_config_.tls_username = UTF16ToUTF8(auth_data->username); | 
| +  ssl_config_.tls_password = UTF16ToUTF8(auth_data->password); | 
| +  ssl_config_.use_tls_auth = true; | 
| +  ssl_config_.ssl3_enabled = false; | 
| +  ssl_config_.tls1_enabled = true; | 
| +} | 
| + | 
| +int HttpNetworkTransaction::RestartWithTLSLogin(CompletionCallback* callback) { | 
| +  DCHECK(!stream_request_.get()); | 
| +  DCHECK(!stream_.get()); | 
| +  DCHECK_EQ(STATE_NONE, next_state_); | 
| + | 
| +  DCHECK(!ssl_config_.tls_username.empty()); | 
| +  DCHECK(!ssl_config_.tls_password.empty()); | 
| +  DCHECK(ssl_config_.use_tls_auth); | 
| +  DCHECK(ssl_config_.tls1_enabled); | 
| +  DCHECK(!ssl_config_.ssl3_enabled); | 
| + | 
| +  DCHECK(response_.login_request_info.get()); | 
| +  DCHECK(tls_auth_data_.get()); | 
| +  session_->tls_client_login_cache()->Add( | 
| +      WideToUTF8(response_.login_request_info->host_and_port), | 
| +      tls_auth_data_); | 
| + | 
| +  // Reset the other member variables. | 
| +  // Note: this is necessary only with SSL renegotiation. | 
| +  ResetStateForRestart(); | 
| +  next_state_ = STATE_CREATE_STREAM; | 
| +  int rv = DoLoop(OK); | 
| +  if (rv == ERR_IO_PENDING) | 
| +    user_callback_ = callback; | 
| +  return rv; | 
| +} | 
| + | 
| int HttpNetworkTransaction::RestartWithAuth( | 
| const string16& username, | 
| const string16& password, | 
| @@ -330,7 +374,9 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, | 
|  | 
| const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const { | 
| return ((headers_valid_ && response_.headers) || response_.ssl_info.cert || | 
| -          response_.cert_request_info) ? &response_ : NULL; | 
| +          !response_.ssl_info.tls_username.empty() || | 
| +          response_.cert_request_info || response_.login_request_info) ? | 
| +      &response_ : NULL; | 
| } | 
|  | 
| LoadState HttpNetworkTransaction::GetLoadState() const { | 
| @@ -425,6 +471,14 @@ void HttpNetworkTransaction::OnNeedsClientAuth( | 
| OnIOComplete(ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | 
| } | 
|  | 
| +void HttpNetworkTransaction::OnNeedsTLSLogin( | 
| +    AuthChallengeInfo* login_info) { | 
| +  DCHECK_EQ(STATE_CREATE_STREAM_COMPLETE, next_state_); | 
| + | 
| +  response_.login_request_info = login_info; | 
| +  OnIOComplete(ERR_TLS_CLIENT_LOGIN_NEEDED); | 
| +} | 
| + | 
| void HttpNetworkTransaction::OnHttpsProxyTunnelResponse( | 
| const HttpResponseInfo& response_info, | 
| HttpStream* stream) { | 
| @@ -438,7 +492,7 @@ void HttpNetworkTransaction::OnHttpsProxyTunnelResponse( | 
| } | 
|  | 
| bool HttpNetworkTransaction::is_https_request() const { | 
| -  return request_->url.SchemeIs("https"); | 
| +  return request_->url.SchemeIs("https") || request_->url.SchemeIs("httpsv"); | 
| } | 
|  | 
| void HttpNetworkTransaction::DoCallback(int rv) { | 
| @@ -542,6 +596,33 @@ int HttpNetworkTransaction::DoLoop(int result) { | 
| } | 
|  | 
| int HttpNetworkTransaction::DoCreateStream() { | 
| +  DCHECK(request_); | 
| + | 
| +  // Set TLS login, if available. | 
| +  if (ssl_config_.use_tls_auth) { | 
| +    if (request_->url.SchemeIs("httpsv")) | 
| +      ssl_config_.require_tls_auth = true; | 
| +    if (ssl_config_.tls_username.empty()) { | 
| +      scoped_refptr<AuthData> tls_auth_data; | 
| +      bool found_login = session_->tls_client_login_cache()->Lookup( | 
| +          net::GetHostAndPort(request_->url), | 
| +          &tls_auth_data); | 
| +      if (found_login) { | 
| +        LOG(INFO) << "Got TLS login from cache"; | 
| +        SetTLSLoginAuthData(tls_auth_data); | 
| +        DCHECK(!ssl_config_.tls_username.empty()); | 
| +        DCHECK(!ssl_config_.tls_password.empty()); | 
| +      } else if (ssl_config_.require_tls_auth) { | 
| +        response_.login_request_info = new AuthChallengeInfo; | 
| +        response_.login_request_info->host_and_port = | 
| +            UTF8ToWide(net::GetHostAndPort(request_->url)); | 
| +        response_.login_request_info->scheme = ASCIIToWide(net::kTLSSRPScheme); | 
| +        response_.login_request_info->over_protocol = AUTH_OVER_TLS; | 
| +        return ERR_TLS_CLIENT_LOGIN_NEEDED; | 
| +      } | 
| +    } | 
| +  } | 
| + | 
| next_state_ = STATE_CREATE_STREAM_COMPLETE; | 
|  | 
| stream_request_.reset( | 
| @@ -1037,16 +1118,56 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { | 
| GetHostAndPort(request_->url)); | 
| } | 
|  | 
| +  // Check for TLS-SRP-related errors. | 
| +  if (ssl_config_.use_tls_auth) { | 
| +    if (ssl_config_.tls_username.empty() && ssl_config_.tls_password.empty()) { | 
| +      if (error == ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT) { | 
| +        // RFC 5054 unknown_psk_identity idiom: The Client Hello contained no | 
| +        // SRP username, but the server wishes to connect using an SRP cipher | 
| +        // suite. | 
| +        error = ERR_TLS_CLIENT_LOGIN_NEEDED; | 
| +      } | 
| +    } else if (!ssl_config_.tls_username.empty() && | 
| +               ssl_config_.tls_password.empty()) { | 
| +      LOG(WARNING) << "SSL handshake error: empty TLS password"; | 
| +    } else if (!ssl_config_.tls_username.empty() && | 
| +               !ssl_config_.tls_password.empty()) { | 
| +      if (error == ERR_SSL_BAD_RECORD_MAC_ALERT || | 
| +          error == ERR_SSL_UNKNOWN_PSK_IDENTITY_ALERT) { | 
| +        // The TLS-SRP login probably failed. | 
| +        // TODO(sqs): also verify that we did attempt to use an SRP cipher suite | 
| +        error = ERR_TLS_CLIENT_LOGIN_FAILED; | 
| +      } | 
| +    } | 
| + | 
| +    if (error == ERR_TLS_CLIENT_LOGIN_FAILED) | 
| +      session_->tls_client_login_cache()->Remove(GetHostAndPort(request_->url)); | 
| + | 
| +    // Handle TLS-SRP errors now. | 
| +    if (error == ERR_TLS_CLIENT_LOGIN_FAILED || | 
| +        error == ERR_TLS_CLIENT_LOGIN_NEEDED) { | 
| +      DCHECK(!response_.login_request_info.get()); | 
| +      response_.login_request_info = new AuthChallengeInfo; | 
| +      response_.login_request_info->host_and_port = | 
| +          UTF8ToWide(GetHostAndPort(request_->url)); | 
| +      response_.login_request_info->scheme = ASCIIToWide(net::kTLSSRPScheme); | 
| +      response_.login_request_info->over_protocol = AUTH_OVER_TLS; | 
| +      return error; | 
| +    } | 
| +  } | 
| + | 
| switch (error) { | 
| case ERR_SSL_PROTOCOL_ERROR: | 
| case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: | 
| case ERR_SSL_DECOMPRESSION_FAILURE_ALERT: | 
| case ERR_SSL_BAD_RECORD_MAC_ALERT: | 
| if (ssl_config_.tls1_enabled && | 
| -          !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) { | 
| +          !SSLConfigService::IsKnownStrictTLSServer(request_->url.host()) && | 
| +          !ssl_config_.require_tls_auth) { | 
| // This could be a TLS-intolerant server, an SSL 3.0 server that | 
| // chose a TLS-only cipher suite or a server with buggy DEFLATE | 
| // support. Turn off TLS 1.0, DEFLATE support and retry. | 
| +        LOG(WARNING) << "Set server TLS intolerant: " << request_->url; | 
| session_->http_stream_factory()->AddTLSIntolerantServer(request_->url); | 
| ResetConnectionAndRequestForResend(); | 
| error = OK; | 
|  |