diff options
author | piatek@google.com <piatek@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-16 19:51:29 +0000 |
---|---|---|
committer | piatek@google.com <piatek@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-16 19:51:29 +0000 |
commit | 14b7e9a496852c1b869749c506d3576fcc6fcf96 (patch) | |
tree | fd541296e6d96b082b8bf5f05d30b3125cf510e2 /net/http | |
parent | f57c14b47cfde98b062f2d40679fa3d2fc88fb82 (diff) | |
download | chromium_src-14b7e9a496852c1b869749c506d3576fcc6fcf96.zip chromium_src-14b7e9a496852c1b869749c506d3576fcc6fcf96.tar.gz chromium_src-14b7e9a496852c1b869749c506d3576fcc6fcf96.tar.bz2 |
Receiving Connection: Proxy-Bypass induces proxy fallback.
BUG=143712
Review URL: https://chromiumcodereview.appspot.com/10987043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@162218 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_network_layer_unittest.cc | 185 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 17 |
2 files changed, 197 insertions, 5 deletions
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc index a82dd00..0891724 100644 --- a/net/http/http_network_layer_unittest.cc +++ b/net/http/http_network_layer_unittest.cc @@ -23,10 +23,15 @@ namespace { class HttpNetworkLayerTest : public PlatformTest { protected: - HttpNetworkLayerTest() - : cert_verifier_(new MockCertVerifier), - proxy_service_(ProxyService::CreateDirect()), - ssl_config_service_(new SSLConfigServiceDefaults) { + HttpNetworkLayerTest() : ssl_config_service_(new SSLConfigServiceDefaults) {} + + virtual void SetUp() { + ConfigureTestDependencies(ProxyService::CreateDirect()); + } + + void ConfigureTestDependencies(ProxyService* proxy_service) { + cert_verifier_.reset(new MockCertVerifier); + proxy_service_.reset(proxy_service); HttpNetworkSession::Params session_params; session_params.client_socket_factory = &mock_socket_factory_; session_params.host_resolver = &host_resolver_; @@ -41,7 +46,7 @@ class HttpNetworkLayerTest : public PlatformTest { MockClientSocketFactory mock_socket_factory_; MockHostResolver host_resolver_; scoped_ptr<CertVerifier> cert_verifier_; - const scoped_ptr<ProxyService> proxy_service_; + scoped_ptr<ProxyService> proxy_service_; const scoped_refptr<SSLConfigService> ssl_config_service_; scoped_refptr<HttpNetworkSession> network_session_; scoped_ptr<HttpNetworkLayer> factory_; @@ -115,6 +120,176 @@ TEST_F(HttpNetworkLayerTest, GET) { EXPECT_EQ("hello world", contents); } +TEST_F(HttpNetworkLayerTest, ServerFallback) { + // Verify that a Connection: Proxy-Bypass header induces proxy fallback to + // a second proxy, if configured. + + // To configure this test, we need to wire up a custom proxy service to use + // a pair of proxies. We'll induce fallback via the first and return + // the expected data via the second. + ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( + "PROXY bad:8080; PROXY good:8080")); + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: proxy-bypass\r\n\r\n"), + MockRead("Bypass message"), + MockRead(SYNCHRONOUS, OK), + }; + MockWrite data_writes[] = { + 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"), + }; + StaticSocketDataProvider data1(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + mock_socket_factory_.AddSocketDataProvider(&data1); + + // Second data provider returns the expected content. + MockRead data_reads2[] = { + MockRead("HTTP/1.0 200 OK\r\n" + "Server: not-proxy\r\n\r\n"), + MockRead("content"), + MockRead(SYNCHRONOUS, OK), + }; + MockWrite data_writes2[] = { + 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"), + }; + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), + data_writes2, arraysize(data_writes2)); + mock_socket_factory_.AddSocketDataProvider(&data2); + + TestCompletionCallback callback; + + HttpRequestInfo request_info; + request_info.url = GURL("http://www.google.com/"); + request_info.method = "GET"; + request_info.load_flags = LOAD_NORMAL; + + scoped_ptr<HttpTransaction> trans; + int rv = factory_->CreateTransaction(&trans, NULL); + EXPECT_EQ(OK, rv); + + rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); + if (rv == ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(OK, rv); + + std::string contents; + rv = ReadTransaction(trans.get(), &contents); + EXPECT_EQ(OK, rv); + + // We should obtain content from the second socket provider write + // corresponding to the fallback proxy. + EXPECT_EQ("content", contents); + // We also have a server header here that isn't set by the proxy. + EXPECT_TRUE(trans->GetResponseInfo()->headers->HasHeaderValue( + "server", "not-proxy")); + // We should also observe the bad proxy in the retry list. + ASSERT_TRUE(1u == proxy_service_->proxy_retry_info().size()); + EXPECT_EQ("bad:8080", (*proxy_service_->proxy_retry_info().begin()).first); +} + +TEST_F(HttpNetworkLayerTest, ServerFallbackDoesntLoop) { + // Verify that a Connection: Proxy-Bypass header will display the original + // proxy's error page content if a fallback option is not configured. + ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult( + "PROXY bad:8080; PROXY alsobad:8080")); + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: proxy-bypass\r\n\r\n"), + MockRead("Bypass message"), + MockRead(SYNCHRONOUS, OK), + }; + MockWrite data_writes[] = { + 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"), + }; + StaticSocketDataProvider data1(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + StaticSocketDataProvider data2(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + mock_socket_factory_.AddSocketDataProvider(&data1); + mock_socket_factory_.AddSocketDataProvider(&data2); + + TestCompletionCallback callback; + + HttpRequestInfo request_info; + request_info.url = GURL("http://www.google.com/"); + request_info.method = "GET"; + request_info.load_flags = LOAD_NORMAL; + + scoped_ptr<HttpTransaction> trans; + int rv = factory_->CreateTransaction(&trans, NULL); + EXPECT_EQ(OK, rv); + + rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); + if (rv == ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(OK, rv); + + std::string contents; + rv = ReadTransaction(trans.get(), &contents); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Bypass message", contents); + + // Despite not falling back to anything, we should still observe the proxies + // in the bad proxies list. + const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info(); + ASSERT_EQ(2u, retry_info.size()); + ASSERT_TRUE(retry_info.find("bad:8080") != retry_info.end()); + ASSERT_TRUE(retry_info.find("alsobad:8080") != retry_info.end()); +} + +TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnection) { + // Verify that a Connection: proxy-bypass header is ignored when returned + // from a directly connected origin server. + ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult("DIRECT")); + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n" + "Connection: proxy-bypass\r\n\r\n"), + MockRead("Bypass message"), + MockRead(SYNCHRONOUS, OK), + }; + MockWrite data_writes[] = { + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + StaticSocketDataProvider data1(data_reads, arraysize(data_reads), + data_writes, arraysize(data_writes)); + mock_socket_factory_.AddSocketDataProvider(&data1); + TestCompletionCallback callback; + + HttpRequestInfo request_info; + request_info.url = GURL("http://www.google.com/"); + request_info.method = "GET"; + request_info.load_flags = LOAD_NORMAL; + + scoped_ptr<HttpTransaction> trans; + int rv = factory_->CreateTransaction(&trans, NULL); + EXPECT_EQ(OK, rv); + + rv = trans->Start(&request_info, callback.callback(), BoundNetLog()); + if (rv == ERR_IO_PENDING) + rv = callback.WaitForResult(); + ASSERT_EQ(OK, rv); + + // We should have read the original page data. + std::string contents; + rv = ReadTransaction(trans.get(), &contents); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Bypass message", contents); + + // We should have no entries in our bad proxy list. + ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size()); +} + } // namespace } // namespace net diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index dd538e2..df1d8fc 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -862,6 +862,23 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { } DCHECK(response_.headers); + // Server-induced fallback is supported only if this is a PAC configured + // proxy. See: http://crbug.com/143712 + if (response_.was_fetched_via_proxy && proxy_info_.did_use_pac_script()) { + if (response_.headers != NULL && + response_.headers->HasHeaderValue("connection", "proxy-bypass")) { + ProxyService* proxy_service = session_->proxy_service(); + if (proxy_service->MarkProxyAsBad(proxy_info_, net_log_)) { + // Only retry in the case of GETs. We don't want to resubmit a POST + // if the proxy took some action. + if (request_->method == "GET") { + ResetConnectionAndRequestForResend(); + return OK; + } + } + } + } + // Like Net.HttpResponseCode, but only for MAIN_FRAME loads. if (request_->load_flags & LOAD_MAIN_FRAME) { const int response_code = response_.headers->response_code(); |