summaryrefslogtreecommitdiffstats
path: root/net/proxy/proxy_bypass_rules.cc
diff options
context:
space:
mode:
authoreroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-19 20:24:06 +0000
committereroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-02-19 20:24:06 +0000
commit7541206c7a5160f3489d563b97f1c841c853dc22 (patch)
treeb69621265589060c0577559c23c86db4de667191 /net/proxy/proxy_bypass_rules.cc
parentd68a04da3be6a4a5db3768f53b2b48735a6ec210 (diff)
downloadchromium_src-7541206c7a5160f3489d563b97f1c841c853dc22.zip
chromium_src-7541206c7a5160f3489d563b97f1c841c853dc22.tar.gz
chromium_src-7541206c7a5160f3489d563b97f1c841c853dc22.tar.bz2
Split out the handling of proxy bypass rules into ProxyBypassRules. There are some pretty complicated rules, and this helps isolate that code and better test it.
This also lays a framework for addressing bug 9835 (IP/CIDR matching) Lastly, adds support for the exclusion format ".domain" on all platforms, which is interpreted as "*.domain". BUG=28112 TEST=ProxyBypassRulesTest.* Review URL: http://codereview.chromium.org/601070 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39486 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/proxy/proxy_bypass_rules.cc')
-rw-r--r--net/proxy/proxy_bypass_rules.cc228
1 files changed, 228 insertions, 0 deletions
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