From b6a50183e21e21207f2dff4953d19aa5be62d166 Mon Sep 17 00:00:00 2001 From: "willchan@chromium.org" Date: Wed, 12 May 2010 22:47:14 +0000 Subject: Add --host-rules support. The format for --host-rules is identical to --host-resolver-rules. The difference is that --host-rules affects the endpoint of the HttpNetworkTransaction, not just the host resolver. So, this means the host passed to the host resolver and the TCP connect(), the tunnel CONNECT, and the SOCKS connect will be different. Review URL: http://codereview.chromium.org/2057007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47083 0039d316-1c4b-4281-b951-d872f2087c98 --- net/base/host_mapping_rules.cc | 85 +++++++++++++++++++++++++++++++++ net/base/host_mapping_rules.h | 61 +++++++++++++++++++++++ net/base/host_mapping_rules_unittest.cc | 56 ++++++++++++++++++++++ net/base/mapped_host_resolver.cc | 75 +++-------------------------- net/base/mapped_host_resolver.h | 31 ++++-------- net/http/http_network_transaction.cc | 29 +++++++---- net/http/http_network_transaction.h | 2 + net/net.gyp | 3 ++ 8 files changed, 242 insertions(+), 100 deletions(-) create mode 100644 net/base/host_mapping_rules.cc create mode 100644 net/base/host_mapping_rules.h create mode 100644 net/base/host_mapping_rules_unittest.cc (limited to 'net') diff --git a/net/base/host_mapping_rules.cc b/net/base/host_mapping_rules.cc new file mode 100644 index 0000000..3296b0e --- /dev/null +++ b/net/base/host_mapping_rules.cc @@ -0,0 +1,85 @@ +// 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/base/host_mapping_rules.h" + +#include "base/logging.h" +#include "base/string_tokenizer.h" +#include "base/string_util.h" +#include "net/base/host_port_pair.h" +#include "net/base/net_util.h" + +namespace net { + +HostMappingRules::HostMappingRules() {} + +bool HostMappingRules::RewriteHost(HostPortPair* host_port) const { + // Check if the hostname was excluded. + for (ExclusionRuleList::const_iterator it = exclusion_rules_.begin(); + it != exclusion_rules_.end(); ++it) { + const ExclusionRule& rule = *it; + if (MatchPatternASCII(host_port->host, rule.hostname_pattern)) + return false; + } + + // Check if the hostname was remapped. + for (MapRuleList::const_iterator it = map_rules_.begin(); + it != map_rules_.end(); ++it) { + const MapRule& rule = *it; + + if (!MatchPatternASCII(host_port->host, rule.hostname_pattern)) + continue; // This rule doesn't apply. + + host_port->host = rule.replacement_hostname; + if (rule.replacement_port != -1) + host_port->port = rule.replacement_port; + return true; + } + + return false; +} + +bool HostMappingRules::AddRuleFromString(const std::string& rule_string) { + std::string trimmed; + TrimWhitespaceASCII(rule_string, TRIM_ALL, &trimmed); + std::vector parts; + SplitString(trimmed, ' ', &parts); + + // Test for EXCLUSION rule. + if (parts.size() == 2 && LowerCaseEqualsASCII(parts[0], "exclude")) { + ExclusionRule rule; + rule.hostname_pattern = StringToLowerASCII(parts[1]); + exclusion_rules_.push_back(rule); + return true; + } + + // Test for MAP rule. + if (parts.size() == 3 && LowerCaseEqualsASCII(parts[0], "map")) { + MapRule rule; + rule.hostname_pattern = StringToLowerASCII(parts[1]); + + if (!ParseHostAndPort(parts[2], &rule.replacement_hostname, + &rule.replacement_port)) { + return false; // Failed parsing the hostname/port. + } + + map_rules_.push_back(rule); + return true; + } + + return false; +} + +void HostMappingRules::SetRulesFromString(const std::string& rules_string) { + exclusion_rules_.clear(); + map_rules_.clear(); + + StringTokenizer rules(rules_string, ","); + while (rules.GetNext()) { + bool ok = AddRuleFromString(rules.token()); + LOG_IF(ERROR, !ok) << "Failed parsing rule: " << rules.token(); + } +} + +} // namespace net diff --git a/net/base/host_mapping_rules.h b/net/base/host_mapping_rules.h new file mode 100644 index 0000000..a754a47 --- /dev/null +++ b/net/base/host_mapping_rules.h @@ -0,0 +1,61 @@ +// 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_BASE_HOST_MAPPING_RULES_H_ +#define NET_BASE_HOST_MAPPING_RULES_H_ + +#include +#include +#include "base/basictypes.h" + +namespace net { + +struct HostPortPair; + +class HostMappingRules { + public: + HostMappingRules(); + + // Modifies |*host_port| based on the current rules. Returns true if the + // RequestInfo was modified, false otherwise. + bool RewriteHost(HostPortPair* host_port) const; + + // Adds a rule to this mapper. The format of the rule can be one of: + // + // "MAP" [":" ] + // "EXCLUDE" + // + // The can be either a hostname, or an IP address literal. + // + // Returns true if the rule was successfully parsed and added. + bool AddRuleFromString(const std::string& rule_string); + + // Sets the rules from a comma separated list of rules. + void SetRulesFromString(const std::string& rules_string); + + private: + struct MapRule { + MapRule() : replacement_port(-1) {} + + std::string hostname_pattern; + std::string replacement_hostname; + int replacement_port; + }; + + struct ExclusionRule { + std::string hostname_pattern; + }; + + typedef std::vector MapRuleList; + typedef std::vector ExclusionRuleList; + + MapRuleList map_rules_; + ExclusionRuleList exclusion_rules_; + + DISALLOW_COPY_AND_ASSIGN(HostMappingRules); +}; + +} // namespace net + +#endif // NET_BASE_HOST_MAPPING_RULES_H_ diff --git a/net/base/host_mapping_rules_unittest.cc b/net/base/host_mapping_rules_unittest.cc new file mode 100644 index 0000000..0cea821 --- /dev/null +++ b/net/base/host_mapping_rules_unittest.cc @@ -0,0 +1,56 @@ +// 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/base/host_mapping_rules.h" + +#include "net/base/host_port_pair.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +TEST(HostMappingRulesTest, SetRulesFromString) { + HostMappingRules rules; + rules.SetRulesFromString( + "map *.com baz , map *.net bar:60, EXCLUDE *.foo.com"); + + HostPortPair host_port("test", 1234); + EXPECT_FALSE(rules.RewriteHost(&host_port)); + EXPECT_EQ("test", host_port.host); + EXPECT_EQ(1234u, host_port.port); + + host_port = HostPortPair("chrome.net", 80); + EXPECT_TRUE(rules.RewriteHost(&host_port)); + EXPECT_EQ("bar", host_port.host); + EXPECT_EQ(60u, host_port.port); + + host_port = HostPortPair("crack.com", 80); + EXPECT_TRUE(rules.RewriteHost(&host_port)); + EXPECT_EQ("baz", host_port.host); + EXPECT_EQ(80u, host_port.port); + + host_port = HostPortPair("wtf.foo.com", 666); + EXPECT_FALSE(rules.RewriteHost(&host_port)); + EXPECT_EQ("wtf.foo.com", host_port.host); + EXPECT_EQ(666u, host_port.port); +} + +// Parsing bad rules should silently discard the rule (and never crash). +TEST(HostMappingRulesTest, ParseInvalidRules) { + HostMappingRules rules; + + EXPECT_FALSE(rules.AddRuleFromString("xyz")); + EXPECT_FALSE(rules.AddRuleFromString("")); + EXPECT_FALSE(rules.AddRuleFromString(" ")); + EXPECT_FALSE(rules.AddRuleFromString("EXCLUDE")); + EXPECT_FALSE(rules.AddRuleFromString("EXCLUDE foo bar")); + EXPECT_FALSE(rules.AddRuleFromString("INCLUDE")); + EXPECT_FALSE(rules.AddRuleFromString("INCLUDE x")); + EXPECT_FALSE(rules.AddRuleFromString("INCLUDE x :10")); +} + +} // namespace + +} // namespace net diff --git a/net/base/mapped_host_resolver.cc b/net/base/mapped_host_resolver.cc index fdd9de7..b401917 100644 --- a/net/base/mapped_host_resolver.cc +++ b/net/base/mapped_host_resolver.cc @@ -6,6 +6,7 @@ #include "base/string_tokenizer.h" #include "base/string_util.h" +#include "net/base/host_port_pair.h" #include "net/base/net_util.h" namespace net { @@ -21,7 +22,11 @@ int MappedHostResolver::Resolve(const RequestInfo& info, const BoundNetLog& net_log) { // Modify the request before forwarding it to |impl_|. RequestInfo modified_info = info; - RewriteRequest(&modified_info); + HostPortPair host_port(info.hostname(), info.port()); + if (rules_.RewriteHost(&host_port)) { + modified_info.set_hostname(host_port.host); + modified_info.set_port(host_port.port); + } return impl_->Resolve(modified_info, addresses, callback, out_req, net_log); } @@ -44,72 +49,4 @@ HostResolverImpl* MappedHostResolver::GetAsHostResolverImpl() { MappedHostResolver::~MappedHostResolver() { } -bool MappedHostResolver::RewriteRequest(RequestInfo* info) const { - // Check if the hostname was excluded. - for (ExclusionRuleList::const_iterator it = exclusion_rules_.begin(); - it != exclusion_rules_.end(); ++it) { - const ExclusionRule& rule = *it; - if (MatchPatternASCII(info->hostname(), rule.hostname_pattern)) - return false; - } - - // Check if the hostname was remapped. - for (MapRuleList::const_iterator it = map_rules_.begin(); - it != map_rules_.end(); ++it) { - const MapRule& rule = *it; - - if (!MatchPatternASCII(info->hostname(), rule.hostname_pattern)) - continue; // This rule doesn't apply. - - info->set_hostname(rule.replacement_hostname); - if (rule.replacement_port != -1) - info->set_port(rule.replacement_port); - return true; - } - - return false; -} - -bool MappedHostResolver::AddRuleFromString(const std::string& rule_string) { - std::string trimmed; - TrimWhitespaceASCII(rule_string, TRIM_ALL, &trimmed); - std::vector parts; - SplitString(trimmed, ' ', &parts); - - // Test for EXCLUSION rule. - if (parts.size() == 2 && LowerCaseEqualsASCII(parts[0], "exclude")) { - ExclusionRule rule; - rule.hostname_pattern = StringToLowerASCII(parts[1]); - exclusion_rules_.push_back(rule); - return true; - } - - // Test for MAP rule. - if (parts.size() == 3 && LowerCaseEqualsASCII(parts[0], "map")) { - MapRule rule; - rule.hostname_pattern = StringToLowerASCII(parts[1]); - - if (!ParseHostAndPort(parts[2], &rule.replacement_hostname, - &rule.replacement_port)) { - return false; // Failed parsing the hostname/port. - } - - map_rules_.push_back(rule); - return true; - } - - return false; -} - -void MappedHostResolver::SetRulesFromString(const std::string& rules_string) { - exclusion_rules_.clear(); - map_rules_.clear(); - - StringTokenizer rules(rules_string, ","); - while (rules.GetNext()) { - bool ok = AddRuleFromString(rules.token()); - LOG_IF(ERROR, !ok) << "Failed parsing rule: " << rules.token(); - } -} - } // namespace net diff --git a/net/base/mapped_host_resolver.h b/net/base/mapped_host_resolver.h index 7339f06..3229209 100644 --- a/net/base/mapped_host_resolver.h +++ b/net/base/mapped_host_resolver.h @@ -9,6 +9,7 @@ #include #include "base/ref_counted.h" +#include "net/base/host_mapping_rules.h" #include "net/base/host_resolver.h" namespace net { @@ -42,37 +43,21 @@ class MappedHostResolver : public HostResolver { // The can be either a hostname, or an IP address literal. // // Returns true if the rule was successfully parsed and added. - bool AddRuleFromString(const std::string& rule_string); + bool AddRuleFromString(const std::string& rule_string) { + return rules_.AddRuleFromString(rule_string); + } // Takes a comma separated list of rules, and assigns them to this resolver. - void SetRulesFromString(const std::string& rules_string); + void SetRulesFromString(const std::string& rules_string) { + rules_.SetRulesFromString(rules_string); + } private: - struct MapRule { - MapRule() : replacement_port(-1) {} - - std::string hostname_pattern; - std::string replacement_hostname; - int replacement_port; - }; - - struct ExclusionRule { - std::string hostname_pattern; - }; - - typedef std::vector MapRuleList; - typedef std::vector ExclusionRuleList; - virtual ~MappedHostResolver(); - // Modifies |*info| based on the current rules. Returns true if the - // RequestInfo was modified, false otherwise. - bool RewriteRequest(RequestInfo* info) const; - scoped_refptr impl_; - MapRuleList map_rules_; - ExclusionRuleList exclusion_rules_; + HostMappingRules rules_; }; } // namespace net diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 2381450..6ac135e 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -17,6 +17,7 @@ #include "build/build_config.h" #include "googleurl/src/gurl.h" #include "net/base/connection_type_histograms.h" +#include "net/base/host_mapping_rules.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -48,6 +49,7 @@ namespace net { namespace { +const HostMappingRules* g_host_mapping_rules = NULL; const std::string* g_next_protos = NULL; bool g_use_alternate_protocols = false; @@ -194,16 +196,20 @@ void ProcessAlternateProtocol(const HttpResponseHeaders& headers, return; } - if (alternate_protocols->HasAlternateProtocolFor(http_host_port_pair)) { + HostPortPair host_port(http_host_port_pair); + if (g_host_mapping_rules) + g_host_mapping_rules->RewriteHost(&host_port); + + if (alternate_protocols->HasAlternateProtocolFor(host_port)) { const HttpAlternateProtocols::PortProtocolPair existing_alternate = - alternate_protocols->GetAlternateProtocolFor(http_host_port_pair); + alternate_protocols->GetAlternateProtocolFor(host_port); // If we think the alternate protocol is broken, don't change it. if (existing_alternate.protocol == HttpAlternateProtocols::BROKEN) return; } alternate_protocols->SetAlternateProtocolFor( - http_host_port_pair, port, HttpAlternateProtocols::NPN_SPDY_1); + host_port, port, HttpAlternateProtocols::NPN_SPDY_1); } class NetLogHttpRequestParameter : public NetLog::EventParameters { @@ -302,6 +308,14 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session) } // static +void HttpNetworkTransaction::SetHostMappingRules(const std::string& rules) { + HostMappingRules* host_mapping_rules = new HostMappingRules(); + host_mapping_rules->SetRulesFromString(rules); + delete g_host_mapping_rules; + g_host_mapping_rules = host_mapping_rules; +} + +// static void HttpNetworkTransaction::SetUseAlternateProtocols(bool value) { g_use_alternate_protocols = value; } @@ -725,6 +739,9 @@ int HttpNetworkTransaction::DoResolveProxy() { endpoint_ = HostPortPair(request_->url.HostNoBrackets(), request_->url.EffectiveIntPort()); + if (g_host_mapping_rules) + g_host_mapping_rules->RewriteHost(&endpoint_); + GURL alternate_endpoint; if (alternate_protocol_mode_ == kUnspecified) { @@ -1232,12 +1249,8 @@ int HttpNetworkTransaction::DoReadHeadersComplete(int result) { return OK; } - HostPortPair http_host_port_pair; - http_host_port_pair.host = request_->url.HostNoBrackets(); - http_host_port_pair.port = request_->url.EffectiveIntPort(); - ProcessAlternateProtocol(*response_.headers, - http_host_port_pair, + endpoint_, session_->mutable_alternate_protocols()); int rv = HandleAuthChallenge(); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 7b033e3..d9fed35 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -42,6 +42,8 @@ class HttpNetworkTransaction : public HttpTransaction { virtual ~HttpNetworkTransaction(); + static void SetHostMappingRules(const std::string& rules); + // Controls whether or not we use the Alternate-Protocol header. static void SetUseAlternateProtocols(bool value); diff --git a/net/net.gyp b/net/net.gyp index d9c85f9..9fb28ce 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -66,6 +66,8 @@ 'base/gzip_header.h', 'base/host_cache.cc', 'base/host_cache.h', + 'base/host_mapping_rules.cc', + 'base/host_mapping_rules.h', 'base/host_port_pair.cc', 'base/host_port_pair.h', 'base/host_resolver.cc', @@ -621,6 +623,7 @@ 'base/filter_unittest.h', 'base/gzip_filter_unittest.cc', 'base/host_cache_unittest.cc', + 'base/host_mapping_rules_unittest.cc', 'base/host_resolver_impl_unittest.cc', 'base/keygen_handler_unittest.cc', 'base/leak_annotations.h', -- cgit v1.1