[go: nahoru, domu]

blob: 6dbee998954b10aea7eccbd4091c2e29f5e55c8d [file] [log] [blame]
// 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.
#include "net/proxy/proxy_service.h"
#include <vector>
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "googleurl/src/gurl.h"
#include "net/base/load_log.h"
#include "net/base/load_log_unittest.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"
#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;
};
} // 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;
scoped_refptr<ProxyService> service(
new ProxyService(new MockProxyConfigService, resolver));
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback;
scoped_refptr<LoadLog> log(new LoadLog(LoadLog::kUnbounded));
int rv = service->ResolveProxy(url, &info, &callback, NULL, log);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(resolver->pending_requests().empty());
EXPECT_TRUE(NULL == service->init_proxy_resolver_log());
EXPECT_TRUE(info.is_direct());
// Check the LoadLog was filled correctly.
EXPECT_EQ(2u, log->events().size());
ExpectLogContains(log, 0, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_BEGIN);
ExpectLogContains(log, 1, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_END);
}
TEST(ProxyServiceTest, PAC) {
MockProxyConfigService* config_service =
new MockProxyConfigService("http://foopy/proxy.pac");
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback;
scoped_refptr<LoadLog> log(new LoadLog(LoadLog::kUnbounded));
int rv = service->ResolveProxy(url, &info, &callback, NULL, log);
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(GURL("http://foopy/proxy.pac"),
resolver->pending_set_pac_script_request()->pac_url());
EXPECT_FALSE(NULL == service->init_proxy_resolver_log());
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());
// Check the LoadLog was filled correctly.
EXPECT_EQ(4u, log->events().size());
ExpectLogContains(log, 0, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_BEGIN);
ExpectLogContains(log, 1, LoadLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
LoadLog::PHASE_BEGIN);
ExpectLogContains(log, 2, LoadLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
LoadLog::PHASE_END);
ExpectLogContains(log, 3, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_END);
}
// 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
GURL url("http://www.google.com/");
ProxyInfo info;
TestCompletionCallback callback1;
int rv = service->ResolveProxy(url, &info, &callback1, NULL, 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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, 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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, 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, 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, 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, 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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, 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, 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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, 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, 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, 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, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver()));
GURL test_url("http://local");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://www.webkit.org");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://74.125.19.147");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://www.msn.com");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://www.msnbc.msn.com");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("HTTP://WWW.MSNBC.MSN.COM");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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");
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
{
GURL test_url("http://www.example.com:99");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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, 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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
}
}
config.proxy_bypass.clear();
config.proxy_bypass.push_back("*.example.com:80");
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://www.example.com");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, NULL);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(info.is_direct());
}
config.proxy_bypass.clear();
config.proxy_bypass.push_back("*.example.com");
{
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config), new MockAsyncProxyResolver));
GURL test_url("http://www.example.com:99");
TestCompletionCallback callback;
int rv = service->ResolveProxy(test_url, &info, &callback, NULL, 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");
{
scoped_refptr<ProxyService> service(new ProxyService(
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, 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, 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]");
{
scoped_refptr<ProxyService> service(new ProxyService(
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, 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, 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;
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(info.is_direct());
EXPECT_EQ("direct://", info.proxy_server().ToURI());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy2:8080", info.proxy_server().ToURI());
}
{
config.proxy_rules.ParseFromString("foopy1:8080");
scoped_refptr<ProxyService> service(new ProxyService(
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, 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);
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("foopy1:8080", info.proxy_server().ToURI());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
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, NULL);
EXPECT_EQ(OK, rv);
EXPECT_FALSE(info.is_direct());
EXPECT_EQ("socks4://foopy2:1080", info.proxy_server().ToURI());
}
{
scoped_refptr<ProxyService> service(new ProxyService(
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, 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;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
// Start 3 requests.
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service->ResolveProxy(
GURL("http://request1"), &info1, &callback1, NULL, 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, NULL);
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, 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 resolver that expects bytes.
TEST(ProxyServiceTest, InitialPACScriptDownload) {
MockProxyConfigService* config_service =
new MockProxyConfigService("http://foopy/proxy.pac");
MockAsyncProxyResolverExpectsBytes* resolver =
new MockAsyncProxyResolverExpectsBytes;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
ProxyInfo info3;
TestCompletionCallback callback3;
rv = service->ResolveProxy(
GURL("http://request3"), &info3, &callback3, NULL, 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 changing the ProxyScriptFetcher while PAC download is in progress.
TEST(ProxyServiceTest, ChangeScriptFetcherWhilePACDownloadInProgress) {
MockProxyConfigService* config_service =
new MockProxyConfigService("http://foopy/proxy.pac");
MockAsyncProxyResolverExpectsBytes* resolver =
new MockAsyncProxyResolverExpectsBytes;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
// At this point the ProxyService should be waiting for the
// ProxyScriptFetcher to invoke its completion callback, notifying it of
// PAC script download completion.
// We now change out the ProxyService's script fetcher. We should restart
// the initialization with the new fetcher.
fetcher = new MockProxyScriptFetcher;
service->SetProxyScriptFetcher(fetcher);
// Nothing has been sent to the resolver yet.
EXPECT_TRUE(resolver->pending_requests().empty());
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(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());
}
// 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;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
MockProxyScriptFetcher* fetcher = new MockProxyScriptFetcher;
service->SetProxyScriptFetcher(fetcher);
// Start 3 requests.
ProxyInfo info1;
TestCompletionCallback callback1;
ProxyService::PacRequest* request1;
scoped_refptr<LoadLog> log1(new LoadLog(LoadLog::kUnbounded));
int rv = service->ResolveProxy(
GURL("http://request1"), &info1, &callback1, &request1, log1);
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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
ProxyInfo info3;
TestCompletionCallback callback3;
rv = service->ResolveProxy(
GURL("http://request3"), &info3, &callback3, NULL, 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);
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.
// Check the LoadLog for request 1 (which was cancelled) got filled properly.
EXPECT_EQ(4u, log1->events().size());
ExpectLogContains(log1, 0, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_BEGIN);
ExpectLogContains(log1, 1, LoadLog::TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC,
LoadLog::PHASE_BEGIN);
// Note that TYPE_PROXY_SERVICE_WAITING_FOR_INIT_PAC is never completed before
// the cancellation occured.
ExpectLogContains(log1, 2, LoadLog::TYPE_CANCELLED, LoadLog::PHASE_NONE);
ExpectLogContains(log1, 3, LoadLog::TYPE_PROXY_SERVICE, LoadLog::PHASE_END);
}
// 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
rv = service->ResolveProxy(
GURL("http://request2"), &info2, &callback2, &request2, 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 -- 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
rv = service->ResolveProxy(
GURL("http://request2"), &info2, &callback2, &request2, 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, "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;
scoped_refptr<ProxyService> service(
new ProxyService(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, NULL);
EXPECT_EQ(ERR_IO_PENDING, rv);
ProxyInfo info2;
TestCompletionCallback callback2;
ProxyService::PacRequest* request2;
rv = service->ResolveProxy(
GURL("http://request2"), &info2, &callback2, &request2, 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 -- 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;
scoped_refptr<ProxyService> service(
new ProxyService(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, 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, 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;
scoped_refptr<ProxyService> service(new ProxyService(
new MockProxyConfigService(config1), new MockAsyncProxyResolverExpectsBytes));
ProxyInfo info;
TestCompletionCallback callback1;
int rv = service->ResolveProxy(
GURL("http://request1"), &info, &callback1, NULL, 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, 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[%" PRIuS "]: %s", i, tests[i].url));
bool is_local = ProxyService::IsLocalName(GURL(tests[i].url));
EXPECT_EQ(tests[i].expected_is_local, is_local);
}
}
// Check that after we have done the auto-detect test, and the configuration
// is updated (with no change), we don't re-try the autodetect test.
// Regression test for http://crbug.com/18526 -- the configuration was being
// mutated to cancel out the automatic settings, which meant UpdateConfig()
// thought it had received a new configuration.
TEST(ProxyServiceTest, UpdateConfigAfterFailedAutodetect) {
ProxyConfig config;
config.auto_detect = true;
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
// Start 1 requests.
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service->ResolveProxy(
GURL("http://www.google.com"), &info1, &callback1, NULL, 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());
// Fail the setting of autodetect script.
EXPECT_EQ(GURL(), resolver->pending_set_pac_script_request()->pac_url());
resolver->pending_set_pac_script_request()->CompleteNow(ERR_FAILED);
// Verify that request ran as expected -- should have fallen back to direct.
EXPECT_EQ(OK, callback1.WaitForResult());
EXPECT_TRUE(info1.is_direct());
// Force the ProxyService to pull down a new proxy configuration.
// (Even though the configuration isn't old/bad).
service->UpdateConfig();
// Start another request -- the effective configuration has not
// changed, so we shouldn't re-run the autodetect step.
// Rather, it should complete synchronously as direct-connect.
ProxyInfo info2;
TestCompletionCallback callback2;
rv = service->ResolveProxy(
GURL("http://www.google.com"), &info2, &callback2, NULL, NULL);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(info2.is_direct());
}
// Test that when going from a configuration that required PAC to one
// that does NOT, we unset the variable |should_use_proxy_resolver_|.
TEST(ProxyServiceTest, UpdateConfigFromPACToDirect) {
ProxyConfig config;
config.auto_detect = true;
MockProxyConfigService* config_service = new MockProxyConfigService(config);
MockAsyncProxyResolver* resolver = new MockAsyncProxyResolver;
scoped_refptr<ProxyService> service(
new ProxyService(config_service, resolver));
// Start 1 request.
ProxyInfo info1;
TestCompletionCallback callback1;
int rv = service->ResolveProxy(
GURL("http://www.google.com"), &info1, &callback1, NULL, 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());
// Successfully set the autodetect script.
EXPECT_EQ(GURL(), resolver->pending_set_pac_script_request()->pac_url());
resolver->pending_set_pac_script_request()->CompleteNow(OK);
// Complete the pending request.
ASSERT_EQ(1u, resolver->pending_requests().size());
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());
// Force the ProxyService to pull down a new proxy configuration.
// (Even though the configuration isn't old/bad).
//
// This new configuration no longer has auto_detect set, so
// requests should complete synchronously now as direct-connect.
config.auto_detect = false;
config_service->config = config;
service->UpdateConfig();
// Start another request -- the effective configuration has changed.
ProxyInfo info2;
TestCompletionCallback callback2;
rv = service->ResolveProxy(
GURL("http://www.google.com"), &info2, &callback2, NULL, NULL);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(info2.is_direct());
}
} // namespace net