diff options
21 files changed, 729 insertions, 585 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 4fc54ea..52e424b 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -1331,7 +1331,7 @@ class SetProxyConfigTask : public Task { } std::string proxy_bypass_list; if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) { - pc->ParseNoProxyList(proxy_bypass_list); + pc->bypass_rules.ParseFromString(proxy_bypass_list); } std::string proxy_server; if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) { diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 79a94cd..bb8cba9 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -948,7 +948,7 @@ net::ProxyConfig* CreateProxyConfig(const CommandLine& command_line) { } if (command_line.HasSwitch(switches::kProxyBypassList)) { - proxy_config->ParseNoProxyList( + proxy_config->bypass_rules.ParseFromString( WideToASCII(command_line.GetSwitchValue( switches::kProxyBypassList))); } diff --git a/chrome/browser/net/chrome_url_request_context_unittest.cc b/chrome/browser/net/chrome_url_request_context_unittest.cc index e1ac43e..e7d679c 100644 --- a/chrome/browser/net/chrome_url_request_context_unittest.cc +++ b/chrome/browser/net/chrome_url_request_context_unittest.cc @@ -59,7 +59,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL pac_url; net::ProxyConfig::ProxyRules proxy_rules; const char* proxy_bypass_list; // newline separated - bool bypass_local_names; } tests[] = { { TEST_DESC("Empty command line"), @@ -71,7 +70,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL(), // pac_url net::ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names }, { TEST_DESC("No proxy"), @@ -83,7 +81,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL(), // pac_url net::ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names }, { TEST_DESC("No proxy with extra parameters."), @@ -95,7 +92,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL(), // pac_url net::ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names }, { TEST_DESC("Single proxy."), @@ -107,7 +103,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL(), // pac_url net::MakeSingleProxyRules("http://proxy:8888"), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names }, { TEST_DESC("Per scheme proxy."), @@ -121,7 +116,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { "", "ftpproxy:8889"), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names }, { TEST_DESC("Per scheme proxy with bypass URLs."), @@ -134,8 +128,8 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { net::MakeProxyPerSchemeRules("httpproxy:8888", "", "ftpproxy:8889"), // proxy_rules - "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", - false // bypass_local_names + // TODO(eroman): 127.0.0.1/8 is unsupported, so it was dropped + "*.google.com\nfoo.com:99\n1.2.3.4:22\n", }, { TEST_DESC("Pac URL with proxy bypass URLs"), @@ -146,8 +140,8 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { false, // auto_detect GURL("http://wpad/wpad.dat"), // pac_url net::ProxyConfig::ProxyRules(), // proxy_rules - "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", - false // bypass_local_names + // TODO(eroman): 127.0.0.1/8 is unsupported, so it was dropped + "*.google.com\nfoo.com:99\n1.2.3.4:22\n", }, { TEST_DESC("Autodetect"), @@ -159,7 +153,6 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { GURL(), // pac_url net::ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false // bypass_local_names } }; @@ -176,8 +169,7 @@ TEST(ChromeUrlRequestContextTest, CreateProxyConfigTest) { EXPECT_EQ(tests[i].auto_detect, config->auto_detect); EXPECT_EQ(tests[i].pac_url, config->pac_url); EXPECT_EQ(tests[i].proxy_bypass_list, - net::FlattenProxyBypass(config->proxy_bypass)); - EXPECT_EQ(tests[i].bypass_local_names, config->proxy_bypass_local_names); + net::FlattenProxyBypass(config->bypass_rules)); EXPECT_EQ(tests[i].proxy_rules, config->proxy_rules); } } diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 2099d95..9f18551 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -537,7 +537,8 @@ const char kProxyAutoDetect[] = "proxy-auto-detect"; // Specify a list of hosts for whom we bypass proxy settings and use direct // connections. Ignored if --proxy-auto-detect or --no-proxy-server are // also specified. -// TODO(robertshield): Specify host format. +// This is a comma separated list of bypass rules. See: +// "net/proxy/proxy_bypass_rules.h" for the format of these rules. const char kProxyBypassList[] = "proxy-bypass-list"; // Use the pac script at the given URL diff --git a/net/net.gyp b/net/net.gyp index 4509616..cf0a9c3 100755 --- a/net/net.gyp +++ b/net/net.gyp @@ -372,6 +372,8 @@ 'ocsp/nss_ocsp.h', 'proxy/init_proxy_resolver.cc', 'proxy/init_proxy_resolver.h', + 'proxy/proxy_bypass_rules.cc', + 'proxy/proxy_bypass_rules.h', 'proxy/proxy_config.cc', 'proxy/proxy_config.h', 'proxy/proxy_config_service.h', @@ -659,6 +661,7 @@ 'http/http_vary_data_unittest.cc', 'proxy/init_proxy_resolver_unittest.cc', 'proxy/mock_proxy_resolver.h', + 'proxy/proxy_bypass_rules_unittest.cc', 'proxy/proxy_config_service_linux_unittest.cc', 'proxy/proxy_config_service_win_unittest.cc', 'proxy/proxy_config_unittest.cc', diff --git a/net/proxy/proxy_bypass_rules.cc b/net/proxy/proxy_bypass_rules.cc new file mode 100644 index 0000000..9cf9d94 --- /dev/null +++ b/net/proxy/proxy_bypass_rules.cc @@ -0,0 +1,228 @@ +// Copyright (c) 2010 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_bypass_rules.h" + +#include "base/logging.h" +#include "base/string_tokenizer.h" +#include "base/string_util.h" +#include "net/base/net_util.h" + +namespace net { + +namespace { + +class HostnamePatternRule : public ProxyBypassRules::Rule { + public: + HostnamePatternRule(const std::string& optional_scheme, + const std::string& hostname_pattern, + int optional_port) + : optional_scheme_(StringToLowerASCII(optional_scheme)), + hostname_pattern_(StringToLowerASCII(hostname_pattern)), + optional_port_(optional_port) { + } + + virtual bool Matches(const GURL& url) const { + if (optional_port_ != -1 && url.EffectiveIntPort() != optional_port_) + return false; // Didn't match port expectation. + + if (!optional_scheme_.empty() && url.scheme() != optional_scheme_) + return false; // Didn't match scheme expectation. + + // Note it is necessary to lower-case the host, since GURL uses capital + // letters for percent-escaped characters. + return MatchPatternASCII(StringToLowerASCII(url.host()), + hostname_pattern_); + } + + virtual std::string ToString() const { + std::string str; + if (!optional_scheme_.empty()) + StringAppendF(&str, "%s://", optional_scheme_.c_str()); + str += hostname_pattern_; + if (optional_port_ != -1) + StringAppendF(&str, ":%d", optional_port_); + return str; + } + + private: + const std::string optional_scheme_; + const std::string hostname_pattern_; + const int optional_port_; +}; + +class BypassLocalRule : public ProxyBypassRules::Rule { + public: + virtual bool Matches(const GURL& url) const { + const std::string& host = url.host(); + if (host == "127.0.0.1" || host == "[::1]") + return true; + return host.find('.') == std::string::npos; + } + + virtual std::string ToString() const { + return "<local>"; + } +}; + +// Returns true if the given string represents an IP address. +bool IsIPAddress(const std::string& domain) { + // From GURL::HostIsIPAddress() + url_canon::RawCanonOutputT<char, 128> ignored_output; + url_canon::CanonHostInfo host_info; + url_parse::Component domain_comp(0, domain.size()); + url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp, + &ignored_output, &host_info); + return host_info.IsIPAddress(); +} + +} // namespace + +ProxyBypassRules::~ProxyBypassRules() { +} + +bool ProxyBypassRules::Matches(const GURL& url) const { + for (RuleList::const_iterator it = rules_.begin(); it != rules_.end(); ++it) { + if ((*it)->Matches(url)) + return true; + } + return false; +} + +bool ProxyBypassRules::Equals(const ProxyBypassRules& other) const { + if (rules_.size() != other.rules().size()) + return false; + + for (size_t i = 0; i < rules_.size(); ++i) { + if (!rules_[i]->Equals(*other.rules()[i])) + return false; + } + return true; +} + +void ProxyBypassRules::ParseFromString(const std::string& raw) { + ParseFromStringInternal(raw, false); +} + +void ProxyBypassRules::ParseFromStringUsingSuffixMatching( + const std::string& raw) { + ParseFromStringInternal(raw, true); +} + +bool ProxyBypassRules::AddRuleForHostname(const std::string& optional_scheme, + const std::string& hostname_pattern, + int optional_port) { + if (hostname_pattern.empty()) + return false; + + rules_.push_back(new HostnamePatternRule(optional_scheme, + hostname_pattern, + optional_port)); + return true; +} + +void ProxyBypassRules::AddRuleToBypassLocal() { + rules_.push_back(new BypassLocalRule); +} + +bool ProxyBypassRules::AddRuleFromString(const std::string& raw) { + return AddRuleFromStringInternalWithLogging(raw, false); +} + +void ProxyBypassRules::Clear() { + rules_.clear(); +} + +void ProxyBypassRules::ParseFromStringInternal( + const std::string& raw, + bool use_hostname_suffix_matching) { + Clear(); + + StringTokenizer entries(raw, ",;"); + while (entries.GetNext()) { + AddRuleFromStringInternalWithLogging(entries.token(), + use_hostname_suffix_matching); + } +} + +bool ProxyBypassRules::AddRuleFromStringInternal( + const std::string& raw_untrimmed, + bool use_hostname_suffix_matching) { + std::string raw; + TrimWhitespaceASCII(raw_untrimmed, TRIM_ALL, &raw); + + // This is the special syntax used by WinInet's bypass list -- we allow it + // on all platforms and interpret it the same way. + if (LowerCaseEqualsASCII(raw, "<local>")) { + AddRuleToBypassLocal(); + return true; + } + + // Extract any scheme-restriction. + std::string::size_type scheme_pos = raw.find("://"); + std::string scheme; + if (scheme_pos != std::string::npos) { + scheme = raw.substr(0, scheme_pos); + raw = raw.substr(scheme_pos + 3); + if (scheme.empty()) + return false; + } + + if (raw.empty()) + return false; + + // If there is a forward slash in the input, it is probably a CIDR style + // mask. + if (raw.find('/') != std::string::npos) { + LOG(WARNING) << "TODO: support CIDR-style proxy bypass entries " + "(http://crbug.com/9835)"; + return false; + } + + // Check if we have an <ip-address>[:port] input. We need to treat this + // separately since the IP literal may not be in a canonical form. + std::string host; + int port; + if (ParseHostAndPort(raw, &host, &port)) { + if (IsIPAddress(host)) { + // Canonicalize the IP literal before adding it as a string pattern. + GURL tmp_url("http://" + host); + return AddRuleForHostname(scheme, tmp_url.host(), port); + } + } + + // Otherwise assume we have <hostname-pattern>[:port]. + std::string::size_type pos_colon = raw.rfind(':'); + host = raw; + port = -1; + if (pos_colon != std::string::npos) { + if (!StringToInt(raw.substr(pos_colon + 1), &port) || + (port < 0 || port > 0xFFFF)) { + return false; // Port was invalid. + } + raw = raw.substr(0, pos_colon); + } + + // Special-case hostnames that begin with a period. + // For example, we remap ".google.com" --> "*.google.com". + if (StartsWithASCII(raw, ".", false)) + raw = "*" + raw; + + // If suffix matching was asked for, make sure the pattern starts with a + // wildcard. + if (use_hostname_suffix_matching && !StartsWithASCII(raw, "*", false)) + raw = "*" + raw; + + return AddRuleForHostname(scheme, raw, port); +} + +bool ProxyBypassRules::AddRuleFromStringInternalWithLogging( + const std::string& raw, + bool use_hostname_suffix_matching) { + bool ok = AddRuleFromStringInternal(raw, use_hostname_suffix_matching); + LOG_IF(WARNING, !ok) << "Unable to parse proxy bypass rule: " << raw; + return ok; +} + +} // namespace net diff --git a/net/proxy/proxy_bypass_rules.h b/net/proxy/proxy_bypass_rules.h new file mode 100644 index 0000000..03bb4ae --- /dev/null +++ b/net/proxy/proxy_bypass_rules.h @@ -0,0 +1,130 @@ +// Copyright (c) 2010 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_PROXY_BYPASS_RULES_H_ +#define NET_PROXY_PROXY_BYPASS_RULES_H_ + +#include <string> +#include <vector> + +#include "base/ref_counted.h" +#include "googleurl/src/gurl.h" + +namespace net { + +// ProxyBypassRules describes the set of URLs that should bypass the proxy +// settings, as a list of rules. A URL is said to match the bypass rules +// if it matches any one of these rules. +class ProxyBypassRules { + public: + // Interface for an individual proxy bypass rule. + class Rule : public base::RefCounted<Rule> { + public: + Rule() {} + virtual ~Rule() {} + + // Returns true if |url| matches the rule. + virtual bool Matches(const GURL& url) const = 0; + + // Returns a string representation of this rule. This is used both for + // visualizing the rules, and also to test equality of a rules list. + virtual std::string ToString() const = 0; + + bool Equals(const Rule& rule) const { + return ToString() == rule.ToString(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(Rule); + }; + + typedef std::vector<scoped_refptr<Rule> > RuleList; + + // Note: This class supports copy constructor and assignment. + + ~ProxyBypassRules(); + + // Returns the current list of rules. + const RuleList& rules() const { return rules_; } + + // Returns true if |url| matches any of the proxy bypass rules. + bool Matches(const GURL& url) const; + + // Returns true if |*this| is equal to |other|; in other words, whether they + // describe the same set of rules. + bool Equals(const ProxyBypassRules& other) const; + + // Initializes the list of rules by parsing the string |raw|. |raw| is a + // comma separated list of rules. See AddRuleFromString() to see the list + // of supported formats. + void ParseFromString(const std::string& raw); + + // This is a variant of ParseFromString, which interprets hostname patterns + // as suffix tests rather than hostname tests (so "google.com" would actually + // match "*google.com"). This is only currently used for the linux no_proxy + // evironment variable. It is less flexible, since with the suffix matching + // format you can't match an individual host. + // NOTE: Use ParseFromString() unless you truly need this behavior. + void ParseFromStringUsingSuffixMatching(const std::string& raw); + + // Adds a rule that matches a URL when all of the following are true: + // (a) The URL's scheme matches |optional_scheme|, if + // |!optional_scheme.empty()| + // (b) The URL's hostname matches |hostname_pattern|. + // (c) The URL's (effective) port number matches |optional_port| if + // |optional_port != -1| + // Returns true if the rule was successfully added. + bool AddRuleForHostname(const std::string& optional_scheme, + const std::string& hostname_pattern, + int optional_port); + + // Adds a rule that bypasses all "local" hostnames. + // This matches IE's interpretation of the + // "Bypass proxy server for local addresses" settings checkbox. Fully + // qualified domain names or IP addresses are considered non-local, + // regardless of what they map to (except for the loopback addresses). + void AddRuleToBypassLocal(); + + // Adds a rule given by the string |raw|. The format of |raw| can be any of + // the following: + // + // [ <scheme> "://" ] <hostname_pattern> [ ":" <port> ] + // "." <hostname_suffix_pattern> [ ":" <port> ] + // [ <scheme> "://" ] <ip_literal> [ ":" <port> ] + // "<local>" + // + // Note that <ip_literal> can be either an IPv4 literal, or an IPv6 literal + // but if it is an IPv6 literal it MUST be surrounded by square brackets, + // as in "[::1]". + // + // Also note that "<local>" means to bypass all local hostnames. (See + // AddRuleToBypassLocal() for details). + // + // Returns true if the rule was successfully added. + // + // TODO(eroman): support IPv6 literals without brackets. + // TODO(eroman): support CIDR-style IP masks. (http://crbug.com/9835). + // + bool AddRuleFromString(const std::string& raw); + + // Removes all the rules. + void Clear(); + + private: + // The following are variants of ParseFromString() and AddRuleFromString(), + // which additionally prefix hostname patterns with a wildcard if + // |use_hostname_suffix_matching| was true. + void ParseFromStringInternal(const std::string& raw, + bool use_hostname_suffix_matching); + bool AddRuleFromStringInternal(const std::string& raw, + bool use_hostname_suffix_matching); + bool AddRuleFromStringInternalWithLogging(const std::string& raw, + bool use_hostname_suffix_matching); + + RuleList rules_; +}; + +} // namespace net + +#endif // NET_PROXY_PROXY_BYPASS_RULES_H_ diff --git a/net/proxy/proxy_bypass_rules_unittest.cc b/net/proxy/proxy_bypass_rules_unittest.cc new file mode 100644 index 0000000..1bf24cb --- /dev/null +++ b/net/proxy/proxy_bypass_rules_unittest.cc @@ -0,0 +1,286 @@ +// Copyright (c) 2010 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_bypass_rules.h" + +#include "base/string_util.h" +#include "net/proxy/proxy_config_service_common_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +TEST(ProxyBypassRulesTest, ParseAndMatchBasicHost) { + ProxyBypassRules rules; + rules.ParseFromString("wWw.gOogle.com"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("www.google.com", rules.rules()[0]->ToString()); + + // All of these match; port, scheme, and non-hostname components don't + // matter. + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99"))); + EXPECT_TRUE(rules.Matches(GURL("https://www.google.com:81"))); + + // Must be a strict host match to work. + EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://xxx.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.baz.org"))); +} + +TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomain) { + ProxyBypassRules rules; + rules.ParseFromString(".gOOgle.com"); + ASSERT_EQ(1u, rules.rules().size()); + // Note that we inferred this was an "ends with" test. + EXPECT_EQ("*.google.com", rules.rules()[0]->ToString()); + + // All of these match; port, scheme, and non-hostname components don't + // matter. + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:99"))); + EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:81"))); + EXPECT_TRUE(rules.Matches(GURL("http://foo.google.com/x/y?q"))); + EXPECT_TRUE(rules.Matches(GURL("http://foo:bar@baz.google.com#x"))); + + // Must be a strict "ends with" to work. + EXPECT_FALSE(rules.Matches(GURL("http://google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org"))); +} + +TEST(ProxyBypassRulesTest, ParseAndMatchBasicDomainWithPort) { + ProxyBypassRules rules; + rules.ParseFromString("*.GOOGLE.com:80"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("*.google.com:80", rules.rules()[0]->ToString()); + + // All of these match; scheme, and non-hostname components don't matter. + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_TRUE(rules.Matches(GURL("ftp://www.google.com:80"))); + EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x"))); + + // Must be a strict "ends with" to work. + EXPECT_FALSE(rules.Matches(GURL("http://google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://foo.google.com.baz.org"))); + + // The ports must match. + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com:90"))); + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); +} + +TEST(ProxyBypassRulesTest, MatchAll) { + ProxyBypassRules rules; + rules.ParseFromString("*"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("*", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_TRUE(rules.Matches(GURL("ftp://www.foobar.com:99"))); + EXPECT_TRUE(rules.Matches(GURL("https://a.google.com:80?x"))); +} + +TEST(ProxyBypassRulesTest, WildcardAtStart) { + ProxyBypassRules rules; + rules.ParseFromString("*.org:443"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("*.org:443", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://www.google.org:443"))); + EXPECT_TRUE(rules.Matches(GURL("https://www.google.org"))); + + EXPECT_FALSE(rules.Matches(GURL("http://www.google.org"))); + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("https://www.google.org.com"))); +} + +TEST(ProxyBypassRulesTest, IPV4Address) { + ProxyBypassRules rules; + rules.ParseFromString("192.168.1.1"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("192.168.1.1", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1"))); + EXPECT_TRUE(rules.Matches(GURL("https://192.168.1.1:90"))); + + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1"))); +} + +TEST(ProxyBypassRulesTest, IPV4AddressWithPort) { + ProxyBypassRules rules; + rules.ParseFromString("192.168.1.1:33"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("192.168.1.1:33", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://192.168.1.1:33"))); + + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://192.168.1.1"))); + EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33"))); +} + +TEST(ProxyBypassRulesTest, IPV6Address) { + ProxyBypassRules rules; + rules.ParseFromString("[3ffe:2a00:100:7031:0:0::1]"); + ASSERT_EQ(1u, rules.rules().size()); + // Note that we canonicalized the IP address. + EXPECT_EQ("[3ffe:2a00:100:7031::1]", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]"))); + EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33"))); + + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://sup.192.168.1.1:33"))); +} + +TEST(ProxyBypassRulesTest, IPV6AddressWithPort) { + ProxyBypassRules rules; + rules.ParseFromString("[3ffe:2a00:100:7031::1]:33"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("[3ffe:2a00:100:7031::1]:33", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]:33"))); + + EXPECT_FALSE(rules.Matches(GURL("http://[3ffe:2a00:100:7031::1]"))); + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com"))); +} + +TEST(ProxyBypassRulesTest, HTTPOnly) { + ProxyBypassRules rules; + rules.ParseFromString("http://www.google.com"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("http://www.google.com", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo"))); + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99"))); + + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://foo.www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org"))); + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); +} + +TEST(ProxyBypassRulesTest, HTTPOnlyWithWildcard) { + ProxyBypassRules rules; + rules.ParseFromString("http://*www.google.com"); + ASSERT_EQ(1u, rules.rules().size()); + EXPECT_EQ("http://*www.google.com", rules.rules()[0]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com/foo"))); + EXPECT_TRUE(rules.Matches(GURL("http://www.google.com:99"))); + EXPECT_TRUE(rules.Matches(GURL("http://foo.www.google.com"))); + + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("ftp://www.google.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://www.google.com.org"))); + EXPECT_FALSE(rules.Matches(GURL("https://www.google.com"))); +} + +TEST(ProxyBypassRulesTest, UseSuffixMatching) { + ProxyBypassRules rules; + rules.ParseFromStringUsingSuffixMatching( + "foo1.com, .foo2.com, 192.168.1.1, " + "*foobar.com:80, *.foo, http://baz, <local>"); + ASSERT_EQ(7u, rules.rules().size()); + EXPECT_EQ("*foo1.com", rules.rules()[0]->ToString()); + EXPECT_EQ("*.foo2.com", rules.rules()[1]->ToString()); + EXPECT_EQ("192.168.1.1", rules.rules()[2]->ToString()); + EXPECT_EQ("*foobar.com:80", rules.rules()[3]->ToString()); + EXPECT_EQ("*.foo", rules.rules()[4]->ToString()); + EXPECT_EQ("http://*baz", rules.rules()[5]->ToString()); + EXPECT_EQ("<local>", rules.rules()[6]->ToString()); + + EXPECT_TRUE(rules.Matches(GURL("http://foo1.com"))); + EXPECT_TRUE(rules.Matches(GURL("http://aaafoo1.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://aaafoo1.com.net"))); +} + +TEST(ProxyBypassRulesTest, MultipleRules) { + ProxyBypassRules rules; + rules.ParseFromString(".google.com , .foobar.com:30"); + ASSERT_EQ(2u, rules.rules().size()); + + EXPECT_TRUE(rules.Matches(GURL("http://baz.google.com:40"))); + EXPECT_FALSE(rules.Matches(GURL("http://google.com:40"))); + EXPECT_TRUE(rules.Matches(GURL("http://bar.foobar.com:30"))); + EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com"))); + EXPECT_FALSE(rules.Matches(GURL("http://bar.foobar.com:33"))); +} + +TEST(ProxyBypassRulesTest, BadInputs) { + ProxyBypassRules rules; + EXPECT_FALSE(rules.AddRuleFromString("://")); + EXPECT_FALSE(rules.AddRuleFromString(" ")); + EXPECT_FALSE(rules.AddRuleFromString("http://")); + EXPECT_FALSE(rules.AddRuleFromString("*.foo.com:-34")); + EXPECT_EQ(0u, rules.rules().size()); +} + +TEST(ProxyBypassRulesTest, Equals) { + ProxyBypassRules rules1; + ProxyBypassRules rules2; + + rules1.ParseFromString("foo1.com, .foo2.com"); + rules2.ParseFromString("foo1.com,.FOo2.com"); + + EXPECT_TRUE(rules1.Equals(rules2)); + EXPECT_TRUE(rules2.Equals(rules1)); + + rules1.ParseFromString(".foo2.com"); + rules2.ParseFromString("foo1.com,.FOo2.com"); + + EXPECT_FALSE(rules1.Equals(rules2)); + EXPECT_FALSE(rules2.Equals(rules1)); +} + +TEST(ProxyBypassRulesTest, BypassLocalNames) { + 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}, + }; + + ProxyBypassRules rules; + rules.ParseFromString("<local>"); + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + SCOPED_TRACE(StringPrintf( + "Test[%d]: %s", static_cast<int>(i), tests[i].url)); + EXPECT_EQ(tests[i].expected_is_local, rules.Matches(GURL(tests[i].url))); + } +} + +} // namespace + +} // namespace net diff --git a/net/proxy/proxy_config.cc b/net/proxy/proxy_config.cc index 836559e..f8fe9f6 100644 --- a/net/proxy/proxy_config.cc +++ b/net/proxy/proxy_config.cc @@ -11,7 +11,6 @@ namespace net { ProxyConfig::ProxyConfig() : auto_detect(false), - proxy_bypass_local_names(false), id_(INVALID_ID) { } @@ -21,8 +20,7 @@ bool ProxyConfig::Equals(const ProxyConfig& other) const { return auto_detect == other.auto_detect && pac_url == other.pac_url && proxy_rules == other.proxy_rules && - proxy_bypass == other.proxy_bypass && - proxy_bypass_local_names == other.proxy_bypass_local_names; + bypass_rules.Equals(other.bypass_rules); } bool ProxyConfig::MayRequirePACResolver() const { @@ -98,72 +96,6 @@ ProxyServer* ProxyConfig::ProxyRules::MapSchemeToProxy( return NULL; // No mapping for this scheme. } -namespace { - -// Returns true if the given string represents an IP address. -bool IsIPAddress(const std::string& domain) { - // From GURL::HostIsIPAddress() - url_canon::RawCanonOutputT<char, 128> ignored_output; - url_canon::CanonHostInfo host_info; - url_parse::Component domain_comp(0, domain.size()); - url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp, - &ignored_output, &host_info); - return host_info.IsIPAddress(); -} - -} // namespace - -void ProxyConfig::ParseNoProxyList(const std::string& no_proxy) { - proxy_bypass.clear(); - if (no_proxy.empty()) - return; - // Traditional semantics: - // A single "*" is specifically allowed and unproxies anything. - // "*" wildcards other than a single "*" entry are not universally - // supported. We will support them, as we get * wildcards for free - // (see MatchPatternASCII() called from - // ProxyService::ShouldBypassProxyForURL()). - // no_proxy is a comma-separated list of <trailing_domain>[:<port>]. - // If no port is specified then any port matches. - // The historical definition has trailing_domain match using a simple - // string "endswith" test, so that the match need not correspond to a - // "." boundary. For example: "google.com" matches "igoogle.com" too. - // Seems like that could be confusing, but we'll obey tradition. - // IP CIDR patterns are supposed to be supported too. We intend - // to do this in proxy_service.cc, but it's currently a TODO. - // See: http://crbug.com/9835. - StringTokenizer no_proxy_list(no_proxy, ","); - while (no_proxy_list.GetNext()) { - std::string bypass_entry = no_proxy_list.token(); - TrimWhitespaceASCII(bypass_entry, TRIM_ALL, &bypass_entry); - if (bypass_entry.empty()) - continue; - if (bypass_entry.at(0) != '*') { - // Insert a wildcard * to obtain an endsWith match, unless the - // entry looks like it might be an IP or CIDR. - // First look for either a :<port> or CIDR mask length suffix. - std::string::const_iterator begin = bypass_entry.begin(); - std::string::const_iterator scan = bypass_entry.end() - 1; - while (scan > begin && IsAsciiDigit(*scan)) - --scan; - std::string potential_ip; - if (*scan == '/' || *scan == ':') - potential_ip = std::string(begin, scan - 1); - else - potential_ip = bypass_entry; - if (!IsIPAddress(potential_ip)) { - // Do insert a wildcard. - bypass_entry.insert(0, "*"); - } - // TODO(sdoyon): When CIDR matching is implemented in - // proxy_service.cc, consider making proxy_bypass more - // sophisticated to avoid parsing out the string on every - // request. - } - proxy_bypass.push_back(bypass_entry); - } -} - } // namespace net namespace { @@ -247,18 +179,15 @@ std::ostream& operator<<(std::ostream& out, const net::ProxyConfig& config) { } out << " Bypass list: "; - if (config.proxy_bypass.empty()) { - out << "[None]\n"; + if (config.bypass_rules.rules().empty()) { + out << "[None]"; } else { - out << "\n"; - std::vector<std::string>::const_iterator it; - for (it = config.proxy_bypass.begin(); - it != config.proxy_bypass.end(); ++it) { - out << " " << *it << "\n"; + net::ProxyBypassRules::RuleList::const_iterator it; + for (it = config.bypass_rules.rules().begin(); + it != config.bypass_rules.rules().end(); ++it) { + out << "\n " << (*it)->ToString(); } } - out << " Bypass local names: " - << BoolToYesNoString(config.proxy_bypass_local_names); return out; } diff --git a/net/proxy/proxy_config.h b/net/proxy/proxy_config.h index c48f74b..bd62465 100644 --- a/net/proxy/proxy_config.h +++ b/net/proxy/proxy_config.h @@ -10,6 +10,7 @@ #include <vector> #include "googleurl/src/gurl.h" +#include "net/proxy/proxy_bypass_rules.h" #include "net/proxy/proxy_server.h" namespace net { @@ -104,20 +105,7 @@ class ProxyConfig { }; ProxyRules proxy_rules; - - // Parses entries from a comma-separated list of hosts for which proxy - // configurations should be bypassed. Clears proxy_bypass and sets it to the - // resulting list. - void ParseNoProxyList(const std::string& no_proxy); - - // Indicates a list of hosts that should bypass any proxy configuration. For - // these hosts, a direct connection should always be used. - // The form <host>:<port> is also supported, meaning that only - // connections on the specified port should be direct. - std::vector<std::string> proxy_bypass; - - // Indicates whether local names (no dots) bypass proxies. - bool proxy_bypass_local_names; + ProxyBypassRules bypass_rules; // Returns true if the given config is equivalent to this config. bool Equals(const ProxyConfig& other) const; diff --git a/net/proxy/proxy_config_service_common_unittest.cc b/net/proxy/proxy_config_service_common_unittest.cc index 1a61468..74baa49 100644 --- a/net/proxy/proxy_config_service_common_unittest.cc +++ b/net/proxy/proxy_config_service_common_unittest.cc @@ -54,11 +54,12 @@ ProxyConfig::ProxyRules MakeProxyPerSchemeRules( "", proxy_http, proxy_https, proxy_ftp, socks_proxy); } -std::string FlattenProxyBypass(const BypassList& proxy_bypass) { +std::string FlattenProxyBypass(const ProxyBypassRules& bypass_rules) { std::string flattened_proxy_bypass; - for (BypassList::const_iterator it = proxy_bypass.begin(); - it != proxy_bypass.end(); ++it) { - flattened_proxy_bypass += *it + "\n"; + for (ProxyBypassRules::RuleList::const_iterator it = + bypass_rules.rules().begin(); + it != bypass_rules.rules().end(); ++it) { + flattened_proxy_bypass += (*it)->ToString() + "\n"; } return flattened_proxy_bypass; } diff --git a/net/proxy/proxy_config_service_common_unittest.h b/net/proxy/proxy_config_service_common_unittest.h index 783fc6f..66ddfa6 100644 --- a/net/proxy/proxy_config_service_common_unittest.h +++ b/net/proxy/proxy_config_service_common_unittest.h @@ -14,6 +14,8 @@ namespace net { +class ProxyBypassRules; + ProxyConfig::ProxyRules MakeProxyRules( ProxyConfig::ProxyRules::Type type, const char* single_proxy, @@ -35,10 +37,8 @@ ProxyConfig::ProxyRules MakeProxyPerSchemeRules( const char* proxy_ftp, const char* socks_proxy); -typedef std::vector<std::string> BypassList; - // Joins the proxy bypass list using "\n" to make it into a single string. -std::string FlattenProxyBypass(const BypassList& proxy_bypass); +std::string FlattenProxyBypass(const ProxyBypassRules& bypass_rules); } // namespace net diff --git a/net/proxy/proxy_config_service_linux.cc b/net/proxy/proxy_config_service_linux.cc index 3ca35c5..4eb6779 100644 --- a/net/proxy/proxy_config_service_linux.cc +++ b/net/proxy/proxy_config_service_linux.cc @@ -163,7 +163,9 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) { // connections. return !no_proxy.empty(); } - config->ParseNoProxyList(no_proxy); + // Note that this uses "suffix" matching. So a bypass of "google.com" + // is understood to mean a bypass of "*google.com". + config->bypass_rules.ParseFromStringUsingSuffixMatching(no_proxy); return true; } @@ -943,10 +945,16 @@ bool ProxyConfigServiceLinux::Delegate::GetConfigFromGConf( } // Now the bypass list. + std::vector<std::string> ignore_hosts_list; gconf_getter_->GetStringList("/system/http_proxy/ignore_hosts", - &config->proxy_bypass); + &ignore_hosts_list); + + config->bypass_rules.Clear(); + for (size_t i = 0; i < ignore_hosts_list.size(); ++i) + config->bypass_rules.AddRuleFromString(ignore_hosts_list[i]); + // Note that there are no settings with semantics corresponding to - // config->proxy_bypass_local_names. + // bypass of local names. return true; } diff --git a/net/proxy/proxy_config_service_linux_unittest.cc b/net/proxy/proxy_config_service_linux_unittest.cc index 4ebc12e..0940ddf 100644 --- a/net/proxy/proxy_config_service_linux_unittest.cc +++ b/net/proxy/proxy_config_service_linux_unittest.cc @@ -367,7 +367,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL pac_url; ProxyConfig::ProxyRules proxy_rules; const char* proxy_bypass_list; // newline separated - bool bypass_local_names; } tests[] = { { TEST_DESC("No proxying"), @@ -385,7 +384,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -404,7 +402,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -423,7 +420,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL("http://wpad/wpad.dat"), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -442,7 +438,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -461,7 +456,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -480,7 +474,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -500,7 +493,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { MakeProxyPerSchemeRules("www.google.com", // proxy_rules "", ""), "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -519,7 +511,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com:88"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -543,7 +534,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { "www.foo.com:110", "ftp.foo.com:121"), "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -562,7 +552,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url MakeSingleProxyRules("socks4://socks.com:99"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -580,7 +569,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com"), // proxy_rules "*.google.com\n", // proxy_bypass_list - false, // bypass_local_names }, }; @@ -600,8 +588,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicGConfTest) { EXPECT_EQ(tests[i].auto_detect, config.auto_detect); EXPECT_EQ(tests[i].pac_url, config.pac_url); EXPECT_EQ(tests[i].proxy_bypass_list, - FlattenProxyBypass(config.proxy_bypass)); - EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); + FlattenProxyBypass(config.bypass_rules)); EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); } } @@ -620,7 +607,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL pac_url; ProxyConfig::ProxyRules proxy_rules; const char* proxy_bypass_list; // newline separated - bool bypass_local_names; } tests[] = { { TEST_DESC("No proxying"), @@ -639,7 +625,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -659,7 +644,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -679,7 +663,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL("http://wpad/wpad.dat"), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -699,7 +682,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -719,7 +701,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -739,7 +720,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com:99"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -759,7 +739,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com:99"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -780,7 +759,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { MakeProxyPerSchemeRules("www.google.com", "www.foo.com:110", "ftp.foo.com:121"), "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -800,7 +778,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("socks4://socks.com:888"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -820,7 +797,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("socks5://socks.com:888"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -840,7 +816,6 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("socks4://socks.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -859,8 +834,8 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { GURL(), // pac_url MakeSingleProxyRules("www.google.com"), // proxy_rules // proxy_bypass_list - "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n", - false, // bypass_local_names + // TODO(eroman): 127.0.0.1/8 is unsupported, so it was dropped + "*.google.com\n*foo.com:99\n1.2.3.4:22\n", }, }; @@ -880,8 +855,7 @@ TEST_F(ProxyConfigServiceLinuxTest, BasicEnvTest) { EXPECT_EQ(tests[i].auto_detect, config.auto_detect); EXPECT_EQ(tests[i].pac_url, config.pac_url); EXPECT_EQ(tests[i].proxy_bypass_list, - FlattenProxyBypass(config.proxy_bypass)); - EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); + FlattenProxyBypass(config.bypass_rules)); EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); } } @@ -930,7 +904,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { GURL pac_url; ProxyConfig::ProxyRules proxy_rules; const char* proxy_bypass_list; // newline separated - bool bypass_local_names; } tests[] = { { TEST_DESC("No proxying"), @@ -943,7 +916,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -957,7 +929,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -972,7 +943,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { GURL("http://wpad/wpad.dat"), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -989,7 +959,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { "www.foo.com", "ftp.foo.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1005,7 +974,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1021,7 +989,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com:88", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1036,7 +1003,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "*.google.com\n", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1051,7 +1017,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "*.google.com\n*.kde.org\n", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1066,7 +1031,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1081,7 +1045,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1096,7 +1059,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1110,7 +1072,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1124,7 +1085,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1138,7 +1098,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", ""), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1153,7 +1112,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", "ftp.foo.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1167,7 +1125,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { GURL("http:// foo"), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, { @@ -1182,7 +1139,6 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { MakeProxyPerSchemeRules("www.google.com", "", "ftp.foo.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, }; @@ -1206,8 +1162,7 @@ TEST_F(ProxyConfigServiceLinuxTest, KDEConfigParser) { EXPECT_EQ(tests[i].auto_detect, config.auto_detect); EXPECT_EQ(tests[i].pac_url, config.pac_url); EXPECT_EQ(tests[i].proxy_bypass_list, - FlattenProxyBypass(config.proxy_bypass)); - EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); + FlattenProxyBypass(config.bypass_rules)); EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); } } diff --git a/net/proxy/proxy_config_service_mac.cc b/net/proxy/proxy_config_service_mac.cc index 3359cc3..74b1ea6 100644 --- a/net/proxy/proxy_config_service_mac.cc +++ b/net/proxy/proxy_config_service_mac.cc @@ -140,7 +140,7 @@ int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) { " to be a CFStringRef but it was not"; } else { - config->proxy_bypass.push_back( + config->bypass_rules.AddRuleFromString( base::SysCFStringRefToUTF8(bypass_item_ref)); } } @@ -148,10 +148,11 @@ int ProxyConfigServiceMac::GetProxyConfig(ProxyConfig* config) { // proxy bypass boolean - config->proxy_bypass_local_names = - GetBoolFromDictionary(config_dict.get(), + if (GetBoolFromDictionary(config_dict.get(), kSCPropNetProxiesExcludeSimpleHostnames, - false); + false)) { + config->bypass_rules.AddRuleToBypassLocal(); + } return OK; } diff --git a/net/proxy/proxy_config_service_win.cc b/net/proxy/proxy_config_service_win.cc index 30c4adb..c39c510 100644 --- a/net/proxy/proxy_config_service_win.cc +++ b/net/proxy/proxy_config_service_win.cc @@ -55,10 +55,7 @@ void ProxyConfigServiceWin::SetFromIEConfig( StringTokenizer proxy_server_bypass_list(proxy_bypass, "; \t\n\r"); while (proxy_server_bypass_list.GetNext()) { std::string bypass_url_domain = proxy_server_bypass_list.token(); - if (bypass_url_domain == "<local>") - config->proxy_bypass_local_names = true; - else - config->proxy_bypass.push_back(bypass_url_domain); + config->bypass_rules.AddRuleFromString(bypass_url_domain); } } if (ie_config.lpszAutoConfigUrl) diff --git a/net/proxy/proxy_config_service_win_unittest.cc b/net/proxy/proxy_config_service_win_unittest.cc index 2b0ff66..ffcb0be 100644 --- a/net/proxy/proxy_config_service_win_unittest.cc +++ b/net/proxy/proxy_config_service_win_unittest.cc @@ -21,7 +21,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL pac_url; ProxyConfig::ProxyRules proxy_rules; const char* proxy_bypass_list; // newline separated - bool bypass_local_names; } tests[] = { // Auto detect. { @@ -37,7 +36,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, // Valid PAC url @@ -54,7 +52,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL("http://wpad/wpad.dat"), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, // Invalid PAC url string. @@ -71,7 +68,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, // Single-host in proxy list. @@ -88,7 +84,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL(), // pac_url MakeSingleProxyRules("www.google.com"), // proxy_rules "", // proxy_bypass_list - false, // bypass_local_names }, // Per-scheme proxy rules. @@ -105,7 +100,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL(), // pac_url MakeProxyPerSchemeRules("www.google.com:80", "www.foo.com:110", ""), "", // proxy_bypass_list - false, // bypass_local_names }, // SOCKS proxy configuration @@ -124,7 +118,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { MakeProxyPerSchemeRules("www.google.com:80", "www.foo.com:110", "ftpproxy:20", "foopy:130"), "", // proxy_bypass_list - false, // bypass_local_names }, // Bypass local names. @@ -139,8 +132,7 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { true, // auto_detect GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules - "", // proxy_bypass_list - true, // bypass_local_names + "<local>\n", // proxy_bypass_list }, // Bypass "google.com" and local names, using semicolon as delimeter @@ -157,8 +149,7 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { true, // auto_detect GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules - "google.com\n", // proxy_bypass_list - true, // bypass_local_names + "<local>\ngoogle.com\n", // proxy_bypass_list }, // Bypass "foo.com" and "google.com", using lines as delimeter. @@ -175,7 +166,6 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { GURL(), // pac_url ProxyConfig::ProxyRules(), // proxy_rules "foo.com\ngoogle.com\n", // proxy_bypass_list - false, // bypass_local_names }, }; @@ -186,8 +176,7 @@ TEST(ProxyConfigServiceWinTest, SetFromIEConfig) { EXPECT_EQ(tests[i].auto_detect, config.auto_detect); EXPECT_EQ(tests[i].pac_url, config.pac_url); EXPECT_EQ(tests[i].proxy_bypass_list, - FlattenProxyBypass(config.proxy_bypass)); - EXPECT_EQ(tests[i].bypass_local_names, config.proxy_bypass_local_names); + FlattenProxyBypass(config.bypass_rules)); EXPECT_EQ(tests[i].proxy_rules, config.proxy_rules); } } diff --git a/net/proxy/proxy_config_unittest.cc b/net/proxy/proxy_config_unittest.cc index 259f1fa..9f6cbaf 100644 --- a/net/proxy/proxy_config_unittest.cc +++ b/net/proxy/proxy_config_unittest.cc @@ -71,26 +71,14 @@ TEST(ProxyConfigTest, Equals) { EXPECT_TRUE(config1.Equals(config2)); EXPECT_TRUE(config2.Equals(config1)); - // Test |ProxyConfig::proxy_bypass|. + // Test |ProxyConfig::bypass_rules|. - config2.proxy_bypass.push_back("*.google.com"); + config2.bypass_rules.AddRuleFromString("*.google.com"); EXPECT_FALSE(config1.Equals(config2)); EXPECT_FALSE(config2.Equals(config1)); - config1.proxy_bypass.push_back("*.google.com"); - - EXPECT_TRUE(config1.Equals(config2)); - EXPECT_TRUE(config2.Equals(config1)); - - // Test |ProxyConfig::proxy_bypass_local_names|. - - config1.proxy_bypass_local_names = true; - - EXPECT_FALSE(config1.Equals(config2)); - EXPECT_FALSE(config2.Equals(config1)); - - config2.proxy_bypass_local_names = true; + config1.bypass_rules.AddRuleFromString("*.google.com"); EXPECT_TRUE(config1.Equals(config2)); EXPECT_TRUE(config2.Equals(config1)); @@ -252,39 +240,6 @@ TEST(ProxyConfigTest, ParseProxyRules) { } } -TEST(ProxyConfigTest, ParseProxyBypassList) { - struct bypass_test { - const char* proxy_bypass_input; - const char* flattened_output; - }; - - const struct { - const char* proxy_bypass_input; - const char* flattened_output; - } tests[] = { - { - "*", - "*\n" - }, - { - ".google.com, .foo.com:42", - "*.google.com\n*.foo.com:42\n" - }, - { - ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8", - "*.google.com\n*foo.com:99\n1.2.3.4:22\n127.0.0.1/8\n" - } - }; - - ProxyConfig config; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - config.ParseNoProxyList(tests[i].proxy_bypass_input); - EXPECT_EQ(tests[i].flattened_output, - FlattenProxyBypass(config.proxy_bypass)); - } -} - std::string ProxyConfigToString(const ProxyConfig& config) { std::ostringstream stream; stream << config; @@ -303,8 +258,7 @@ TEST(ProxyConfigTest, ToString) { " Custom PAC script: [None]\n" "Manual settings:\n" " Proxy server: single-proxy:81\n" - " Bypass list: [None]\n" - " Bypass local names: No", + " Bypass list: [None]", ProxyConfigToString(config)); } @@ -320,8 +274,7 @@ TEST(ProxyConfigTest, ToString) { " Custom PAC script: http://custom/pac.js\n" "Manual settings:\n" " Proxy server: single-proxy:81\n" - " Bypass list: [None]\n" - " Bypass local names: No", + " Bypass list: [None]", ProxyConfigToString(config)); } @@ -330,9 +283,9 @@ TEST(ProxyConfigTest, ToString) { ProxyConfig config; config.auto_detect = false; config.proxy_rules.ParseFromString("http://single-proxy:81"); - config.proxy_bypass.push_back("google.com"); - config.proxy_bypass.push_back("bypass2.net:1730"); - config.proxy_bypass_local_names = true; + config.bypass_rules.AddRuleFromString("google.com"); + config.bypass_rules.AddRuleFromString("bypass2.net:1730"); + config.bypass_rules.AddRuleToBypassLocal(); EXPECT_EQ("Automatic settings:\n" " Auto-detect: No\n" @@ -342,7 +295,7 @@ TEST(ProxyConfigTest, ToString) { " Bypass list: \n" " google.com\n" " bypass2.net:1730\n" - " Bypass local names: Yes", + " <local>", ProxyConfigToString(config)); } @@ -360,8 +313,7 @@ TEST(ProxyConfigTest, ToString) { " Proxy server: \n" " HTTP: proxy-for-http:1801\n" " HTTPS: proxy-for-https:1802\n" - " Bypass list: [None]\n" - " Bypass local names: No", + " Bypass list: [None]", ProxyConfigToString(config)); } @@ -379,8 +331,7 @@ TEST(ProxyConfigTest, ToString) { " Proxy server: \n" " HTTP: proxy-for-http:1801\n" " SOCKS: socks4://socks-server:6083\n" - " Bypass list: [None]\n" - " Bypass local names: No", + " Bypass list: [None]", ProxyConfigToString(config)); } @@ -394,8 +345,7 @@ TEST(ProxyConfigTest, ToString) { " Custom PAC script: [None]\n" "Manual settings:\n" " Proxy server: [None]\n" - " Bypass list: [None]\n" - " Bypass local names: No", + " Bypass list: [None]", ProxyConfigToString(config)); } } diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 90fd297..fa7ba4d 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -334,7 +334,7 @@ void ProxyService::ApplyProxyRules(const GURL& url, ProxyInfo* result) { DCHECK(!proxy_rules.empty()); - if (ShouldBypassProxyForURL(url)) { + if (config_.bypass_rules.Matches(url)) { result->UseDirect(); return; } @@ -692,90 +692,6 @@ void ProxyService::UpdateConfigIfOld(LoadLog* load_log) { UpdateConfig(load_log); } -bool ProxyService::ShouldBypassProxyForURL(const GURL& url) { - std::string url_domain = url.scheme(); - if (!url_domain.empty()) - url_domain += "://"; - - url_domain += url.host(); - // This isn't superfluous; GURL case canonicalization doesn't hit the embedded - // percent-encoded characters. - StringToLowerASCII(&url_domain); - - // TODO(eroman): use GetHostAndPort(). - std::string url_domain_and_port = url_domain + ":" - + IntToString(url.EffectiveIntPort()); - - if (config_.proxy_bypass_local_names && IsLocalName(url)) - return true; - - for(std::vector<std::string>::const_iterator i = config_.proxy_bypass.begin(); - i != config_.proxy_bypass.end(); ++i) { - std::string bypass_url_domain = *i; - - // The proxy server bypass list can contain entities with http/https - // If no scheme is specified then it indicates that all schemes are - // allowed for the current entry. For matching this we just use - // the protocol scheme of the url passed in. - size_t scheme_colon = bypass_url_domain.find("://"); - if (scheme_colon == std::string::npos) { - std::string bypass_url_domain_with_scheme = url.scheme(); - scheme_colon = bypass_url_domain_with_scheme.length(); - bypass_url_domain_with_scheme += "://"; - bypass_url_domain_with_scheme += bypass_url_domain; - - bypass_url_domain = bypass_url_domain_with_scheme; - } - std::string* url_compare_reference = &url_domain; - size_t port_colon = bypass_url_domain.rfind(":"); - if (port_colon > scheme_colon) { - // If our match pattern includes a colon followed by a digit, - // and either it's preceded by ']' (IPv6 with port) - // or has no other colon (IPv4), - // then match against <domain>:<port>. - // TODO(sdoyon): straighten this out, in particular the IPv6 brackets, - // and do the parsing in ProxyConfig when we do the CIDR matching - // mentioned below. - std::string::const_iterator domain_begin = - bypass_url_domain.begin() + scheme_colon + 3; // after :// - std::string::const_iterator port_iter = - bypass_url_domain.begin() + port_colon; - std::string::const_iterator end = bypass_url_domain.end(); - if ((port_iter + 1) < end && IsAsciiDigit(*(port_iter + 1)) && - (*(port_iter - 1) == ']' || - std::find(domain_begin, port_iter, ':') == port_iter)) - url_compare_reference = &url_domain_and_port; - } - - StringToLowerASCII(&bypass_url_domain); - - if (MatchPatternASCII(*url_compare_reference, bypass_url_domain)) - return true; - - // Some systems (the Mac, for example) allow CIDR-style specification of - // proxy bypass for IP-specified hosts (e.g. "10.0.0.0/8"; see - // http://www.tcd.ie/iss/internet/osx_proxy.php for a real-world example). - // That's kinda cool so we'll provide that for everyone. - // TODO(avi): implement here. See: http://crbug.com/9835. - // IP addresses ought to be canonicalized for comparison (whether - // with CIDR, port, or IP address alone). - } - - return false; -} - -// This matches IE's interpretation of the -// "Bypass proxy server for local addresses" settings checkbox. Fully -// qualified domain names or IP addresses are considered non-local, -// regardless of what they map to. -// -// static -bool ProxyService::IsLocalName(const GURL& url) { - const std::string& host = url.host(); - if (host == "127.0.0.1" || host == "[::1]") - return true; - return host.find('.') == std::string::npos; -} void ProxyService::OnIPAddressChanged() { DCHECK(network_change_notifier_); diff --git a/net/proxy/proxy_service.h b/net/proxy/proxy_service.h index 8614d555..5798214 100644 --- a/net/proxy/proxy_service.h +++ b/net/proxy/proxy_service.h @@ -178,7 +178,6 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>, private: friend class base::RefCountedThreadSafe<ProxyService>; - FRIEND_TEST(ProxyServiceTest, IsLocalName); FRIEND_TEST(ProxyServiceTest, UpdateConfigAfterFailedAutodetect); FRIEND_TEST(ProxyServiceTest, UpdateConfigFromPACToDirect); friend class PacRequest; @@ -253,15 +252,6 @@ class ProxyService : public base::RefCountedThreadSafe<ProxyService>, int result_code, LoadLog* load_log); - // Returns true if the URL passed in should not go through the proxy server. - // 1. If the proxy settings say to bypass local names, and |IsLocalName(url)|. - // 2. The URL matches one of the entities in the proxy bypass list. - bool ShouldBypassProxyForURL(const GURL& url); - - // Returns true if |url| is to an intranet site (using non-FQDN as the - // heuristic). - static bool IsLocalName(const GURL& url); - // NetworkChangeNotifier::Observer methods: virtual void OnIPAddressChanged(); diff --git a/net/proxy/proxy_service_unittest.cc b/net/proxy/proxy_service_unittest.cc index b6804ce..802806c 100644 --- a/net/proxy/proxy_service_unittest.cc +++ b/net/proxy/proxy_service_unittest.cc @@ -674,212 +674,33 @@ TEST(ProxyServiceTest, ProxyFallback_BadConfig) { } TEST(ProxyServiceTest, ProxyBypassList) { - // Test what happens when a proxy bypass list is specified. + // Test that the proxy bypass rules are consulted. - ProxyInfo info; + TestCompletionCallback callback[2]; + ProxyInfo info[2]; 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(), - NULL)); - 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(), - NULL)); - 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.bypass_rules.ParseFromString("*.org"); - 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, NULL)); - 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, NULL)); - 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()); - } + scoped_refptr<ProxyService> service(new ProxyService( + new MockProxyConfigService(config), new MockAsyncProxyResolver, NULL)); - 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, NULL)); - 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()); - } + int rv; + GURL url1("http://www.webkit.org"); + GURL url2("http://www.webkit.com"); - 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, NULL)); - 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()); - } + // Request for a .org domain should bypass proxy. + rv = service->ResolveProxy(url1, &info[0], &callback[0], NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_TRUE(info[0].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, NULL)); - 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()); - } + // Request for a .com domain hits the proxy. + rv = service->ResolveProxy(url2, &info[1], &callback[1], NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("foopy1:8080", info[1].proxy_server().ToURI()); } -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, NULL)); - { - 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, NULL)); - 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, NULL)); - 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, NULL)); - { - 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, NULL)); - { - 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; @@ -1491,7 +1312,7 @@ TEST(ProxyServiceTest, BypassDoesntApplyToPac) { 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"); + config.bypass_rules.ParseFromString("www.google.com"); MockProxyConfigService* config_service = new MockProxyConfigService(config); MockAsyncProxyResolverExpectsBytes* resolver = @@ -1644,47 +1465,6 @@ TEST(ProxyServiceTest, ResetProxyConfigService) { 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 |