summaryrefslogtreecommitdiffstats
path: root/net/proxy
diff options
context:
space:
mode:
authorhamaji@chromium.org <hamaji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 12:11:05 +0000
committerhamaji@chromium.org <hamaji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-06 12:11:05 +0000
commita692c6f3a59e711bc38fc72fce3c938deec64da0 (patch)
tree0583e80059992b55252390a7891e1651ba1c2ab3 /net/proxy
parent4bd778d6cd4e108a38caeda9b283f01691fe7ecf (diff)
downloadchromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.zip
chromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.tar.gz
chromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.tar.bz2
Reverting r22591. It seems to be making purify fail.
r22590: http://build.chromium.org/buildbot/waterfall/builders/XP%20Unit%20(purify)/builds/5026 r22591: http://build.chromium.org/buildbot/waterfall/builders/XP%20Unit%20(purify)/builds/5030 TEST=none BUG=none TBR=eroman Review URL: http://codereview.chromium.org/165048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22603 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/proxy')
-rw-r--r--net/proxy/mock_proxy_resolver.h1375
-rw-r--r--net/proxy/proxy_service_unittest.cc151
2 files changed, 1517 insertions, 9 deletions
diff --git a/net/proxy/mock_proxy_resolver.h b/net/proxy/mock_proxy_resolver.h
index 0b1e8a5..0dac40b 100644
--- a/net/proxy/mock_proxy_resolver.h
+++ b/net/proxy/mock_proxy_resolver.h
@@ -1,18 +1,40 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2008 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 NET_PROXY_MOCK_PROXY_RESOLVER_H_
-#define NET_PROXY_MOCK_PROXY_RESOLVER_H_
-
#include <vector>
#include "base/logging.h"
+#include "base/string_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_resolver.h"
+#include "net/proxy/proxy_script_fetcher.h"
+#include "net/proxy/proxy_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+// TODO(eroman): Write a test which exercises
+// ProxyService::SuspendAllPendingRequests().
namespace net {
+namespace {
+
+class MockProxyConfigService: public ProxyConfigService {
+ public:
+ MockProxyConfigService() {} // Direct connect.
+ explicit MockProxyConfigService(const ProxyConfig& pc) : config(pc) {}
+ explicit MockProxyConfigService(const std::string& pac_url) {
+ config.pac_url = GURL(pac_url);
+ }
+
+ virtual int GetProxyConfig(ProxyConfig* results) {
+ *results = config;
+ return OK;
+ }
+
+ ProxyConfig config;
+};
// Asynchronous mock proxy resolver. All requests complete asynchronously,
// user must call Request::CompleteNow() on a pending request to signal it.
@@ -111,7 +133,7 @@ class MockAsyncProxyResolverBase : public ProxyResolver {
virtual int SetPacScript(const GURL& pac_url,
const std::string& pac_bytes,
CompletionCallback* callback) {
- DCHECK(!pending_set_pac_script_request_.get());
+ EXPECT_EQ(NULL, pending_set_pac_script_request_.get());
pending_set_pac_script_request_.reset(
new SetPacScriptRequest(this, pac_url, pac_bytes, callback));
// Finished when user calls SetPacScriptRequest::CompleteNow().
@@ -138,7 +160,7 @@ class MockAsyncProxyResolverBase : public ProxyResolver {
}
void RemovePendingSetPacScriptRequest(SetPacScriptRequest* request) {
- DCHECK_EQ(request, pending_set_pac_script_request());
+ EXPECT_EQ(request, pending_set_pac_script_request());
pending_set_pac_script_request_.reset();
}
@@ -164,6 +186,1343 @@ class MockAsyncProxyResolverExpectsBytes : public MockAsyncProxyResolverBase {
: MockAsyncProxyResolverBase(true /*expects_pac_bytes*/) {}
};
-} // namespace net
+} // namespace
+
+// A mock ProxyScriptFetcher. No result will be returned to the fetch client
+// until we call NotifyFetchCompletion() to set the results.
+class MockProxyScriptFetcher : public ProxyScriptFetcher {
+ public:
+ MockProxyScriptFetcher()
+ : pending_request_callback_(NULL), pending_request_bytes_(NULL) {
+ }
+
+ // ProxyScriptFetcher implementation.
+ virtual int Fetch(const GURL& url,
+ std::string* bytes,
+ CompletionCallback* callback) {
+ DCHECK(!has_pending_request());
+
+ // Save the caller's information, and have them wait.
+ pending_request_url_ = url;
+ pending_request_callback_ = callback;
+ pending_request_bytes_ = bytes;
+ return ERR_IO_PENDING;
+ }
+
+ void NotifyFetchCompletion(int result, const std::string& bytes) {
+ DCHECK(has_pending_request());
+ *pending_request_bytes_ = bytes;
+ CompletionCallback* callback = pending_request_callback_;
+ pending_request_callback_ = NULL;
+ callback->Run(result);
+ }
+
+ virtual void Cancel() {}
+
+ const GURL& pending_request_url() const {
+ return pending_request_url_;
+ }
+
+ bool has_pending_request() const {
+ return pending_request_callback_ != NULL;
+ }
+
+ private:
+ GURL pending_request_url_;
+ CompletionCallback* pending_request_callback_;
+ std::string* pending_request_bytes_;
+};
+
+TEST(ProxyServiceTest, Direct) {
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+ ProxyService service(new MockProxyConfigService, resolver);
+
+ GURL url("http://www.google.com/");
+
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(resolver->pending_requests().empty());
+
+ EXPECT_TRUE(info.is_direct());
+}
+
+TEST(ProxyServiceTest, PAC) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://www.google.com/");
+
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(url, &info, &callback, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("foopy");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy:80", info.proxy_server().ToURI());
+}
+
+// Test that the proxy resolver does not see the URL's username/password
+// or its reference section.
+TEST(ProxyServiceTest, PAC_NoIdentityOrHash) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://username:password@www.google.com/?ref#hash#hash");
+
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(url, &info, &callback, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ // The URL should have been simplified, stripping the username/password/hash.
+ EXPECT_EQ(GURL("http://www.google.com/?ref"),
+ resolver->pending_requests()[0]->url());
+
+ // We end here without ever completing the request -- destruction of
+ // ProxyService will cancel the outstanding request.
+}
+
+TEST(ProxyServiceTest, PAC_FailoverToDirect) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://www.google.com/");
+
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(url, &info, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("foopy:8080");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy:8080", info.proxy_server().ToURI());
+
+ // Now, imagine that connecting to foopy:8080 fails.
+ TestCompletionCallback callback2;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback2, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+}
+
+TEST(ProxyServiceTest, ProxyResolverFails) {
+ // Test what happens when the ProxyResolver fails (this could represent
+ // a failure to download the PAC script in the case of ProxyResolvers which
+ // do the fetch internally.)
+ // TODO(eroman): change this comment.
+
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ // Start first resolve request.
+ GURL url("http://www.google.com/");
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(url, &info, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Fail the first resolve request in MockAsyncProxyResolver.
+ resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
+
+ EXPECT_EQ(ERR_FAILED, callback1.WaitForResult());
+
+ // The second resolve request will automatically select direct connect,
+ // because it has cached the configuration as being bad.
+ TestCompletionCallback callback2;
+ rv = service.ResolveProxy(url, &info, &callback2, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ EXPECT_TRUE(resolver->pending_requests().empty());
+
+ // But, if that fails, then we should give the proxy config another shot
+ // since we have never tried it with this URL before.
+ TestCompletionCallback callback3;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("foopy_valid:8080");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy_valid:8080", info.proxy_server().ToURI());
+}
+
+TEST(ProxyServiceTest, ProxyFallback) {
+ // Test what happens when we specify multiple proxy servers and some of them
+ // are bad.
+
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://www.google.com/");
+
+ // Get the proxy information.
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(url, &info, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver.
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // The first item is valid.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+
+ // Fake an error on the proxy.
+ TestCompletionCallback callback2;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback2, NULL);
+ EXPECT_EQ(OK, rv);
+
+ // The second proxy should be specified.
+ EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
+
+ TestCompletionCallback callback3;
+ rv = service.ResolveProxy(url, &info, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver -- the second result is already known
+ // to be bad.
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy3:7070;foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy3:7070", info.proxy_server().ToURI());
+
+ // We fake another error. It should now try the third one.
+ TestCompletionCallback callback4;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback4, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
+
+ // Fake another error, the last proxy is gone, the list should now be empty.
+ TestCompletionCallback callback5;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback5, NULL);
+ EXPECT_EQ(OK, rv); // We try direct.
+ EXPECT_TRUE(info.is_direct());
+
+ // If it fails again, we don't have anything else to try.
+ TestCompletionCallback callback6;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback6, NULL);
+ EXPECT_EQ(ERR_FAILED, rv);
+
+ // TODO(nsylvain): Test that the proxy can be retried after the delay.
+}
+
+TEST(ProxyServiceTest, ProxyFallback_NewSettings) {
+ // Test proxy failover when new settings are available.
+
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://www.google.com/");
+
+ // Get the proxy information.
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(url, &info, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ // Set the result in proxy resolver.
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // The first item is valid.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+
+ // Fake an error on the proxy, and also a new configuration on the proxy.
+ config_service->config = ProxyConfig();
+ config_service->config.pac_url = GURL("http://foopy-new/proxy.pac");
+
+ TestCompletionCallback callback2;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback2, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy-new/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // The first proxy is still there since the configuration changed.
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+
+ // We fake another error. It should now ignore the first one.
+ TestCompletionCallback callback3;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback3, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
+
+ // We simulate a new configuration.
+ config_service->config = ProxyConfig();
+ config_service->config.pac_url = GURL("http://foopy-new2/proxy.pac");
+
+ // We fake another error. It should go back to the first proxy.
+ TestCompletionCallback callback4;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback4, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy-new2/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback4.WaitForResult());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+}
+
+TEST(ProxyServiceTest, ProxyFallback_BadConfig) {
+ // Test proxy failover when the configuration is bad.
+
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ GURL url("http://www.google.com/");
+
+ // Get the proxy information.
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(url, &info, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // The first item is valid.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+
+ // Fake a proxy error.
+ TestCompletionCallback callback2;
+ rv = service.ReconsiderProxyAfterError(url, &info, &callback2, NULL);
+ EXPECT_EQ(OK, rv);
+
+ // The first proxy is ignored, and the second one is selected.
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy2:9090", info.proxy_server().ToURI());
+
+ // Fake a PAC failure.
+ ProxyInfo info2;
+ TestCompletionCallback callback3;
+ rv = service.ResolveProxy(url, &info2, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ resolver->pending_requests()[0]->CompleteNow(ERR_FAILED);
+
+ // No proxy servers are returned. It's a direct connection.
+ EXPECT_EQ(ERR_FAILED, callback3.WaitForResult());
+ EXPECT_TRUE(info2.is_direct());
+
+ // The PAC will now be fixed and will return a proxy server.
+ // It should also clear the list of bad proxies.
+
+ // Try to resolve, it will still return "direct" because we have no reason
+ // to check the config since everything works.
+ ProxyInfo info3;
+ TestCompletionCallback callback4;
+ rv = service.ResolveProxy(url, &info3, &callback4, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info3.is_direct());
+
+ // But if the direct connection fails, we check if the ProxyInfo tried to
+ // resolve the proxy before, and if not (like in this case), we give the
+ // PAC another try.
+ TestCompletionCallback callback5;
+ rv = service.ReconsiderProxyAfterError(url, &info3, &callback5, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(url, resolver->pending_requests()[0]->url());
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy(
+ "foopy1:8080;foopy2:9090");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // The first proxy is still there since the list of bad proxies got cleared.
+ EXPECT_EQ(OK, callback5.WaitForResult());
+ EXPECT_FALSE(info3.is_direct());
+ EXPECT_EQ("foopy1:8080", info3.proxy_server().ToURI());
+}
+
+TEST(ProxyServiceTest, ProxyBypassList) {
+ // Test what happens when a proxy bypass list is specified.
+
+ ProxyInfo info;
+ ProxyConfig config;
+ config.proxy_rules.ParseFromString("foopy1:8080;foopy2:9090");
+ config.auto_detect = false;
+ config.proxy_bypass_local_names = true;
+
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver());
+ GURL url("http://www.google.com/");
+ // Get the proxy information.
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ }
+
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver());
+ GURL test_url("http://local");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.org");
+ config.proxy_bypass_local_names = true;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.webkit.org");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.org");
+ config.proxy_bypass.push_back("7*");
+ config.proxy_bypass_local_names = true;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://74.125.19.147");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.org");
+ config.proxy_bypass_local_names = true;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.msn.com");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.MSN.COM");
+ config.proxy_bypass_local_names = true;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.msnbc.msn.com");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.msn.com");
+ config.proxy_bypass_local_names = true;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("HTTP://WWW.MSNBC.MSN.COM");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+}
+
+TEST(ProxyServiceTest, ProxyBypassListWithPorts) {
+ // Test port specification in bypass list entries.
+ ProxyInfo info;
+ ProxyConfig config;
+ config.proxy_rules.ParseFromString("foopy1:8080;foopy2:9090");
+ config.auto_detect = false;
+ config.proxy_bypass_local_names = false;
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.example.com:99");
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ {
+ GURL test_url("http://www.example.com:99");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+ {
+ GURL test_url("http://www.example.com:100");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ }
+ {
+ GURL test_url("http://www.example.com");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ }
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.example.com:80");
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.example.com");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("*.example.com");
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.example.com:99");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+
+ // IPv6 with port.
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("[3ffe:2a00:100:7031::1]:99");
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ {
+ GURL test_url("http://[3ffe:2a00:100:7031::1]:99/");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+ {
+ GURL test_url("http://[3ffe:2a00:100:7031::1]/");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ }
+ }
+
+ // IPv6 without port. The bypass entry ought to work without the
+ // brackets, but the bypass matching logic in ProxyService is
+ // currently limited.
+ config.proxy_bypass.clear();
+ config.proxy_bypass.push_back("[3ffe:2a00:100:7031::1]");
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ {
+ GURL test_url("http://[3ffe:2a00:100:7031::1]:99/");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+ {
+ GURL test_url("http://[3ffe:2a00:100:7031::1]/");
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ }
+ }
+}
+
+TEST(ProxyServiceTest, PerProtocolProxyTests) {
+ ProxyConfig config;
+ config.proxy_rules.ParseFromString("http=foopy1:8080;https=foopy2:8080");
+ config.auto_detect = false;
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.msn.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+ }
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("ftp://ftp.google.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_TRUE(info.is_direct());
+ EXPECT_EQ("direct://", info.proxy_server().ToURI());
+ }
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("https://webbranch.techcu.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
+ }
+ {
+ config.proxy_rules.ParseFromString("foopy1:8080");
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.microsoft.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+ }
+}
+
+// If only HTTP and a SOCKS proxy are specified, check if ftp/https queries
+// fall back to the SOCKS proxy.
+TEST(ProxyServiceTest, DefaultProxyFallbackToSOCKS) {
+ ProxyConfig config;
+ config.proxy_rules.ParseFromString("http=foopy1:8080;socks=foopy2:1080");
+ config.auto_detect = false;
+ EXPECT_EQ(ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME,
+ config.proxy_rules.type);
+
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("http://www.msn.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+ }
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("ftp://ftp.google.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
+ }
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("https://webbranch.techcu.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
+ }
+ {
+ ProxyService service(new MockProxyConfigService(config),
+ new MockAsyncProxyResolver);
+ GURL test_url("unknown://www.microsoft.com");
+ ProxyInfo info;
+ TestCompletionCallback callback;
+ int rv = service.ResolveProxy(test_url, &info, &callback, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_FALSE(info.is_direct());
+ EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
+ }
+}
+
+// Test cancellation of an in-progress request.
+TEST(ProxyServiceTest, CancelInProgressRequest) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
+
+ ProxyService service(config_service, resolver);
+
+ // Start 3 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Nothing has been sent to the proxy resolver yet, since the proxy
+ // resolver has not been configured yet.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // Successfully initialize the PAC script.
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"),
+ resolver->pending_set_pac_script_request()->pac_url());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ ProxyService::PacRequest* request2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, &request2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_EQ(2u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
+
+ ProxyInfo info3;
+ TestCompletionCallback callback3;
+ rv = service.ResolveProxy(
+ GURL("http://request3"), &info3, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_EQ(3u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
+
+ // Cancel the second request
+ service.CancelPacRequest(request2);
+
+ ASSERT_EQ(2u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
+ EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[1]->url());
+
+ // Complete the two un-cancelled requests.
+ // We complete the last one first, just to mix it up a bit.
+ resolver->pending_requests()[1]->results()->UseNamedProxy("request3:80");
+ resolver->pending_requests()[1]->CompleteNow(OK);
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // Complete and verify that requests ran as expected.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
+
+ EXPECT_FALSE(callback2.have_result()); // Cancelled.
+ ASSERT_EQ(1u, resolver->cancelled_requests().size());
+ EXPECT_EQ(GURL("http://request2"), resolver->cancelled_requests()[0]->url());
+
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
+}
+
+// Test the initial PAC download for ProxyResolverWithoutFetch.
+TEST(ProxyServiceTest, InitialPACScriptDownload) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 3 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // The first request should have triggered download of PAC script.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ProxyInfo info3;
+ TestCompletionCallback callback3;
+ rv = service.ResolveProxy(
+ GURL("http://request3"), &info3, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Nothing has been sent to the resolver yet.
+ EXPECT_TRUE(resolver->pending_requests().empty());
+
+ // At this point the ProxyService should be waiting for the
+ // ProxyScriptFetcher to invoke its completion callback, notifying it of
+ // PAC script download completion.
+ fetcher->NotifyFetchCompletion(OK, "pac-v1");
+
+ // Now that the PAC script is downloaded, it will have been sent to the proxy
+ // resolver.
+ EXPECT_EQ("pac-v1", resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(3u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
+ EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
+ EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[2]->url());
+
+ // Complete all the requests (in some order).
+ // Note that as we complete requests, they shift up in |pending_requests()|.
+
+ resolver->pending_requests()[2]->results()->UseNamedProxy("request3:80");
+ resolver->pending_requests()[2]->CompleteNow(OK);
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // Complete and verify that requests ran as expected.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
+
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
+}
+
+// Test cancellation of a request, while the PAC script is being fetched.
+TEST(ProxyServiceTest, CancelWhilePACFetching) {
+ MockProxyConfigService* config_service =
+ new MockProxyConfigService("http://foopy/proxy.pac");
+
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 3 requests.
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ ProxyService::PacRequest* request1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, &request1);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // The first request should have triggered download of PAC script.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ ProxyService::PacRequest* request2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, &request2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ProxyInfo info3;
+ TestCompletionCallback callback3;
+ rv = service.ResolveProxy(
+ GURL("http://request3"), &info3, &callback3, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Nothing has been sent to the resolver yet.
+ EXPECT_TRUE(resolver->pending_requests().empty());
+
+ // Cancel the first 2 requests.
+ service.CancelPacRequest(request1);
+ service.CancelPacRequest(request2);
+
+ // At this point the ProxyService should be waiting for the
+ // ProxyScriptFetcher to invoke its completion callback, notifying it of
+ // PAC script download completion.
+ fetcher->NotifyFetchCompletion(OK, "pac-v1");
+
+ // Now that the PAC script is downloaded, it will have been sent to the
+ // proxy resolver.
+ EXPECT_EQ("pac-v1", resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
-#endif // NET_PROXY_MOCK_PROXY_RESOLVER_H_
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request3"), resolver->pending_requests()[0]->url());
+
+ // Complete all the requests.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request3:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback3.WaitForResult());
+ EXPECT_EQ("request3:80", info3.proxy_server().ToURI());
+
+ EXPECT_TRUE(resolver->cancelled_requests().empty());
+
+ EXPECT_FALSE(callback1.have_result()); // Cancelled.
+ EXPECT_FALSE(callback2.have_result()); // Cancelled.
+}
+
+// Test that if auto-detect fails, we fall-back to the custom pac.
+TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac) {
+ ProxyConfig config;
+ config.auto_detect = true;
+ config.pac_url = GURL("http://foopy/proxy.pac");
+ config.proxy_rules.ParseFromString("http=foopy:80"); // Won't be used.
+
+ MockProxyConfigService* config_service = new MockProxyConfigService(config);
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 2 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ ProxyService::PacRequest* request2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, &request2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Check that nothing has been sent to the proxy resolver yet.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // It should be trying to auto-detect first -- FAIL the autodetect during
+ // the script download.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(ERR_FAILED, "");
+
+ // Next it should be trying the custom PAC url.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(OK, "custom-pac-script");
+
+ EXPECT_EQ("custom-pac-script",
+ resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ // Now finally, the pending requests should have been sent to the resolver
+ // (which was initialized with custom PAC script).
+
+ ASSERT_EQ(2u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
+ EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
+
+ // Complete the pending requests.
+ resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
+ resolver->pending_requests()[1]->CompleteNow(OK);
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // Verify that requests ran as expected.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
+}
+
+// This is the same test as FallbackFromAutodetectToCustomPac, except
+// the auto-detect script fails parsing rather than downloading.
+TEST(ProxyServiceTest, FallbackFromAutodetectToCustomPac2) {
+ ProxyConfig config;
+ config.auto_detect = true;
+ config.pac_url = GURL("http://foopy/proxy.pac");
+ config.proxy_rules.ParseFromString("http=foopy:80"); // Won't be used.
+
+ MockProxyConfigService* config_service = new MockProxyConfigService(config);
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 2 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ ProxyService::PacRequest* request2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, &request2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Check that nothing has been sent to the proxy resolver yet.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // It should be trying to auto-detect first -- succeed the download.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(OK, "invalid-script-contents");
+
+ // Simulate a parse error.
+ EXPECT_EQ("invalid-script-contents",
+ resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(
+ ERR_PAC_SCRIPT_FAILED);
+
+ // Next it should be trying the custom PAC url.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(OK, "custom-pac-script");
+
+ EXPECT_EQ("custom-pac-script",
+ resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ // Now finally, the pending requests should have been sent to the resolver
+ // (which was initialized with custom PAC script).
+
+ ASSERT_EQ(2u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://request1"), resolver->pending_requests()[0]->url());
+ EXPECT_EQ(GURL("http://request2"), resolver->pending_requests()[1]->url());
+
+ // Complete the pending requests.
+ resolver->pending_requests()[1]->results()->UseNamedProxy("request2:80");
+ resolver->pending_requests()[1]->CompleteNow(OK);
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // Verify that requests ran as expected.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
+}
+
+// Test that if all of auto-detect, a custom PAC script, and manual settings
+// are given, then we will try them in that order.
+TEST(ProxyServiceTest, FallbackFromAutodetectToCustomToManual) {
+ ProxyConfig config;
+ config.auto_detect = true;
+ config.pac_url = GURL("http://foopy/proxy.pac");
+ config.proxy_rules.ParseFromString("http=foopy:80");
+
+ MockProxyConfigService* config_service = new MockProxyConfigService(config);
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 2 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ ProxyService::PacRequest* request2;
+ rv = service.ResolveProxy(
+ GURL("http://request2"), &info2, &callback2, &request2);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Check that nothing has been sent to the proxy resolver yet.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // It should be trying to auto-detect first -- fail the download.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(ERR_FAILED, "");
+
+ // Next it should be trying the custom PAC url -- fail the download.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://foopy/proxy.pac"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(ERR_FAILED, "");
+
+ // Since we never managed to initialize a ProxyResolver, nothing should have
+ // been sent to it.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // Verify that requests ran as expected -- they should have fallen back to
+ // the manual proxy configuration for HTTP urls.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("foopy:80", info1.proxy_server().ToURI());
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("foopy:80", info2.proxy_server().ToURI());
+}
+
+// Test that the bypass rules are NOT applied when using autodetect.
+TEST(ProxyServiceTest, BypassDoesntApplyToPac) {
+ ProxyConfig config;
+ config.auto_detect = true;
+ config.pac_url = GURL("http://foopy/proxy.pac");
+ config.proxy_rules.ParseFromString("http=foopy:80"); // Not used.
+ config.proxy_bypass.push_back("www.google.com");
+
+ MockProxyConfigService* config_service = new MockProxyConfigService(config);
+ MockAsyncProxyResolverExpectsBytes* resolver =
+ new MockAsyncProxyResolverExpectsBytes;
+ ProxyService service(config_service, resolver);
+
+ MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
+ service.SetProxyScriptFetcher(fetcher);
+
+ // Start 1 requests.
+
+ ProxyInfo info1;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://www.google.com"), &info1, &callback1, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ // Check that nothing has been sent to the proxy resolver yet.
+ ASSERT_EQ(0u, resolver->pending_requests().size());
+
+ // It should be trying to auto-detect first -- succeed the download.
+ EXPECT_TRUE(fetcher->has_pending_request());
+ EXPECT_EQ(GURL("http://wpad/wpad.dat"), fetcher->pending_request_url());
+ fetcher->NotifyFetchCompletion(OK, "auto-detect");
+
+ EXPECT_EQ("auto-detect",
+ resolver->pending_set_pac_script_request()->pac_bytes());
+ resolver->pending_set_pac_script_request()->CompleteNow(OK);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://www.google.com"),
+ resolver->pending_requests()[0]->url());
+
+ // Complete the pending request.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request1:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ // Verify that request ran as expected.
+ EXPECT_EQ(OK, callback1.WaitForResult());
+ EXPECT_EQ("request1:80", info1.proxy_server().ToURI());
+
+ // Start another request, it should pickup the bypass item.
+ ProxyInfo info2;
+ TestCompletionCallback callback2;
+ rv = service.ResolveProxy(
+ GURL("http://www.google.com"), &info2, &callback2, NULL);
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ ASSERT_EQ(1u, resolver->pending_requests().size());
+ EXPECT_EQ(GURL("http://www.google.com"),
+ resolver->pending_requests()[0]->url());
+
+ // Complete the pending request.
+ resolver->pending_requests()[0]->results()->UseNamedProxy("request2:80");
+ resolver->pending_requests()[0]->CompleteNow(OK);
+
+ EXPECT_EQ(OK, callback2.WaitForResult());
+ EXPECT_EQ("request2:80", info2.proxy_server().ToURI());
+}
+
+TEST(ProxyServiceTest, ResetProxyConfigService) {
+ ProxyConfig config1;
+ config1.proxy_rules.ParseFromString("foopy1:8080");
+ config1.auto_detect = false;
+ ProxyService service(new MockProxyConfigService(config1),
+ new MockAsyncProxyResolverExpectsBytes);
+
+ ProxyInfo info;
+ TestCompletionCallback callback1;
+ int rv = service.ResolveProxy(
+ GURL("http://request1"), &info, &callback1, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
+
+ ProxyConfig config2;
+ config2.proxy_rules.ParseFromString("foopy2:8080");
+ config2.auto_detect = false;
+ service.ResetConfigService(new MockProxyConfigService(config2));
+ TestCompletionCallback callback2;
+ rv = service.ResolveProxy(GURL("http://request2"), &info, &callback2, NULL);
+ EXPECT_EQ(OK, rv);
+ EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
+}
+
+TEST(ProxyServiceTest, IsLocalName) {
+ const struct {
+ const char* url;
+ bool expected_is_local;
+ } tests[] = {
+ // Single-component hostnames are considered local.
+ {"http://localhost/x", true},
+ {"http://www", true},
+
+ // IPv4 loopback interface.
+ {"http://127.0.0.1/x", true},
+ {"http://127.0.0.1:80/x", true},
+
+ // IPv6 loopback interface.
+ {"http://[::1]:80/x", true},
+ {"http://[0:0::1]:6233/x", true},
+ {"http://[0:0:0:0:0:0:0:1]/x", true},
+
+ // Non-local URLs.
+ {"http://foo.com/", false},
+ {"http://localhost.i/", false},
+ {"http://www.google.com/", false},
+ {"http://192.168.0.1/", false},
+
+ // Try with different protocols.
+ {"ftp://127.0.0.1/x", true},
+ {"ftp://foobar.com/x", false},
+
+ // This is a bit of a gray-area, but GURL does not strip trailing dots
+ // in host-names, so the following are considered non-local.
+ {"http://www./x", false},
+ {"http://localhost./x", false},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ SCOPED_TRACE(StringPrintf("Test[%d]: %s", i, tests[i].url));
+ bool is_local = ProxyService::IsLocalName(GURL(tests[i].url));
+ EXPECT_EQ(tests[i].expected_is_local, is_local);
+ }
+}
+
+} // namespace net
diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc
index f4deb67..3b3eb49 100644
--- a/net/proxy/proxy_service_unittest.cc
+++ b/net/proxy/proxy_service_unittest.cc
@@ -9,7 +9,6 @@
#include "googleurl/src/gurl.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
-#include "net/proxy/mock_proxy_resolver.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_resolver.h"
#include "net/proxy/proxy_script_fetcher.h"
@@ -37,6 +36,156 @@ class MockProxyConfigService: public ProxyConfigService {
ProxyConfig config;
};
+// Asynchronous mock proxy resolver. All requests complete asynchronously,
+// user must call Request::CompleteNow() on a pending request to signal it.
+class MockAsyncProxyResolverBase : public ProxyResolver {
+ public:
+ class Request : public base::RefCounted<Request> {
+ public:
+ Request(MockAsyncProxyResolverBase* resolver,
+ const GURL& url,
+ ProxyInfo* results,
+ CompletionCallback* callback)
+ : resolver_(resolver),
+ url_(url),
+ results_(results),
+ callback_(callback),
+ origin_loop_(MessageLoop::current()) {
+ }
+
+ const GURL& url() const { return url_; }
+ ProxyInfo* results() const { return results_; }
+ CompletionCallback* callback() const { return callback_; }
+
+ void CompleteNow(int rv) {
+ CompletionCallback* callback = callback_;
+
+ // May delete |this|.
+ resolver_->RemovePendingRequest(this);
+
+ callback->Run(rv);
+ }
+
+ private:
+ MockAsyncProxyResolverBase* resolver_;
+ const GURL url_;
+ ProxyInfo* results_;
+ CompletionCallback* callback_;
+ MessageLoop* origin_loop_;
+ };
+
+ class SetPacScriptRequest {
+ public:
+ SetPacScriptRequest(MockAsyncProxyResolverBase* resolver,
+ const GURL& pac_url,
+ const std::string& pac_bytes,
+ CompletionCallback* callback)
+ : resolver_(resolver),
+ pac_url_(pac_url),
+ pac_bytes_(pac_bytes),
+ callback_(callback),
+ origin_loop_(MessageLoop::current()) {
+ }
+
+ const GURL& pac_url() const { return pac_url_; }
+ const std::string& pac_bytes() const { return pac_bytes_; }
+
+ void CompleteNow(int rv) {
+ CompletionCallback* callback = callback_;
+
+ // Will delete |this|.
+ resolver_->RemovePendingSetPacScriptRequest(this);
+
+ callback->Run(rv);
+ }
+
+ private:
+ MockAsyncProxyResolverBase* resolver_;
+ const GURL pac_url_;
+ const std::string pac_bytes_;
+ CompletionCallback* callback_;
+ MessageLoop* origin_loop_;
+ };
+
+ typedef std::vector<scoped_refptr<Request> > RequestsList;
+
+ // ProxyResolver implementation:
+ virtual int GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ CompletionCallback* callback,
+ RequestHandle* request_handle) {
+ scoped_refptr<Request> request = new Request(this, url, results, callback);
+ pending_requests_.push_back(request);
+
+ if (request_handle)
+ *request_handle = reinterpret_cast<RequestHandle>(request.get());
+
+ // Test code completes the request by calling request->CompleteNow().
+ return ERR_IO_PENDING;
+ }
+
+ virtual void CancelRequest(RequestHandle request_handle) {
+ scoped_refptr<Request> request = reinterpret_cast<Request*>(request_handle);
+ cancelled_requests_.push_back(request);
+ RemovePendingRequest(request);
+ }
+
+ virtual int SetPacScript(const GURL& pac_url,
+ const std::string& pac_bytes,
+ CompletionCallback* callback) {
+ EXPECT_EQ(NULL, pending_set_pac_script_request_.get());
+ pending_set_pac_script_request_.reset(
+ new SetPacScriptRequest(this, pac_url, pac_bytes, callback));
+ // Finished when user calls SetPacScriptRequest::CompleteNow().
+ return ERR_IO_PENDING;
+ }
+
+ const RequestsList& pending_requests() const {
+ return pending_requests_;
+ }
+
+ const RequestsList& cancelled_requests() const {
+ return cancelled_requests_;
+ }
+
+ SetPacScriptRequest* pending_set_pac_script_request() const {
+ return pending_set_pac_script_request_.get();
+ }
+
+ void RemovePendingRequest(Request* request) {
+ RequestsList::iterator it = std::find(
+ pending_requests_.begin(), pending_requests_.end(), request);
+ DCHECK(it != pending_requests_.end());
+ pending_requests_.erase(it);
+ }
+
+ void RemovePendingSetPacScriptRequest(SetPacScriptRequest* request) {
+ EXPECT_EQ(request, pending_set_pac_script_request());
+ pending_set_pac_script_request_.reset();
+ }
+
+ protected:
+ explicit MockAsyncProxyResolverBase(bool expects_pac_bytes)
+ : ProxyResolver(expects_pac_bytes) {}
+
+ private:
+ RequestsList pending_requests_;
+ RequestsList cancelled_requests_;
+ scoped_ptr<SetPacScriptRequest> pending_set_pac_script_request_;
+};
+
+class MockAsyncProxyResolver : public MockAsyncProxyResolverBase {
+ public:
+ MockAsyncProxyResolver()
+ : MockAsyncProxyResolverBase(false /*expects_pac_bytes*/) {}
+};
+
+class MockAsyncProxyResolverExpectsBytes : public MockAsyncProxyResolverBase {
+ public:
+ MockAsyncProxyResolverExpectsBytes()
+ : MockAsyncProxyResolverBase(true /*expects_pac_bytes*/) {}
+};
+
} // namespace
// A mock ProxyScriptFetcher. No result will be returned to the fetch client