summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/net_error_list.h3
-rw-r--r--net/http/http_network_transaction.cc15
-rw-r--r--net/http/http_network_transaction_unittest.cc59
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".