summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-28 21:17:40 +0000
committerbengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-28 21:17:40 +0000
commit3d498f757ecce8dd3a8d77ab71c5c6249bd9ac64 (patch)
tree5b735db3b8500bb2a3244a124563f336e7d62a11
parentba570755b30f617e177c4575d34b0aecfccc3ada (diff)
downloadchromium_src-3d498f757ecce8dd3a8d77ab71c5c6249bd9ac64.zip
chromium_src-3d498f757ecce8dd3a8d77ab71c5c6249bd9ac64.tar.gz
chromium_src-3d498f757ecce8dd3a8d77ab71c5c6249bd9ac64.tar.bz2
Added support for a new HTTP response header called Chrome-Proxy, which is restricted to only the data compression proxy. The header carries a comma-separated list of instructions for proxy/Chrome interaction. This change introduces one instruction, "bypass," which specifies a number of seconds that Chrome should bypass the proxy.
BUG=306631 Review URL: https://codereview.chromium.org/26515005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231404 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/http/http_network_layer_unittest.cc114
-rw-r--r--net/http/http_network_transaction.cc30
-rw-r--r--net/http/http_response_headers.cc40
-rw-r--r--net/http/http_response_headers.h9
-rw-r--r--net/http/http_response_headers_unittest.cc125
-rw-r--r--net/proxy/proxy_list.cc22
-rw-r--r--net/proxy/proxy_list.h6
-rw-r--r--net/proxy/proxy_service.cc4
-rw-r--r--net/proxy/proxy_service.h12
9 files changed, 308 insertions, 54 deletions
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 6d2ea35..b040595 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -48,6 +48,12 @@ class HttpNetworkLayerTest : public PlatformTest {
factory_.reset(new HttpNetworkLayer(network_session_.get()));
}
+#if defined (SPDY_PROXY_AUTH_ORIGIN)
+ std::string GetChromeProxy() {
+ return HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)).ToString();
+ }
+#endif
+
void ExecuteRequestExpectingContentAndHeader(const std::string& content,
const std::string& header,
const std::string& value) {
@@ -80,33 +86,41 @@ class HttpNetworkLayerTest : public PlatformTest {
}
// Check that |proxy_count| proxies are in the retry list.
- // These will be, in order, "bad:8080" and "alsobad:8080".
- void TestBadProxies(unsigned int proxy_count) {
+ // These will be, in order, |bad_proxy| and |bad_proxy2|".
+ void TestBadProxies(unsigned int proxy_count, const std::string& bad_proxy,
+ 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:8080") != retry_info.end());
+ ASSERT_TRUE(retry_info.find(bad_proxy) != retry_info.end());
if (proxy_count > 1)
- ASSERT_TRUE(retry_info.find("alsobad:8080") != retry_info.end());
+ ASSERT_TRUE(retry_info.find(bad_proxy2) != retry_info.end());
}
// Simulates a request through a proxy which returns a bypass, which is then
// retried through a second proxy that doesn't bypass.
// Checks that the expected requests were issued, the expected content was
- // recieved, and the first proxy ("bad:8080") was marked as bad.
- void TestProxyFallback() {
+ // recieved, and the first proxy |bad_proxy| was marked as bad.
+ 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"),
MockRead("Bypass message"),
MockRead(SYNCHRONOUS, OK),
};
+ TestProxyFallbackWithMockReads(bad_proxy, data_reads,
+ arraysize(data_reads));
+ }
+
+ void TestProxyFallbackWithMockReads(const std::string& bad_proxy,
+ MockRead data_reads[],
+ int data_reads_size) {
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),
+ StaticSocketDataProvider data1(data_reads, data_reads_size,
data_writes, arraysize(data_writes));
mock_socket_factory_.AddSocketDataProvider(&data1);
@@ -131,14 +145,14 @@ class HttpNetworkLayerTest : public PlatformTest {
ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
// We should also observe the bad proxy in the retry list.
- TestBadProxies(1u);
+ TestBadProxies(1u, bad_proxy, "");
}
// Simulates a request through a proxy which returns a bypass, which is then
// retried through a direct connection to the origin site.
// Checks that the expected requests were issued, the expected content was
- // received, and the proxy ("bad:8080") was marked as bad.
- void TestProxyFallbackToDirect() {
+ // received, and the proxy |bad_proxy| was marked as bad.
+ 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"),
@@ -175,7 +189,7 @@ class HttpNetworkLayerTest : public PlatformTest {
ExecuteRequestExpectingContentAndHeader("content", "server", "not-proxy");
// We should also observe the bad proxy in the retry list.
- TestBadProxies(1u);
+ TestBadProxies(1u, bad_proxy, "");
}
// Simulates a request through a proxy which returns a bypass, under a
@@ -183,7 +197,9 @@ class HttpNetworkLayerTest : public PlatformTest {
// are expected to be configured.
// Checks that the expected requests were issued, the bypass message was the
// final received content, and all proxies were marked as bad.
- void TestProxyFallbackFail(unsigned int proxy_count) {
+ void TestProxyFallbackFail(unsigned int proxy_count,
+ const std::string& bad_proxy,
+ const std::string& bad_proxy2) {
MockRead data_reads[] = {
MockRead("HTTP/1.1 200 OK\r\n"
"Connection: proxy-bypass\r\n\r\n"),
@@ -208,7 +224,7 @@ class HttpNetworkLayerTest : public PlatformTest {
ExecuteRequestExpectingContentAndHeader("Bypass message", "", "");
// We should also observe the bad proxy or proxies in the retry list.
- TestBadProxies(proxy_count);
+ TestBadProxies(proxy_count, bad_proxy, bad_proxy2);
}
MockClientSocketFactory mock_socket_factory_;
@@ -299,52 +315,68 @@ TEST_F(HttpNetworkLayerTest, GET) {
// - bypass with one proxy configured which is bypassed with no defined
// fallback
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassPac) {
+ std::string bad_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
- "PROXY bad:8080; PROXY good:8080"));
- TestProxyFallback();
+ "PROXY " + bad_proxy + "; PROXY good:8080"));
+ TestProxyFallback(bad_proxy);
}
TEST_F(HttpNetworkLayerTest, ServerTwoProxyBypassFixed) {
- ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080, good:8080"));
- TestProxyFallback();
+ std::string bad_proxy = GetChromeProxy();
+ ConfigureTestDependencies(
+ ProxyService::CreateFixed(bad_proxy +", good:8080"));
+ TestProxyFallback(bad_proxy);
}
TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassPac) {
+ std::string bad_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
- "PROXY bad:8080; DIRECT"));
- TestProxyFallbackToDirect();
+ "PROXY " + bad_proxy + "; DIRECT"));
+ TestProxyFallbackToDirect(bad_proxy);
}
TEST_F(HttpNetworkLayerTest, ServerOneProxyWithDirectBypassFixed) {
- ConfigureTestDependencies(ProxyService::CreateFixed( "bad:8080, direct://"));
- TestProxyFallbackToDirect();
+ std::string bad_proxy = GetChromeProxy();
+ ConfigureTestDependencies(
+ ProxyService::CreateFixed(bad_proxy + ", direct://"));
+ TestProxyFallbackToDirect(bad_proxy);
}
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassPac) {
+ std::string bad_proxy = GetChromeProxy();
+ std::string bad_proxy2 =
+ HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
- "PROXY bad:8080; PROXY alsobad:8080"));
- TestProxyFallbackFail(2u);
+ "PROXY " + bad_proxy + "; PROXY " + bad_proxy2));
+ TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
}
TEST_F(HttpNetworkLayerTest, ServerTwoProxyDoubleBypassFixed) {
+ std::string bad_proxy = GetChromeProxy();
+ std::string bad_proxy2 =
+ HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)).ToString();
ConfigureTestDependencies(ProxyService::CreateFixed(
- "bad:8080, alsobad:8080"));
- TestProxyFallbackFail(2u);
+ bad_proxy + ", " + bad_proxy2));
+ TestProxyFallbackFail(2u, bad_proxy, bad_proxy2);
}
+#endif
TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassPac) {
+ std::string bad_proxy = GetChromeProxy();
ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
- "PROXY bad:8080"));
- TestProxyFallbackFail(1u);
+ "PROXY " + bad_proxy));
+ TestProxyFallbackFail(1u, bad_proxy, "");
}
TEST_F(HttpNetworkLayerTest, ServerOneProxyNoDirectBypassFixed) {
- ConfigureTestDependencies(ProxyService::CreateFixed("bad:8080"));
- TestProxyFallbackFail(1u);
+ std::string bad_proxy = GetChromeProxy();
+ ConfigureTestDependencies(ProxyService::CreateFixed(bad_proxy));
+ TestProxyFallbackFail(1u, bad_proxy, "");
}
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
TEST_F(HttpNetworkLayerTest, ServerFallbackOnInternalServerError) {
// Verify that "500 Internal Server Error" via the data reduction proxy
// induces proxy fallback to a second proxy, if configured.
@@ -466,6 +498,28 @@ TEST_F(HttpNetworkLayerTest, ProxyBypassIgnoredOnDirectConnectionPac) {
ASSERT_EQ(0u, proxy_service_->proxy_retry_info().size());
}
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+TEST_F(HttpNetworkLayerTest, ServerFallbackWithProxyTimedBypass) {
+ // Verify that a Chrome-Proxy: bypass=<seconds> header induces proxy
+ // fallback to a second proxy, if configured.
+ std::string bad_proxy = GetChromeProxy();
+ ConfigureTestDependencies(ProxyService::CreateFixedFromPacResult(
+ "PROXY " + bad_proxy + "; PROXY good:8080"));
+
+ MockRead data_reads[] = {
+ MockRead("HTTP/1.1 200 OK\r\n"
+ "Connection: keep-alive\r\n"
+ "Chrome-Proxy: bypass=86400\r\n\r\n"),
+ MockRead("Bypass message"),
+ MockRead(SYNCHRONOUS, OK),
+ };
+
+ TestProxyFallbackWithMockReads(bad_proxy, data_reads, arraysize(data_reads));
+ EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
+ (*proxy_service_->proxy_retry_info().begin()).second.current_delay);
+}
+#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
+
TEST_F(HttpNetworkLayerTest, NetworkVerified) {
MockRead data_reads[] = {
MockRead("HTTP/1.0 200 OK\r\n\r\n"),
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 9101872..95b9a48 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -19,6 +19,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "net/base/auth.h"
@@ -925,24 +926,34 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
}
DCHECK(response_.headers.get());
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
// Server-induced fallback; see: http://crbug.com/143712
if (response_.was_fetched_via_proxy && response_.headers.get() != NULL) {
- bool should_fallback =
- response_.headers->HasHeaderValue("connection", "proxy-bypass");
+ base::TimeDelta bypass_duration;
+ bool chrome_proxy_used =
+ proxy_info_.proxy_server().host_port_pair().Equals(
+ HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
+#if defined(DATA_REDUCTION_FALLBACK_HOST)
+ if (!chrome_proxy_used) {
+ chrome_proxy_used =
+ proxy_info_.proxy_server().host_port_pair().Equals(
+ HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)));
+ }
+#endif
+ bool should_fallback = chrome_proxy_used &&
+ response_.headers->GetChromeProxyInfo(&bypass_duration);
// Additionally, fallback if a 500 is returned via the data reduction proxy.
// This is conservative, as the 500 might have been generated by the origin,
// and not the proxy.
-#if defined(SPDY_PROXY_AUTH_ORIGIN)
if (!should_fallback) {
- should_fallback =
- response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR &&
- proxy_info_.proxy_server().host_port_pair().Equals(
- HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
+ should_fallback = chrome_proxy_used &&
+ response_.headers->response_code() == HTTP_INTERNAL_SERVER_ERROR;
}
-#endif
+
if (should_fallback) {
ProxyService* proxy_service = session_->proxy_service();
- if (proxy_service->MarkProxyAsBad(proxy_info_, net_log_)) {
+ if (proxy_service->MarkProxyAsBad(proxy_info_, bypass_duration,
+ 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") {
@@ -952,6 +963,7 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
}
}
}
+#endif
// 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 6047aa1..87e3cdb 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -1354,4 +1354,44 @@ bool HttpResponseHeaders::IsChunkEncoded() const {
HasHeaderValue("Transfer-Encoding", "chunked");
}
+#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;
+
+ void* iter = NULL;
+ std::string value;
+ while (EnumerateHeader(&iter, name, &value)) {
+ if (value.size() > kBypassPrefixLen) {
+ if (LowerCaseEqualsASCII(value.begin(),
+ value.begin() + kBypassPrefixLen,
+ kBypassPrefix)) {
+ int64 seconds;
+ if (!base::StringToInt64(StringPiece(value.begin() + kBypassPrefixLen,
+ value.end()),
+ &seconds) || seconds < 0) {
+ continue; // In case there is a well formed bypass instruction.
+ }
+ *bypass_duration = TimeDelta::FromSeconds(seconds);
+ return true;
+ }
+ }
+ }
+ // TODO(bengr): Deprecate the use of Connection: Proxy-Bypass.
+ if (HasHeaderValue("Connection", kProxyBypass))
+ return true;
+
+ return false;
+}
+#endif
+
} // namespace net
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index 6107597..a212980 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -250,6 +250,15 @@ class NET_EXPORT HttpResponseHeaders
// Returns true if the response is chunk-encoded.
bool IsChunkEncoded() const;
+#if defined (SPDY_PROXY_AUTH_ORIGIN)
+ // 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;
+#endif
+
// Creates a Value for use with the NetLog containing the response headers.
base::Value* NetLogCallback(NetLog::LogLevel log_level) const;
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 8bde289e..5904bea 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1877,3 +1877,128 @@ TEST(HttpResponseHeadersTest, ToNetLogParamAndBackAgain) {
parsed->GetNormalizedHeaders(&normalized_recreated);
EXPECT_EQ(normalized_parsed, normalized_recreated);
}
+
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+TEST(HttpResponseHeadersTest, GetProxyBypassInfo) {
+ const struct {
+ const char* headers;
+ bool expected_result;
+ int64 expected_retry_delay;
+ } tests[] = {
+ { "HTTP/1.1 200 OK\n"
+ "Content-Length: 999\n",
+ false,
+ 0,
+ },
+ { "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
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 86400
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=0\n"
+ "Content-Length: 999\n",
+ true,
+ 0
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=-1\n"
+ "Content-Length: 999\n",
+ false,
+ 0
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=xyz\n"
+ "Content-Length: 999\n",
+ false,
+ 0
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass\n"
+ "Content-Length: 999\n",
+ false,
+ 0
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: foo=abc, bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 86400
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=86400, bar=abc\n"
+ "Content-Length: 999\n",
+ true,
+ 86400
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=3600\n"
+ "Chrome-Proxy: bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 3600
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=3600, bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 3600
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass=, bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 86400
+ },
+ { "HTTP/1.1 200 OK\n"
+ "connection: keep-alive\n"
+ "Chrome-Proxy: bypass\n"
+ "Chrome-Proxy: bypass=86400\n"
+ "Content-Length: 999\n",
+ true,
+ 86400
+ },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ std::string headers(tests[i].headers);
+ HeadersToRaw(&headers);
+ scoped_refptr<net::HttpResponseHeaders> parsed(
+ new net::HttpResponseHeaders(headers));
+
+ base::TimeDelta duration;
+ EXPECT_EQ(tests[i].expected_result,
+ parsed->GetChromeProxyInfo(&duration));
+ EXPECT_EQ(tests[i].expected_retry_delay, duration.InSeconds());
+ }
+}
+#endif // defined(SPDY_PROXY_AUTH_ORIGIN)
diff --git a/net/proxy/proxy_list.cc b/net/proxy/proxy_list.cc
index baa638f..bd7cbfb 100644
--- a/net/proxy/proxy_list.cc
+++ b/net/proxy/proxy_list.cc
@@ -185,23 +185,27 @@ bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info,
NOTREACHED();
return false;
}
- UpdateRetryInfoOnFallback(proxy_retry_info, net_log);
+ UpdateRetryInfoOnFallback(proxy_retry_info, base::TimeDelta(), net_log);
// Remove this proxy from our list.
proxies_.erase(proxies_.begin());
return !proxies_.empty();
}
-void ProxyList::UpdateRetryInfoOnFallback(
- ProxyRetryInfoMap* proxy_retry_info, const BoundNetLog& net_log) const {
+void ProxyList::UpdateRetryInfoOnFallback(ProxyRetryInfoMap* proxy_retry_info,
+ base::TimeDelta retry_delay,
+ const BoundNetLog& net_log) const {
// Time to wait before retrying a bad proxy server.
-#if defined(OS_ANDROID) || defined(OS_IOS)
- // Randomize the timeout over a range from one to five minutes.
- const TimeDelta proxy_retry_delay =
- TimeDelta::FromMilliseconds(base::RandInt(1 * 60 * 1000, 5 * 60 * 1000));
+ if (retry_delay == base::TimeDelta()) {
+#if defined(SPDY_PROXY_AUTH_ORIGIN)
+ // Randomize the timeout over a range from one to five minutes.
+ retry_delay =
+ TimeDelta::FromMilliseconds(
+ base::RandInt(1 * 60 * 1000, 5 * 60 * 1000));
#else
- const TimeDelta proxy_retry_delay = TimeDelta::FromMinutes(5);
+ retry_delay = TimeDelta::FromMinutes(5);
#endif
+ }
if (proxies_.empty()) {
NOTREACHED();
@@ -218,7 +222,7 @@ void ProxyList::UpdateRetryInfoOnFallback(
iter->second.bad_until = TimeTicks::Now() + iter->second.current_delay;
} else {
ProxyRetryInfo retry_info;
- retry_info.current_delay = proxy_retry_delay;
+ retry_info.current_delay = retry_delay;
retry_info.bad_until = TimeTicks().Now() + retry_info.current_delay;
(*proxy_retry_info)[key] = retry_info;
}
diff --git a/net/proxy/proxy_list.h b/net/proxy/proxy_list.h
index 9f5fa59..33a78a8 100644
--- a/net/proxy/proxy_list.h
+++ b/net/proxy/proxy_list.h
@@ -14,6 +14,7 @@
namespace base {
class ListValue;
+class TimeDelta;
}
namespace net {
@@ -89,8 +90,11 @@ class NET_EXPORT_PRIVATE ProxyList {
// Updates |proxy_retry_info| to indicate that the first proxy in the list
// is bad. This is distinct from Fallback(), above, to allow updating proxy
- // retry information without modifying a given transction's proxy list.
+ // 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;
private:
diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc
index e3b13e3..4f9c8be 100644
--- a/net/proxy/proxy_service.cc
+++ b/net/proxy/proxy_service.cc
@@ -1179,8 +1179,10 @@ int ProxyService::ReconsiderProxyAfterError(const GURL& url,
}
bool ProxyService::MarkProxyAsBad(const ProxyInfo& result,
+ base::TimeDelta retry_delay,
const BoundNetLog& net_log) {
- result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, net_log);
+ result.proxy_list_.UpdateRetryInfoOnFallback(&proxy_retry_info_, retry_delay,
+ 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 6639911..7e4e306 100644
--- a/net/proxy/proxy_service.h
+++ b/net/proxy/proxy_service.h
@@ -27,6 +27,7 @@ class GURL;
namespace base {
class MessageLoop;
class SingleThreadTaskRunner;
+class TimeDelta;
} // namespace base
namespace net {
@@ -147,10 +148,13 @@ 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|. Returns true
- // if there will be at least one proxy remaining in the list after fallback
- // and false otherwise.
- bool MarkProxyAsBad(const ProxyInfo& results, const BoundNetLog& net_log);
+ // 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);
// 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