diff options
-rw-r--r-- | net/base/net_error_list.h | 3 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 15 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 59 |
3 files changed, 74 insertions, 3 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 31d27d7..9cc2205 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -96,8 +96,7 @@ NET_ERROR(SSL_VERSION_OR_CIPHER_MISMATCH, -113) // The server requested a renegotiation (rehandshake). NET_ERROR(SSL_RENEGOTIATION_REQUESTED, -114) -// The proxy claimed to want authenication but didn't provide the proper -// challenge headers. +// The proxy requested authentication (for tunnel establishment). NET_ERROR(PROXY_AUTH_REQUESTED, -115) // Certificate error codes diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 93b5a5d..95c0aef 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -207,6 +207,17 @@ int HttpNetworkTransaction::Read(IOBuffer* buf, int buf_len, if (!connection_.is_initialized()) return 0; // connection_ has been reset. Treat like EOF. + if (establishing_tunnel_) { + // We're trying to read the body of the response but we're still trying to + // establish an SSL tunnel through the proxy. We can't read these bytes + // when establishing a tunnel because they might be controlled by an active + // network attacker. We don't worry about this for HTTP because an active + // network attacker can already control HTTP sessions. + // We reach this case when the user cancels a 407 proxy auth prompt. + // See http://crbug.com/8473 + return ERR_TUNNEL_CONNECTION_FAILED; + } + read_buf_ = buf; read_buf_len_ = buf_len; @@ -1002,7 +1013,9 @@ int HttpNetworkTransaction::DidReadResponseHeaders() { // domain name does not exist." LOG(WARNING) << "Blocked proxy response to CONNECT request with status " << - headers->response_code() << "."; + headers->response_code() << " for " << + request_->url.host() << ":" << + request_->url.EffectiveIntPort() << "."; return ERR_TUNNEL_CONNECTION_FAILED; } } diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index e73fc45..337f6c7 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1159,6 +1159,65 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { EXPECT_EQ(L"basic", response->auth_challenge->scheme); } +// Test that we don't read the response body when we fail to establish a tunnel, +// even if the user cancels the proxy's auth attempt. +TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { + // Configure against proxy server "myproxy:70". + scoped_ptr<net::ProxyService> proxy_service( + CreateFixedProxyService("myproxy:70")); + + scoped_refptr<net::HttpNetworkSession> session( + CreateSession(proxy_service.get())); + + scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction( + session.get(), &mock_socket_factory)); + + net::HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + request.load_flags = 0; + + // Since we have proxy, should try to establish tunnel. + MockWrite data_writes[] = { + MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" + "Host: www.google.com\r\n\r\n"), + }; + + // The proxy responds to the connect with a 407. + MockRead data_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(false, net::ERR_UNEXPECTED), // Should not be reached. + }; + + MockSocket data; + data.writes = data_writes; + data.reads = data_reads; + mock_sockets[0] = &data; + mock_sockets[1] = NULL; + + TestCompletionCallback callback; + + int rv = trans->Start(&request, &callback); + EXPECT_EQ(net::ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(net::OK, rv); + + const net::HttpResponseInfo* response = trans->GetResponseInfo(); + EXPECT_FALSE(response == NULL); + + EXPECT_TRUE(response->headers->IsKeepAlive()); + EXPECT_EQ(407, response->headers->response_code()); + EXPECT_EQ(10, response->headers->GetContentLength()); + EXPECT_TRUE(net::HttpVersion(1, 1) == response->headers->GetHttpVersion()); + + std::string response_data; + rv = ReadTransaction(trans.get(), &response_data); + EXPECT_EQ(net::ERR_TUNNEL_CONNECTION_FAILED, rv); +} + static void ConnectStatusHelperWithExpectedStatus( const MockRead& status, int expected_status) { // Configure against proxy server "myproxy:70". |