Fix crash bug in new SSLClientSocketPool.
We also need to push additional error state out of the SSLClientSocketPool on a ERR_SSL_CLIENT_AUTH_CERT_NEEDED error.

BUG=49197
TEST=no crash when visiting https://foafssl.org/srv/idp?authreqissuer=http://foaf.me/index.php

Review URL: http://codereview.chromium.org/2827053

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52693 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc
index 7093e14..de2fd94c 100644
--- a/net/socket/client_socket_handle.cc
+++ b/net/socket/client_socket_handle.cc
@@ -58,7 +58,7 @@
 
 void ClientSocketHandle::ResetErrorState() {
   is_ssl_error_ = false;
-  tunnel_auth_response_info_ = HttpResponseInfo();
+  ssl_error_response_info_ = HttpResponseInfo();
 }
 
 LoadState ClientSocketHandle::GetLoadState() const {
diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h
index b8e6cc34..7fdf784 100644
--- a/net/socket/client_socket_handle.h
+++ b/net/socket/client_socket_handle.h
@@ -104,27 +104,28 @@
   void set_socket(ClientSocket* s) { socket_.reset(s); }
   void set_idle_time(base::TimeDelta idle_time) { idle_time_ = idle_time; }
   void set_pool_id(int id) { pool_id_ = id; }
-  void set_tunnel_auth_response_info(
-      const scoped_refptr<HttpResponseHeaders>& headers,
-      const scoped_refptr<AuthChallengeInfo>& auth_challenge) {
-    tunnel_auth_response_info_.headers = headers;
-    tunnel_auth_response_info_.auth_challenge = auth_challenge;
-  }
   void set_is_ssl_error(bool is_ssl_error) { is_ssl_error_ = is_ssl_error; }
+  void set_ssl_error_response_info(const HttpResponseInfo& ssl_error_state) {
+    ssl_error_response_info_ = ssl_error_state;
+  }
+
+  // Only valid if there is no |socket_|.
+  bool is_ssl_error() const {
+    DCHECK(socket_.get() == NULL);
+    return is_ssl_error_;
+  }
+  // On an ERR_PROXY_AUTH_REQUESTED error, the |headers| and |auth_challenge|
+  // fields are filled in. On an ERR_SSL_CLIENT_AUTH_CERT_NEEDED error,
+  // the |cert_request_info| field is set.
+  const HttpResponseInfo& ssl_error_response_info() const {
+    return ssl_error_response_info_;
+  }
 
   // These may only be used if is_initialized() is true.
   const std::string& group_name() const { return group_name_; }
   int id() const { return pool_id_; }
   ClientSocket* socket() { return socket_.get(); }
   ClientSocket* release_socket() { return socket_.release(); }
-  const HttpResponseInfo& tunnel_auth_response_info() const {
-    return tunnel_auth_response_info_;
-  }
-  // Only valid if there is no |socket_|.
-  bool is_ssl_error() const {
-    DCHECK(socket_.get() == NULL);
-    return is_ssl_error_;
-  }
   bool is_reused() const { return is_reused_; }
   base::TimeDelta idle_time() const { return idle_time_; }
   SocketReuseType reuse_type() const {
@@ -176,7 +177,7 @@
   base::TimeDelta idle_time_;
   int pool_id_;  // See ClientSocketPool::ReleaseSocket() for an explanation.
   bool is_ssl_error_;
-  HttpResponseInfo tunnel_auth_response_info_;
+  HttpResponseInfo ssl_error_response_info_;
   base::TimeTicks init_time_;
   base::TimeDelta setup_time_;
 
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 9686794..55f1949 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -155,8 +155,9 @@
     if (store_additional_error_state_) {
       // Set all of the additional error state fields in some way.
       handle->set_is_ssl_error(true);
-      scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
-      handle->set_tunnel_auth_response_info(headers, NULL);
+      HttpResponseInfo info;
+      info.headers = new HttpResponseHeaders("");
+      handle->set_ssl_error_response_info(info);
     }
   }
 
@@ -626,14 +627,15 @@
   TestSocketRequest req(&request_order_, &completion_count_);
   // Set the additional error state members to ensure that they get cleared.
   req.handle()->set_is_ssl_error(true);
-  scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
-  req.handle()->set_tunnel_auth_response_info(headers, NULL);
+  HttpResponseInfo info;
+  info.headers = new HttpResponseHeaders("");
+  req.handle()->set_ssl_error_response_info(info);
   EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
                                                       kDefaultPriority, &req,
                                                       pool_, log.bound()));
   EXPECT_FALSE(req.handle()->socket());
   EXPECT_FALSE(req.handle()->is_ssl_error());
-  EXPECT_TRUE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
+  EXPECT_TRUE(req.handle()->ssl_error_response_info().headers.get() == NULL);
 
   EXPECT_EQ(3u, log.entries().size());
   EXPECT_TRUE(LogContainsBeginEvent(
@@ -1386,14 +1388,15 @@
   CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
   // Set the additional error state members to ensure that they get cleared.
   req.handle()->set_is_ssl_error(true);
-  scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
-  req.handle()->set_tunnel_auth_response_info(headers, NULL);
+  HttpResponseInfo info;
+  info.headers = new HttpResponseHeaders("");
+  req.handle()->set_ssl_error_response_info(info);
   EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
                                                &req, pool_, log.bound()));
   EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
   EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
   EXPECT_FALSE(req.handle()->is_ssl_error());
-  EXPECT_TRUE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
+  EXPECT_TRUE(req.handle()->ssl_error_response_info().headers.get() == NULL);
 
   EXPECT_EQ(3u, log.entries().size());
   EXPECT_TRUE(LogContainsBeginEvent(
@@ -1598,7 +1601,7 @@
   EXPECT_FALSE(req.handle()->is_initialized());
   EXPECT_FALSE(req.handle()->socket());
   EXPECT_TRUE(req.handle()->is_ssl_error());
-  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
+  EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
   req.handle()->Reset();
 }
 
@@ -1615,7 +1618,7 @@
   EXPECT_FALSE(req.handle()->is_initialized());
   EXPECT_FALSE(req.handle()->socket());
   EXPECT_TRUE(req.handle()->is_ssl_error());
-  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
+  EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
   req.handle()->Reset();
 }
 
@@ -1861,7 +1864,7 @@
   EXPECT_FALSE(req.handle()->is_initialized());
   EXPECT_FALSE(req.handle()->socket());
   EXPECT_TRUE(req.handle()->is_ssl_error());
-  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
+  EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
 }
 
 // http://crbug.com/44724 regression test.
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index cfe3df49..d7f18e9 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -229,15 +229,11 @@
     return OK;
   }
 
-  if (result == ERR_PROXY_AUTH_REQUESTED) {
-    // Extract the information needed to prompt for the proxy authentication.
-    // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|,
-    // we can easily set the state.
-    const HttpResponseInfo* tunnel_response = tunnel_socket->GetResponseInfo();
-
-    http_auth_response_headers_ = tunnel_response->headers;
-    http_auth_auth_challenge_ = tunnel_response->auth_challenge;
-  }
+  // Extract the information needed to prompt for the proxy authentication.
+  // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|,
+  // we can easily set the state.
+  if (result == ERR_PROXY_AUTH_REQUESTED)
+    error_response_info_ = *tunnel_socket->GetResponseInfo();
 
   if (result < 0)
     return result;
@@ -255,9 +251,7 @@
 }
 
 void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) {
-  if (http_auth_response_headers_.get() != NULL)
-    handle->set_tunnel_auth_response_info(http_auth_response_headers_,
-                                          http_auth_auth_challenge_);
+  handle->set_ssl_error_response_info(error_response_info_);
   if (!ssl_connect_start_time_.is_null())
     handle->set_is_ssl_error(true);
 }
@@ -313,8 +307,13 @@
                                  base::TimeDelta::FromMinutes(10),
                                  100);
   }
-  if (result == OK || IsCertificateError(result))
+
+  if (result == OK || IsCertificateError(result)) {
     set_socket(ssl_socket_.release());
+  } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
+    error_response_info_.cert_request_info = new SSLCertRequestInfo;
+    ssl_socket_->GetSSLCertRequestInfo(error_response_info_.cert_request_info);
+  }
 
   return result;
 }
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index 48bba9c..fd5bbb3f 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -141,8 +141,7 @@
   // The time the DoSSLConnect() method was called.
   base::TimeTicks ssl_connect_start_time_;
 
-  scoped_refptr<HttpResponseHeaders> http_auth_response_headers_;
-  scoped_refptr<AuthChallengeInfo> http_auth_auth_challenge_;
+  HttpResponseInfo error_response_info_;
 
   DISALLOW_COPY_AND_ASSIGN(SSLConnectJob);
 };
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 30ff5da..ca864c9a 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -585,7 +585,7 @@
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
   EXPECT_FALSE(handle.is_ssl_error());
-  const HttpResponseInfo& tunnel_info = handle.tunnel_auth_response_info();
+  const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
   EXPECT_EQ(tunnel_info.headers->response_code(), 407);
 }
 
@@ -633,7 +633,7 @@
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
   EXPECT_FALSE(handle.is_ssl_error());
-  const HttpResponseInfo& tunnel_info = handle.tunnel_auth_response_info();
+  const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
   EXPECT_EQ(tunnel_info.headers->response_code(), 407);
 
   params->http_proxy_params()->auth_controller()->ResetAuth(std::wstring(),
@@ -698,7 +698,7 @@
   EXPECT_FALSE(handle.is_initialized());
   EXPECT_FALSE(handle.socket());
   EXPECT_FALSE(handle.is_ssl_error());
-  const HttpResponseInfo& tunnel_info = handle.tunnel_auth_response_info();
+  const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info();
   EXPECT_EQ(tunnel_info.headers->response_code(), 407);
 
   params->http_proxy_params()->auth_controller()->ResetAuth(std::wstring(),