blob: 216b28ddb57530b87295d5ab55b1718f206d96f7 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/proxy_resolution/proxy_config.h"
#include "base/json/json_writer.h"
#include "base/test/gtest_util.h"
#include "base/values.h"
#include "build/buildflag.h"
#include "net/base/proxy_string_util.h"
#include "net/net_buildflags.h"
#include "net/proxy_resolution/proxy_config_service_common_unittest.h"
#include "net/proxy_resolution/proxy_info.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
namespace {
void ExpectProxyServerEquals(const char* expectation,
const ProxyList& proxy_list) {
if (expectation == nullptr) {
EXPECT_TRUE(proxy_list.IsEmpty());
} else {
EXPECT_EQ(expectation, proxy_list.ToDebugString());
}
}
TEST(ProxyConfigTest, Equals) {
// Test |ProxyConfig::auto_detect|.
ProxyConfig config1;
config1.set_auto_detect(true);
ProxyConfig config2;
config2.set_auto_detect(false);
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config2.set_auto_detect(true);
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
// Test |ProxyConfig::pac_url|.
config2.set_pac_url(GURL("http://wpad/wpad.dat"));
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.set_pac_url(GURL("http://wpad/wpad.dat"));
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
// Test |ProxyConfig::proxy_rules|.
config2.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
config2.proxy_rules().single_proxies.SetSingleProxyServer(
ProxyUriToProxyServer("myproxy:80", ProxyServer::SCHEME_HTTP));
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
config1.proxy_rules().single_proxies.SetSingleProxyServer(
ProxyUriToProxyServer("myproxy:100", ProxyServer::SCHEME_HTTP));
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().single_proxies.SetSingleProxyServer(
ProxyUriToProxyServer("myproxy", ProxyServer::SCHEME_HTTP));
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
// Test |ProxyConfig::bypass_rules|.
config2.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
// Test |ProxyConfig::proxy_rules.reverse_bypass|.
config2.proxy_rules().reverse_bypass = true;
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().reverse_bypass = true;
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
}
#if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
TEST(ProxyConfigTest, EqualsMultiProxyChains) {
ProxyConfig config1;
ProxyConfig config2;
config2.proxy_rules().type =
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
config2.proxy_rules().proxies_for_https.SetSingleProxyChain(
MultiProxyUrisToProxyChain("[https://foopy:443 https://hoopy:443]",
ProxyServer::SCHEME_HTTPS));
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().type =
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
config1.proxy_rules().proxies_for_https.SetSingleProxyChain(
MultiProxyUrisToProxyChain("[https://foopy:80 https://hoopy:80]",
ProxyServer::SCHEME_HTTPS));
EXPECT_FALSE(config1.Equals(config2));
EXPECT_FALSE(config2.Equals(config1));
config1.proxy_rules().proxies_for_https.SetSingleProxyChain(
MultiProxyUrisToProxyChain("[https://foopy https://hoopy]",
ProxyServer::SCHEME_HTTPS));
EXPECT_TRUE(config1.Equals(config2));
EXPECT_TRUE(config2.Equals(config1));
}
#endif // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
struct ProxyConfigToValueTestCase {
ProxyConfig config;
const char* expected_value_json;
};
class ProxyConfigToValueTest
: public ::testing::TestWithParam<ProxyConfigToValueTestCase> {};
TEST_P(ProxyConfigToValueTest, ToValueJSON) {
const ProxyConfigToValueTestCase& test_case = GetParam();
base::Value value = test_case.config.ToValue();
std::string json_string;
ASSERT_TRUE(base::JSONWriter::Write(value, &json_string));
EXPECT_EQ(std::string(test_case.expected_value_json), json_string);
}
ProxyConfigToValueTestCase GetTestCaseDirect() {
return {ProxyConfig::CreateDirect(), "{}"};
}
ProxyConfigToValueTestCase GetTestCaseAutoDetect() {
return {ProxyConfig::CreateAutoDetect(), "{\"auto_detect\":true}"};
}
ProxyConfigToValueTestCase GetTestCasePacUrl() {
ProxyConfig config;
config.set_pac_url(GURL("http://www.example.com/test.pac"));
return {std::move(config),
"{\"pac_url\":\"http://www.example.com/test.pac\"}"};
}
ProxyConfigToValueTestCase GetTestCasePacUrlMandatory() {
ProxyConfig config;
config.set_pac_url(GURL("http://www.example.com/test.pac"));
config.set_pac_mandatory(true);
return {std::move(config),
"{\"pac_mandatory\":true,\"pac_url\":\"http://www.example.com/"
"test.pac\"}"};
}
ProxyConfigToValueTestCase GetTestCasePacUrlAndAutoDetect() {
ProxyConfig config = ProxyConfig::CreateAutoDetect();
config.set_pac_url(GURL("http://www.example.com/test.pac"));
return {
std::move(config),
"{\"auto_detect\":true,\"pac_url\":\"http://www.example.com/test.pac\"}"};
}
ProxyConfigToValueTestCase GetTestCaseSingleProxy() {
ProxyConfig config;
config.proxy_rules().ParseFromString("https://proxy1:8080");
return {std::move(config), "{\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
}
ProxyConfigToValueTestCase GetTestCaseSingleProxyWithBypass() {
ProxyConfig config;
config.proxy_rules().ParseFromString("https://proxy1:8080");
config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
config.proxy_rules().bypass_rules.AddRuleFromString("192.168.0.1/16");
return {std::move(config),
"{\"bypass_list\":[\"*.google.com\",\"192.168.0.1/"
"16\"],\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
}
ProxyConfigToValueTestCase GetTestCaseSingleProxyWithReversedBypass() {
ProxyConfig config;
config.proxy_rules().ParseFromString("https://proxy1:8080");
config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
config.proxy_rules().reverse_bypass = true;
return {std::move(config),
"{\"bypass_list\":[\"*.google.com\"],\"reverse_bypass\":true,"
"\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
}
ProxyConfigToValueTestCase GetTestCaseProxyPerScheme() {
ProxyConfig config;
config.proxy_rules().ParseFromString(
"http=https://proxy1:8080;https=socks5://proxy2");
config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
config.set_pac_url(GURL("http://wpad/wpad.dat"));
config.set_auto_detect(true);
return {
std::move(config),
"{\"auto_detect\":true,\"bypass_list\":[\"*.google.com\"],\"pac_url\":"
"\"http://wpad/wpad.dat\",\"proxy_per_scheme\":{\"http\":[\"[https://"
"proxy1:8080]\"],\"https\":[\"[socks5://proxy2:1080]\"]}}"};
}
ProxyConfigToValueTestCase GetTestCaseSingleProxyList() {
ProxyConfig config;
config.proxy_rules().ParseFromString(
"https://proxy1:8080,http://proxy2,direct://");
return {
std::move(config),
"{\"single_proxy\":[\"[https://proxy1:8080]\",\"[proxy2:80]\",\"direct://"
"\"]}"};
}
#if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
// Multi-proxy chains present
ProxyConfigToValueTestCase GetTestCaseMultiProxyChainProxyPerScheme() {
ProxyConfig config;
config.proxy_rules().ParseFromString(
"http=[https://proxy1:8080 https://proxy2:8080];https=socks5://proxy2",
/*allow_bracketed_proxy_chains=*/true);
config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
config.set_pac_url(GURL("http://wpad/wpad.dat"));
config.set_auto_detect(true);
return {std::move(config),
"{\"auto_detect\":true,\"bypass_list\":[\"*.google.com\"],\"pac_"
"url\":\"http://wpad/"
"wpad.dat\",\"proxy_per_scheme\":{\"http\":[\"[https://proxy1:8080, "
"https://proxy2:8080]\"],\"https\":[\"[socks5://proxy2:1080]\"]}}"};
}
#endif // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
INSTANTIATE_TEST_SUITE_P(
All,
ProxyConfigToValueTest,
testing::Values(GetTestCaseDirect(),
GetTestCaseAutoDetect(),
GetTestCasePacUrl(),
GetTestCasePacUrlMandatory(),
GetTestCasePacUrlAndAutoDetect(),
GetTestCaseSingleProxy(),
GetTestCaseSingleProxyWithBypass(),
GetTestCaseSingleProxyWithReversedBypass(),
GetTestCaseProxyPerScheme(),
#if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
GetTestCaseMultiProxyChainProxyPerScheme(),
#endif // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
GetTestCaseSingleProxyList()));
TEST(ProxyConfigTest, ParseProxyRules) {
const struct {
const char* proxy_rules;
ProxyConfig::ProxyRules::Type type;
// These will be PAC-stle strings, eg 'PROXY foo.com'
const char* single_proxy;
const char* proxy_for_http;
const char* proxy_for_https;
const char* proxy_for_ftp;
const char* fallback_proxy;
} tests[] = {
// One HTTP proxy for all schemes.
{
"myproxy:80",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"PROXY myproxy:80",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Multiple HTTP proxies for all schemes.
{
"myproxy:80,https://myotherproxy",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"PROXY myproxy:80;HTTPS myotherproxy:443",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Only specify a proxy server for "http://" urls.
{
"http=myproxy:80",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY myproxy:80",
nullptr,
nullptr,
nullptr,
},
// Specify an HTTP proxy for "ftp://" and a SOCKS proxy for "https://"
// urls.
{
"ftp=ftp-proxy ; https=socks4://foopy",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
"SOCKS foopy:1080",
"PROXY ftp-proxy:80",
nullptr,
},
// Give a scheme-specific proxy as well as a non-scheme specific.
// The first entry "foopy" takes precedence marking this list as
// Type::PROXY_LIST.
{
"foopy ; ftp=ftp-proxy",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"PROXY foopy:80",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Give a scheme-specific proxy as well as a non-scheme specific.
// The first entry "ftp=ftp-proxy" takes precedence marking this list as
// Type::PROXY_LIST_PER_SCHEME.
{
"ftp=ftp-proxy ; foopy",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
nullptr,
"PROXY ftp-proxy:80",
nullptr,
},
// Include a list of entries for a single scheme.
{
"ftp=ftp1,ftp2,ftp3",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
nullptr,
"PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
nullptr,
},
// Include multiple entries for the same scheme -- they accumulate.
{
"http=http1,http2; http=http3",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY http1:80;PROXY http2:80;PROXY http3:80",
nullptr,
nullptr,
nullptr,
},
// Include lists of entries for multiple schemes.
{
"ftp=ftp1,ftp2,ftp3 ; http=http1,http2; ",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY http1:80;PROXY http2:80",
nullptr,
"PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
nullptr,
},
// Include non-default proxy schemes.
{
"http=https://secure_proxy; ftp=socks4://socks_proxy; "
"https=socks://foo",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"HTTPS secure_proxy:443",
"SOCKS5 foo:1080",
"SOCKS socks_proxy:1080",
nullptr,
},
// Only SOCKS proxy present, others being blank.
{
"socks=foopy",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
nullptr,
nullptr,
"SOCKS foopy:1080",
},
// SOCKS proxy present along with other proxies too
{
"http=httpproxy ; https=httpsproxy ; ftp=ftpproxy ; socks=foopy ",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY httpproxy:80",
"PROXY httpsproxy:80",
"PROXY ftpproxy:80",
"SOCKS foopy:1080",
},
// SOCKS proxy (with modifier) present along with some proxies
// (FTP being blank)
{
"http=httpproxy ; https=httpsproxy ; socks=socks5://foopy ",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY httpproxy:80",
"PROXY httpsproxy:80",
nullptr,
"SOCKS5 foopy:1080",
},
// Include unsupported schemes -- they are discarded.
{
"crazy=foopy ; foo=bar ; https=myhttpsproxy",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
"PROXY myhttpsproxy:80",
nullptr,
nullptr,
},
// direct:// as first option for a scheme.
{
"http=direct://,myhttpproxy; https=direct://",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"DIRECT;PROXY myhttpproxy:80",
"DIRECT",
nullptr,
nullptr,
},
// direct:// as a second option for a scheme.
{
"http=myhttpproxy,direct://",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"PROXY myhttpproxy:80;DIRECT",
nullptr,
nullptr,
nullptr,
},
// Multi-proxy bracketed URIs will result in no proxy being set
{
"http=[https://proxy1:8080 https://proxy2:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
}
};
ProxyConfig config;
for (const auto& test : tests) {
config.proxy_rules().ParseFromString(test.proxy_rules);
EXPECT_EQ(test.type, config.proxy_rules().type);
ExpectProxyServerEquals(test.single_proxy,
config.proxy_rules().single_proxies);
ExpectProxyServerEquals(test.proxy_for_http,
config.proxy_rules().proxies_for_http);
ExpectProxyServerEquals(test.proxy_for_https,
config.proxy_rules().proxies_for_https);
ExpectProxyServerEquals(test.proxy_for_ftp,
config.proxy_rules().proxies_for_ftp);
ExpectProxyServerEquals(test.fallback_proxy,
config.proxy_rules().fallback_proxies);
}
}
#if BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
// When the bool to allow quic proxy support is false, there should be no valid
// proxies in the config.
TEST(ProxyConfigTest, ParseProxyRulesQuicIsNotAllowed) {
ProxyConfig config;
config.proxy_rules().ParseFromString("quic://foopy:443",
/*allow_bracketed_proxy_chains=*/false,
/*is_quic_allowed=*/false);
EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST,
config.proxy_rules().type);
ExpectProxyServerEquals(nullptr, config.proxy_rules().single_proxies);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_http);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_https);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_ftp);
ExpectProxyServerEquals(nullptr, config.proxy_rules().fallback_proxies);
}
// When the bool to allow quic proxy support is true, a valid quic proxy should
// be found in the config.
TEST(ProxyConfigTest, ParseProxyRulesQuicIsAllowed) {
ProxyConfig config;
config.proxy_rules().ParseFromString("quic://foopy:443",
/*allow_bracketed_proxy_chains=*/false,
/*is_quic_allowed=*/true);
EXPECT_EQ(ProxyConfig::ProxyRules::Type::PROXY_LIST,
config.proxy_rules().type);
ExpectProxyServerEquals("QUIC foopy:443",
config.proxy_rules().single_proxies);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_http);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_https);
ExpectProxyServerEquals(nullptr, config.proxy_rules().proxies_for_ftp);
ExpectProxyServerEquals(nullptr, config.proxy_rules().fallback_proxies);
}
#endif // BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
#if !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
// When the build flag is disabled for QUIC support, `ParseFromString` should
// not allow QUIC proxy support by setting bool to true. A true value should
// crash.
TEST(ProxyConfigTest,
ParseProxyRulesDisallowQuicProxySupportIfBuildFlagDisabled) {
ProxyConfig config;
EXPECT_CHECK_DEATH(config.proxy_rules().ParseFromString(
"quic://foopy:443",
/*allow_bracketed_proxy_chains=*/false, /*is_quic_allowed=*/true));
}
#endif // !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
#if !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
// In release builds, `ParseFromString` should not allow parsing of multi-proxy
// chains by setting bool to true. A true value should crash.
TEST(ProxyConfigTest, ParseProxyRulesDisallowMultiProxyChainsInReleaseBuilds) {
ProxyConfig config;
EXPECT_CHECK_DEATH(config.proxy_rules().ParseFromString(
"http=[https://proxy1:8080 https://proxy2:8080]", true));
}
#endif // !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
#if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
// Tests for multi-proxy chains which are currently only allowed in debug mode.
TEST(ProxyConfigTest, MultiProxyChainsParseProxyRules) {
const struct {
const char* proxy_rules;
ProxyConfig::ProxyRules::Type type;
// For multi-proxy chains, proxies within a single chain will be formatted
// within a bracket separated by a space and comma.
const char* single_proxy;
const char* proxy_for_http;
const char* proxy_for_https;
const char* proxy_for_ftp;
const char* fallback_proxy;
} tests[] = {
// One HTTP proxy for all schemes.
{
"[https://proxy1:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"HTTPS proxy1:8080",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Multiple proxies for all schemes.
{
"[https://proxy1:8080 https://proxy2:8080],[https://proxy3:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"[https://proxy1:8080, https://proxy2:8080];HTTPS proxy3:8080",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Only specify a proxy chain for "http://" urls.
{
"http=[https://proxy1:8080 https://proxy2:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"[https://proxy1:8080, https://proxy2:8080]",
nullptr,
nullptr,
nullptr,
},
// Specify different multi-proxy chains for different schemes.
{
"http=[https://proxy1:8080 https://proxy2:8080] ; "
"https=[https://proxy3:8080 https://proxy4:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"[https://proxy1:8080, https://proxy2:8080]",
"[https://proxy3:8080, https://proxy4:8080]",
nullptr,
nullptr,
},
// Give a scheme-specific proxy as well as a non-scheme specific.
// The first entry takes precedence marking this list as Type::PROXY_LIST.
{
"[https://proxy1:8080 https://proxy2:8080] ; "
"http=[https://proxy3:8080 https://proxy4:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST,
"[https://proxy1:8080, https://proxy2:8080]",
nullptr,
nullptr,
nullptr,
nullptr,
},
// Give a scheme-specific proxy as well as a non-scheme specific.
// The first entry takes precedence marking this list as
// Type::PROXY_LIST_PER_SCHEME.
{
"http=[https://proxy3:8080 https://proxy4:8080] ; "
"[https://proxy1:8080 https://proxy2:8080]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"[https://proxy3:8080, https://proxy4:8080]",
nullptr,
nullptr,
nullptr,
},
// Include a list of entries for a single scheme.
{
"ftp=[https://proxy1:80 https://proxy2:80],[https://proxy3:80 "
"https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
nullptr,
"[https://proxy1:80, https://proxy2:80];[https://proxy3:80, "
"https://proxy4:80];[https://proxy5:80, https://proxy6:80]",
nullptr,
},
// Include multiple entries for the same scheme -- they accumulate.
{
"http=[https://proxy1:80 https://proxy2:80]; http=[https://proxy3:80 "
"https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"[https://proxy1:80, https://proxy2:80];[https://proxy3:80, "
"https://proxy4:80];[https://proxy5:80, https://proxy6:80]",
nullptr,
nullptr,
nullptr,
},
// Include lists of entries for multiple schemes.
{
"http=[https://proxy1:80 https://proxy2:80]; ftp=[https://proxy3:80 "
"https://proxy4:80],[https://proxy5:80 https://proxy6:80]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
"[https://proxy1:80, https://proxy2:80]",
nullptr,
"[https://proxy3:80, https://proxy4:80];[https://proxy5:80, "
"https://proxy6:80]",
nullptr,
},
// Include unsupported schemes -- they are discarded.
{
"crazy=[https://proxy1:80 https://proxy2:80] ; foo=bar ; "
"https=[https://proxy3:80 https://proxy4:80]",
ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
nullptr,
nullptr,
"[https://proxy3:80, https://proxy4:80]",
nullptr,
nullptr,
},
};
ProxyConfig config;
for (const auto& test : tests) {
config.proxy_rules().ParseFromString(test.proxy_rules, true);
EXPECT_EQ(test.type, config.proxy_rules().type);
ExpectProxyServerEquals(test.single_proxy,
config.proxy_rules().single_proxies);
ExpectProxyServerEquals(test.proxy_for_http,
config.proxy_rules().proxies_for_http);
ExpectProxyServerEquals(test.proxy_for_https,
config.proxy_rules().proxies_for_https);
ExpectProxyServerEquals(test.proxy_for_ftp,
config.proxy_rules().proxies_for_ftp);
ExpectProxyServerEquals(test.fallback_proxy,
config.proxy_rules().fallback_proxies);
}
}
#endif // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
TEST(ProxyConfigTest, ProxyRulesSetBypassFlag) {
// Test whether the did_bypass_proxy() flag is set in proxy info correctly.
ProxyConfig::ProxyRules rules;
ProxyInfo result;
rules.ParseFromString("http=httpproxy:80");
rules.bypass_rules.AddRuleFromString(".com");
rules.Apply(GURL("http://example.com"), &result);
EXPECT_TRUE(result.is_direct_only());
EXPECT_TRUE(result.did_bypass_proxy());
rules.Apply(GURL("http://example.org"), &result);
EXPECT_FALSE(result.is_direct());
EXPECT_FALSE(result.did_bypass_proxy());
// Try with reversed bypass rules.
rules.reverse_bypass = true;
rules.Apply(GURL("http://example.org"), &result);
EXPECT_TRUE(result.is_direct_only());
EXPECT_TRUE(result.did_bypass_proxy());
rules.Apply(GURL("http://example.com"), &result);
EXPECT_FALSE(result.is_direct());
EXPECT_FALSE(result.did_bypass_proxy());
}
static const char kWsUrl[] = "ws://example.com/echo";
static const char kWssUrl[] = "wss://example.com/echo";
class ProxyConfigWebSocketTest : public ::testing::Test {
protected:
void ParseFromString(const std::string& rules) {
rules_.ParseFromString(rules);
}
void Apply(const GURL& gurl) { rules_.Apply(gurl, &info_); }
std::string ToDebugString() const { return info_.ToDebugString(); }
static GURL WsUrl() { return GURL(kWsUrl); }
static GURL WssUrl() { return GURL(kWssUrl); }
ProxyConfig::ProxyRules rules_;
ProxyInfo info_;
};
// If a single proxy is set for all protocols, WebSocket uses it.
TEST_F(ProxyConfigWebSocketTest, UsesProxy) {
ParseFromString("proxy:3128");
Apply(WsUrl());
EXPECT_EQ("PROXY proxy:3128", ToDebugString());
}
// See RFC6455 Section 4.1. item 3, "_Proxy Usage_". Note that this favors a
// SOCKSv4 proxy (although technically the spec only notes SOCKSv5).
TEST_F(ProxyConfigWebSocketTest, PrefersSocksV4) {
ParseFromString(
"http=proxy:3128 ; https=sslproxy:3128 ; socks=socksproxy:1080");
Apply(WsUrl());
EXPECT_EQ("SOCKS socksproxy:1080", ToDebugString());
}
// See RFC6455 Section 4.1. item 3, "_Proxy Usage_".
TEST_F(ProxyConfigWebSocketTest, PrefersSocksV5) {
ParseFromString(
"http=proxy:3128 ; https=sslproxy:3128 ; socks=socks5://socksproxy:1080");
Apply(WsUrl());
EXPECT_EQ("SOCKS5 socksproxy:1080", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, PrefersHttpsToHttp) {
ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
Apply(WssUrl());
EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
}
// Tests when a proxy-per-url-scheme configuration was used, and proxies are
// specified for http://, https://, and a fallback proxy (non-SOCKS).
// Even though the fallback proxy is not SOCKS, it is still favored over the
// proxy for http://* and https://*.
TEST_F(ProxyConfigWebSocketTest, PrefersNonSocksFallbackOverHttps) {
// The notation for "socks=" is abused to set the "fallback proxy".
ParseFromString(
"http=proxy:3128 ; https=sslproxy:3128; socks=https://httpsproxy");
EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
Apply(WssUrl());
EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
}
// Tests when a proxy-per-url-scheme configuration was used, and the fallback
// proxy is a non-SOCKS proxy, and no proxy was given for https://* or
// http://*. The fallback proxy is used.
TEST_F(ProxyConfigWebSocketTest, UsesNonSocksFallbackProxy) {
// The notation for "socks=" is abused to set the "fallback proxy".
ParseFromString("ftp=ftpproxy:3128; socks=https://httpsproxy");
EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
Apply(WssUrl());
EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, PrefersHttpsEvenForWs) {
ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
Apply(WsUrl());
EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, PrefersHttpToDirect) {
ParseFromString("http=proxy:3128");
Apply(WssUrl());
EXPECT_EQ("PROXY proxy:3128", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, IgnoresFtpProxy) {
ParseFromString("ftp=ftpproxy:3128");
Apply(WssUrl());
EXPECT_EQ("DIRECT", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, ObeysBypassRules) {
ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
rules_.bypass_rules.AddRuleFromString(".chromium.org");
Apply(GURL("wss://codereview.chromium.org/feed"));
EXPECT_EQ("DIRECT", ToDebugString());
}
TEST_F(ProxyConfigWebSocketTest, ObeysLocalBypass) {
ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
rules_.bypass_rules.AddRuleFromString("<local>");
Apply(GURL("ws://localhost/feed"));
EXPECT_EQ("DIRECT", ToDebugString());
}
} // namespace
} // namespace net