diff options
author | bengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 21:17:40 +0000 |
---|---|---|
committer | bengr@chromium.org <bengr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 21:17:40 +0000 |
commit | 3d498f757ecce8dd3a8d77ab71c5c6249bd9ac64 (patch) | |
tree | 5b735db3b8500bb2a3244a124563f336e7d62a11 | |
parent | ba570755b30f617e177c4575d34b0aecfccc3ada (diff) | |
download | chromium_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.cc | 114 | ||||
-rw-r--r-- | net/http/http_network_transaction.cc | 30 | ||||
-rw-r--r-- | net/http/http_response_headers.cc | 40 | ||||
-rw-r--r-- | net/http/http_response_headers.h | 9 | ||||
-rw-r--r-- | net/http/http_response_headers_unittest.cc | 125 | ||||
-rw-r--r-- | net/proxy/proxy_list.cc | 22 | ||||
-rw-r--r-- | net/proxy/proxy_list.h | 6 | ||||
-rw-r--r-- | net/proxy/proxy_service.cc | 4 | ||||
-rw-r--r-- | net/proxy/proxy_service.h | 12 |
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 |