diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 422 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket.cc | 45 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket.h | 17 | ||||
-rw-r--r-- | net/http/http_proxy_client_socket_pool_unittest.cc | 30 | ||||
-rw-r--r-- | net/http/http_proxy_utils.cc | 20 | ||||
-rw-r--r-- | net/http/http_proxy_utils.h | 11 | ||||
-rw-r--r-- | net/http/http_stream_factory_impl_job.cc | 18 | ||||
-rw-r--r-- | net/http/proxy_client_socket.h | 10 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket.cc | 23 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket.h | 10 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket_unittest.cc | 74 |
11 files changed, 97 insertions, 583 deletions
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index 8bbd17c..bcc83bb 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1682,9 +1682,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { 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"), - }; - MockWrite data_writes2[] = { // 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" @@ -1704,9 +1702,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { 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 data_reads2[] = { MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), MockRead("HTTP/1.1 200 OK\r\n"), @@ -1717,10 +1713,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); SSLSocketDataProvider ssl(true, OK); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); @@ -1933,368 +1926,6 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { session->CloseAllConnections(); } -// 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, BasicAuthHttpsProxyNoKeepAlive) { - 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; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // 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"), - }; - - MockWrite data_writes2[] = { - // 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 data_reads2[] = { - 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: 5\r\n\r\n"), - MockRead(false, "hello"), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - SSLSocketDataProvider proxy(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); - SSLSocketDataProvider proxy2(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy2); - SSLSocketDataProvider server(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&server); - - TestOldCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, &callback1, log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestOldCompletionCallback callback2; - - rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback2); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(5, 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); - - trans.reset(); - session->CloseAllConnections(); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// proxy connection, when setting up an SSL tunnel. -TEST_F(HttpNetworkTransactionTest, BasicAuthHttpsProxyKeepAlive) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - // Ensure that proxy authentication is attempted even - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://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)); - - // 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 Zm9vOmJheg==\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("Content-Length: 10\r\n\r\n"), - MockRead("0123456789"), - - // Wrong credentials (wrong password). - 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"), - // No response body because the test stops reading here. - MockRead(false, ERR_UNEXPECTED), // Should not be reached. - }; - - 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); - - TestOldCompletionCallback callback1; - - int rv = trans->Start(&request, &callback1, log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(10, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestOldCompletionCallback callback2; - - // Wrong password (should be "bar"). - rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBaz), &callback2); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(10, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - // Flush the idle socket before the NetLog and HttpNetworkTransaction go - // out of scope. - session->CloseAllConnections(); -} - -// Test the request-challenge-retry sequence for basic auth, through -// a SPDY proxy over a single SPDY session. -TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { - 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; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should try to establish tunnel. - scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - const char* const kAuthCredentials[] = { - "proxy-authorization", "Basic Zm9vOmJhcg==", - }; - scoped_ptr<spdy::SpdyFrame> connect2( - ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); - // fetch https://www.google.com/ via HTTP - const char get[] = "GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"; - scoped_ptr<spdy::SpdyFrame> wrapped_get( - ConstructSpdyBodyFrame(3, get, strlen(get), false)); - - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, true), - CreateMockWrite(*rst, 2, true), - CreateMockWrite(*connect2, 3), - CreateMockWrite(*wrapped_get, 5) - }; - - // The proxy responds to the connect with a 407, using a persistent - // connection. - const char* const kAuthChallenge[] = { - "status", "407 Proxy Authentication Required", - "version", "HTTP/1.1", - "proxy-authenticate", "Basic realm=\"MyRealm1\"", - }; - - scoped_ptr<spdy::SpdyFrame> conn_auth_resp( - ConstructSpdyControlFrame(NULL, - 0, - false, - 1, - LOWEST, - spdy::SYN_REPLY, - spdy::CONTROL_FLAG_NONE, - kAuthChallenge, - arraysize(kAuthChallenge))); - - scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); - const char resp[] = "HTTP/1.1 200 OK\r\n" - "Content-Length: 5\r\n\r\n"; - - scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( - ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); - scoped_ptr<spdy::SpdyFrame> wrapped_body( - ConstructSpdyBodyFrame(3, "hello", 10, false)); - MockRead spdy_reads[] = { - CreateMockRead(*conn_auth_resp, 1, true), - CreateMockRead(*conn_resp, 4, true), - CreateMockRead(*wrapped_get_resp, 5, true), - CreateMockRead(*wrapped_body, 6, true), - MockRead(false, ERR_IO_PENDING), - }; - - scoped_refptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data); - // Negotiate SPDY to the proxy - SSLSocketDataProvider proxy(true, OK); - proxy.next_proto_status = SSLClientSocket::kNextProtoNegotiated; - proxy.next_proto = "spdy/2"; - proxy.was_npn_negotiated = true; - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); - // Vanilla SSL to the server - SSLSocketDataProvider server(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&server); - - TestOldCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, &callback1, log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(response->auth_challenge.get() != NULL); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestOldCompletionCallback callback2; - - rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), &callback2); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(5, 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); - - trans.reset(); - session->CloseAllConnections(); -} - // Test when a server (non-proxy) returns a 407 (proxy-authenticate). // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { @@ -7697,7 +7328,7 @@ TEST_F(HttpNetworkTransactionTest, // - HTTP or HTTPS backend (to include proxy tunneling). // - Non-authenticating and authenticating backend. // -// In all, there are 44 reasonable permutations (for example, if there are +// In all, there are 44 reasonable permuations (for example, if there are // problems generating an auth token for an authenticating proxy, we don't // need to test all permutations of the backend server). // @@ -8517,10 +8148,8 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); HttpAuthHandlerMock::Factory* auth_factory = new HttpAuthHandlerMock::Factory(); - HttpAuthHandlerMock* auth_handler1 = new HttpAuthHandlerMock(); - auth_factory->AddMockHandler(auth_handler1, HttpAuth::AUTH_PROXY); - HttpAuthHandlerMock* auth_handler2 = new HttpAuthHandlerMock(); - auth_factory->AddMockHandler(auth_handler2, HttpAuth::AUTH_PROXY); + HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); + auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); auth_factory->set_do_init_from_challenge(true); session_deps.http_auth_handler_factory.reset(auth_factory); @@ -8552,6 +8181,11 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { // After the failure, a tunnel is established to www.google.com using // Proxy-Authorization headers. There is then a SPDY request round. // + // NOTE: Despite the "Proxy-Connection: Close", these are done on the + // same MockTCPClientSocket since the underlying HttpNetworkClientSocket + // does a Disconnect and Connect on the same socket, rather than trying + // to obtain a new one. + // // NOTE: Originally, the proxy response to the second CONNECT request // simply returned another 407 so the unit test could skip the SSL connection // establishment and SPDY framing issues. Alas, the @@ -8568,17 +8202,7 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { "Host: www.google.com\r\n" "Proxy-Connection: keep-alive\r\n" "\r\n"), - }; - - MockWrite data_writes_3[] = { - // Non-alternate protocol job that will run in parallel - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "\r\n"), - }; - MockWrite data_writes_4[] = { // Second connection attempt with Proxy-Authorization. MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" "Host: www.google.com\r\n" @@ -8592,7 +8216,6 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" "Proxy-Authenticate: Mock\r\n" "Proxy-Connection: close\r\n" - "Content-Length: 0\r\n" "\r\n"); const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; MockRead data_reads_2[] = { @@ -8600,35 +8223,19 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), MockRead(true, kRejectConnectResponse, arraysize(kRejectConnectResponse) - 1, 1), - }; - // Hang forever so we can ensure the alt job wins - MockRead data_reads_3[] = { - MockRead(false, ERR_IO_PENDING), - }; - - MockRead data_reads_4[] = { // Second connection attempt passes MockRead(true, kAcceptConnectResponse, - arraysize(kAcceptConnectResponse) -1, 1), + arraysize(kAcceptConnectResponse) -1, 4), // SPDY response - CreateMockRead(*resp.get(), 3), - CreateMockRead(*data.get(), 3), - MockRead(true, 0, 0, 4), + CreateMockRead(*resp.get(), 6), + CreateMockRead(*data.get(), 6), + MockRead(true, 0, 0, 6), }; scoped_refptr<OrderedSocketData> data_2( new OrderedSocketData(data_reads_2, arraysize(data_reads_2), data_writes_2, arraysize(data_writes_2))); - scoped_refptr<OrderedSocketData> data_3( - new OrderedSocketData(data_reads_3, arraysize(data_reads_3), - data_writes_3, arraysize(data_writes_3))); - // Hang forever so we can ensure the alt job wins - MockConnect conn_3(false, ERR_IO_PENDING); - data_3->set_connect_data(conn_3); - scoped_refptr<OrderedSocketData> data_4( - new OrderedSocketData(data_reads_4, arraysize(data_reads_4), - data_writes_4, arraysize(data_writes_4))); SSLSocketDataProvider ssl(true, OK); ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; @@ -8643,9 +8250,6 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { session_deps.socket_factory.AddSocketDataProvider(&data_1); session_deps.socket_factory.AddSocketDataProvider(data_2.get()); - session_deps.socket_factory.AddSocketDataProvider(data_3.get()); - session_deps.socket_factory.AddSocketDataProvider(data_4.get()); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); session_deps.socket_factory.AddSocketDataProvider( &hanging_non_alternate_protocol_socket); @@ -8676,7 +8280,7 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { // After all that work, these two lines (or actually, just the scheme) are // what this test is all about. Make sure it happens correctly. - const GURL& request_url = auth_handler2->request_url(); + const GURL& request_url = auth_handler->request_url(); EXPECT_EQ("https", request_url.scheme()); EXPECT_EQ("www.google.com", request_url.host()); diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index 1434c655..32ccb1b 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -68,7 +68,7 @@ int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { DCHECK(!user_callback_); int rv = PrepareForAuthRestart(); - if (rv != OK || next_state_ == STATE_NONE) + if (rv != OK) return rv; rv = DoLoop(OK); @@ -77,11 +77,6 @@ int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { return rv; } -const -scoped_refptr<HttpAuthController>& HttpProxyClientSocket::auth_controller() { - return auth_; -} - const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { return response_.headers ? &response_ : NULL; } @@ -256,7 +251,10 @@ int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { next_state_ = STATE_GENERATE_AUTH_TOKEN; transport_->set_is_reused(true); } else { - next_state_ = STATE_NONE; + // 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(); } // Reset the other member variables. @@ -269,6 +267,17 @@ int HttpProxyClientSocket::DidDrainBodyForAuthRestart(bool keep_alive) { return OK; } +int HttpProxyClientSocket::HandleAuthChallenge() { + DCHECK(response_.headers); + + int rv = auth_->HandleAuthChallenge(response_.headers, false, true, net_log_); + response_.auth_challenge = auth_->auth_info(); + if (rv == OK) + return ERR_PROXY_AUTH_REQUESTED; + + return rv; +} + void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { LOG(WARNING) << "Blocked proxy response with status " << response_code << " to CONNECT request for " @@ -338,6 +347,13 @@ 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: @@ -436,7 +452,7 @@ int HttpProxyClientSocket::DoReadHeadersComplete(int result) { // authentication code is smart enough to avoid being tricked by an // active network attacker. // The next state is intentionally not set as it should be STATE_NONE; - return HandleAuthChallenge(auth_, &response_, net_log_); + return HandleAuthChallenge(); default: if (is_https_proxy_) @@ -472,4 +488,17 @@ 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; +} + } // namespace net diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index 70db3707..def0221 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -50,6 +50,15 @@ class HttpProxyClientSocket : public ProxyClientSocket { // On destruction Disconnect() is called. virtual ~HttpProxyClientSocket(); + // If Connect (or its callback) returns PROXY_AUTH_REQUESTED, then + // credentials should be added to the HttpAuthController before calling + // RestartWithAuth. + int RestartWithAuth(OldCompletionCallback* callback); + + const scoped_refptr<HttpAuthController>& auth_controller() { + return auth_; + } + bool using_spdy() { return using_spdy_; } @@ -57,8 +66,6 @@ class HttpProxyClientSocket : public ProxyClientSocket { // ProxyClientSocket methods: virtual const HttpResponseInfo* GetConnectResponseInfo() const OVERRIDE; virtual HttpStream* CreateConnectResponseStream() OVERRIDE; - virtual int RestartWithAuth(OldCompletionCallback* callback) OVERRIDE; - virtual const scoped_refptr<HttpAuthController>& auth_controller() OVERRIDE; // StreamSocket methods: virtual int Connect(OldCompletionCallback* callback) OVERRIDE; @@ -96,6 +103,8 @@ class HttpProxyClientSocket : public ProxyClientSocket { STATE_READ_HEADERS_COMPLETE, STATE_DRAIN_BODY, STATE_DRAIN_BODY_COMPLETE, + STATE_TCP_RESTART, + STATE_TCP_RESTART_COMPLETE, STATE_DONE, }; @@ -107,6 +116,8 @@ class HttpProxyClientSocket : public ProxyClientSocket { int PrepareForAuthRestart(); int DidDrainBodyForAuthRestart(bool keep_alive); + int HandleAuthChallenge(); + void LogBlockedTunnelResponse(int response_code) const; void DoCallback(int result); @@ -121,6 +132,8 @@ class HttpProxyClientSocket : public ProxyClientSocket { int DoReadHeadersComplete(int result); int DoDrainBody(); int DoDrainBodyComplete(int result); + int DoTCPRestart(); + int DoTCPRestartComplete(int result); OldCompletionCallbackImpl<HttpProxyClientSocket> io_callback_; State next_state_; diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index d7b56867..175f167 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -257,22 +257,9 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) { CreateMockWrite(*req, 0, true), CreateMockWrite(*rst, 2, true), }; - static const char* const kAuthChallenge[] = { - "status", "407 Proxy Authentication Required", - "version", "HTTP/1.1", - "proxy-authenticate", "Basic realm=\"MyRealm1\"", - }; - scoped_ptr<spdy::SpdyFrame> resp( - ConstructSpdyControlFrame(NULL, - 0, - false, - 1, - LOWEST, - spdy::SYN_REPLY, - spdy::CONTROL_FLAG_NONE, - kAuthChallenge, - arraysize(kAuthChallenge))); + ConstructSpdySynReplyError( + "407 Proxy Authentication Required", NULL, 0, 1)); MockRead spdy_reads[] = { CreateMockWrite(*resp, 1, true), MockRead(true, 0, 3) @@ -289,16 +276,21 @@ TEST_P(HttpProxyClientSocketPoolTest, NeedAuth) { EXPECT_FALSE(handle_.is_initialized()); EXPECT_FALSE(handle_.socket()); - data_->RunFor(GetParam() == SPDY ? 2 : 4); + data_->RunFor(4); rv = callback_.WaitForResult(); - EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv); - EXPECT_TRUE(handle_.is_initialized()); - ASSERT_TRUE(handle_.socket()); if (GetParam() != SPDY) { + EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv); + EXPECT_TRUE(handle_.is_initialized()); + ASSERT_TRUE(handle_.socket()); HttpProxyClientSocket* tunnel_socket = static_cast<HttpProxyClientSocket*>(handle_.socket()); EXPECT_FALSE(tunnel_socket->IsConnected()); EXPECT_FALSE(tunnel_socket->using_spdy()); + } else { + // Proxy auth is not really implemented for SPDY yet + EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); + EXPECT_FALSE(handle_.is_initialized()); + EXPECT_FALSE(handle_.socket()); } } diff --git a/net/http/http_proxy_utils.cc b/net/http/http_proxy_utils.cc index 459c346..e93c8ee 100644 --- a/net/http/http_proxy_utils.cc +++ b/net/http/http_proxy_utils.cc @@ -1,19 +1,14 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. #include "net/http/http_proxy_utils.h" -#include "base/logging.h" #include "base/stringprintf.h" #include "googleurl/src/gurl.h" #include "net/base/host_port_pair.h" -#include "net/base/net_errors.h" #include "net/base/net_util.h" -#include "net/http/http_auth_controller.h" #include "net/http/http_request_info.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_response_info.h" namespace net { @@ -41,17 +36,4 @@ void BuildTunnelRequest( request_headers->MergeFrom(auth_headers); } -int HandleAuthChallenge(HttpAuthController *auth, - HttpResponseInfo* response, - const BoundNetLog& net_log) { - DCHECK(response->headers); - - int rv = auth->HandleAuthChallenge(response->headers, false, true, net_log); - response->auth_challenge = auth->auth_info(); - if (rv == OK) - return ERR_PROXY_AUTH_REQUESTED; - - return rv; -} - } // namespace net diff --git a/net/http/http_proxy_utils.h b/net/http/http_proxy_utils.h index 3257f7f..9d18fc8 100644 --- a/net/http/http_proxy_utils.h +++ b/net/http/http_proxy_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 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. @@ -10,9 +10,6 @@ namespace net { -class BoundNetLog; -class HttpAuthController; -class HttpResponseInfo; struct HttpRequestInfo; class HttpRequestHeaders; class HostPortPair; @@ -26,12 +23,6 @@ void BuildTunnelRequest(const HttpRequestInfo& request_info, std::string* request_line, HttpRequestHeaders* request_headers); -// When an auth challenge (407 response) is received during tunnel construction -// this method should be called. -int HandleAuthChallenge(HttpAuthController *auth, - HttpResponseInfo* response, - const BoundNetLog& net_log); - } // namespace net #endif // NET_HTTP_HTTP_PROXY_UTILS_H_ diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index a6ca05e..6fb88dc 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -369,10 +369,10 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) { DCHECK(connection_->socket()); DCHECK(establishing_tunnel_); - ProxyClientSocket* proxy_socket = - static_cast<ProxyClientSocket*>(connection_->socket()); + HttpProxyClientSocket* http_proxy_socket = + static_cast<HttpProxyClientSocket*>(connection_->socket()); const HttpResponseInfo* tunnel_auth_response = - proxy_socket->GetConnectResponseInfo(); + http_proxy_socket->GetConnectResponseInfo(); next_state_ = STATE_WAITING_USER_ACTION; MessageLoop::current()->PostTask( @@ -381,7 +381,7 @@ int HttpStreamFactoryImpl::Job::RunLoop(int result) { &HttpStreamFactoryImpl::Job::OnNeedsProxyAuthCallback, ptr_factory_.GetWeakPtr(), *tunnel_auth_response, - proxy_socket->auth_controller())); + http_proxy_socket->auth_controller())); } return ERR_IO_PENDING; @@ -898,9 +898,9 @@ int HttpStreamFactoryImpl::Job::DoCreateStreamComplete(int result) { int HttpStreamFactoryImpl::Job::DoRestartTunnelAuth() { next_state_ = STATE_RESTART_TUNNEL_AUTH_COMPLETE; - ProxyClientSocket* proxy_socket = - static_cast<ProxyClientSocket*>(connection_->socket()); - return proxy_socket->RestartWithAuth(&io_callback_); + HttpProxyClientSocket* http_proxy_socket = + static_cast<HttpProxyClientSocket*>(connection_->socket()); + return http_proxy_socket->RestartWithAuth(&io_callback_); } int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) { @@ -908,14 +908,14 @@ int HttpStreamFactoryImpl::Job::DoRestartTunnelAuthComplete(int result) { return result; if (result == OK) { - // Now that we've got the ProxyClientSocket prepared to restart. We have + // 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. establishing_tunnel_ = false; - ReturnToStateInitConnection(!connection_->socket()->IsConnectedAndIdle()); + ReturnToStateInitConnection(false /* do not close connection */); return OK; } diff --git a/net/http/proxy_client_socket.h b/net/http/proxy_client_socket.h index 1fd4f79..451e098 100644 --- a/net/http/proxy_client_socket.h +++ b/net/http/proxy_client_socket.h @@ -10,7 +10,6 @@ namespace net { -class HttpAuthController; class HttpStream; class HttpResponseInfo; @@ -27,15 +26,6 @@ class NET_EXPORT_PRIVATE ProxyClientSocket : public StreamSocket { // which can be used to read the response body. virtual HttpStream* CreateConnectResponseStream() = 0; - // Returns the HttpAuthController which can be used - // to interact with an HTTP Proxy Authorization Required (407) request. - virtual const scoped_refptr<HttpAuthController>& auth_controller() = 0; - - // If Connect (or its callback) returns PROXY_AUTH_REQUESTED, then - // credentials should be added to the HttpAuthController before calling - // RestartWithAuth. - virtual int RestartWithAuth(OldCompletionCallback* callback) = 0; - private: DISALLOW_COPY_AND_ASSIGN(ProxyClientSocket); }; diff --git a/net/spdy/spdy_proxy_client_socket.cc b/net/spdy/spdy_proxy_client_socket.cc index 6ef88e7..1b2674d 100644 --- a/net/spdy/spdy_proxy_client_socket.cc +++ b/net/spdy/spdy_proxy_client_socket.cc @@ -63,19 +63,6 @@ const HttpResponseInfo* SpdyProxyClientSocket::GetConnectResponseInfo() const { return response_.headers ? &response_ : NULL; } -int SpdyProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { - // A SPDY Stream can only handle a single request, so the underlying - // stream may not be reused and a new SpdyProxyClientSocket must be - // created (possibly on top of the same SPDY Session). - next_state_ = STATE_DISCONNECTED; - return OK; -} - -const -scoped_refptr<HttpAuthController>& SpdyProxyClientSocket::auth_controller() { - return auth_; -} - HttpStream* SpdyProxyClientSocket::CreateConnectResponseStream() { DCHECK(response_stream_.get()); return response_stream_.release(); @@ -397,16 +384,6 @@ int SpdyProxyClientSocket::DoReadReplyComplete(int result) { if (response_.headers->response_code() == 200) { return OK; } else if (response_.headers->response_code() == 407) { - int rv = HandleAuthChallenge(auth_, &response_, net_log_); - if (rv != ERR_PROXY_AUTH_REQUESTED) { - return rv; - } - // SPDY only supports basic and digest auth - if (auth_->auth_info() && - (auth_->auth_info()->scheme == "basic" || - auth_->auth_info()->scheme == "digest")) { - return ERR_PROXY_AUTH_REQUESTED; - } return ERR_TUNNEL_CONNECTION_FAILED; } else { // Immediately hand off our SpdyStream to a newly created SpdyHttpStream diff --git a/net/spdy/spdy_proxy_client_socket.h b/net/spdy/spdy_proxy_client_socket.h index 9875a05..8a9237b 100644 --- a/net/spdy/spdy_proxy_client_socket.h +++ b/net/spdy/spdy_proxy_client_socket.h @@ -53,11 +53,17 @@ class NET_EXPORT_PRIVATE SpdyProxyClientSocket : public ProxyClientSocket, // On destruction Disconnect() is called. virtual ~SpdyProxyClientSocket(); + const scoped_refptr<HttpAuthController>& auth_controller() { + return auth_; + } + // ProxyClientSocket methods: virtual const HttpResponseInfo* GetConnectResponseInfo() const OVERRIDE; + + // In the event of a non-200 response to the CONNECT request, this + // method may be called to return an HttpStream in order to read + // the response body. virtual HttpStream* CreateConnectResponseStream() OVERRIDE; - virtual int RestartWithAuth(OldCompletionCallback* callback) OVERRIDE; - virtual const scoped_refptr<HttpAuthController>& auth_controller() OVERRIDE; // StreamSocket methods: virtual int Connect(OldCompletionCallback* callback) OVERRIDE; diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc index 89aba7e..323b6db 100644 --- a/net/spdy/spdy_proxy_client_socket_unittest.cc +++ b/net/spdy/spdy_proxy_client_socket_unittest.cc @@ -66,7 +66,6 @@ class SpdyProxyClientSocketTest : public PlatformTest { spdy::SpdyFrame* ConstructConnectAuthRequestFrame(); spdy::SpdyFrame* ConstructConnectReplyFrame(); spdy::SpdyFrame* ConstructConnectAuthReplyFrame(); - spdy::SpdyFrame* ConstructNtlmAuthReplyFrame(); spdy::SpdyFrame* ConstructConnectErrorReplyFrame(); spdy::SpdyFrame* ConstructBodyFrame(const char* data, int length); scoped_refptr<IOBufferWithSize> CreateBuffer(const char* data, int size); @@ -388,26 +387,6 @@ spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectAuthReplyFrame() { arraysize(kStandardReplyHeaders)); } -// Constructs a SPDY SYN_REPLY frame to match the SPDY CONNECT which -// requires Proxy Authentication using NTLM. -spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructNtlmAuthReplyFrame() { - const char* const kStandardReplyHeaders[] = { - "status", "407 Proxy Authentication Required", - "version", "HTTP/1.1", - "proxy-authenticate", "NTLM", - }; - - return ConstructSpdyControlFrame(NULL, - 0, - false, - kStreamId, - LOWEST, - spdy::SYN_REPLY, - spdy::CONTROL_FLAG_NONE, - kStandardReplyHeaders, - arraysize(kStandardReplyHeaders)); -} - // Constructs a SPDY SYN_REPLY frame with an HTTP 500 error. spdy::SpdyFrame* SpdyProxyClientSocketTest::ConstructConnectErrorReplyFrame() { const char* const kStandardReplyHeaders[] = { @@ -454,23 +433,6 @@ TEST_F(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) { AssertConnectionEstablished(); } -TEST_F(SpdyProxyClientSocketTest, ConnectWithUnsupportedAuth) { - scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); - MockWrite writes[] = { - CreateMockWrite(*conn, 0, false), - }; - - scoped_ptr<spdy::SpdyFrame> resp(ConstructNtlmAuthReplyFrame()); - MockRead reads[] = { - CreateMockRead(*resp, 1, true), - MockRead(true, 0, 3), // EOF - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes)); - - AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED); -} - TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) { scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); MockWrite writes[] = { @@ -485,7 +447,7 @@ TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) { Initialize(reads, arraysize(reads), writes, arraysize(writes)); - AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); + AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED); const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); ASSERT_TRUE(response != NULL); @@ -514,38 +476,6 @@ TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) { AssertConnectionEstablished(); } -TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRestart) { - scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); - scoped_ptr<spdy::SpdyFrame> auth(ConstructConnectAuthRequestFrame()); - MockWrite writes[] = { - CreateMockWrite(*conn, 0, false), - }; - - scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectAuthReplyFrame()); - scoped_ptr<spdy::SpdyFrame> auth_resp(ConstructConnectReplyFrame()); - MockRead reads[] = { - CreateMockRead(*resp, 1, true), - MockRead(true, 0, 3), // EOF - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes)); - - AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); - - const HttpResponseInfo* response = sock_->GetConnectResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_EQ(407, response->headers->response_code()); - ASSERT_EQ("Proxy Authentication Required", - response->headers->GetStatusText()); - - AddAuthToCache(); - - ASSERT_EQ(OK, sock_->RestartWithAuth(&read_callback_)); - // A SpdyProxyClientSocket sits on a single SPDY stream which can - // only be used for a single request/response. - ASSERT_FALSE(sock_->IsConnectedAndIdle()); -} - TEST_F(SpdyProxyClientSocketTest, ConnectFails) { scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame()); MockWrite writes[] = { @@ -891,7 +821,7 @@ TEST_F(SpdyProxyClientSocketTest, ReadAuthResponseBody) { Initialize(reads, arraysize(reads), writes, arraysize(writes)); - AssertConnectFails(ERR_PROXY_AUTH_REQUESTED); + AssertConnectFails(ERR_TUNNEL_CONNECTION_FAILED); Run(2); // SpdySession consumes the next two reads and sends then to // sock_ to be buffered. |