diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-18 08:03:38 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-02-18 08:03:38 +0000 |
commit | 9087aa3c473281af9c216d060d00baa4e1af4216 (patch) | |
tree | 11020a066a239d0042247611052c43f7fd0859ef /net | |
parent | 3517fd50b20611670f08aedfff25451f6fe9e313 (diff) | |
download | chromium_src-9087aa3c473281af9c216d060d00baa4e1af4216.zip chromium_src-9087aa3c473281af9c216d060d00baa4e1af4216.tar.gz chromium_src-9087aa3c473281af9c216d060d00baa4e1af4216.tar.bz2 |
Add a command-line flag to remap hostnames based on patterns.
This is a generalization of the --testing-fixed-server flag.
BUG=36053
TEST=MappedHostResolverTest.*
Review URL: http://codereview.chromium.org/647001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39342 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/fixed_host_resolver.cc | 46 | ||||
-rw-r--r-- | net/base/fixed_host_resolver.h | 41 | ||||
-rw-r--r-- | net/base/host_resolver.h | 7 | ||||
-rw-r--r-- | net/base/mapped_host_resolver.cc | 111 | ||||
-rw-r--r-- | net/base/mapped_host_resolver.h | 79 | ||||
-rw-r--r-- | net/base/mapped_host_resolver_unittest.cc | 148 | ||||
-rwxr-xr-x | net/net.gyp | 5 |
7 files changed, 348 insertions, 89 deletions
diff --git a/net/base/fixed_host_resolver.cc b/net/base/fixed_host_resolver.cc deleted file mode 100644 index 47089f1..0000000 --- a/net/base/fixed_host_resolver.cc +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2009 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/fixed_host_resolver.h" - -#include "net/base/net_errors.h" -#include "net/base/net_util.h" -#include "net/base/host_resolver_impl.h" - -namespace net { - -FixedHostResolver::FixedHostResolver(const std::string& host) - : initialized_(false) { - int port; - std::string parsed_host; - if (!ParseHostAndPort(host, &parsed_host, &port)) { - LOG(DFATAL) << "Invalid FixedHostResolver information: " << host; - return; - } - - int rv = SystemHostResolverProc(host, net::ADDRESS_FAMILY_UNSPECIFIED, - &address_); - if (rv != OK) { - LOG(ERROR) << "Could not resolve fixed host: " << host; - return; - } - - initialized_ = true; -} - -int FixedHostResolver::Resolve(const RequestInfo& info, - AddressList* addresses, - CompletionCallback* callback, - RequestHandle* out_req, - LoadLog* load_log) { - if (!initialized_) - return ERR_NAME_NOT_RESOLVED; - - DCHECK(addresses); - addresses->Copy(address_.head()); - addresses->SetPort(info.port()); - return OK; -} - -} // namespace net diff --git a/net/base/fixed_host_resolver.h b/net/base/fixed_host_resolver.h deleted file mode 100644 index ee7b114..0000000 --- a/net/base/fixed_host_resolver.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2009 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_FIXED_HOST_RESOLVER_H_ -#define NET_BASE_FIXED_HOST_RESOLVER_H_ - -#include <string> - -#include "net/base/address_list.h" -#include "net/base/host_resolver.h" - -namespace net { - -// A FixedHostResolver resolves all addresses to a single address. -class FixedHostResolver : public HostResolver { - public: - // |host| is a string representing the resolution. - // example: foo.myproxy.com - explicit FixedHostResolver(const std::string& host); - - // HostResolver methods: - virtual int Resolve(const RequestInfo& info, - AddressList* addresses, - CompletionCallback* callback, - RequestHandle* out_req, - LoadLog* load_log); - virtual void CancelRequest(RequestHandle req) {} - virtual void AddObserver(Observer* observer) {} - virtual void RemoveObserver(Observer* observer) {} - - private: - ~FixedHostResolver() {} - - AddressList address_; - bool initialized_; -}; - -} // namespace net - -#endif // NET_BASE_MOCK_HOST_RESOLVER_H_ diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h index a960805..da431f3 100644 --- a/net/base/host_resolver.h +++ b/net/base/host_resolver.h @@ -46,7 +46,14 @@ class HostResolver : public base::RefCountedThreadSafe<HostResolver> { priority_(MEDIUM) {} int port() const { return port_; } + void set_port(int port) { + port_ = port; + } + const std::string& hostname() const { return hostname_; } + void set_hostname(const std::string& hostname) { + hostname_ = hostname; + } AddressFamily address_family() const { return address_family_; } void set_address_family(AddressFamily address_family) { diff --git a/net/base/mapped_host_resolver.cc b/net/base/mapped_host_resolver.cc new file mode 100644 index 0000000..3624a9b --- /dev/null +++ b/net/base/mapped_host_resolver.cc @@ -0,0 +1,111 @@ +// 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/mapped_host_resolver.h" + +#include "base/string_tokenizer.h" +#include "base/string_util.h" +#include "net/base/net_util.h" + +namespace net { + +MappedHostResolver::MappedHostResolver(HostResolver* impl) + : impl_(impl) { +} + +int MappedHostResolver::Resolve(const RequestInfo& info, + AddressList* addresses, + CompletionCallback* callback, + RequestHandle* out_req, + LoadLog* load_log) { + // Modify the request before forwarding it to |impl_|. + RequestInfo modified_info = info; + RewriteRequest(&modified_info); + return impl_->Resolve(modified_info, addresses, callback, out_req, load_log); +} + +void MappedHostResolver::CancelRequest(RequestHandle req) { + impl_->CancelRequest(req); +} + +void MappedHostResolver::AddObserver(Observer* observer) { + impl_->AddObserver(observer); +} + +void MappedHostResolver::RemoveObserver(Observer* observer) { + impl_->RemoveObserver(observer); +} + +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<std::string> 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 new file mode 100644 index 0000000..af78a9c --- /dev/null +++ b/net/base/mapped_host_resolver.h @@ -0,0 +1,79 @@ +// 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_MAPPED_HOST_RESOLVER_H_ +#define NET_BASE_MAPPED_HOST_RESOLVER_H_ + +#include <string> +#include <vector> + +#include "base/ref_counted.h" +#include "net/base/host_resolver.h" + +namespace net { + +// This class wraps an existing HostResolver instance, but modifies the +// request before passing it off to |impl|. This is different from +// MockHostResolver which does the remapping at the HostResolverProc +// layer, so it is able to preserve the effectiveness of the cache. +class MappedHostResolver : public HostResolver { + public: + // Creates a MappedHostResolver that forwards all of its requests through + // |impl|. + explicit MappedHostResolver(HostResolver* impl); + + // HostResolver methods: + virtual int Resolve(const RequestInfo& info, + AddressList* addresses, + CompletionCallback* callback, + RequestHandle* out_req, + LoadLog* load_log); + virtual void CancelRequest(RequestHandle req); + virtual void AddObserver(Observer* observer); + virtual void RemoveObserver(Observer* observer); + + // Adds a rule to this mapper. The format of the rule can be one of: + // + // "MAP" <hostname_pattern> <replacement_host> [":" <replacement_port>] + // "EXCLUDE" <hostname_pattern> + // + // The <replacement_host> 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); + + // Takes a comma separated list of rules, and assigns them to this resolver. + 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<MapRule> MapRuleList; + typedef std::vector<ExclusionRule> 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<HostResolver> impl_; + + MapRuleList map_rules_; + ExclusionRuleList exclusion_rules_; +}; + +} // namespace net + +#endif // NET_BASE_MAPPED_HOST_RESOLVER_H_ diff --git a/net/base/mapped_host_resolver_unittest.cc b/net/base/mapped_host_resolver_unittest.cc new file mode 100644 index 0000000..6da84e0 --- /dev/null +++ b/net/base/mapped_host_resolver_unittest.cc @@ -0,0 +1,148 @@ +// 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/mapped_host_resolver.h" + +#include "net/base/mock_host_resolver.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +TEST(MappedHostResolverTest, Inclusion) { + // Create a mock host resolver, with specific hostname to IP mappings. + scoped_refptr<MockHostResolver> resolver_impl = new MockHostResolver(); + resolver_impl->rules()->AddSimulatedFailure("*google.com"); + resolver_impl->rules()->AddRule("baz.com", "192.168.1.5"); + resolver_impl->rules()->AddRule("foo.com", "192.168.1.8"); + resolver_impl->rules()->AddRule("proxy", "192.168.1.11"); + + // Create a remapped resolver that uses |resolver_impl|. + scoped_refptr<MappedHostResolver> resolver = + new MappedHostResolver(resolver_impl); + + int rv; + AddressList address_list; + + // Try resolving "www.google.com:80". There are no mappings yet, so this + // hits |resolver_impl| and fails. + rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); + + // Remap *.google.com to baz.com. + EXPECT_TRUE(resolver->AddRuleFromString("map *.google.com baz.com")); + + // Try resolving "www.google.com:80". Should be remapped to "baz.com:80". + rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.5", NetAddressToString(address_list.head())); + EXPECT_EQ(80, address_list.GetPort()); + + // Try resolving "foo.com:77". This will NOT be remapped, so result + // is "foo.com:77". + rv = resolver->Resolve(HostResolver::RequestInfo("foo.com", 77), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.8", NetAddressToString(address_list.head())); + EXPECT_EQ(77, address_list.GetPort()); + + // Remap "*.org" to "proxy:99". + EXPECT_TRUE(resolver->AddRuleFromString("Map *.org proxy:99")); + + // Try resolving "chromium.org:61". Should be remapped to "proxy:99". + rv = resolver->Resolve(HostResolver::RequestInfo("chromium.org", 61), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.11", NetAddressToString(address_list.head())); + EXPECT_EQ(99, address_list.GetPort()); +} + +// Tests that exclusions are respected. +TEST(MappedHostResolverTest, Exclusion) { + // Create a mock host resolver, with specific hostname to IP mappings. + scoped_refptr<MockHostResolver> resolver_impl = new MockHostResolver(); + resolver_impl->rules()->AddRule("baz", "192.168.1.5"); + resolver_impl->rules()->AddRule("www.google.com", "192.168.1.3"); + + // Create a remapped resolver that uses |resolver_impl|. + scoped_refptr<MappedHostResolver> resolver = + new MappedHostResolver(resolver_impl); + + int rv; + AddressList address_list; + + // Remap "*.com" to "baz". + EXPECT_TRUE(resolver->AddRuleFromString("map *.com baz")); + + // Add an exclusion for "*.google.com". + EXPECT_TRUE(resolver->AddRuleFromString("EXCLUDE *.google.com")); + + // Try resolving "www.google.com". Should not be remapped due to exclusion). + rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.3", NetAddressToString(address_list.head())); + EXPECT_EQ(80, address_list.GetPort()); + + // Try resolving "chrome.com:80". Should be remapped to "baz:80". + rv = resolver->Resolve(HostResolver::RequestInfo("chrome.com", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.5", NetAddressToString(address_list.head())); + EXPECT_EQ(80, address_list.GetPort()); +} + +TEST(MappedHostResolverTest, SetRulesFromString) { + // Create a mock host resolver, with specific hostname to IP mappings. + scoped_refptr<MockHostResolver> resolver_impl = new MockHostResolver(); + resolver_impl->rules()->AddRule("baz", "192.168.1.7"); + resolver_impl->rules()->AddRule("bar", "192.168.1.9"); + + // Create a remapped resolver that uses |resolver_impl|. + scoped_refptr<MappedHostResolver> resolver = + new MappedHostResolver(resolver_impl); + + int rv; + AddressList address_list; + + // Remap "*.com" to "baz", and *.net to "bar:60". + resolver->SetRulesFromString("map *.com baz , map *.net bar:60"); + + // Try resolving "www.google.com". Should be remapped to "baz". + rv = resolver->Resolve(HostResolver::RequestInfo("www.google.com", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.7", NetAddressToString(address_list.head())); + EXPECT_EQ(80, address_list.GetPort()); + + // Try resolving "chrome.net:80". Should be remapped to "bar:60". + rv = resolver->Resolve(HostResolver::RequestInfo("chrome.net", 80), + &address_list, NULL, NULL, NULL); + EXPECT_EQ(OK, rv); + EXPECT_EQ("192.168.1.9", NetAddressToString(address_list.head())); + EXPECT_EQ(60, address_list.GetPort()); +} + +// Parsing bad rules should silently discard the rule (and never crash). +TEST(MappedHostResolverTest, ParseInvalidRules) { + scoped_refptr<MappedHostResolver> resolver = new MappedHostResolver(NULL); + + EXPECT_FALSE(resolver->AddRuleFromString("xyz")); + EXPECT_FALSE(resolver->AddRuleFromString("")); + EXPECT_FALSE(resolver->AddRuleFromString(" ")); + EXPECT_FALSE(resolver->AddRuleFromString("EXCLUDE")); + EXPECT_FALSE(resolver->AddRuleFromString("EXCLUDE foo bar")); + EXPECT_FALSE(resolver->AddRuleFromString("INCLUDE")); + EXPECT_FALSE(resolver->AddRuleFromString("INCLUDE x")); + EXPECT_FALSE(resolver->AddRuleFromString("INCLUDE x :10")); +} + +} // namespace + +} // namespace net diff --git a/net/net.gyp b/net/net.gyp index b6f6062..599f683 100755 --- a/net/net.gyp +++ b/net/net.gyp @@ -58,8 +58,6 @@ 'base/file_stream_win.cc', 'base/filter.cc', 'base/filter.h', - 'base/fixed_host_resolver.cc', - 'base/fixed_host_resolver.h', 'base/gzip_filter.cc', 'base/gzip_filter.h', 'base/gzip_header.cc', @@ -89,6 +87,8 @@ 'base/load_log_util.cc', 'base/load_log_util.h', 'base/load_states.h', + 'base/mapped_host_resolver.cc', + 'base/mapped_host_resolver.h', 'base/mime_sniffer.cc', 'base/mime_sniffer.h', 'base/mime_util.cc', @@ -600,6 +600,7 @@ 'base/load_log_util_unittest.cc', 'base/listen_socket_unittest.cc', 'base/listen_socket_unittest.h', + 'base/mapped_host_resolver_unittest.cc', 'base/mime_sniffer_unittest.cc', 'base/mime_util_unittest.cc', 'base/mock_network_change_notifier.h', |