diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_error_list.h | 5 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 106 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 7 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 105 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket.cc | 52 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket.h | 17 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.cc | 14 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool.h | 9 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool_unittest.cc | 70 | ||||
-rw-r--r-- | net/socket/client_socket_handle.cc | 1 | ||||
-rw-r--r-- | net/socket/client_socket_handle.h | 7 | ||||
-rw-r--r-- | net/socket/socket_test_util.cc | 47 | ||||
-rw-r--r-- | net/socket/socket_test_util.h | 40 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.cc | 28 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool.h | 4 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_pool_unittest.cc | 236 |
16 files changed, 389 insertions, 359 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 53849631..e302a9f 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -167,6 +167,11 @@ NET_ERROR(PROXY_AUTH_REQUESTED, -127) // A known TLS strict server didn't offer the renegotiation extension. NET_ERROR(SSL_UNSAFE_NEGOTIATION, -128) +// The socket is reporting that we tried to provide new credentials after a +// a failed attempt on a connection without keep alive. We need to +// reestablish the transport socket in order to retry the authentication. +NET_ERROR(RETRY_CONNECTION, -129) + // Certificate error codes // // The values of certificate error codes must be consecutive. diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index bb17bcb..fdf8e9f 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -337,8 +337,7 @@ int HttpNetworkTransaction::RestartWithAuth( if (target == HttpAuth::AUTH_PROXY && using_ssl_ && proxy_info_.is_http()) { DCHECK(establishing_tunnel_); - next_state_ = STATE_RESTART_TUNNEL_AUTH; - auth_controllers_[target] = NULL; + next_state_ = STATE_INIT_CONNECTION; ResetStateForRestart(); } else { PrepareForAuthRestart(target); @@ -539,13 +538,6 @@ int HttpNetworkTransaction::DoLoop(int result) { case STATE_INIT_CONNECTION_COMPLETE: rv = DoInitConnectionComplete(rv); break; - case STATE_RESTART_TUNNEL_AUTH: - DCHECK_EQ(OK, rv); - rv = DoRestartTunnelAuth(); - break; - case STATE_RESTART_TUNNEL_AUTH_COMPLETE: - rv = DoRestartTunnelAuthComplete(rv); - break; case STATE_GENERATE_PROXY_AUTH_TOKEN: DCHECK_EQ(OK, rv); rv = DoGenerateProxyAuthToken(); @@ -731,6 +723,15 @@ int HttpNetworkTransaction::DoInitConnection() { DCHECK(proxy_info_.proxy_server().is_valid()); next_state_ = STATE_INIT_CONNECTION_COMPLETE; + // Now that the proxy server has been resolved, create the auth_controllers_. + for (int i = 0; i < HttpAuth::AUTH_NUM_TARGETS; i++) { + HttpAuth::Target target = static_cast<HttpAuth::Target>(i); + if (!auth_controllers_[target].get()) + auth_controllers_[target] = new HttpAuthController(target, + AuthURL(target), + session_); + } + bool want_spdy_over_npn = alternate_protocol_mode_ == kUsingAlternateProtocol && alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2; using_ssl_ = request_->url.SchemeIs("https") || @@ -780,10 +781,15 @@ int HttpNetworkTransaction::DoInitConnection() { request_->referrer, disable_resolver_cache); if (proxy_info_.is_http()) { - establishing_tunnel_ = using_ssl_; + scoped_refptr<HttpAuthController> http_proxy_auth; + if (using_ssl_) { + http_proxy_auth = auth_controllers_[HttpAuth::AUTH_PROXY]; + establishing_tunnel_ = true; + } http_proxy_params = new HttpProxySocketParams(proxy_tcp_params, request_->url, endpoint_, - session_, using_ssl_); + http_proxy_auth, + using_ssl_); } else { DCHECK(proxy_info_.is_socks()); char socks_version; @@ -891,13 +897,14 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { if (result == ERR_PROXY_AUTH_REQUESTED) { DCHECK(!ssl_started); - // Other state (i.e. |using_ssl_|) suggests that |connection_| will have an - // SSL socket, but there was an error before that could happened. This - // puts the in progress HttpProxy socket into |connection_| in order to - // complete the auth. The tunnel restart code is carefully to remove it - // before returning control to the rest of this class. - connection_.reset(connection_->release_pending_http_proxy_connection()); - return HandleTunnelAuthFailure(result); + const HttpResponseInfo& tunnel_auth_response = + connection_->ssl_error_response_info(); + + response_.headers = tunnel_auth_response.headers; + response_.auth_challenge = tunnel_auth_response.auth_challenge; + headers_valid_ = true; + pending_auth_target_ = HttpAuth::AUTH_PROXY; + return OK; } if ((!ssl_started && result < 0 && @@ -977,44 +984,12 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { return OK; } -int HttpNetworkTransaction::DoRestartTunnelAuth() { - next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE; - HttpProxyClientSocket* http_proxy_socket = - static_cast<HttpProxyClientSocket*>(connection_->socket()); - return http_proxy_socket->RestartWithAuth(&io_callback_); -} - -int HttpNetworkTransaction::DoRestartTunnelAuthComplete(int result) { - if (result == ERR_PROXY_AUTH_REQUESTED) - return HandleTunnelAuthFailure(result); - - if (result == OK) { - // Now that we've got the HttpProxyClientSocket connected. We have - // to release it as an idle socket into the pool and start the connection - // process from the beginning. Trying to pass it in with the - // SSLSocketParams might cause a deadlock since params are dispatched - // interchangeably. This request won't necessarily get this http proxy - // socket, but there will be forward progress. - connection_->Reset(); - establishing_tunnel_ = false; - next_state_ = STATE_INIT_CONNECTION; - return OK; - } - - return ReconsiderProxyAfterError(result); -} - int HttpNetworkTransaction::DoGenerateProxyAuthToken() { next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE; if (!ShouldApplyProxyAuth()) return OK; - HttpAuth::Target target = HttpAuth::AUTH_PROXY; - if (!auth_controllers_[target].get()) - auth_controllers_[target] = new HttpAuthController(target, AuthURL(target), - session_); - return auth_controllers_[target]->MaybeGenerateAuthToken(request_, - &io_callback_, - net_log_); + return auth_controllers_[HttpAuth::AUTH_PROXY]->MaybeGenerateAuthToken( + request_, &io_callback_, net_log_); } int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { @@ -1026,15 +1001,10 @@ int HttpNetworkTransaction::DoGenerateProxyAuthTokenComplete(int rv) { int HttpNetworkTransaction::DoGenerateServerAuthToken() { next_state_ = STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE; - HttpAuth::Target target = HttpAuth::AUTH_SERVER; - if (!auth_controllers_[target].get()) - auth_controllers_[target] = new HttpAuthController(target, AuthURL(target), - session_); if (!ShouldApplyServerAuth()) return OK; - return auth_controllers_[target]->MaybeGenerateAuthToken(request_, - &io_callback_, - net_log_); + return auth_controllers_[HttpAuth::AUTH_SERVER]->MaybeGenerateAuthToken( + request_, &io_callback_, net_log_); } int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { @@ -1557,24 +1527,6 @@ void HttpNetworkTransaction::LogTransactionMetrics() const { } } -int HttpNetworkTransaction::HandleTunnelAuthFailure(int error) { - DCHECK(establishing_tunnel_); - DCHECK_EQ(ERR_PROXY_AUTH_REQUESTED, error); - HttpProxyClientSocket* http_proxy_socket = - static_cast<HttpProxyClientSocket*>(connection_->socket()); - - const HttpResponseInfo* tunnel_auth_response = - http_proxy_socket->GetResponseInfo(); - response_.headers = tunnel_auth_response->headers; - response_.auth_challenge = tunnel_auth_response->auth_challenge; - headers_valid_ = true; - - auth_controllers_[HttpAuth::AUTH_PROXY] = - http_proxy_socket->auth_controller(); - pending_auth_target_ = HttpAuth::AUTH_PROXY; - return OK; -} - int HttpNetworkTransaction::HandleCertificateError(int error) { DCHECK(using_ssl_); DCHECK(IsCertificateError(error)); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index b3a083c..8117325 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -91,8 +91,6 @@ class HttpNetworkTransaction : public HttpTransaction { STATE_RESOLVE_PROXY_COMPLETE, STATE_INIT_CONNECTION, STATE_INIT_CONNECTION_COMPLETE, - STATE_RESTART_TUNNEL_AUTH, - STATE_RESTART_TUNNEL_AUTH_COMPLETE, STATE_GENERATE_PROXY_AUTH_TOKEN, STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE, STATE_GENERATE_SERVER_AUTH_TOKEN, @@ -136,8 +134,6 @@ class HttpNetworkTransaction : public HttpTransaction { int DoResolveProxyComplete(int result); int DoInitConnection(); int DoInitConnectionComplete(int result); - int DoRestartTunnelAuth(); - int DoRestartTunnelAuthComplete(int result); int DoGenerateProxyAuthToken(); int DoGenerateProxyAuthTokenComplete(int result); int DoGenerateServerAuthToken(); @@ -174,9 +170,6 @@ class HttpNetworkTransaction : public HttpTransaction { static void LogIOErrorMetrics(const ClientSocketHandle& handle); - // Called to handle an HTTP proxy tunnel request for auth. - int HandleTunnelAuthFailure(int error); - // Called to handle a certificate error. Returns OK if the error should be // ignored. Otherwise, stores the certificate in response_.ssl_info and // returns the same error code. diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index d6e5779..b5f614c 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1343,111 +1343,6 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { EXPECT_EQ(100, response->headers->GetContentLength()); } -// Test the request-challenge-retry sequence for basic auth, over a connection -// that requires a restart when setting up an SSL tunnel. -TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - // The proxy responds to the connect with a 407, using a persistent - // connection. - MockRead data_reads1[] = { - // No credentials. - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Proxy-Connection: close\r\n\r\n"), - - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(false, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, &callback1, log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - size_t pos = ExpectLogContainsSomewhere( - log.entries(), 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - log.entries(), pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_FALSE(response == NULL); - - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should have been set in response->auth_challenge. - ASSERT_FALSE(response->auth_challenge.get() == NULL); - - EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); - EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); - EXPECT_EQ(L"basic", response->auth_challenge->scheme); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth(kFoo, kBar, &callback2); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_FALSE(response == NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should not be set. - EXPECT_TRUE(response->auth_challenge.get() == NULL); -} - // Test the request-challenge-retry sequence for basic auth, over a keep-alive // proxy connection, when setting up an SSL tunnel. TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index 1c76c36..02c2666 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -50,20 +50,18 @@ void BuildTunnelRequest(const HttpRequestInfo* request_info, HttpProxyClientSocket::HttpProxyClientSocket( ClientSocketHandle* transport_socket, const GURL& request_url, - const HostPortPair& endpoint, const HostPortPair& proxy_server, - const scoped_refptr<HttpNetworkSession>& session, bool tunnel) + const HostPortPair& endpoint, const scoped_refptr<HttpAuthController>& auth, + bool tunnel) : ALLOW_THIS_IN_INITIALIZER_LIST( io_callback_(this, &HttpProxyClientSocket::OnIOComplete)), next_state_(STATE_NONE), user_callback_(NULL), transport_(transport_socket), endpoint_(endpoint), - auth_(tunnel ? - new HttpAuthController(HttpAuth::AUTH_PROXY, - GURL("http://" + proxy_server.ToString()), - session) : NULL), + auth_(auth), tunnel_(tunnel), net_log_(transport_socket->socket()->NetLog()) { + DCHECK_EQ(tunnel, auth != NULL); // Synthesize the bits of a request that we actually use. request_.url = request_url; request_.method = "GET"; @@ -128,14 +126,13 @@ int HttpProxyClientSocket::PrepareForAuthRestart() { } int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { + int rc = OK; if (keep_alive && transport_->socket()->IsConnectedAndIdle()) { next_state_ = STATE_GENERATE_AUTH_TOKEN; transport_->set_is_reused(true); } else { - // This assumes that the underlying transport socket is a TCP socket, - // since only TCP sockets are restartable. - next_state_ = STATE_TCP_RESTART; transport_->socket()->Disconnect(); + rc = ERR_RETRY_CONNECTION; } // Reset the other member variables. @@ -143,7 +140,7 @@ int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { http_stream_.reset(); request_headers_.clear(); response_ = HttpResponseInfo(); - return OK; + return rc; } void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { @@ -162,16 +159,19 @@ void HttpProxyClientSocket::Disconnect() { } bool HttpProxyClientSocket::IsConnected() const { - return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); + return transport_->socket()->IsConnected(); } bool HttpProxyClientSocket::IsConnectedAndIdle() const { - return next_state_ == STATE_DONE && - transport_->socket()->IsConnectedAndIdle(); + return transport_->socket()->IsConnectedAndIdle(); +} + +bool HttpProxyClientSocket::NeedsRestartWithAuth() const { + return next_state_ != STATE_DONE; } int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, - CompletionCallback* callback) { + CompletionCallback* callback) { DCHECK(!user_callback_); if (next_state_ != STATE_DONE) { // We're trying to read the body of the response but we're still trying @@ -273,13 +273,6 @@ int HttpProxyClientSocket::DoLoop(int last_io_result) { case STATE_DRAIN_BODY_COMPLETE: rv = DoDrainBodyComplete(rv); break; - case STATE_TCP_RESTART: - DCHECK_EQ(OK, rv); - rv = DoTCPRestart(); - break; - case STATE_TCP_RESTART_COMPLETE: - rv = DoTCPRestartComplete(rv); - break; case STATE_DONE: break; default: @@ -287,8 +280,8 @@ int HttpProxyClientSocket::DoLoop(int last_io_result) { rv = ERR_UNEXPECTED; break; } - } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE && - next_state_ != STATE_DONE); + } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE + && next_state_ != STATE_DONE); return rv; } @@ -413,19 +406,6 @@ int HttpProxyClientSocket::DoDrainBodyComplete(int result) { return OK; } -int HttpProxyClientSocket::DoTCPRestart() { - next_state_ = STATE_TCP_RESTART_COMPLETE; - return transport_->socket()->Connect(&io_callback_); -} - -int HttpProxyClientSocket::DoTCPRestartComplete(int result) { - if (result != OK) - return result; - - next_state_ = STATE_GENERATE_AUTH_TOKEN; - return result; -} - int HttpProxyClientSocket::HandleAuthChallenge() { DCHECK(response_.headers); diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index ef4f76c..317b220 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -35,8 +35,7 @@ class HttpProxyClientSocket : public ClientSocket { // this socket will establish an Http tunnel. HttpProxyClientSocket(ClientSocketHandle* transport_socket, const GURL& request_url, const HostPortPair& endpoint, - const HostPortPair& proxy_server, - const scoped_refptr<HttpNetworkSession>& session, + const scoped_refptr<HttpAuthController>& auth, bool tunnel); // On destruction Disconnect() is called. @@ -47,12 +46,12 @@ class HttpProxyClientSocket : public ClientSocket { // RestartWithAuth. int RestartWithAuth(CompletionCallback* callback); - const HttpResponseInfo* GetResponseInfo() const { - return response_.headers ? &response_ : NULL; - } + // Indicates if RestartWithAuth needs to be called. i.e. if Connect + // returned PROXY_AUTH_REQUESTED. Only valid after Connect has been called. + bool NeedsRestartWithAuth() const; - const scoped_refptr<HttpAuthController>& auth_controller() { - return auth_; + const HttpResponseInfo* GetResponseInfo() const { + return response_.headers ? &response_ : NULL; } // ClientSocket methods: @@ -86,8 +85,6 @@ class HttpProxyClientSocket : public ClientSocket { STATE_RESOLVE_CANONICAL_NAME_COMPLETE, STATE_DRAIN_BODY, STATE_DRAIN_BODY_COMPLETE, - STATE_TCP_RESTART, - STATE_TCP_RESTART_COMPLETE, STATE_DONE, }; @@ -115,8 +112,6 @@ class HttpProxyClientSocket : public ClientSocket { int DoReadHeadersComplete(int result); int DoDrainBody(); int DoDrainBodyComplete(int result); - int DoTCPRestart(); - int DoTCPRestartComplete(int result); CompletionCallbackImpl<HttpProxyClientSocket> io_callback_; State next_state_; diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 783c10f..a142576 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc @@ -7,7 +7,6 @@ #include "base/time.h" #include "googleurl/src/gurl.h" #include "net/base/net_errors.h" -#include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket.h" #include "net/socket/client_socket_factory.h" #include "net/socket/client_socket_handle.h" @@ -19,12 +18,12 @@ HttpProxySocketParams::HttpProxySocketParams( const scoped_refptr<TCPSocketParams>& proxy_server, const GURL& request_url, HostPortPair endpoint, - scoped_refptr<HttpNetworkSession> session, + scoped_refptr<HttpAuthController> auth_controller, bool tunnel) : tcp_params_(proxy_server), request_url_(request_url), endpoint_(endpoint), - session_(session), + auth_controller_(auth_controller), tunnel_(tunnel) { } @@ -134,22 +133,19 @@ int HttpProxyConnectJob::DoTCPConnectComplete(int result) { int HttpProxyConnectJob::DoHttpProxyConnect() { next_state_ = kStateHttpProxyConnectComplete; - const HostResolver::RequestInfo& tcp_destination = - params_->tcp_params()->destination(); - HostPortPair proxy_server(tcp_destination.hostname(), - tcp_destination.port()); // Add a HttpProxy connection on top of the tcp socket. socket_.reset(new HttpProxyClientSocket(tcp_socket_handle_.release(), params_->request_url(), params_->endpoint(), - proxy_server, - params_->session(), + params_->auth_controller(), params_->tunnel())); return socket_->Connect(&callback_); } int HttpProxyConnectJob::DoHttpProxyConnectComplete(int result) { + DCHECK_NE(result, ERR_RETRY_CONNECTION); + if (result == OK || result == ERR_PROXY_AUTH_REQUESTED) set_socket(socket_.release()); diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index 347a2427..63d5c02 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -26,13 +26,12 @@ namespace net { class ClientSocketFactory; class ConnectJobFactory; class HttpAuthController; -class HttpNetworkSession; class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { public: HttpProxySocketParams(const scoped_refptr<TCPSocketParams>& proxy_server, const GURL& request_url, HostPortPair endpoint, - scoped_refptr<HttpNetworkSession> session, + scoped_refptr<HttpAuthController> auth_controller, bool tunnel); const scoped_refptr<TCPSocketParams>& tcp_params() const { @@ -40,8 +39,8 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { } const GURL& request_url() const { return request_url_; } const HostPortPair& endpoint() const { return endpoint_; } - const scoped_refptr<HttpNetworkSession>& session() { - return session_; + const scoped_refptr<HttpAuthController>& auth_controller() { + return auth_controller_; } bool tunnel() const { return tunnel_; } @@ -52,7 +51,7 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { const scoped_refptr<TCPSocketParams> tcp_params_; const GURL request_url_; const HostPortPair endpoint_; - const scoped_refptr<HttpNetworkSession> session_; + const scoped_refptr<HttpAuthController> auth_controller_; const bool tunnel_; DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams); diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 3e06c3b..9400dd8 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -6,19 +6,12 @@ #include "base/callback.h" #include "base/compiler_specific.h" -#include "base/string_util.h" -#include "net/base/mock_host_resolver.h" #include "net/base/net_errors.h" -#include "net/base/ssl_config_service_defaults.h" #include "net/base/test_completion_callback.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_network_session.h" #include "net/http/http_proxy_client_socket.h" -#include "net/proxy/proxy_service.h" #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" -#include "net/spdy/spdy_session_pool.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -36,34 +29,19 @@ class HttpProxyClientSocketPoolTest : public ClientSocketPoolTest { tcp_histograms_(new ClientSocketPoolHistograms("MockTCP")), tcp_socket_pool_(new MockTCPClientSocketPool(kMaxSockets, kMaxSocketsPerGroup, tcp_histograms_, &tcp_client_socket_factory_)), - http_auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault()), - session_(new HttpNetworkSession(new MockHostResolver, - ProxyService::CreateNull(), - &socket_factory_, - new SSLConfigServiceDefaults, - new SpdySessionPool(), - http_auth_handler_factory_.get(), - NULL, - NULL)), notunnel_socket_params_(new HttpProxySocketParams( ignored_tcp_socket_params_, GURL("http://host"), HostPortPair("host", 80), NULL, false)), + auth_controller_(new MockHttpAuthController), tunnel_socket_params_(new HttpProxySocketParams( ignored_tcp_socket_params_, GURL("http://host"), - HostPortPair("host", 80), session_, true)), + HostPortPair("host", 80), auth_controller_, true)), http_proxy_histograms_( new ClientSocketPoolHistograms("HttpProxyUnitTest")), pool_(new HttpProxyClientSocketPool(kMaxSockets, kMaxSocketsPerGroup, http_proxy_histograms_, NULL, tcp_socket_pool_, NULL)) { } - void AddAuthToCache() { - const string16 kFoo(ASCIIToUTF16("foo")); - const string16 kBar(ASCIIToUTF16("bar")); - session_->auth_cache()->Add(GURL("http://proxy/"), "MyRealm1", "Basic", - "Basic realm=MyRealm1", kFoo, kBar, "/"); - } - int StartRequest(const std::string& group_name, RequestPriority priority) { return StartRequestUsingPool( pool_, group_name, priority, tunnel_socket_params_); @@ -74,10 +52,8 @@ class HttpProxyClientSocketPoolTest : public ClientSocketPoolTest { MockClientSocketFactory tcp_client_socket_factory_; scoped_refptr<MockTCPClientSocketPool> tcp_socket_pool_; - MockClientSocketFactory socket_factory_; - scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; - scoped_refptr<HttpNetworkSession> session_; scoped_refptr<HttpProxySocketParams> notunnel_socket_params_; + scoped_refptr<MockHttpAuthController> auth_controller_; scoped_refptr<HttpProxySocketParams> tunnel_socket_params_; scoped_refptr<ClientSocketPoolHistograms> http_proxy_histograms_; scoped_refptr<HttpProxyClientSocketPool> pool_; @@ -96,7 +72,7 @@ TEST_F(HttpProxyClientSocketPoolTest, NoTunnel) { EXPECT_TRUE(handle.socket()); HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(handle.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) { @@ -116,6 +92,10 @@ TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) { arraysize(writes)); tcp_client_socket_factory_.AddSocketDataProvider(&data); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData(""), + }; + auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data)); ClientSocketHandle handle; TestCompletionCallback callback; @@ -130,7 +110,7 @@ TEST_F(HttpProxyClientSocketPoolTest, NeedAuth) { EXPECT_TRUE(handle.socket()); HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(handle.socket()); - EXPECT_FALSE(tunnel_socket->IsConnected()); + EXPECT_TRUE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { @@ -139,7 +119,7 @@ TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { "CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"), @@ -149,7 +129,10 @@ TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { data.set_connect_data(MockConnect(false, 0)); tcp_client_socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; + auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data)); ClientSocketHandle handle; TestCompletionCallback callback; @@ -160,7 +143,7 @@ TEST_F(HttpProxyClientSocketPoolTest, HaveAuth) { EXPECT_TRUE(handle.socket()); HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(handle.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { @@ -168,7 +151,7 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { MockWrite("CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), @@ -177,7 +160,10 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { arraysize(writes)); tcp_client_socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; + auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data)); ClientSocketHandle handle; TestCompletionCallback callback; @@ -192,7 +178,7 @@ TEST_F(HttpProxyClientSocketPoolTest, AsyncHaveAuth) { EXPECT_TRUE(handle.socket()); HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(handle.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); + EXPECT_FALSE(tunnel_socket->NeedsRestartWithAuth()); } TEST_F(HttpProxyClientSocketPoolTest, TCPError) { @@ -219,7 +205,7 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) { MockWrite("CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead("HTTP/1.1 200 Conn"), @@ -229,7 +215,10 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelUnexpectedClose) { arraysize(writes)); tcp_client_socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; + auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data)); ClientSocketHandle handle; TestCompletionCallback callback; @@ -249,7 +238,7 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelSetupError) { MockWrite("CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), @@ -258,7 +247,10 @@ TEST_F(HttpProxyClientSocketPoolTest, TunnelSetupError) { arraysize(writes)); tcp_client_socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; + auth_controller_->SetMockAuthControllerData(auth_data, arraysize(auth_data)); ClientSocketHandle handle; TestCompletionCallback callback; diff --git a/net/socket/client_socket_handle.cc b/net/socket/client_socket_handle.cc index d9ccbd5..de2fd94 100644 --- a/net/socket/client_socket_handle.cc +++ b/net/socket/client_socket_handle.cc @@ -59,7 +59,6 @@ void ClientSocketHandle::ResetInternal(bool cancel) { void ClientSocketHandle::ResetErrorState() { is_ssl_error_ = false; ssl_error_response_info_ = HttpResponseInfo(); - pending_http_proxy_connection_.reset(); } LoadState ClientSocketHandle::GetLoadState() const { diff --git a/net/socket/client_socket_handle.h b/net/socket/client_socket_handle.h index adccc89..a25bfdb 100644 --- a/net/socket/client_socket_handle.h +++ b/net/socket/client_socket_handle.h @@ -109,9 +109,6 @@ class ClientSocketHandle { void set_ssl_error_response_info(const HttpResponseInfo& ssl_error_state) { ssl_error_response_info_ = ssl_error_state; } - void set_pending_http_proxy_connection(ClientSocketHandle* connection) { - pending_http_proxy_connection_.reset(connection); - } // Only valid if there is no |socket_|. bool is_ssl_error() const { @@ -124,9 +121,6 @@ class ClientSocketHandle { const HttpResponseInfo& ssl_error_response_info() const { return ssl_error_response_info_; } - ClientSocketHandle* release_pending_http_proxy_connection() { - return pending_http_proxy_connection_.release(); - } // These may only be used if is_initialized() is true. const std::string& group_name() const { return group_name_; } @@ -185,7 +179,6 @@ class ClientSocketHandle { int pool_id_; // See ClientSocketPool::ReleaseSocket() for an explanation. bool is_ssl_error_; HttpResponseInfo ssl_error_response_info_; - scoped_ptr<ClientSocketHandle> pending_http_proxy_connection_; base::TimeTicks init_time_; base::TimeDelta setup_time_; diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc index ce7f3fc06..d4d74a7 100644 --- a/net/socket/socket_test_util.cc +++ b/net/socket/socket_test_util.cc @@ -886,6 +886,53 @@ void MockSOCKSClientSocketPool::ReleaseSocket(const std::string& group_name, MockSOCKSClientSocketPool::~MockSOCKSClientSocketPool() {} +MockHttpAuthController::MockHttpAuthController() + : HttpAuthController(HttpAuth::AUTH_PROXY, GURL(), + scoped_refptr<HttpNetworkSession>(NULL)), + data_(NULL), + data_index_(0), + data_count_(0) { +} + +void MockHttpAuthController::SetMockAuthControllerData( + struct MockHttpAuthControllerData* data, size_t count) { + data_ = data; + data_count_ = count; +} + +int MockHttpAuthController::MaybeGenerateAuthToken( + const HttpRequestInfo* request, + CompletionCallback* callback, + const BoundNetLog& net_log) { + return OK; +} + +void MockHttpAuthController::AddAuthorizationHeader( + HttpRequestHeaders* authorization_headers) { + authorization_headers->AddHeadersFromString(CurrentData().auth_header); +} + +int MockHttpAuthController::HandleAuthChallenge( + scoped_refptr<HttpResponseHeaders> headers, + bool do_not_send_server_auth, + bool establishing_tunnel, + const BoundNetLog& net_log) { + return OK; +} + +void MockHttpAuthController::ResetAuth(const string16& username, + const string16& password) { + data_index_++; +} + +bool MockHttpAuthController::HaveAuth() const { + return CurrentData().auth_header.size() != 0; +} + +bool MockHttpAuthController::HaveAuthHandler() const { + return HaveAuth(); +} + const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; const int kSOCKS5GreetRequestLength = arraysize(kSOCKS5GreetRequest); diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h index 0ccf878..1a0ab11 100644 --- a/net/socket/socket_test_util.h +++ b/net/socket/socket_test_util.h @@ -695,6 +695,46 @@ class MockSOCKSClientSocketPool : public SOCKSClientSocketPool { DISALLOW_COPY_AND_ASSIGN(MockSOCKSClientSocketPool); }; +struct MockHttpAuthControllerData { + explicit MockHttpAuthControllerData(std::string header) + : auth_header(header) {} + + std::string auth_header; +}; + +class MockHttpAuthController : public HttpAuthController { + public: + MockHttpAuthController(); + void SetMockAuthControllerData(struct MockHttpAuthControllerData* data, + size_t data_length); + + // HttpAuthController methods. + virtual int MaybeGenerateAuthToken(const HttpRequestInfo* request, + CompletionCallback* callback, + const BoundNetLog& net_log); + virtual void AddAuthorizationHeader( + HttpRequestHeaders* authorization_headers); + virtual int HandleAuthChallenge(scoped_refptr<HttpResponseHeaders> headers, + bool do_not_send_server_auth, + bool establishing_tunnel, + const BoundNetLog& net_log); + virtual void ResetAuth(const string16& username, + const string16& password); + virtual bool HaveAuthHandler() const; + virtual bool HaveAuth() const; + + private: + virtual ~MockHttpAuthController() {} + const struct MockHttpAuthControllerData& CurrentData() const { + DCHECK(data_index_ < data_count_); + return data_[data_index_]; + } + + MockHttpAuthControllerData* data_; + size_t data_index_; + size_t data_count_; +}; + // Constants for a successful SOCKS v5 handshake. extern const char kSOCKS5GreetRequest[]; extern const int kSOCKS5GreetRequestLength; diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index 5ed450e..03e2e80 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc @@ -103,6 +103,11 @@ LoadState SSLConnectJob::GetLoadState() const { } int SSLConnectJob::ConnectInternal() { + DetermineFirstState(); + return DoLoop(OK); +} + +void SSLConnectJob::DetermineFirstState() { switch (params_->proxy()) { case ProxyServer::SCHEME_DIRECT: next_state_ = STATE_TCP_CONNECT; @@ -118,7 +123,6 @@ int SSLConnectJob::ConnectInternal() { NOTREACHED() << "unknown proxy type"; break; } - return DoLoop(OK); } void SSLConnectJob::OnIOComplete(int result) { @@ -210,7 +214,6 @@ int SSLConnectJob::DoSOCKSConnectComplete(int result) { int SSLConnectJob::DoTunnelConnect() { DCHECK(http_proxy_pool_.get()); next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; - transport_socket_handle_.reset(new ClientSocketHandle()); scoped_refptr<HttpProxySocketParams> http_proxy_params = params_->http_proxy_params(); @@ -225,6 +228,12 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) { HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(socket); + if (result == ERR_RETRY_CONNECTION) { + DetermineFirstState(); + transport_socket_handle_->socket()->Disconnect(); + return OK; + } + // Extract the information needed to prompt for the proxy authentication. // so that when ClientSocketPoolBaseHelper calls |GetAdditionalErrorState|, // we can easily set the state. @@ -234,17 +243,20 @@ int SSLConnectJob::DoTunnelConnectComplete(int result) { if (result < 0) return result; - DCHECK(tunnel_socket->IsConnected()); + if (tunnel_socket->NeedsRestartWithAuth()) { + // We must have gotten an 'idle' tunnel socket that is waiting for auth. + // The HttpAuthController should have new credentials, we just need + // to retry. + next_state_ = STATE_TUNNEL_CONNECT_COMPLETE; + return tunnel_socket->RestartWithAuth(&callback_); + } + next_state_ = STATE_SSL_CONNECT; return result; } void SSLConnectJob::GetAdditionalErrorState(ClientSocketHandle * handle) { - if (error_response_info_.headers) { - handle->set_ssl_error_response_info(error_response_info_); - handle->set_pending_http_proxy_connection( - transport_socket_handle_.release()); - } + handle->set_ssl_error_response_info(error_response_info_); if (!ssl_connect_start_time_.is_null()) handle->set_is_ssl_error(true); } diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h index 9857c61..b44985f 100644 --- a/net/socket/ssl_client_socket_pool.h +++ b/net/socket/ssl_client_socket_pool.h @@ -44,7 +44,7 @@ class SSLSocketParams : public base::RefCounted<SSLSocketParams> { bool want_spdy_over_npn); const scoped_refptr<TCPSocketParams>& tcp_params() { return tcp_params_; } - const scoped_refptr<HttpProxySocketParams>& http_proxy_params() { + const scoped_refptr<HttpProxySocketParams>& http_proxy_params () { return http_proxy_params_; } const scoped_refptr<SOCKSSocketParams>& socks_params() { @@ -114,6 +114,8 @@ class SSLConnectJob : public ConnectJob { // Otherwise, it returns a net error code. virtual int ConnectInternal(); + void DetermineFirstState(); + void OnIOComplete(int result); // Runs the state transition loop. diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index 047a647..efc4795 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc @@ -6,14 +6,13 @@ #include "base/callback.h" #include "base/compiler_specific.h" -#include "base/string_util.h" #include "base/time.h" #include "net/base/auth.h" #include "net/base/mock_host_resolver.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/base/ssl_config_service_defaults.h" -#include "net/http/http_auth_handler_factory.h" +#include "net/http/http_auth_controller.h" #include "net/http/http_network_session.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" @@ -21,7 +20,6 @@ #include "net/socket/client_socket_handle.h" #include "net/socket/client_socket_pool_histograms.h" #include "net/socket/socket_test_util.h" -#include "net/spdy/spdy_session_pool.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -34,16 +32,7 @@ const int kMaxSocketsPerGroup = 6; class SSLClientSocketPoolTest : public ClientSocketPoolTest { protected: SSLClientSocketPoolTest() - : http_auth_handler_factory_(HttpAuthHandlerFactory::CreateDefault()), - session_(new HttpNetworkSession(new MockHostResolver, - ProxyService::CreateNull(), - &socket_factory_, - new SSLConfigServiceDefaults, - new SpdySessionPool(), - http_auth_handler_factory_.get(), - NULL, - NULL)), - direct_tcp_socket_params_(new TCPSocketParams( + : direct_tcp_socket_params_(new TCPSocketParams( HostPortPair("host", 443), MEDIUM, GURL(), false)), tcp_socket_pool_(new MockTCPClientSocketPool( kMaxSockets, @@ -52,9 +41,6 @@ class SSLClientSocketPoolTest : public ClientSocketPoolTest { &socket_factory_)), proxy_tcp_socket_params_(new TCPSocketParams( HostPortPair("proxy", 443), MEDIUM, GURL(), false)), - http_proxy_socket_params_(new HttpProxySocketParams( - proxy_tcp_socket_params_, GURL("http://host"), - HostPortPair("host", 80), session_, true)), http_proxy_socket_pool_(new HttpProxyClientSocketPool( kMaxSockets, kMaxSocketsPerGroup, @@ -88,30 +74,33 @@ class SSLClientSocketPoolTest : public ClientSocketPoolTest { NULL); } - scoped_refptr<SSLSocketParams> SSLParams(ProxyServer::Scheme proxy, - bool want_spdy_over_npn) { + scoped_refptr<SSLSocketParams> SSLParams( + ProxyServer::Scheme proxy, struct MockHttpAuthControllerData* auth_data, + size_t auth_data_len, bool want_spdy_over_ssl, bool want_spdy_over_npn) { + scoped_refptr<HttpProxySocketParams> http_proxy_params; + if (proxy == ProxyServer::SCHEME_HTTP) { + scoped_refptr<MockHttpAuthController> auth_controller = + new MockHttpAuthController(); + auth_controller->SetMockAuthControllerData(auth_data, auth_data_len); + http_proxy_params = new HttpProxySocketParams(proxy_tcp_socket_params_, + GURL("http://host"), + HostPortPair("host", 80), + auth_controller, true); + } + return make_scoped_refptr(new SSLSocketParams( proxy == ProxyServer::SCHEME_DIRECT ? direct_tcp_socket_params_ : NULL, - proxy == ProxyServer::SCHEME_HTTP ? http_proxy_socket_params_ : NULL, + http_proxy_params, proxy == ProxyServer::SCHEME_SOCKS5 ? socks_socket_params_ : NULL, proxy, "host", ssl_config_, 0, - false, + want_spdy_over_ssl, want_spdy_over_npn)); } - void AddAuthToCache() { - const string16 kFoo(ASCIIToUTF16("foo")); - const string16 kBar(ASCIIToUTF16("bar")); - session_->auth_cache()->Add(GURL("http://proxy:443/"), "MyRealm1", "Basic", - "Basic realm=MyRealm1", kFoo, kBar, "/"); - } - MockClientSocketFactory socket_factory_; - scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; - scoped_refptr<HttpNetworkSession> session_; scoped_refptr<TCPSocketParams> direct_tcp_socket_params_; scoped_refptr<MockTCPClientSocketPool> tcp_socket_pool_; @@ -134,7 +123,7 @@ TEST_F(SSLClientSocketPoolTest, TCPFail) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; int rv = handle.Init("a", params, MEDIUM, NULL, pool_, BoundNetLog()); @@ -151,7 +140,7 @@ TEST_F(SSLClientSocketPoolTest, TCPFailAsync) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -175,7 +164,7 @@ TEST_F(SSLClientSocketPoolTest, BasicDirect) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -193,7 +182,7 @@ TEST_F(SSLClientSocketPoolTest, BasicDirectAsync) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -215,7 +204,7 @@ TEST_F(SSLClientSocketPoolTest, DirectCertError) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -237,7 +226,7 @@ TEST_F(SSLClientSocketPoolTest, DirectSSLError) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -262,7 +251,7 @@ TEST_F(SSLClientSocketPoolTest, DirectWithNPN) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -288,7 +277,7 @@ TEST_F(SSLClientSocketPoolTest, DirectNoSPDY) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - true); + NULL, 0, false, true); ClientSocketHandle handle; TestCompletionCallback callback; @@ -313,7 +302,7 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - true); + NULL, 0, false, true); ClientSocketHandle handle; TestCompletionCallback callback; @@ -344,7 +333,7 @@ TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) { CreatePool(true /* tcp pool */, false, false); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_DIRECT, - true); + NULL, 0, false, true); ClientSocketHandle handle; TestCompletionCallback callback; @@ -372,7 +361,7 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFail) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -390,7 +379,7 @@ TEST_F(SSLClientSocketPoolTest, SOCKSFailAsync) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -414,7 +403,7 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasic) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -432,7 +421,7 @@ TEST_F(SSLClientSocketPoolTest, SOCKSBasicAsync) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_SOCKS5, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -453,7 +442,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFail) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -471,7 +460,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyFailAsync) { CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, - false); + NULL, 0, false, false); ClientSocketHandle handle; TestCompletionCallback callback; @@ -492,7 +481,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) { "CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead(false, "HTTP/1.1 200 Connection Established\r\n\r\n"), @@ -501,12 +490,17 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasic) { arraysize(writes)); data.set_connect_data(MockConnect(false, OK)); socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; SSLSocketDataProvider ssl(false, OK); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, + auth_data, + arraysize(auth_data), + false, false); ClientSocketHandle handle; @@ -522,7 +516,7 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) { MockWrite("CONNECT host:80 HTTP/1.1\r\n" "Host: host\r\n" "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), }; MockRead reads[] = { MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), @@ -530,12 +524,17 @@ TEST_F(SSLClientSocketPoolTest, HttpProxyBasicAsync) { StaticSocketDataProvider data(reads, arraysize(reads), writes, arraysize(writes)); socket_factory_.AddSocketDataProvider(&data); - AddAuthToCache(); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; SSLSocketDataProvider ssl(true, OK); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, + auth_data, + arraysize(auth_data), + false, false); ClientSocketHandle handle; @@ -565,11 +564,135 @@ TEST_F(SSLClientSocketPoolTest, NeedProxyAuth) { StaticSocketDataProvider data(reads, arraysize(reads), writes, arraysize(writes)); socket_factory_.AddSocketDataProvider(&data); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData(""), + }; + SSLSocketDataProvider ssl(true, OK); + socket_factory_.AddSSLSocketDataProvider(&ssl); + + CreatePool(false, true /* http proxy pool */, true /* socks pool */); + scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, + auth_data, + arraysize(auth_data), + false, + false); + + ClientSocketHandle handle; + TestCompletionCallback callback; + int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + + EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult()); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle.is_ssl_error()); + const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info(); + EXPECT_EQ(tunnel_info.headers->response_code(), 407); +} + +TEST_F(SSLClientSocketPoolTest, DoProxyAuth) { + MockWrite writes[] = { + MockWrite("CONNECT host:80 HTTP/1.1\r\n" + "Host: host\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + MockWrite("CONNECT host:80 HTTP/1.1\r\n" + "Host: host\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), + }; + MockRead reads[] = { + MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), + MockRead("Content-Length: 10\r\n\r\n"), + MockRead("0123456789"), + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + }; + StaticSocketDataProvider data(reads, arraysize(reads), writes, + arraysize(writes)); + socket_factory_.AddSocketDataProvider(&data); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData(""), + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; + SSLSocketDataProvider ssl(true, OK); + socket_factory_.AddSSLSocketDataProvider(&ssl); + + CreatePool(false, true /* http proxy pool */, true /* socks pool */); + scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, + auth_data, + arraysize(auth_data), + false, + false); + + ClientSocketHandle handle; + TestCompletionCallback callback; + int rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + + EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult()); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + EXPECT_FALSE(handle.is_ssl_error()); + const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info(); + EXPECT_EQ(tunnel_info.headers->response_code(), 407); + + params->http_proxy_params()->auth_controller()->ResetAuth(string16(), + string16()); + rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + + // Test that http://crbug.com/49325 doesn't regress. + EXPECT_EQ(handle.GetLoadState(), LOAD_STATE_ESTABLISHING_PROXY_TUNNEL); + + EXPECT_EQ(OK, callback.WaitForResult()); + EXPECT_TRUE(handle.is_initialized()); + EXPECT_TRUE(handle.socket()); +} + +TEST_F(SSLClientSocketPoolTest, DoProxyAuthNoKeepAlive) { + MockWrite writes1[] = { + MockWrite("CONNECT host:80 HTTP/1.1\r\n" + "Host: host\r\n" + "Proxy-Connection: keep-alive\r\n\r\n"), + }; + MockWrite writes2[] = { + MockWrite("CONNECT host:80 HTTP/1.1\r\n" + "Host: host\r\n" + "Proxy-Connection: keep-alive\r\n" + "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), + }; + MockRead reads1[] = { + MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), + MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"), + MockRead("Content0123456789"), + }; + MockRead reads2[] = { + MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), + }; + StaticSocketDataProvider data1(reads1, arraysize(reads1), writes1, + arraysize(writes1)); + socket_factory_.AddSocketDataProvider(&data1); + StaticSocketDataProvider data2(reads2, arraysize(reads2), writes2, + arraysize(writes2)); + socket_factory_.AddSocketDataProvider(&data2); + MockHttpAuthControllerData auth_data[] = { + MockHttpAuthControllerData(""), + MockHttpAuthControllerData("Proxy-Authorization: Basic Zm9vOmJheg=="), + }; SSLSocketDataProvider ssl(true, OK); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(false, true /* http proxy pool */, true /* socks pool */); scoped_refptr<SSLSocketParams> params = SSLParams(ProxyServer::SCHEME_HTTP, + auth_data, + arraysize(auth_data), + false, false); ClientSocketHandle handle; @@ -585,10 +708,17 @@ TEST_F(SSLClientSocketPoolTest, NeedProxyAuth) { EXPECT_FALSE(handle.is_ssl_error()); const HttpResponseInfo& tunnel_info = handle.ssl_error_response_info(); EXPECT_EQ(tunnel_info.headers->response_code(), 407); - scoped_ptr<ClientSocketHandle> tunnel_handle( - handle.release_pending_http_proxy_connection()); - EXPECT_TRUE(tunnel_handle->socket()); - EXPECT_FALSE(tunnel_handle->socket()->IsConnected()); + + params->http_proxy_params()->auth_controller()->ResetAuth(string16(), + string16()); + rv = handle.Init("a", params, MEDIUM, &callback, pool_, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_FALSE(handle.is_initialized()); + EXPECT_FALSE(handle.socket()); + + EXPECT_EQ(OK, callback.WaitForResult()); + EXPECT_TRUE(handle.is_initialized()); + EXPECT_TRUE(handle.socket()); } // It would be nice to also test the timeouts in SSLClientSocketPool. |