summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 20:42:27 +0000
committerbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 20:42:27 +0000
commita4fd43af496cfbc4185ee01818122ca7ae6926a9 (patch)
treedb589682a4de95d85b7954a0a86571034c6df435
parent716c016d95025a8f4d42baab6639b9dc90498f2d (diff)
downloadchromium_src-a4fd43af496cfbc4185ee01818122ca7ae6926a9.zip
chromium_src-a4fd43af496cfbc4185ee01818122ca7ae6926a9.tar.gz
chromium_src-a4fd43af496cfbc4185ee01818122ca7ae6926a9.tar.bz2
Accept Chrome-Proxy: block=xxx to bypass all Chrome proxies
BUG=325333 Review URL: https://codereview.chromium.org/98373005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240737 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_network_layer_unittest.cc61
-rw-r--r--net/http/http_network_transaction.cc39
-rw-r--r--net/http/http_response_headers.cc61
-rw-r--r--net/http/http_response_headers.h30
-rw-r--r--net/http/http_response_headers_unittest.cc82
-rw-r--r--net/proxy/proxy_list.cc58
-rw-r--r--net/proxy/proxy_list.h22
-rw-r--r--net/proxy/proxy_server.cc19
-rw-r--r--net/proxy/proxy_service.cc9
-rw-r--r--net/proxy/proxy_service.h16
10 files changed, 280 insertions, 117 deletions
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index fc5b43c..174ae2e 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -48,12 +48,18 @@ class HttpNetworkLayerTest : public PlatformTest {
factory_.reset(new HttpNetworkLayer(network_session_.get()));
}
-#if defined (SPDY_PROXY_AUTH_ORIGIN)
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
std::string GetChromeProxy() {
return HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString();
}
#endif
+#if defined(SPDY_PROXY_AUTH_ORIGIN) && defined(DATA_REDUCTION_FALLBACK_HOST)
+ std::string GetChromeFallbackProxy() {
+ return HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
+ }
+#endif
+
void ExecuteRequestExpectingContentAndHeader(const std::string& content,
const std::string& header,
const std::string& value) {
@@ -103,17 +109,19 @@ class HttpNetworkLayerTest : public PlatformTest {
void TestProxyFallback(const std::string& bad_proxy) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: proxy-bypass\r\n\r\n"),
+ "Chrome-Proxy: bypass=0\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
- TestProxyFallbackWithMockReads(bad_proxy, data_reads,
- arraysize(data_reads));
+ TestProxyFallbackWithMockReads(bad_proxy, "", data_reads,
+ arraysize(data_reads), 1u);
}
void TestProxyFallbackWithMockReads(const std::string& bad_proxy,
+ const std::string& bad_proxy2,
MockRead data_reads[],
- int data_reads_size) {
+ int data_reads_size,
+ unsigned int expected_retry_info_size) {
MockWrite data_writes[] = {
MockWrite("GET http://www.google.com/ HTTP/1.1\r\n"
"Host: www.google.com\r\n"
@@ -145,7 +153,7 @@ class HttpNetworkLayerTest : public PlatformTest {
ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
// We should also observe the bad proxy in the retry list.
- TestBadProxies(1u, bad_proxy, "");
+ TestBadProxies(expected_retry_info_size, bad_proxy, bad_proxy2);
}
// Simulates a request through a proxy which returns a bypass, which is then
@@ -155,7 +163,7 @@ class HttpNetworkLayerTest : public PlatformTest {
void TestProxyFallbackToDirect(const std::string& bad_proxy) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: proxy-bypass\r\n\r\n"),
+ "Chrome-Proxy: bypass=0\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
@@ -202,7 +210,7 @@ class HttpNetworkLayerTest : public PlatformTest {
const std::string& bad_proxy2) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: proxy-bypass\r\n\r\n"),
+ "Chrome-Proxy: bypass=0\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
@@ -305,7 +313,7 @@ TEST_F(HttpNetworkLayerTest, GET) {
}
// Proxy bypass tests. These tests run through various server-induced
-// proxy-bypass scenarios using both PAC file and fixed proxy params.
+// proxy bypass scenarios using both PAC file and fixed proxy params.
// The test scenarios are:
// - bypass with two proxies configured and the first but not the second
// is bypassed.
@@ -468,13 +476,13 @@ TEST_F(HttpNetworkLayerTest, ServerFallbackOn5xxError) {
#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnectionPac) {
- // Verify that a Connection: proxy-bypass header is ignored when returned
- // from a directly connected origin server.
+ // 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"
- "Connection: proxy-bypass\r\n\r\n"),
+ "Chrome-Proxy: bypass=0\r\n\r\n"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
@@ -528,10 +536,37 @@ TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
MockRead(SYNCHRONOUS, OK),
};
- TestProxyFallbackWithMockReads(bad_proxy, data_reads, arraysize(data_reads));
+ TestProxyFallbackWithMockReads(bad_proxy, "", data_reads,
+ arraysize(data_reads), 1u);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
+ (*proxy_service_->proxy_retry_info().begin()).second.current_delay);
+}
+
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypassAll) {
+ // Verify that a Chrome-Proxy: block=<seconds> header bypasses a
+ // a configured Chrome-Proxy and fallback and induces proxy fallback to a
+ // third proxy, if configured.
+ std::string bad_proxy = GetChromeProxy();
+ std::string fallback_proxy = GetChromeFallbackProxy();
+ ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
+ "PROXY " + bad_proxy + "; PROXY " + fallback_proxy +
+ "; PROXY good:8080"));
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Chrome-Proxy: block=86400\r\n\r\n"),
+ MockRead("Bypass message"),
+ MockRead(SYNCHRONOUS, OK),
+ };
+
+ TestProxyFallbackWithMockReads(bad_proxy, fallback_proxy, data_reads,
+ arraysize(data_reads), 2u);
EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
(*proxy_service_->proxy_retry_info().begin()).second.current_delay);
}
+#endif // defined(DATA_REDUCTION_FALLBACK_HOST)
#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
TEST_F(HttpNetworkLayerTest, NetworkVerified) {
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 4b55a5f..66d7364 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -61,7 +61,13 @@
#include "net/ssl/ssl_connection_status_flags.h"
#include "url/gurl.h"
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+#include "net/proxy/proxy_server.h"
+#endif
+
+
using base::Time;
+using base::TimeDelta;
namespace net {
@@ -951,7 +957,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
if (response_.was_fetched_via_proxy && response_.headers.get() != NULL) {
ProxyService::DataReductionProxyBypassEventType proxy_bypass_event =
ProxyService::BYPASS_EVENT_TYPE_MAX;
- base::TimeDelta bypass_duration;
+ net::HttpResponseHeaders::ChromeProxyInfo chrome_proxy_info;
bool chrome_proxy_used =
proxy_info_.proxy_server().isDataReductionProxy();
bool chrome_fallback_proxy_used = false;
@@ -963,11 +969,11 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
#endif
if (chrome_proxy_used || chrome_fallback_proxy_used) {
- if (response_.headers->GetChromeProxyInfo(&bypass_duration)) {
- proxy_bypass_event =
- (bypass_duration < base::TimeDelta::FromMinutes(30) ?
- ProxyService::SHORT_BYPASS :
- ProxyService::LONG_BYPASS);
+ 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 or 502 is returned via the data
// reduction proxy. This is conservative, as the 500 or 502 might have
@@ -985,8 +991,23 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
proxy_service->RecordDataReductionProxyBypassInfo(
chrome_proxy_used, proxy_info_.proxy_server(), proxy_bypass_event);
- if (proxy_service->MarkProxyAsBad(proxy_info_, bypass_duration,
- net_log_)) {
+ ProxyServer proxy_server;
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+ if (chrome_proxy_used && chrome_proxy_info.bypass_all) {
+ // TODO(bengr): Rename as DATA_REDUCTION_FALLBACK_ORIGIN.
+ GURL proxy_url(DATA_REDUCTION_FALLBACK_HOST);
+ if (proxy_url.SchemeIsHTTPOrHTTPS()) {
+ proxy_server = ProxyServer(proxy_url.SchemeIs("http") ?
+ ProxyServer::SCHEME_HTTP :
+ ProxyServer::SCHEME_HTTPS,
+ HostPortPair::FromURL(proxy_url));
+ }
+ }
+#endif
+ if (proxy_service->MarkProxiesAsBad(proxy_info_,
+ chrome_proxy_info.bypass_duration,
+ proxy_server,
+ 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") {
@@ -997,7 +1018,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
}
}
}
-#endif
+#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
// Like Net.HttpResponseCode, but only for MAIN_FRAME loads.
if (request_->load_flags & LOAD_MAIN_FRAME) {
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index 26cdd2ab2..9d95153 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -1355,39 +1355,54 @@ bool HttpResponseHeaders::IsChunkEncoded() const {
}
#if defined(SPDY_PROXY_AUTH_ORIGIN)
-bool HttpResponseHeaders::GetChromeProxyInfo(
- base::TimeDelta* bypass_duration) const {
- const char kProxyBypass[] = "proxy-bypass";
- *bypass_duration = base::TimeDelta();
-
- // Support header of the form Chrome-Proxy: bypass=<duration>, where
- // <duration> is the number of seconds to wait before retrying
- // the proxy. If the duration is 0, then the default proxy retry delay
- // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used.
- std::string name = "chrome-proxy";
- const char kBypassPrefix[] = "bypass=";
- const size_t kBypassPrefixLen = arraysize(kBypassPrefix) - 1;
-
+bool HttpResponseHeaders::GetChromeProxyBypassDuration(
+ const std::string& action_prefix,
+ base::TimeDelta* duration) const {
void* iter = NULL;
std::string value;
+ std::string name = "chrome-proxy";
+
while (EnumerateHeader(&iter, name, &value)) {
- if (value.size() > kBypassPrefixLen) {
+ if (value.size() > action_prefix.size()) {
if (LowerCaseEqualsASCII(value.begin(),
- value.begin() + kBypassPrefixLen,
- kBypassPrefix)) {
+ value.begin() + action_prefix.size(),
+ action_prefix.c_str())) {
int64 seconds;
- if (!base::StringToInt64(StringPiece(value.begin() + kBypassPrefixLen,
- value.end()),
- &seconds) || seconds < 0) {
- continue; // In case there is a well formed bypass instruction.
+ if (!base::StringToInt64(
+ StringPiece(value.begin() + action_prefix.size(), value.end()),
+ &seconds) || seconds < 0) {
+ continue; // In case there is a well formed instruction.
}
- *bypass_duration = TimeDelta::FromSeconds(seconds);
+ *duration = TimeDelta::FromSeconds(seconds);
return true;
}
}
}
- // TODO(bengr): Deprecate the use of Connection: Proxy-Bypass.
- if (HasHeaderValue("Connection", kProxyBypass))
+ return false;
+}
+
+bool HttpResponseHeaders::GetChromeProxyInfo(
+ ChromeProxyInfo* proxy_info) const {
+ DCHECK(proxy_info);
+ proxy_info->bypass_all = false;
+ proxy_info->bypass_duration = base::TimeDelta();
+
+ // Support header of the form Chrome-Proxy: bypass|block=<duration>, where
+ // <duration> is the number of seconds to wait before retrying
+ // the proxy. If the duration is 0, then the default proxy retry delay
+ // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used.
+ // 'bypass' instructs Chrome to bypass the currently connected Chrome proxy,
+ // whereas 'block' instructs Chrome to bypass all available Chrome proxies.
+
+ // 'block' takes precedence over 'bypass', so look for it first.
+ // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop.
+ if (GetChromeProxyBypassDuration("block=", &proxy_info->bypass_duration)) {
+ proxy_info->bypass_all = true;
+ return true;
+ }
+
+ // Next, look for 'bypass'.
+ if (GetChromeProxyBypassDuration("bypass=", &proxy_info->bypass_duration))
return true;
return false;
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index a212980..e54ac5d 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -251,12 +251,25 @@ class NET_EXPORT HttpResponseHeaders
bool IsChunkEncoded() const;
#if defined (SPDY_PROXY_AUTH_ORIGIN)
+ // Contains instructions contained in the Chrome-Proxy header.
+ struct ChromeProxyInfo {
+ ChromeProxyInfo() : bypass_all(false) {}
+
+ // True if Chrome should bypass all available Chrome proxies. False if only
+ // the currently connected Chrome proxy should be bypassed.
+ bool bypass_all;
+
+ // Amount of time to bypass the Chrome proxy or proxies.
+ base::TimeDelta bypass_duration;
+ };
+
// Returns true if the Chrome-Proxy header is present and contains a bypass
- // delay. Sets |bypass_duration| to the specified delay if greater than 0, and
- // to 0 otherwise to indicate that the default proxy delay (as specified in
- // |ProxyList::UpdateRetryInfoOnFallback|) should be used. |bypass_duration|
- // must be non-NULL.
- bool GetChromeProxyInfo(base::TimeDelta* bypass_duration) const;
+ // delay. Sets |proxy_info->bypass_duration| to the specified delay if greater
+ // than 0, and to 0 otherwise to indicate that the default proxy delay
+ // (as specified in |ProxyList::UpdateRetryInfoOnFallback|) should be used.
+ // If all available Chrome proxies should by bypassed, |bypass_all| is set to
+ // true. |proxy_info| must be non-NULL.
+ bool GetChromeProxyInfo(ChromeProxyInfo* proxy_info) const;
#endif
// Creates a Value for use with the NetLog containing the response headers.
@@ -357,6 +370,13 @@ class NET_EXPORT HttpResponseHeaders
// Adds the set of transport security state headers.
static void AddSecurityStateHeaders(HeaderSet* header_names);
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+ // Searches for the specified Chrome-Proxy action, and if present interprets
+ // its value as a duration in seconds.
+ bool GetChromeProxyBypassDuration(const std::string& action_prefix,
+ base::TimeDelta* duration) const;
+#endif
+
// We keep a list of ParsedHeader objects. These tell us where to locate the
// header-value pairs within raw_headers_.
HeaderList parsed_;
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 5904bea..4be7478 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1884,79 +1884,76 @@ TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
const char* headers;
bool expected_result;
int64 expected_retry_delay;
+ bool expected_bypass_all;
} tests[] = {
{ "HTTP/1.1 200 OK\n"
"Content-Length: 999\n",
false,
0,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Content-Length: 999\n",
false,
0,
- },
- { "HTTP/1.1 200 OK\n"
- "connection: proxy-bypass\n"
- "Content-Length: 999\n",
- true,
- 0,
- },
- { "HTTP/1.1 200 OK\n"
- "connection: proxy-bypass\n"
- "Chrome-Proxy: bypass=86400\n"
- "Content-Length: 999\n",
- true,
- 86400
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=86400\n"
"Content-Length: 999\n",
true,
- 86400
+ 86400,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=0\n"
"Content-Length: 999\n",
true,
- 0
+ 0,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=-1\n"
"Content-Length: 999\n",
false,
- 0
+ 0,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=xyz\n"
"Content-Length: 999\n",
false,
- 0
+ 0,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass\n"
"Content-Length: 999\n",
false,
- 0
+ 0,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: foo=abc, bypass=86400\n"
"Content-Length: 999\n",
true,
- 86400
+ 86400,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=86400, bar=abc\n"
"Content-Length: 999\n",
true,
- 86400
+ 86400,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
@@ -1964,21 +1961,24 @@ TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
"Chrome-Proxy: bypass=86400\n"
"Content-Length: 999\n",
true,
- 3600
+ 3600,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=3600, bypass=86400\n"
"Content-Length: 999\n",
true,
- 3600
+ 3600,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
"Chrome-Proxy: bypass=, bypass=86400\n"
"Content-Length: 999\n",
true,
- 86400
+ 86400,
+ false,
},
{ "HTTP/1.1 200 OK\n"
"connection: keep-alive\n"
@@ -1986,7 +1986,32 @@ TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
"Chrome-Proxy: bypass=86400\n"
"Content-Length: 999\n",
true,
- 86400
+ 86400,
+ false,
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: block=, block=3600\n"
+ "Content-Length: 999\n",
+ true,
+ 3600,
+ true,
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=86400, block=3600\n"
+ "Content-Length: 999\n",
+ true,
+ 3600,
+ true,
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: proxy-bypass\n"
+ "Chrome-Proxy: block=, bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 86400,
+ false,
},
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
@@ -1995,10 +2020,13 @@ TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
scoped_refptr<net::HttpResponseHeaders> parsed(
new net::HttpResponseHeaders(headers));
- base::TimeDelta duration;
+ net::HttpResponseHeaders::ChromeProxyInfo chrome_proxy_info;
EXPECT_EQ(tests[i].expected_result,
- parsed->GetChromeProxyInfo(&duration));
- EXPECT_EQ(tests[i].expected_retry_delay, duration.InSeconds());
+ parsed->GetChromeProxyInfo(&chrome_proxy_info));
+ EXPECT_EQ(tests[i].expected_retry_delay,
+ chrome_proxy_info.bypass_duration.InSeconds());
+ EXPECT_EQ(tests[i].expected_bypass_all,
+ chrome_proxy_info.bypass_all);
}
}
#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
diff --git a/net/proxy/proxy_list.cc b/net/proxy/proxy_list.cc
index bd7cbfb..5328402 100644
--- a/net/proxy/proxy_list.cc
+++ b/net/proxy/proxy_list.cc
@@ -185,16 +185,39 @@ bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
NOTREACHED();
return false;
}
- UpdateRetryInfoOnFallback(proxy_retry_info, base::TimeDelta(), net_log);
+ UpdateRetryInfoOnFallback(proxy_retry_info, base::TimeDelta(), ProxyServer(),
+ net_log);
// Remove this proxy from our list.
proxies_.erase(proxies_.begin());
return !proxies_.empty();
}
-void ProxyList::UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
- base::TimeDelta retry_delay,
- const BoundNetLog& net_log) const {
+void ProxyList::AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
+ base::TimeDelta retry_delay,
+ const std::string& proxy_key,
+ const BoundNetLog& net_log) const {
+ // Mark this proxy as bad.
+ ProxyRetryInfoMap::iterator iter = proxy_retry_info->find(proxy_key);
+ if (iter != proxy_retry_info->end()) {
+ // TODO(nsylvain): This is not the first time we get this. We should
+ // double the retry time. Bug 997660.
+ iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay;
+ } else {
+ ProxyRetryInfo retry_info;
+ retry_info.current_delay = retry_delay;
+ retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay;
+ (*proxy_retry_info)[proxy_key] = retry_info;
+ }
+ net_log.AddEvent(NetLog::TYPE_PROXY_LIST_FALLBACK,
+ NetLog::StringCallback("bad_proxy", &proxy_key));
+}
+
+void ProxyList::UpdateRetryInfoOnFallback(
+ ProxyRetryInfoMap* proxy_retry_info,
+ base::TimeDelta retry_delay,
+ const ProxyServer& another_proxy_to_bypass,
+ const BoundNetLog& net_log) const {
// Time to wait before retrying a bad proxy server.
if (retry_delay == base::TimeDelta()) {
#if defined(SPDY_PROXY_AUTH_ORIGIN)
@@ -214,20 +237,21 @@ void ProxyList::UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
if (!proxies_[0].is_direct()) {
std::string key = proxies_[0].ToURI();
- // Mark this proxy as bad.
- ProxyRetryInfoMap::iterator iter = proxy_retry_info->find(key);
- if (iter != proxy_retry_info->end()) {
- // TODO(nsylvain): This is not the first time we get this. We should
- // double the retry time. Bug 997660.
- iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay;
- } else {
- ProxyRetryInfo retry_info;
- retry_info.current_delay = retry_delay;
- retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay;
- (*proxy_retry_info)[key] = retry_info;
+ AddProxyToRetryList(proxy_retry_info, retry_delay, key, net_log);
+
+ // If additional proxies to bypass are specified, add these to the retry
+ // map as well.
+ if (another_proxy_to_bypass.is_valid()) {
+ // Start at index 1 because index 0 is already handled above.
+ for (size_t j = 1; j < proxies_.size(); ++j) {
+ if (proxies_[j].is_direct())
+ break;
+ if (another_proxy_to_bypass == proxies_[j]) {
+ key = proxies_[j].ToURI();
+ AddProxyToRetryList(proxy_retry_info, retry_delay, key, net_log);
+ }
+ }
}
- net_log.AddEvent(NetLog::TYPE_PROXY_LIST_FALLBACK,
- NetLog::StringCallback("bad_proxy", &key));
}
}
diff --git a/net/proxy/proxy_list.h b/net/proxy/proxy_list.h
index 33a78a8..e8df0ba 100644
--- a/net/proxy/proxy_list.h
+++ b/net/proxy/proxy_list.h
@@ -92,12 +92,26 @@ class NET_EXPORT_PRIVATE ProxyList {
// is bad. This is distinct from Fallback(), above, to allow updating proxy
// retry information without modifying a given transction's proxy list. Will
// retry after |retry_delay| if positive, and will use the default proxy retry
- // duration otherwise.
- void UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
- base::TimeDelta retry_delay,
- const BoundNetLog& net_log) const;
+ // duration otherwise. Additionally updates |proxy_retry_info| with
+ // |another_proxy_to_bypass| if non-empty.
+ void UpdateRetryInfoOnFallback(
+ ProxyRetryInfoMap* proxy_retry_info,
+ base::TimeDelta retry_delay,
+ const ProxyServer& another_proxy_to_bypass,
+ const BoundNetLog& net_log) const;
private:
+ // Updates |proxy_retry_info| to indicate that the proxy in |proxies_| with
+ // the URI of |proxy_key| is bad. The |proxy_key| must start with the scheme
+ // (only if https) followed by the host and then an explicit port. For
+ // example, if the proxy origin is https://proxy.chromium.org:443/ the key is
+ // https://proxy.chrome.org:443 whereas if the origin is
+ // http://proxy.chrome.org/, the key is proxy.chrome.org:80.
+ void AddProxyToRetryList(ProxyRetryInfoMap* proxy_retry_info,
+ base::TimeDelta retry_delay,
+ const std::string& proxy_key,
+ const BoundNetLog& net_log) const;
+
// List of proxies.
std::vector<ProxyServer> proxies_;
};
diff --git a/net/proxy/proxy_server.cc b/net/proxy/proxy_server.cc
index 3b8bd03..a6ea5de 100644
--- a/net/proxy/proxy_server.cc
+++ b/net/proxy/proxy_server.cc
@@ -208,19 +208,20 @@ ProxyServer::Scheme ProxyServer::GetSchemeFromURI(const std::string& scheme) {
return GetSchemeFromURIInternal(scheme.begin(), scheme.end());
}
+// TODO(bengr): Use |scheme_| to indicate that this is the data reduction proxy.
#if defined(SPDY_PROXY_AUTH_ORIGIN)
- bool ProxyServer::isDataReductionProxy() const {
- return host_port_pair_.Equals(
- HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
- }
+bool ProxyServer::isDataReductionProxy() const {
+ return host_port_pair_.Equals(
+ HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
+}
- bool ProxyServer::isDataReductionProxyFallback() const {
+bool ProxyServer::isDataReductionProxyFallback() const {
#if defined(DATA_REDUCTION_FALLBACK_HOST)
- return host_port_pair_.Equals(
- HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)));
+ return host_port_pair_.Equals(
+ HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)));
#endif // defined(DATA_REDUCTION_FALLBACK_HOST)
- return false;
- }
+ return false;
+}
#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
// static
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index b18b47b..9d4125b 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -1192,10 +1192,13 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
return did_fallback ? OK : ERR_FAILED;
}
-bool ProxyService::MarkProxyAsBad(const ProxyInfo& result,
- base::TimeDelta retry_delay,
- const BoundNetLog& net_log) {
+bool ProxyService::MarkProxiesAsBad(
+ const ProxyInfo& result,
+ base::TimeDelta retry_delay,
+ const ProxyServer& another_bad_proxy,
+ const BoundNetLog& net_log) {
result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
+ another_bad_proxy,
net_log);
return result.proxy_list_.HasUntriedProxies(proxy_retry_info_);
}
diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h
index 3573711..91c713d 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -148,13 +148,15 @@ class NET_EXPORT ProxyService : public NetworkChangeNotifier::IPAddressObserver,
const BoundNetLog& net_log);
// Explicitly trigger proxy fallback for the given |results| by updating our
- // list of bad proxies to include the first entry of |results|. Will retry
- // after |retry_delay| if positive, and will use the default proxy retry
- // duration otherwise. Returns true if there will be at least one proxy
- // remaining in the list after fallback and false otherwise.
- bool MarkProxyAsBad(const ProxyInfo& results,
- base::TimeDelta retry_delay,
- const BoundNetLog& net_log);
+ // list of bad proxies to include the first entry of |results|, and,
+ // optionally, another bad proxy. Will retry after |retry_delay| if positive,
+ // and will use the default proxy retry duration otherwise. Returns true if
+ // there will be at least one proxy remaining in the list after fallback and
+ // false otherwise.
+ bool MarkProxiesAsBad(const ProxyInfo& results,
+ base::TimeDelta retry_delay,
+ const ProxyServer& another_bad_proxy,
+ const BoundNetLog& net_log);
// Called to report that the last proxy connection succeeded. If |proxy_info|
// has a non empty proxy_retry_info map, the proxies that have been tried (and