Index: net/http/http_network_transaction.cc |
=================================================================== |
--- net/http/http_network_transaction.cc (revision 18321) |
+++ net/http/http_network_transaction.cc (working copy) |
@@ -1,4 +1,4 @@ |
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
+// Copyright (c) 2006-2009 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. |
@@ -17,6 +17,7 @@ |
#include "net/base/load_flags.h" |
#include "net/base/net_errors.h" |
#include "net/base/net_util.h" |
+#include "net/base/ssl_cert_request_info.h" |
#include "net/base/ssl_client_socket.h" |
#include "net/base/upload_data_stream.h" |
#include "net/http/http_auth.h" |
@@ -189,6 +190,21 @@ |
return rv; |
} |
+int HttpNetworkTransaction::RestartWithCertificate( |
+ X509Certificate* client_cert, |
+ CompletionCallback* callback) { |
+ ssl_config_.client_cert = client_cert; |
+ ssl_config_.send_client_cert = true; |
+ next_state_ = STATE_INIT_CONNECTION; |
+ // Reset the other member variables. |
+ // Note: this is necessary only with SSL renegotiation. |
+ ResetStateForRestart(); |
+ int rv = DoLoop(OK); |
+ if (rv == ERR_IO_PENDING) |
+ user_callback_ = callback; |
+ return rv; |
+} |
+ |
int HttpNetworkTransaction::RestartWithAuth( |
const std::wstring& username, |
const std::wstring& password, |
@@ -346,7 +362,8 @@ |
} |
const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const { |
- return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL; |
+ return (response_.headers || response_.ssl_info.cert || |
+ response_.cert_request_info) ? &response_ : NULL; |
} |
LoadState HttpNetworkTransaction::GetLoadState() const { |
@@ -603,6 +620,8 @@ |
if (result == OK) { |
next_state_ = STATE_WRITE_HEADERS; |
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
+ HandleCertificateRequest(); |
} else { |
result = HandleSSLHandshakeError(result); |
} |
@@ -746,13 +765,19 @@ |
} |
int HttpNetworkTransaction::DoReadHeadersComplete(int result) { |
- if (using_ssl_ && IsCertificateError(result)) { |
- // We don't handle a certificate error during SSL renegotiation, so we |
- // have to return an error that's not in the certificate error range |
- // (-2xx). |
- LOG(ERROR) << "Got a server certificate with error " << result |
- << " during SSL renegotiation"; |
- result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; |
+ // We can get a certificate error or ERR_SSL_CLIENT_AUTH_CERT_NEEDED here |
+ // due to SSL renegotiation. |
+ if (using_ssl_) { |
+ if (IsCertificateError(result)) { |
+ // We don't handle a certificate error during SSL renegotiation, so we |
+ // have to return an error that's not in the certificate error range |
+ // (-2xx). |
+ LOG(ERROR) << "Got a server certificate with error " << result |
+ << " during SSL renegotiation"; |
+ result = ERR_CERT_ERROR_IN_SSL_RENEGOTIATION; |
+ } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { |
+ HandleCertificateRequest(); |
+ } |
} |
if (result < 0) |
@@ -1217,6 +1242,18 @@ |
return error; |
} |
+void HttpNetworkTransaction::HandleCertificateRequest() { |
+ response_.cert_request_info = new SSLCertRequestInfo; |
+ SSLClientSocket* ssl_socket = |
+ reinterpret_cast<SSLClientSocket*>(connection_.socket()); |
+ ssl_socket->GetSSLCertRequestInfo(response_.cert_request_info); |
+ |
+ // Close the connection while the user is selecting a certificate to send |
+ // to the server. |
+ connection_.socket()->Disconnect(); |
+ connection_.Reset(); |
+} |
+ |
int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { |
switch (error) { |
case ERR_SSL_PROTOCOL_ERROR: |