Skip to content

Commit

Permalink
Bypass data reduction proxy if response not via it
Browse files Browse the repository at this point in the history
The change verifies that a request sent to the data reduction
proxy has a corresponding response that contains the data
reduction proxy's Via header.

BUG=335633

Review URL: https://codereview.chromium.org/144653007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249184 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
bengr@chromium.org committed Feb 6, 2014
1 parent 2592f18 commit 59ca4da
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 9 deletions.
74 changes: 67 additions & 7 deletions net/http/http_network_layer_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ class HttpNetworkLayerTest : public PlatformTest {
const std::string& bad_proxy2) {
const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info();
ASSERT_EQ(proxy_count, retry_info.size());
ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end());
if (proxy_count > 0)
ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end());
if (proxy_count > 1)
ASSERT_TRUE(retry_info.find(bad_proxy2) != retry_info.end());
}
Expand Down Expand Up @@ -135,7 +136,7 @@ class HttpNetworkLayerTest : public PlatformTest {
MockRead data_reads[],
int data_reads_size,
std::string method,
std::string content,
std::string content_of_retry,
bool retry_expected,
unsigned int expected_retry_info_size) {
std::string trailer =
Expand All @@ -160,8 +161,8 @@ class HttpNetworkLayerTest : public PlatformTest {
size_t data_reads2_index = 0;
data_reads2[data_reads2_index++] = MockRead("HTTP/1.0 200 OK\r\n"
"Server: not-proxy\r\n\r\n");
if (!content.empty())
data_reads2[data_reads2_index++] = MockRead(content.c_str());
if (!content_of_retry.empty())
data_reads2[data_reads2_index++] = MockRead(content_of_retry.c_str());
data_reads2[data_reads2_index++] = MockRead(SYNCHRONOUS, OK);

MockWrite data_writes2[] = {
Expand All @@ -174,7 +175,7 @@ class HttpNetworkLayerTest : public PlatformTest {
// Expect that we get "content" and not "Bypass message", and that there's
// a "not-proxy" "Server:" header in the final response.
if (retry_expected) {
ExecuteRequestExpectingContentAndHeader(method, content,
ExecuteRequestExpectingContentAndHeader(method, content_of_retry,
"server", "not-proxy");
} else {
ExecuteRequestExpectingContentAndHeader(method, "Bypass message", "", "");
Expand Down Expand Up @@ -621,7 +622,8 @@ TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: keep-alive\r\n"
"Chrome-Proxy: bypass=86400\r\n\r\n"),
"Chrome-Proxy: bypass=86400\r\n"
"Via: 1.1 Chrome Compression Proxy\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
Expand All @@ -632,6 +634,63 @@ TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
(*proxy_service_->proxy_retry_info().begin()).second.current_delay);
}

TEST_F(HttpNetworkLayerTest, ServerFallbackWithWrongViaHeader) {
// Verify that a Via header that lacks the Chrome-Proxy induces proxy fallback
// to a second proxy, if configured.
std::string chrome_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
"PROXY " + chrome_proxy + "; PROXY good:8080"));

MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: keep-alive\r\n"
"Via: 1.0 some-other-proxy\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};

TestProxyFallbackWithMockReads(chrome_proxy, std::string(), data_reads,
arraysize(data_reads), 1u);
}

TEST_F(HttpNetworkLayerTest, ServerFallbackWithNoViaHeader) {
// Verify that the lack of a Via header induces proxy fallback to a second
// proxy, if configured.
std::string chrome_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
"PROXY " + chrome_proxy + "; PROXY good:8080"));

MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: keep-alive\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};

TestProxyFallbackWithMockReads(chrome_proxy, std::string(), data_reads,
arraysize(data_reads), 1u);
}

TEST_F(HttpNetworkLayerTest, NoServerFallbackWithChainedViaHeader) {
// Verify that Chrome will not be induced to bypass the Chrome proxy when
// the Chrome Proxy via header is present, even if that header is chained.
std::string chrome_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
"PROXY " + chrome_proxy + "; PROXY good:8080"));

MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: keep-alive\r\n"
"Via: 1.1 Chrome Compression Proxy, 1.0 some-other-proxy\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};

TestProxyFallbackByMethodWithMockReads(chrome_proxy, std::string(),
data_reads, arraysize(data_reads),
"GET", std::string(), false, 0);
}

#if defined(DATA_REDUCTION_FALLBACK_HOST)
TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypassAll) {
// Verify that a Chrome-Proxy: block=<seconds> header bypasses a
Expand All @@ -646,7 +705,8 @@ TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypassAll) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: keep-alive\r\n"
"Chrome-Proxy: block=86400\r\n\r\n"),
"Chrome-Proxy: block=86400\r\n"
"Via: 1.1 Chrome Compression Proxy\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
Expand Down
31 changes: 29 additions & 2 deletions net/http/http_network_transaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "url/gurl.h"

#if defined(SPDY_PROXY_AUTH_ORIGIN)
#include <algorithm>
#include "net/proxy/proxy_server.h"
#endif

Expand Down Expand Up @@ -118,6 +119,30 @@ base::Value* NetLogSSLVersionFallbackCallback(
return dict;
}

#if defined(SPDY_PROXY_AUTH_ORIGIN)
// Returns true if |response_headers| contains the data reduction proxy Via
// header value.
bool IsChromeProxyResponse(const net::HttpResponseHeaders* response_headers) {
if (!response_headers) {
return false;
}
const char kDataReductionProxyViaValue[] = "1.1 Chrome Compression Proxy";
size_t value_len = strlen(kDataReductionProxyViaValue);
void* iter = NULL;
std::string temp;
while (response_headers->EnumerateHeader(&iter, "Via", &temp)) {
std::string::const_iterator it =
std::search(temp.begin(), temp.end(),
kDataReductionProxyViaValue,
kDataReductionProxyViaValue + value_len,
base::CaseInsensitiveCompareASCII<char>());
if (it != temp.end())
return true;
}
return false;
}
#endif

} // namespace

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1018,14 +1043,16 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
#endif

if (chrome_proxy_used || chrome_fallback_proxy_used) {
if (response_.headers->GetChromeProxyInfo(&chrome_proxy_info)) {
if (!IsChromeProxyResponse(response_.headers.get())) {
proxy_bypass_event = ProxyService::MISSING_VIA_HEADER;
} else if (response_.headers->GetChromeProxyInfo(&chrome_proxy_info)) {
if (chrome_proxy_info.bypass_duration < TimeDelta::FromMinutes(30))
proxy_bypass_event = ProxyService::SHORT_BYPASS;
else
proxy_bypass_event = ProxyService::LONG_BYPASS;
} else {
// Additionally, fallback if a 500, 502 or 503 is returned via the data
// reduction proxy. This is conservative, as the 500, 501 or 502 might
// reduction proxy. This is conservative, as the 500, 502 or 503 might
// have been generated by the origin, and not the proxy.
if (response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR ||
response_.headers->response_code() == HTTP_BAD_GATEWAY ||
Expand Down
3 changes: 3 additions & 0 deletions net/proxy/proxy_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
// Bypass the proxy because of any other error.
ERROR_BYPASS,

// Bypass the proxy because responses appear not to be coming via it.
MISSING_VIA_HEADER,

// This must always be last.
BYPASS_EVENT_TYPE_MAX
};
Expand Down
1 change: 1 addition & 0 deletions tools/metrics/histograms/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23265,6 +23265,7 @@ other types of suffix sets.
<int value="1" label="Long bypass"/>
<int value="2" label="Bypass due to internal server error"/>
<int value="3" label="Bypass due to other error"/>
<int value="4" label="Bypass due to missing via header"/>
</enum>

<enum name="DataReductionProxyProbeURLFetchResult" type="int">
Expand Down

0 comments on commit 59ca4da

Please sign in to comment.