summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-13 13:17:15 +0000
committerbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-13 13:17:15 +0000
commitd8fc4720c06d9e57d5fd98d6d6b723fffddbe159 (patch)
tree665d9568104f3bfe1330e7d7b567cbe8c5d003d3 /components
parenta2d6ed8e40f2747490558f311c438fa0245d262a (diff)
downloadchromium_src-d8fc4720c06d9e57d5fd98d6d6b723fffddbe159.zip
chromium_src-d8fc4720c06d9e57d5fd98d6d6b723fffddbe159.tar.gz
chromium_src-d8fc4720c06d9e57d5fd98d6d6b723fffddbe159.tar.bz2
Moved data reduction proxy bypass logic to a NetworkDelegate
BUG=367221 Review URL: https://codereview.chromium.org/286903018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277009 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/components_tests.gyp1
-rw-r--r--components/data_reduction_proxy.gypi2
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_params.cc56
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_params.h33
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc83
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc155
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h59
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc670
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc4
-rw-r--r--components/data_reduction_proxy/browser/data_reduction_proxy_settings.h72
10 files changed, 1094 insertions, 41 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 8e5cc53..7129e06 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -76,6 +76,7 @@
'data_reduction_proxy/browser/data_reduction_proxy_config_service_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_metrics_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc',
+ 'data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc',
'data_reduction_proxy/browser/data_reduction_proxy_settings_unittest.cc',
'data_reduction_proxy/browser/http_auth_handler_data_reduction_proxy_unittest.cc',
'dom_distiller/core/article_entry_unittest.cc',
diff --git a/components/data_reduction_proxy.gypi b/components/data_reduction_proxy.gypi
index bfe50a2..89eced8 100644
--- a/components/data_reduction_proxy.gypi
+++ b/components/data_reduction_proxy.gypi
@@ -30,6 +30,8 @@
'data_reduction_proxy/browser/data_reduction_proxy_params.h',
'data_reduction_proxy/browser/data_reduction_proxy_prefs.cc',
'data_reduction_proxy/browser/data_reduction_proxy_prefs.h',
+ 'data_reduction_proxy/browser/data_reduction_proxy_protocol.cc',
+ 'data_reduction_proxy/browser/data_reduction_proxy_protocol.h',
'data_reduction_proxy/browser/data_reduction_proxy_settings.cc',
'data_reduction_proxy/browser/data_reduction_proxy_settings.h',
'data_reduction_proxy/browser/http_auth_handler_data_reduction_proxy.cc',
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_params.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_params.cc
index f1c0ab5..16e0d20 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_params.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/metrics/field_trial.h"
#include "components/data_reduction_proxy/common/data_reduction_proxy_switches.h"
+#include "net/url_request/url_request.h"
using base::FieldTrialList;
@@ -25,7 +26,7 @@ bool DataReductionProxyParams::IsIncludedInFieldTrial() {
// static
bool DataReductionProxyParams::IsIncludedInAlternativeFieldTrial() {
return base::FieldTrialList::FindFullName(
- "DataCompressionProxyAlternativeConfiguration") == kEnabled;
+ "DataCompressionProxyAlternativeConfiguration") == kEnabled;
}
// static
@@ -225,6 +226,59 @@ void DataReductionProxyParams::InitWithoutChecks() {
}
+bool DataReductionProxyParams::WasDataReductionProxyUsed(
+ const net::URLRequest* request,
+ std::pair<GURL, GURL>* proxy_servers) const {
+ DCHECK(request);
+ return IsDataReductionProxy(request->proxy_server(), proxy_servers);
+}
+
+bool DataReductionProxyParams::IsDataReductionProxy(
+ const net::HostPortPair& host_port_pair,
+ std::pair<GURL, GURL>* proxy_servers) const {
+ if (net::HostPortPair::FromURL(origin()).Equals(host_port_pair)) {
+ if (proxy_servers) {
+ (*proxy_servers).first = origin();
+ if (fallback_allowed())
+ (*proxy_servers).second = fallback_origin();
+ }
+ return true;
+ }
+ if (fallback_allowed() &&
+ net::HostPortPair::FromURL(fallback_origin()).Equals(host_port_pair)) {
+ if (proxy_servers) {
+ (*proxy_servers).first = fallback_origin();
+ (*proxy_servers).second = GURL();
+ }
+ return true;
+ }
+ if (net::HostPortPair::FromURL(alt_origin()).Equals(host_port_pair)) {
+ if (proxy_servers) {
+ (*proxy_servers).first = alt_origin();
+ if (fallback_allowed())
+ (*proxy_servers).second = alt_fallback_origin();
+ }
+ return true;
+ }
+ if (fallback_allowed() &&
+ net::HostPortPair::FromURL(alt_fallback_origin()).Equals(
+ host_port_pair)) {
+ if (proxy_servers) {
+ (*proxy_servers).first = alt_fallback_origin();
+ (*proxy_servers).second = GURL();
+ }
+ return true;
+ }
+ if (net::HostPortPair::FromURL(ssl_origin()).Equals(host_port_pair)) {
+ if (proxy_servers) {
+ (*proxy_servers).first = ssl_origin();
+ (*proxy_servers).second = GURL();
+ }
+ return true;
+ }
+ return false;
+}
+
std::string DataReductionProxyParams::GetDefaultKey() const {
#if defined(SPDY_PROXY_AUTH_VALUE)
return SPDY_PROXY_AUTH_VALUE;
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_params.h b/components/data_reduction_proxy/browser/data_reduction_proxy_params.h
index 7eaf4a4..0285001 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_params.h
@@ -5,19 +5,27 @@
#ifndef COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_PARAMS_H_
#define COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_PARAMS_H_
+#include <string>
+#include <utility>
#include <vector>
#include "base/macros.h"
+#include "net/base/host_port_pair.h"
#include "url/gurl.h"
-namespace data_reduction_proxy {
+namespace net {
+class URLRequest;
+}
+namespace data_reduction_proxy {
// Provides initialization parameters. Proxy origins, the probe url, and the
// authentication key are taken from flags if available and from preprocessor
-// constants otherwise. Only the key may be changed after construction.
+// constants otherwise. Only the key may be changed after construction. The
+// DataReductionProxySettings class and others use this class to determine
+// the necessary DNS names and keys to configure use of the data reduction
+// proxy.
class DataReductionProxyParams {
public:
-
static const unsigned int kAllowed = (1 << 0);
static const unsigned int kFallbackAllowed = (1 << 1);
static const unsigned int kAlternativeAllowed = (1 << 2);
@@ -61,6 +69,25 @@ class DataReductionProxyParams {
virtual ~DataReductionProxyParams();
+ // Returns true if a data reduction proxy was used for the given |request|.
+ // If true, |proxy_servers.first| will contain the name of the proxy that was
+ // used. |proxy_servers.second| will contain the name of the data reduction
+ // proxy server that would be used if |proxy_server.first| is bypassed, if one
+ // exists. |proxy_servers| can be NULL if the caller isn't interested in its
+ // values.
+ virtual bool WasDataReductionProxyUsed(
+ const net::URLRequest* request,
+ std::pair<GURL, GURL>* proxy_servers) const;
+
+ // Returns true if the specified |host_port_pair| matches a data reduction
+ // proxy. If true, |proxy_servers.first| will contain the name of the proxy
+ // that matches. |proxy_servers.second| will contain the name of the
+ // data reduction proxy server that would be used if |proxy_server.first| is
+ // bypassed, if one exists. |proxy_servers| can be NULL if the caller isn't
+ // interested in its values.
+ bool IsDataReductionProxy(const net::HostPortPair& host_port_pair,
+ std::pair<GURL, GURL>* proxy_servers) const;
+
// Returns the data reduction proxy primary origin.
const GURL& origin() const {
return origin_;
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc
index 37cb3bb..725acf1 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_params_unittest.cc
@@ -42,6 +42,7 @@ static const unsigned int HAS_EVERYTHING = 0xff;
} // namespace
namespace data_reduction_proxy {
+namespace {
class TestDataReductionProxyParams : public DataReductionProxyParams {
public:
@@ -101,6 +102,7 @@ class TestDataReductionProxyParams : public DataReductionProxyParams {
unsigned int has_definitions_;
bool init_result_;
};
+} // namespace
class DataReductionProxyParamsTest : public testing::Test {
public:
@@ -292,4 +294,85 @@ TEST_F(DataReductionProxyParamsTest, InvalidConfigurations) {
}
}
+TEST_F(DataReductionProxyParamsTest, IsDataReductionProxy) {
+ const struct {
+ net::HostPortPair host_port_pair;
+ bool fallback_allowed;
+ bool expected_result;
+ net::HostPortPair expected_first;
+ net::HostPortPair expected_second;
+ } tests[] = {
+ { net::HostPortPair::FromURL(GURL(kDefaultOrigin)),
+ true,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultOrigin)),
+ net::HostPortPair::FromURL(GURL(kDefaultFallbackOrigin))
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultOrigin)),
+ false,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultOrigin)),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultFallbackOrigin)),
+ true,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultFallbackOrigin)),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultFallbackOrigin)),
+ false,
+ false,
+ net::HostPortPair::FromURL(GURL()),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultAltOrigin)),
+ true,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultAltOrigin)),
+ net::HostPortPair::FromURL(GURL(kDefaultAltFallbackOrigin))
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultAltOrigin)),
+ false,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultAltOrigin)),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultAltFallbackOrigin)),
+ true,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultAltFallbackOrigin)),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultAltFallbackOrigin)),
+ false,
+ false,
+ net::HostPortPair::FromURL(GURL()),
+ net::HostPortPair::FromURL(GURL())
+ },
+ { net::HostPortPair::FromURL(GURL(kDefaultSSLOrigin)),
+ true,
+ true,
+ net::HostPortPair::FromURL(GURL(kDefaultSSLOrigin)),
+ net::HostPortPair::FromURL(GURL())
+ },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ int flags = DataReductionProxyParams::kAllowed |
+ DataReductionProxyParams::kAlternativeAllowed;
+ if (tests[i].fallback_allowed)
+ flags |= DataReductionProxyParams::kFallbackAllowed;
+ TestDataReductionProxyParams params(flags,
+ HAS_EVERYTHING & ~HAS_DEV_ORIGIN);
+ std::pair<GURL, GURL> proxy_servers;
+ EXPECT_EQ(tests[i].expected_result,
+ params.IsDataReductionProxy(
+ tests[i].host_port_pair, &proxy_servers));
+ EXPECT_TRUE(tests[i].expected_first.Equals(
+ net::HostPortPair::FromURL(proxy_servers.first)));
+ EXPECT_TRUE(tests[i].expected_second.Equals(
+ net::HostPortPair::FromURL(proxy_servers.second)));
+ }
+}
+
} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc
new file mode 100644
index 0000000..c050e40
--- /dev/null
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.cc
@@ -0,0 +1,155 @@
+// Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_response_headers.h"
+#include "net/proxy/proxy_info.h"
+#include "net/proxy/proxy_list.h"
+#include "net/proxy/proxy_server.h"
+#include "net/proxy/proxy_service.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "url/gurl.h"
+
+namespace {
+bool SetProxyServerFromGURL(const GURL& gurl,
+ net::ProxyServer* proxy_server) {
+ DCHECK(proxy_server);
+ if (!gurl.SchemeIsHTTPOrHTTPS())
+ return false;
+ *proxy_server = net::ProxyServer(gurl.SchemeIs("http") ?
+ net::ProxyServer::SCHEME_HTTP :
+ net::ProxyServer::SCHEME_HTTPS,
+ net::HostPortPair::FromURL(gurl));
+ return true;
+}
+} // namespace
+
+namespace data_reduction_proxy {
+
+bool MaybeBypassProxyAndPrepareToRetry(
+ const DataReductionProxyParams* data_reduction_proxy_params,
+ net::URLRequest* request,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
+ if (!data_reduction_proxy_params)
+ return false;
+ std::pair<GURL, GURL> data_reduction_proxies;
+ if (!data_reduction_proxy_params->WasDataReductionProxyUsed(
+ request, &data_reduction_proxies)) {
+ return false;
+ }
+
+ // Empty implies either that the request was served from cache or that
+ // request was served directly from the origin.
+ if (request->proxy_server().IsEmpty())
+ return false;
+
+ if (data_reduction_proxies.first.is_empty())
+ return false;
+
+ net::HttpResponseHeaders::DataReductionProxyInfo data_reduction_proxy_info;
+ net::ProxyService::DataReductionProxyBypassEventType bypass_type =
+ original_response_headers->GetDataReductionProxyBypassEventType(
+ &data_reduction_proxy_info);
+
+ if (bypass_type == net::ProxyService::BYPASS_EVENT_TYPE_MAX) {
+ return false;
+ }
+
+ DCHECK(request->context());
+ DCHECK(request->context()->proxy_service());
+ net::ProxyServer proxy_server;
+ SetProxyServerFromGURL(data_reduction_proxies.first, &proxy_server);
+ request->context()->proxy_service()->RecordDataReductionProxyBypassInfo(
+ !data_reduction_proxies.second.is_empty(), proxy_server, bypass_type);
+
+ MarkProxiesAsBadUntil(request,
+ data_reduction_proxy_info.bypass_duration,
+ data_reduction_proxy_info.bypass_all,
+ data_reduction_proxies);
+
+ // Only retry idempotent methods.
+ if (!IsRequestIdempotent(request))
+ return false;
+
+ OverrideResponseAsRedirect(request,
+ original_response_headers,
+ override_response_headers);
+ return true;
+}
+
+
+
+bool IsRequestIdempotent(const net::URLRequest* request) {
+ DCHECK(request);
+ if (request->method() == "GET" ||
+ request->method() == "OPTIONS" ||
+ request->method() == "HEAD" ||
+ request->method() == "PUT" ||
+ request->method() == "DELETE" ||
+ request->method() == "TRACE")
+ return true;
+ return false;
+}
+
+void OverrideResponseAsRedirect(
+ net::URLRequest* request,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
+ DCHECK(request);
+ DCHECK(original_response_headers);
+ DCHECK(override_response_headers->get() == NULL);
+
+ request->SetLoadFlags(request->load_flags() |
+ net::LOAD_DISABLE_CACHE |
+ net::LOAD_BYPASS_PROXY);
+ *override_response_headers = new net::HttpResponseHeaders(
+ original_response_headers->raw_headers());
+ (*override_response_headers)->ReplaceStatusLine("HTTP/1.1 302 Found");
+ (*override_response_headers)->RemoveHeader("Location");
+ (*override_response_headers)->AddHeader("Location: " +
+ request->url().spec());
+ // TODO(bengr): Should we pop_back the request->url_chain?
+}
+
+void MarkProxiesAsBadUntil(
+ net::URLRequest* request,
+ base::TimeDelta& bypass_duration,
+ bool bypass_all,
+ const std::pair<GURL, GURL>& data_reduction_proxies) {
+ DCHECK(!data_reduction_proxies.first.is_empty());
+ // Synthesize a suitable |ProxyInfo| to add the proxies to the
+ // |ProxyRetryInfoMap| of the proxy service.
+ net::ProxyList proxy_list;
+ net::ProxyServer primary;
+ SetProxyServerFromGURL(data_reduction_proxies.first, &primary);
+ if (primary.is_valid())
+ proxy_list.AddProxyServer(primary);
+ net::ProxyServer fallback;
+ if (bypass_all) {
+ if (!data_reduction_proxies.second.is_empty())
+ SetProxyServerFromGURL(data_reduction_proxies.second, &fallback);
+ if (fallback.is_valid())
+ proxy_list.AddProxyServer(fallback);
+ proxy_list.AddProxyServer(net::ProxyServer::Direct());
+ }
+ net::ProxyInfo proxy_info;
+ proxy_info.UseProxyList(proxy_list);
+ DCHECK(request->context());
+ net::ProxyService* proxy_service = request->context()->proxy_service();
+ DCHECK(proxy_service);
+
+ proxy_service->MarkProxiesAsBadUntil(proxy_info,
+ bypass_duration,
+ fallback,
+ request->net_log());
+}
+
+} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h
new file mode 100644
index 0000000..4c28498
--- /dev/null
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h
@@ -0,0 +1,59 @@
+// Copyright 2014 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.
+
+#ifndef COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_PROTOCOL_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_PROTOCOL_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+class TimeDelta;
+}
+
+namespace net {
+class HttpResponseHeaders;
+class ProxyServer;
+class URLRequest;
+}
+
+class GURL;
+
+namespace data_reduction_proxy {
+
+class DataReductionProxyParams;
+
+// Decides whether to mark the data reduction proxy as temporarily bad and
+// put it on the proxy retry list. Returns true if the request should be
+// retried. Sets |override_response_headers| to redirect if so.
+bool MaybeBypassProxyAndPrepareToRetry(
+ const DataReductionProxyParams* params,
+ net::URLRequest* request,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers);
+
+// Returns true if the request method is idempotent. Only idempotent requests
+// are retried on a bypass. Visible as part of the public API for testing.
+bool IsRequestIdempotent(const net::URLRequest* request);
+
+// Sets the override headers to contain a status line that indicates a
+// redirect (a 302), a "Location:" header that points to the request url,
+// and sets load flags to bypass proxies. Visible as part of the public API for
+// testing.
+void OverrideResponseAsRedirect(
+ net::URLRequest* request,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers);
+
+// Adds non-empty entries in |data_reduction_proxies| to the retry map
+// maintained by the proxy service of the request. Adds
+// |data_reduction_proxies.second| to the retry list only if |bypass_all| is
+// true. Visible as part of the public API for testing.
+void MarkProxiesAsBadUntil(net::URLRequest* request,
+ base::TimeDelta& bypass_duration,
+ bool bypass_all,
+ const std::pair<GURL, GURL>& data_reduction_proxies);
+
+} // namespace data_reduction_proxy
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_PROTOCOL_H_
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc
new file mode 100644
index 0000000..fb732f8
--- /dev/null
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_protocol_unittest.cc
@@ -0,0 +1,670 @@
+// Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
+
+#include <utility>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
+#include "net/base/completion_callback.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/network_delegate.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/http_transaction_test_util.h"
+#include "net/socket/socket_test_util.h"
+#include "net/ssl/ssl_config_service.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::HttpNetworkLayer;
+using net::HttpNetworkSession;
+using net::HttpResponseHeaders;
+using net::HostPortPair;
+using net::MockRead;
+using net::MockWrite;
+using net::ProxyRetryInfoMap;
+using net::ProxyService;
+using net::StaticSocketDataProvider;
+using net::TestDelegate;
+using net::TransportSecurityState;
+using net::URLRequest;
+using net::URLRequestContext;
+
+
+namespace {
+// Transform "normal"-looking headers (\n-separated) to the appropriate
+// input format for ParseRawHeaders (\0-separated).
+void HeadersToRaw(std::string* headers) {
+ std::replace(headers->begin(), headers->end(), '\n', '\0');
+ if (!headers->empty())
+ *headers += '\0';
+}
+
+std::string GetDataReductionProxy() {
+ return "https://proxy1.com:443/";
+}
+
+std::string GetDataReductionProxyFallback() {
+ return "http://proxy2.com:80/";
+}
+} // namespace
+
+
+namespace data_reduction_proxy {
+namespace {
+class TestDataReductionProxyParams : public DataReductionProxyParams {
+ public:
+ TestDataReductionProxyParams() : DataReductionProxyParams(0, false) {}
+
+ virtual bool WasDataReductionProxyUsed(
+ const net::URLRequest* request,
+ std::pair<GURL, GURL>* proxy_servers) const OVERRIDE;
+};
+
+bool TestDataReductionProxyParams::WasDataReductionProxyUsed(
+ const net::URLRequest* request,
+ std::pair<GURL, GURL>* proxy_servers) const {
+ if (net::HostPortPair::FromURL(GURL(GetDataReductionProxy())).Equals(
+ request->proxy_server())) {
+ proxy_servers->first = GURL(GetDataReductionProxy());
+ proxy_servers->second = GURL(GetDataReductionProxyFallback());
+ return true;
+ }
+ if (net::HostPortPair::FromURL(
+ GURL(GetDataReductionProxyFallback())).Equals(
+ request->proxy_server())) {
+ proxy_servers->first = GURL(GetDataReductionProxyFallback());
+ proxy_servers->second = GURL();
+ return true;
+ }
+ return false;
+}
+} // namespace
+
+// A test network delegate that exercises the bypass logic of the data
+// reduction proxy.
+class TestDataReductionProxyNetworkDelegate : public net::NetworkDelegate {
+ public:
+ TestDataReductionProxyNetworkDelegate(
+ TestDataReductionProxyParams* test_params)
+ : net::NetworkDelegate(), test_data_reduction_proxy_params_(test_params) {
+ }
+
+ virtual int OnHeadersReceived(
+ URLRequest* request,
+ const net::CompletionCallback& callback,
+ const HttpResponseHeaders* original_response_headers,
+ scoped_refptr<HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url) OVERRIDE {
+ data_reduction_proxy::MaybeBypassProxyAndPrepareToRetry(
+ test_data_reduction_proxy_params_,
+ request,
+ original_response_headers,
+ override_response_headers);
+ return net::OK;
+ }
+
+ TestDataReductionProxyParams* test_data_reduction_proxy_params_;
+};
+
+// Constructs a |URLRequestContext| that uses a |MockSocketFactory| to simulate
+// requests and responses.
+class DataReductionProxyProtocolTest : public testing::Test {
+ public:
+ DataReductionProxyProtocolTest()
+ : ssl_config_service_(new net::SSLConfigServiceDefaults) {}
+
+ // Sets up the |URLRequestContext| with the provided |ProxyService|.
+ void ConfigureTestDependencies(ProxyService* proxy_service) {
+ cert_verifier_.reset(new net::MockCertVerifier);
+ transport_security_state_.reset(new TransportSecurityState);
+ proxy_service_.reset(proxy_service);
+ HttpNetworkSession::Params session_params;
+ session_params.client_socket_factory = &mock_socket_factory_;
+ session_params.host_resolver = &host_resolver_;
+ session_params.cert_verifier = cert_verifier_.get();
+ session_params.transport_security_state = transport_security_state_.get();
+ session_params.proxy_service = proxy_service_.get();
+ session_params.ssl_config_service = ssl_config_service_.get();
+ session_params.http_server_properties =
+ http_server_properties_.GetWeakPtr();
+ network_session_ = new HttpNetworkSession(session_params);
+ factory_.reset(new HttpNetworkLayer(network_session_.get()));
+
+ proxy_params_.reset(new TestDataReductionProxyParams());
+ network_delegate_.reset(new TestDataReductionProxyNetworkDelegate(
+ proxy_params_.get()));
+
+ context_.reset(new URLRequestContext());
+ context_->set_host_resolver(&host_resolver_);
+ context_->set_cert_verifier(cert_verifier_.get());
+ context_->set_proxy_service(proxy_service_.get());
+ context_->set_ssl_config_service(ssl_config_service_.get());
+ context_->set_http_transaction_factory(factory_.get());
+ context_->set_http_server_properties(http_server_properties_.GetWeakPtr());
+ context_->set_transport_security_state(transport_security_state_.get());
+ context_->set_network_delegate(network_delegate_.get());
+ }
+
+ // Simulates a request to a data reduction proxy that may result in bypassing
+ // the proxy and retrying the the request.
+ // Runs a test with the given request |method| that expects the first response
+ // from the server to be |first_response|. If |expected_retry|, the test
+ // will expect a retry of the request. A response body will be expected
+ // if |expect_response_body|.
+ void TestProxyFallback(const char* method,
+ const char* first_response,
+ bool expected_retry,
+ bool expect_response_body) {
+ std::string payload1 =
+ (expected_retry ? "Bypass message" : "content");
+ MockRead data_reads[] = {
+ MockRead(first_response),
+ MockRead(payload1.c_str()),
+ MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ std::string m(method);
+ std::string trailer =
+ (m == "HEAD" || m == "PUT" || m == "POST") ?
+ "Content-Length: 0\r\n" : "";
+
+ std::string request1 =
+ base::StringPrintf("%s http://www.google.com/ HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n%s"
+ "User-Agent:\r\n"
+ "Accept-Encoding: gzip,deflate\r\n\r\n",
+ method, trailer.c_str());
+ MockWrite data_writes[] = {
+ MockWrite(request1.c_str()),
+ };
+ StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ mock_socket_factory_.AddSocketDataProvider(&data1);
+
+ MockRead data_reads2[] = {
+ MockRead("HTTP/1.0 200 OK\r\n"
+ "Server: not-proxy\r\n\r\n"),
+ MockRead("content"),
+ MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ std::string request2 =
+ base::StringPrintf("%s / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n%s"
+ "User-Agent:\r\n"
+ "Accept-Encoding: gzip,deflate\r\n\r\n",
+ method, trailer.c_str());
+ MockWrite data_writes2[] = {
+ MockWrite(request2.c_str()),
+ };
+ StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
+ data_writes2, arraysize(data_writes2));
+ if (expected_retry) {
+ mock_socket_factory_.AddSocketDataProvider(&data2);
+ }
+
+ // Expect that we get "content" and not "Bypass message", and that there's
+ // a "not-proxy" "Server:" header in the final response.
+ ExecuteRequestExpectingContentAndHeader(
+ method,
+ (expect_response_body ? "content" : ""),
+ "server",
+ (expected_retry == 0 ? "proxy" : "not-proxy"),
+ expected_retry);
+ }
+
+ // Starts a request with the given |method| and checks that the response
+ // contains |content| and the the header |header|: |value|, if |header| is
+ // non-empty. Verifies that the request's URL chain is the right length
+ // depending on whether or not a retry was expected (|expected_retry|).
+ void ExecuteRequestExpectingContentAndHeader(const std::string& method,
+ const std::string& content,
+ const std::string& header,
+ const std::string& value,
+ bool expected_retry) {
+ TestDelegate d;
+ URLRequest r(GURL("http://www.google.com/"),
+ net::DEFAULT_PRIORITY,
+ &d,
+ context_.get());
+ r.set_method(method);
+ r.SetLoadFlags(net::LOAD_NORMAL);
+
+ r.Start();
+ base::RunLoop().Run();
+
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
+ EXPECT_EQ(net::OK, r.status().error());
+ if (expected_retry)
+ EXPECT_EQ(2U, r.url_chain().size());
+ else
+ EXPECT_EQ(1U, r.url_chain().size());
+
+ if (!header.empty()) {
+ // We also have a server header here that isn't set by the proxy.
+ EXPECT_TRUE(r.response_headers()->HasHeaderValue(header, value));
+ }
+
+ EXPECT_EQ(content, d.data_received());
+ }
+
+ // Returns the key to the |ProxyRetryInfoMap|.
+ std::string GetProxyKey(std::string proxy) {
+ GURL gurl(proxy);
+ std::string host_port = HostPortPair::FromURL(GURL(proxy)).ToString();
+ if (gurl.SchemeIs("https"))
+ return "https://" + host_port;
+ return host_port;
+ }
+
+ // Checks that |expected_num_bad_proxies| proxies are on the proxy retry list.
+ // If the list has one proxy, it should match |bad_proxy|. If it has two
+ // proxies, it should match |bad_proxy| and |bad_proxy2|. Checks also that
+ // the current delay associated with each bad proxy is |duration_seconds|.
+ void TestBadProxies(unsigned int expected_num_bad_proxies,
+ int duration_seconds,
+ const std::string& bad_proxy,
+ const std::string& bad_proxy2) {
+ const ProxyRetryInfoMap& retry_info = proxy_service_->proxy_retry_info();
+ ASSERT_EQ(expected_num_bad_proxies, retry_info.size());
+
+ base::TimeDelta expected_min_duration;
+ base::TimeDelta expected_max_duration;
+ if (duration_seconds == 0) {
+ expected_min_duration = base::TimeDelta::FromMinutes(1);
+ expected_max_duration = base::TimeDelta::FromMinutes(5);
+ }
+ else {
+ expected_min_duration = base::TimeDelta::FromSeconds(duration_seconds);
+ expected_max_duration = base::TimeDelta::FromSeconds(duration_seconds);
+ }
+
+ if (expected_num_bad_proxies >= 1u) {
+ ProxyRetryInfoMap::const_iterator i =
+ retry_info.find(GetProxyKey(bad_proxy));
+ ASSERT_TRUE(i != retry_info.end());
+ EXPECT_TRUE(expected_min_duration <= (*i).second.current_delay);
+ EXPECT_TRUE((*i).second.current_delay <= expected_max_duration);
+ }
+ if (expected_num_bad_proxies == 2u) {
+ ProxyRetryInfoMap::const_iterator i =
+ retry_info.find(GetProxyKey(bad_proxy2));
+ ASSERT_TRUE(i != retry_info.end());
+ EXPECT_TRUE(expected_min_duration <= (*i).second.current_delay);
+ EXPECT_TRUE((*i).second.current_delay <= expected_max_duration);
+ }
+ }
+
+ protected:
+ base::MessageLoopForIO loop_;
+
+ net::MockClientSocketFactory mock_socket_factory_;
+ net::MockHostResolver host_resolver_;
+ scoped_ptr<net::CertVerifier> cert_verifier_;
+ scoped_ptr<TransportSecurityState> transport_security_state_;
+ scoped_ptr<ProxyService> proxy_service_;
+ const scoped_refptr<net::SSLConfigService> ssl_config_service_;
+ scoped_refptr<HttpNetworkSession> network_session_;
+ scoped_ptr<HttpNetworkLayer> factory_;
+ net::HttpServerPropertiesImpl http_server_properties_;
+ scoped_ptr<TestDataReductionProxyParams> proxy_params_;
+ scoped_ptr<TestDataReductionProxyNetworkDelegate> network_delegate_;
+
+ scoped_ptr<URLRequestContext> context_;
+};
+
+// Tests that request are deemed idempotent or not according to the method used.
+TEST_F(DataReductionProxyProtocolTest, TestIdempotency) {
+ net::TestURLRequestContext context;
+ const struct {
+ const char* method;
+ bool expected_result;
+ } tests[] = {
+ { "GET", true },
+ { "OPTIONS", true },
+ { "HEAD", true },
+ { "PUT", true },
+ { "DELETE", true },
+ { "TRACE", true },
+ { "POST", false },
+ { "CONNECT", false },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ net::TestURLRequest request(GURL("http://www.google.com/"),
+ net::DEFAULT_PRIORITY,
+ NULL,
+ &context);
+ request.set_method(tests[i].method);
+ EXPECT_EQ(tests[i].expected_result, IsRequestIdempotent(&request));
+ }
+}
+
+// Tests that the response is correctly overwritten as a redirect.
+TEST_F(DataReductionProxyProtocolTest, OverrideResponseAsRedirect) {
+ net::TestURLRequestContext context;
+ const struct {
+ const char* headers;
+ const char* expected_headers;
+ } tests[] = {
+ { "HTTP/1.1 200 0K\n"
+ "Chrome-Proxy: block=1\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n",
+
+ "HTTP/1.1 302 Found\n"
+ "Chrome-Proxy: block=1\n"
+ "Via: 1.1 Chrome-Compression-Proxy\n"
+ "Location: http://www.google.com/\n"
+ },
+ { "HTTP/1.1 302 Found\n"
+ "Location: http://foo.com/\n",
+
+ "HTTP/1.1 302 Found\n"
+ "Location: http://www.google.com/\n"
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ std::string headers(tests[i].headers);
+ HeadersToRaw(&headers);
+ scoped_refptr<HttpResponseHeaders> original_response_headers(
+ new HttpResponseHeaders(headers));
+ scoped_refptr<HttpResponseHeaders> override_response_headers;
+ TestDelegate test_delegate;
+ net::TestURLRequest request(GURL("http://www.google.com/"),
+ net::DEFAULT_PRIORITY,
+ NULL,
+ &context);
+ OverrideResponseAsRedirect(&request,
+ original_response_headers,
+ &override_response_headers);
+ int expected_flags = net::LOAD_DISABLE_CACHE | net::LOAD_BYPASS_PROXY;
+ EXPECT_EQ(expected_flags, request.load_flags());
+ std::string override_headers;
+ override_response_headers->GetNormalizedHeaders(&override_headers);
+ EXPECT_EQ(std::string(tests[i].expected_headers), override_headers);
+ }
+}
+
+
+// After each test, the proxy retry info will contain zero, one, or two of the
+// data reduction proxies depending on whether no bypass was indicated by the
+// initial response, a single proxy bypass was indicated, or a double bypass
+// was indicated. In both the single and double bypass cases, if the request
+// was idempotent, it will be retried over a direct connection.
+TEST_F(DataReductionProxyProtocolTest, BypassLogic) {
+ std::string primary = GetDataReductionProxy();
+ std::string fallback = GetDataReductionProxyFallback();
+ const struct {
+ const char* method;
+ const char* first_response;
+ bool expected_retry;
+ size_t expected_bad_proxy_count;
+ bool expect_response_body;
+ int expected_duration;
+ } tests[] = {
+ // Valid data reduction proxy response with no bypass message.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ false,
+ 0u,
+ true,
+ -1
+ },
+ // Valid data reduction proxy response with older, but still valid via
+ // header.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome Compression Proxy\r\n\r\n",
+ false,
+ 0u,
+ true,
+ -1
+ },
+ // Valid data reduction proxy response with chained via header,
+ // no bypass message.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy, 1.0 some-other-proxy\r\n\r\n",
+ false,
+ 0u,
+ true,
+ -1
+ },
+ // Valid data reduction proxy response with a bypass message.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Valid data reduction proxy response with a bypass message.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=1\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 1
+ },
+ // Same as above with the OPTIONS method, which is idempotent.
+ { "OPTIONS",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Same as above with the HEAD method, which is idempotent.
+ { "HEAD",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ false,
+ 0
+ },
+ // Same as above with the PUT method, which is idempotent.
+ { "PUT",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Same as above with the DELETE method, which is idempotent.
+ { "DELETE",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Same as above with the TRACE method, which is idempotent.
+ { "TRACE",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // 500 responses should be bypassed.
+ { "GET",
+ "HTTP/1.1 500 Internal Server Error\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // 502 responses should be bypassed.
+ { "GET",
+ "HTTP/1.1 502 Internal Server Error\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // 503 responses should be bypassed.
+ { "GET",
+ "HTTP/1.1 503 Internal Server Error\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Invalid data reduction proxy response. Missing Via header.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Invalid data reduction proxy response. Wrong Via header.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Via: 1.0 some-other-proxy\r\n\r\n",
+ true,
+ 1u,
+ true,
+ 0
+ },
+ // Valid data reduction proxy response. 304 missing Via header.
+ { "GET",
+ "HTTP/1.1 304 Not Modified\r\n"
+ "Server: proxy\r\n\r\n",
+ false,
+ 0u,
+ false,
+ 0
+ },
+ // Valid data reduction proxy response with a bypass message. It will
+ // not be retried because the request is non-idempotent.
+ { "POST",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: bypass=0\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ false,
+ 1u,
+ true,
+ 0
+ },
+ // Valid data reduction proxy response with block message. Both proxies
+ // should be on the retry list when it completes.
+ { "GET",
+ "HTTP/1.1 200 OK\r\n"
+ "Server: proxy\r\n"
+ "Chrome-Proxy: block=1\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ true,
+ 2u,
+ true,
+ 1
+ }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ ConfigureTestDependencies(
+ ProxyService::CreateFixedFromPacResult("PROXY " +
+ HostPortPair::FromURL(GURL(primary)).ToString() + "; PROXY " +
+ HostPortPair::FromURL(GURL(fallback)).ToString() + "; DIRECT"));
+ TestProxyFallback(tests[i].method,
+ tests[i].first_response,
+ tests[i].expected_retry,
+ tests[i].expect_response_body);
+
+ // We should also observe the bad proxy in the retry list.
+ TestBadProxies(tests[i].expected_bad_proxy_count,
+ tests[i].expected_duration,
+ primary, fallback);
+ }
+}
+
+TEST_F(DataReductionProxyProtocolTest,
+ ProxyBypassIgnoredOnDirectConnection) {
+ // Verify that a Chrome-Proxy 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"
+ "Chrome-Proxy: bypass=0\r\n\r\n"),
+ MockRead("Bypass message"),
+ MockRead(net::SYNCHRONOUS, net::OK),
+ };
+ MockWrite data_writes[] = {
+ MockWrite("GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent:\r\n"
+ "Accept-Encoding: gzip,deflate\r\n\r\n"),
+ };
+ StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
+ data_writes, arraysize(data_writes));
+ mock_socket_factory_.AddSocketDataProvider(&data1);
+
+ TestDelegate d;
+ URLRequest r(GURL("http://www.google.com/"),
+ net::DEFAULT_PRIORITY,
+ &d,
+ context_.get());
+ r.set_method("GET");
+ r.SetLoadFlags(net::LOAD_NORMAL);
+
+ r.Start();
+ base::RunLoop().Run();
+
+ EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
+ EXPECT_EQ(net::OK, r.status().error());
+
+ EXPECT_EQ("Bypass message", d.data_received());
+
+ // We should have no entries in our bad proxy list.
+ TestBadProxies(0, -1, "", "");
+}
+
+} // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc
index 1f7cd2f..5fc9213e 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_settings.cc
@@ -247,7 +247,8 @@ bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
DataReductionProxyParams::IsKeySetOnCommandLine();
}
-bool DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() {
+bool
+DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() const {
return data_reduction_proxy_alternative_enabled_.GetValue();
}
@@ -590,6 +591,7 @@ net::URLFetcher* DataReductionProxySettings::GetURLFetcher() {
// Configure max retries to be at most kMaxRetries times for 5xx errors.
static const int kMaxRetries = 5;
fetcher->SetMaxRetriesOn5xx(kMaxRetries);
+ fetcher->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
return fetcher;
}
diff --git a/components/data_reduction_proxy/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/browser/data_reduction_proxy_settings.h
index cf0abe1..c7fb154 100644
--- a/components/data_reduction_proxy/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/browser/data_reduction_proxy_settings.h
@@ -41,41 +41,41 @@ const unsigned int kNumDaysInHistorySummary = 30;
COMPILE_ASSERT(kNumDaysInHistorySummary <= kNumDaysInHistory,
DataReductionProxySettings_summary_too_long);
- // Values of the UMA DataReductionProxy.StartupState histogram.
- // This enum must remain synchronized with DataReductionProxyStartupState
- // in metrics/histograms/histograms.xml.
- enum ProxyStartupState {
- PROXY_NOT_AVAILABLE = 0,
- PROXY_DISABLED,
- PROXY_ENABLED,
- PROXY_STARTUP_STATE_COUNT,
- };
-
- // Values of the UMA DataReductionProxy.ProbeURL histogram.
- // This enum must remain synchronized with
- // DataReductionProxyProbeURLFetchResult in metrics/histograms/histograms.xml.
- // TODO(marq): Rename these histogram buckets with s/DISABLED/RESTRICTED/, so
- // their names match the behavior they track.
- enum ProbeURLFetchResult {
- // The probe failed because the Internet was disconnected.
- INTERNET_DISCONNECTED = 0,
-
- // The probe failed for any other reason, and as a result, the proxy was
- // disabled.
- FAILED_PROXY_DISABLED,
-
- // The probe failed, but the proxy was already restricted.
- FAILED_PROXY_ALREADY_DISABLED,
-
- // THe probe succeeded, and as a result the proxy was restricted.
- SUCCEEDED_PROXY_ENABLED,
-
- // The probe succeeded, but the proxy was already restricted.
- SUCCEEDED_PROXY_ALREADY_ENABLED,
-
- // This must always be last.
- PROBE_URL_FETCH_RESULT_COUNT
- };
+// Values of the UMA DataReductionProxy.StartupState histogram.
+// This enum must remain synchronized with DataReductionProxyStartupState
+// in metrics/histograms/histograms.xml.
+enum ProxyStartupState {
+ PROXY_NOT_AVAILABLE = 0,
+ PROXY_DISABLED,
+ PROXY_ENABLED,
+ PROXY_STARTUP_STATE_COUNT,
+};
+
+// Values of the UMA DataReductionProxy.ProbeURL histogram.
+// This enum must remain synchronized with
+// DataReductionProxyProbeURLFetchResult in metrics/histograms/histograms.xml.
+// TODO(marq): Rename these histogram buckets with s/DISABLED/RESTRICTED/, so
+// their names match the behavior they track.
+enum ProbeURLFetchResult {
+ // The probe failed because the Internet was disconnected.
+ INTERNET_DISCONNECTED = 0,
+
+ // The probe failed for any other reason, and as a result, the proxy was
+ // disabled.
+ FAILED_PROXY_DISABLED,
+
+ // The probe failed, but the proxy was already restricted.
+ FAILED_PROXY_ALREADY_DISABLED,
+
+ // The probe succeeded, and as a result the proxy was restricted.
+ SUCCEEDED_PROXY_ENABLED,
+
+ // The probe succeeded, but the proxy was already restricted.
+ SUCCEEDED_PROXY_ALREADY_ENABLED,
+
+ // This must always be last.
+ PROBE_URL_FETCH_RESULT_COUNT
+};
// Central point for configuring the data reduction proxy.
// This object lives on the UI thread and all of its methods are expected to
@@ -141,7 +141,7 @@ class DataReductionProxySettings
bool IsDataReductionProxyEnabled();
// Returns true if the alternative proxy is enabled.
- bool IsDataReductionProxyAlternativeEnabled();
+ bool IsDataReductionProxyAlternativeEnabled() const;
// Returns true if the proxy is managed by an adminstrator's policy.
bool IsDataReductionProxyManaged();