summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-15 22:04:32 +0000
committerericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-15 22:04:32 +0000
commitb59ff376c5d5b950774fcbe65727611d51832b75 (patch)
treea37598ddd4e9ec0530d5820bcce1f47bafa89289
parent89d70652ad0bb9e7f419c17516fad279d8a4db32 (diff)
downloadchromium_src-b59ff376c5d5b950774fcbe65727611d51832b75.zip
chromium_src-b59ff376c5d5b950774fcbe65727611d51832b75.tar.gz
chromium_src-b59ff376c5d5b950774fcbe65727611d51832b75.tar.bz2
Refactorings surrounding HostResolver:
(1) Extract HostResolver to an interface. The existing concrete implementation is now named HostResolverImpl. This makes it possible to create mocks with more complex behavior (i.e. choose via rules if response will be sync vs async). (2) Transform HostMapper into HostResolverProc. Conceptually HostResolverProc maps a hostname to a socket address, whereas HostMapper mapped a hostname to another hostname (so you were still at the mercy of the system's host resolver). With HostResolverProc you can specify the exact AddressList, making it possible to run tests requiring IPv6 socketaddrs on systems (like WinXP) that don't actually support it. (3) Add a MockHostResolver implementation of HostResolver. This replaces the [ScopedHostMapper + RuleBasedHostMapper + HostResolver] combo. It is less clunky and a bit more expressive. BUG=http://crbug.com/16452 R=willchan TEST=existing Review URL: http://codereview.chromium.org/149511 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20795 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_unittest.cc20
-rw-r--r--chrome/browser/net/dns_global.cc6
-rw-r--r--chrome/browser/net/dns_master_unittest.cc88
-rw-r--r--chrome/browser/search_engines/template_url_scraper_unittest.cc8
-rw-r--r--chrome/test/in_process_browser_test.cc19
-rw-r--r--chrome/test/in_process_browser_test.h10
-rw-r--r--chrome/test/unit/chrome_test_suite.h24
-rw-r--r--net/base/address_list_unittest.cc23
-rw-r--r--net/base/host_resolver.cc608
-rw-r--r--net/base/host_resolver.h159
-rw-r--r--net/base/host_resolver_impl.cc483
-rw-r--r--net/base/host_resolver_impl.h136
-rw-r--r--net/base/host_resolver_impl_unittest.cc (renamed from net/base/host_resolver_unittest.cc)236
-rw-r--r--net/base/host_resolver_proc.cc180
-rw-r--r--net/base/host_resolver_proc.h69
-rw-r--r--net/base/mock_host_resolver.cc154
-rw-r--r--net/base/mock_host_resolver.h143
-rw-r--r--net/base/run_all_unittests.cc12
-rw-r--r--net/ftp/ftp_network_transaction_unittest.cc11
-rw-r--r--net/http/http_network_layer_unittest.cc8
-rw-r--r--net/http/http_network_transaction_unittest.cc25
-rw-r--r--net/net.gyp10
-rw-r--r--net/proxy/proxy_resolver_perftest.cc4
-rw-r--r--net/proxy/proxy_resolver_v8.h2
-rw-r--r--net/proxy/proxy_resolver_v8_unittest.cc14
-rw-r--r--net/proxy/proxy_script_fetcher_unittest.cc2
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc11
-rw-r--r--net/socket/socks5_client_socket_unittest.cc22
-rw-r--r--net/socket/socks_client_socket_unittest.cc23
-rw-r--r--net/socket/ssl_client_socket_unittest.cc22
-rw-r--r--net/socket/ssl_test_util.cc2
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc22
-rw-r--r--net/socket/tcp_client_socket_unittest.cc2
-rw-r--r--net/socket/tcp_pinger_unittest.cc4
-rw-r--r--net/tools/fetch/fetch_client.cc4
-rw-r--r--net/url_request/url_request_unittest.cc2
-rw-r--r--net/url_request/url_request_unittest.h4
-rw-r--r--webkit/tools/test_shell/test_shell_request_context.cc2
38 files changed, 1503 insertions, 1071 deletions
diff --git a/chrome/browser/browser_unittest.cc b/chrome/browser/browser_unittest.cc
index 1ef86da..702d1dce 100644
--- a/chrome/browser/browser_unittest.cc
+++ b/chrome/browser/browser_unittest.cc
@@ -4,21 +4,21 @@
#include "chrome/browser/browser.h"
#include "chrome/test/in_process_browser_test.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
class BrowserTest : public InProcessBrowserTest {
public:
BrowserTest() {
- host_mapper_ = new net::RuleBasedHostMapper();
+ host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL);
// Avoid making external DNS lookups. In this test we don't need this
// to succeed.
- host_mapper_->AddSimulatedFailure("*.google.com");
- scoped_host_mapper_.Init(host_mapper_.get());
+ host_resolver_proc_->AddSimulatedFailure("*.google.com");
+ scoped_host_resolver_proc_.Init(host_resolver_proc_.get());
}
private:
- scoped_refptr<net::RuleBasedHostMapper> host_mapper_;
- net::ScopedHostMapper scoped_host_mapper_;
+ scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_;
+ net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
};
/*
@@ -38,7 +38,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, NoTabsInPopups) {
// Now try opening another tab in the popup browser.
popup_browser->AddTabWithURL(GURL("about:blank"), GURL(),
PageTransition::TYPED, true, -1, NULL);
-
+
// The popup should still only have one tab.
EXPECT_EQ(1, popup_browser->tab_count());
@@ -54,7 +54,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, NoTabsInPopups) {
// Now try opening another tab in the app browser.
app_browser->AddTabWithURL(GURL("about:blank"), GURL(),
PageTransition::TYPED, true, -1, NULL);
-
+
// The popup should still only have one tab.
EXPECT_EQ(1, app_browser->tab_count());
@@ -70,7 +70,7 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, NoTabsInPopups) {
// Now try opening another tab in the app popup browser.
app_popup_browser->AddTabWithURL(GURL("about:blank"), GURL(),
PageTransition::TYPED, true, -1, NULL);
-
+
// The popup should still only have one tab.
EXPECT_EQ(1, app_popup_browser->tab_count());
@@ -82,4 +82,4 @@ IN_PROC_BROWSER_TEST_F(BrowserTest, NoTabsInPopups) {
app_browser->CloseAllTabs();
app_popup_browser->CloseAllTabs();
}
-*/ \ No newline at end of file
+*/
diff --git a/chrome/browser/net/dns_global.cc b/chrome/browser/net/dns_global.cc
index d18ea45..25829e7 100644
--- a/chrome/browser/net/dns_global.cc
+++ b/chrome/browser/net/dns_global.cc
@@ -476,11 +476,7 @@ static void DiscardAllPrefetchState() {
net::HostResolver* GetGlobalHostResolver() {
// Called from UI thread.
if (!global_host_resolver) {
- static const size_t kMaxHostCacheEntries = 100;
- static const size_t kHostCacheExpirationSeconds = 60; // 1 minute.
-
- global_host_resolver = new net::HostResolver(
- kMaxHostCacheEntries, kHostCacheExpirationSeconds * 1000);
+ global_host_resolver = net::CreateSystemHostResolver();
}
return global_host_resolver;
}
diff --git a/chrome/browser/net/dns_master_unittest.cc b/chrome/browser/net/dns_master_unittest.cc
index 61ffd68..c3746bb 100644
--- a/chrome/browser/net/dns_master_unittest.cc
+++ b/chrome/browser/net/dns_master_unittest.cc
@@ -10,13 +10,13 @@
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
+#include "base/string_util.h"
#include "base/timer.h"
#include "chrome/browser/net/dns_global.h"
#include "chrome/browser/net/dns_host_info.h"
#include "chrome/common/net/dns.h"
#include "net/base/address_list.h"
-#include "net/base/host_resolver.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/winsock_init.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -59,10 +59,9 @@ class WaitForResolutionHelper {
class DnsMasterTest : public testing::Test {
public:
DnsMasterTest()
- : mapper_(new net::RuleBasedHostMapper()),
+ : host_resolver_(new net::MockHostResolver()),
default_max_queueing_delay_(TimeDelta::FromMilliseconds(
- DnsPrefetcherInit::kMaxQueueingDelayMs)),
- scoped_mapper_(mapper_.get()) {
+ DnsPrefetcherInit::kMaxQueueingDelayMs)) {
}
protected:
@@ -70,10 +69,11 @@ class DnsMasterTest : public testing::Test {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
- mapper_->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
- mapper_->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
- mapper_->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
- mapper_->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
+ net::RuleBasedHostResolverProc* rules = host_resolver_->rules();
+ rules->AddRuleWithLatency("www.google.com", "127.0.0.1", 50);
+ rules->AddRuleWithLatency("gmail.google.com.com", "127.0.0.1", 70);
+ rules->AddRuleWithLatency("mail.google.com", "127.0.0.1", 44);
+ rules->AddRuleWithLatency("gmail.com", "127.0.0.1", 63);
}
void WaitForResolution(DnsMaster* master, const NameList& hosts) {
@@ -84,15 +84,18 @@ class DnsMasterTest : public testing::Test {
MessageLoop::current()->Run();
}
- scoped_refptr<net::RuleBasedHostMapper> mapper_;
+ private:
+ // IMPORTANT: do not move this below |host_resolver_|; the host resolver
+ // must not outlive the message loop, otherwise bad things can happen
+ // (like posting to a deleted message loop).
+ MessageLoop loop;
+
+ protected:
+ scoped_refptr<net::MockHostResolver> host_resolver_;
// Shorthand to access TimeDelta of DnsPrefetcherInit::kMaxQueueingDelayMs.
// (It would be a static constant... except style rules preclude that :-/ ).
const TimeDelta default_max_queueing_delay_;
-
- private:
- MessageLoop loop;
- net::ScopedHostMapper scoped_mapper_;
};
//------------------------------------------------------------------------------
@@ -113,15 +116,15 @@ static std::string GetNonexistantDomain() {
//------------------------------------------------------------------------------
// Use a blocking function to contrast results we get via async services.
//------------------------------------------------------------------------------
-TimeDelta BlockingDnsLookup(const std::string& hostname) {
- Time start = Time::Now();
+TimeDelta BlockingDnsLookup(net::HostResolver* resolver,
+ const std::string& hostname) {
+ Time start = Time::Now();
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
- net::AddressList addresses;
- net::HostResolver::RequestInfo info(hostname, 80);
- resolver->Resolve(info, &addresses, NULL, NULL);
+ net::AddressList addresses;
+ net::HostResolver::RequestInfo info(hostname, 80);
+ resolver->Resolve(info, &addresses, NULL, NULL);
- return Time::Now() - start;
+ return Time::Now() - start;
}
//------------------------------------------------------------------------------
@@ -129,7 +132,9 @@ TimeDelta BlockingDnsLookup(const std::string& hostname) {
// First test to be sure the OS is caching lookups, which is the whole premise
// of DNS prefetching.
TEST_F(DnsMasterTest, OsCachesLookupsTest) {
- mapper_->AllowDirectLookup("*.google.com");
+ // Make sure caching is disabled in the mock host resolver.
+ host_resolver_->Reset(NULL, 0, 0);
+ host_resolver_->rules()->AllowDirectLookup("*.google.com");
const Time start = Time::Now();
int all_lookups = 0;
@@ -140,13 +145,13 @@ TEST_F(DnsMasterTest, OsCachesLookupsTest) {
std::string badname;
badname = GetNonexistantDomain();
- TimeDelta duration = BlockingDnsLookup(badname);
+ TimeDelta duration = BlockingDnsLookup(host_resolver_, badname);
// Produce more than one result and remove the largest one
// to reduce flakiness.
std::vector<TimeDelta> cached_results;
for (int j = 0; j < 3; j++)
- cached_results.push_back(BlockingDnsLookup(badname));
+ cached_results.push_back(BlockingDnsLookup(host_resolver_, badname));
std::sort(cached_results.begin(), cached_results.end());
cached_results.pop_back();
@@ -168,14 +173,14 @@ TEST_F(DnsMasterTest, OsCachesLookupsTest) {
}
TEST_F(DnsMasterTest, StartupShutdownTest) {
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
testing_master->Shutdown();
}
TEST_F(DnsMasterTest, BenefitLookupTest) {
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
@@ -236,10 +241,11 @@ TEST_F(DnsMasterTest, BenefitLookupTest) {
}
TEST_F(DnsMasterTest, ShutdownWhenResolutionIsPendingTest) {
- scoped_refptr<net::WaitingHostMapper> mapper = new net::WaitingHostMapper();
- net::ScopedHostMapper scoped_mapper(mapper.get());
+ scoped_refptr<net::WaitingHostResolverProc> resolver_proc =
+ new net::WaitingHostResolverProc(NULL);
+ host_resolver_->Reset(resolver_proc, 0, 0);
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
@@ -258,12 +264,12 @@ TEST_F(DnsMasterTest, ShutdownWhenResolutionIsPendingTest) {
testing_master->Shutdown();
// Clean up after ourselves.
- mapper->Signal();
+ resolver_proc->Signal();
MessageLoop::current()->RunAllPending();
}
TEST_F(DnsMasterTest, SingleLookupTest) {
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
@@ -291,9 +297,9 @@ TEST_F(DnsMasterTest, SingleLookupTest) {
}
TEST_F(DnsMasterTest, ConcurrentLookupTest) {
- mapper_->AddSimulatedFailure("*.notfound");
+ host_resolver_->rules()->AddSimulatedFailure("*.notfound");
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
@@ -313,12 +319,6 @@ TEST_F(DnsMasterTest, ConcurrentLookupTest) {
names.insert(names.end(), goog4);
names.insert(names.end(), goog);
- // Warm up the *OS* cache for all the goog domains.
- BlockingDnsLookup(goog);
- BlockingDnsLookup(goog2);
- BlockingDnsLookup(goog3);
- BlockingDnsLookup(goog4);
-
// Try to flood the master with many concurrent requests.
for (int i = 0; i < 10; i++)
testing_master->ResolveList(names, DnsHostInfo::PAGE_SCAN_MOTIVATED);
@@ -346,9 +346,9 @@ TEST_F(DnsMasterTest, ConcurrentLookupTest) {
}
TEST_F(DnsMasterTest, DISABLED_MassiveConcurrentLookupTest) {
- mapper_->AddSimulatedFailure("*.notfound");
+ host_resolver_->rules()->AddSimulatedFailure("*.notfound");
- scoped_refptr<DnsMaster> testing_master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> testing_master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
@@ -453,7 +453,7 @@ int GetLatencyFromSerialization(const std::string& motivation,
// Make sure nil referral lists really have no entries, and no latency listed.
TEST_F(DnsMasterTest, ReferrerSerializationNilTest) {
- scoped_refptr<DnsMaster> master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
ListValue referral_list;
@@ -469,7 +469,7 @@ TEST_F(DnsMasterTest, ReferrerSerializationNilTest) {
// deserialized into the database, and can be extracted back out via
// serialization without being changed.
TEST_F(DnsMasterTest, ReferrerSerializationSingleReferrerTest) {
- scoped_refptr<DnsMaster> master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
std::string motivation_hostname = "www.google.com";
@@ -494,7 +494,7 @@ TEST_F(DnsMasterTest, ReferrerSerializationSingleReferrerTest) {
// Make sure the Trim() functionality works as expected.
TEST_F(DnsMasterTest, ReferrerSerializationTrimTest) {
- scoped_refptr<DnsMaster> master = new DnsMaster(new net::HostResolver,
+ scoped_refptr<DnsMaster> master = new DnsMaster(host_resolver_,
MessageLoop::current(), default_max_queueing_delay_,
DnsPrefetcherInit::kMaxConcurrentLookups);
std::string motivation_hostname = "www.google.com";
diff --git a/chrome/browser/search_engines/template_url_scraper_unittest.cc b/chrome/browser/search_engines/template_url_scraper_unittest.cc
index 71aace7..a93790f 100644
--- a/chrome/browser/search_engines/template_url_scraper_unittest.cc
+++ b/chrome/browser/search_engines/template_url_scraper_unittest.cc
@@ -11,7 +11,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_util.h"
namespace {
@@ -21,10 +21,10 @@ class TemplateURLScraperTest : public InProcessBrowserTest {
}
protected:
- virtual void ConfigureHostMapper(net::RuleBasedHostMapper* host_mapper) {
- InProcessBrowserTest::ConfigureHostMapper(host_mapper);
+ virtual void ConfigureHostResolverProc(net::RuleBasedHostResolverProc* proc) {
+ InProcessBrowserTest::ConfigureHostResolverProc(proc);
// We use foo.com in our tests.
- host_mapper->AddRule("*.foo.com", "localhost");
+ proc->AddRule("*.foo.com", "localhost");
}
private:
diff --git a/chrome/test/in_process_browser_test.cc b/chrome/test/in_process_browser_test.cc
index b43edd2..7544b49 100644
--- a/chrome/test/in_process_browser_test.cc
+++ b/chrome/test/in_process_browser_test.cc
@@ -26,7 +26,7 @@
#include "chrome/common/main_function_params.h"
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/ui_test_utils.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "sandbox/src/dep.h"
extern int BrowserMain(const MainFunctionParams&);
@@ -140,10 +140,11 @@ void InProcessBrowserTest::SetUp() {
params.ui_task =
NewRunnableMethod(this, &InProcessBrowserTest::RunTestOnMainThreadLoop);
- scoped_refptr<net::RuleBasedHostMapper> host_mapper(
- new net::RuleBasedHostMapper());
- ConfigureHostMapper(host_mapper.get());
- net::ScopedHostMapper scoped_host_mapper(host_mapper.get());
+ scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc(
+ new net::RuleBasedHostResolverProc(NULL));
+ ConfigureHostResolverProc(host_resolver_proc);
+ net::ScopedDefaultHostResolverProc scoped_host_resolver_proc(
+ host_resolver_proc);
BrowserMain(params);
}
@@ -241,12 +242,12 @@ void InProcessBrowserTest::RunTestOnMainThreadLoop() {
MessageLoopForUI::current()->Quit();
}
-void InProcessBrowserTest::ConfigureHostMapper(
- net::RuleBasedHostMapper* host_mapper) {
- host_mapper->AllowDirectLookup("*.google.com");
+void InProcessBrowserTest::ConfigureHostResolverProc(
+ net::RuleBasedHostResolverProc* host_resolver_proc) {
+ host_resolver_proc->AllowDirectLookup("*.google.com");
// See http://en.wikipedia.org/wiki/Web_Proxy_Autodiscovery_Protocol
// We don't want the test code to use it.
- host_mapper->AddSimulatedFailure("wpad");
+ host_resolver_proc->AddSimulatedFailure("wpad");
}
void InProcessBrowserTest::TimedOut() {
diff --git a/chrome/test/in_process_browser_test.h b/chrome/test/in_process_browser_test.h
index bec71d9..11a2880 100644
--- a/chrome/test/in_process_browser_test.h
+++ b/chrome/test/in_process_browser_test.h
@@ -11,7 +11,7 @@
class Browser;
class Profile;
namespace net {
-class RuleBasedHostMapper;
+class RuleBasedHostResolverProc;
}
// Base class for tests wanting to bring up a browser in the unit test process.
@@ -66,10 +66,10 @@ class InProcessBrowserTest : public testing::Test {
// main thread before the browser is torn down.
virtual void CleanUpOnMainThread() {}
- // Allows subclasses to configure the host mapper. By default this blocks
- // requests to google.com as Chrome pings that on startup and we don't want to
- // do that during testing.
- virtual void ConfigureHostMapper(net::RuleBasedHostMapper* host_mapper);
+ // Allows subclasses to configure the host resolver procedure. By default
+ // this blocks requests to google.com as Chrome pings that on startup and we
+ // don't want to do that during testing.
+ virtual void ConfigureHostResolverProc(net::RuleBasedHostResolverProc* proc);
// Invoked when a test is not finishing in a timely manner.
void TimedOut();
diff --git a/chrome/test/unit/chrome_test_suite.h b/chrome/test/unit/chrome_test_suite.h
index 7c49d72..7f8733b 100644
--- a/chrome/test/unit/chrome_test_suite.h
+++ b/chrome/test/unit/chrome_test_suite.h
@@ -28,15 +28,17 @@
#include "chrome/common/mac_app_names.h"
#endif
#include "chrome/test/testing_browser_process.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_util.h"
// In many cases it may be not obvious that a test makes a real DNS lookup.
// We generally don't want to rely on external DNS servers for our tests,
-// so this mapper catches external queries.
-class WarningHostMapper : public net::HostMapper {
+// so this host resolver procedure catches external queries.
+class WarningHostResolverProc : public net::HostResolverProc {
public:
- virtual std::string Map(const std::string& host) {
+ WarningHostResolverProc() : HostResolverProc(NULL) {}
+
+ virtual int Resolve(const std::string& host, net::AddressList* addrlist) {
const char* kLocalHostNames[] = {"localhost", "127.0.0.1"};
bool local = false;
@@ -51,11 +53,11 @@ class WarningHostMapper : public net::HostMapper {
}
// Make the test fail so it's harder to ignore.
- // If you really need to make real DNS query, use net::RuleBasedHostMapper
- // and its AllowDirectLookup method.
+ // If you really need to make real DNS query, use
+ // net::RuleBasedHostResolverProc and its AllowDirectLookup method.
EXPECT_TRUE(local) << "Making external DNS lookup of " << host;
- return MapUsingPrevious(host);
+ return ResolveUsingPrevious(host, addrlist);
}
};
@@ -71,8 +73,8 @@ class ChromeTestSuite : public TestSuite {
TestSuite::Initialize();
- host_mapper_ = new WarningHostMapper();
- scoped_host_mapper_.Init(host_mapper_.get());
+ host_resolver_proc_ = new WarningHostResolverProc();
+ scoped_host_resolver_proc_.Init(host_resolver_proc_.get());
chrome::RegisterPathProvider();
app::RegisterPathProvider();
@@ -140,8 +142,8 @@ class ChromeTestSuite : public TestSuite {
StatsTable* stats_table_;
ScopedOleInitializer ole_initializer_;
- scoped_refptr<WarningHostMapper> host_mapper_;
- net::ScopedHostMapper scoped_host_mapper_;
+ scoped_refptr<WarningHostResolverProc> host_resolver_proc_;
+ net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
};
#endif // CHROME_TEST_UNIT_CHROME_TEST_SUITE_H_
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index d594c85..d8ab3c1 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -4,15 +4,8 @@
#include "net/base/address_list.h"
-#if defined(OS_WIN)
-#include <ws2tcpip.h>
-#include <wspiapi.h> // Needed for Win2k compat.
-#elif defined(OS_POSIX)
-#include <netdb.h>
-#include <sys/socket.h>
-#endif
-
#include "base/string_util.h"
+#include "net/base/host_resolver_proc.h"
#include "net/base/net_util.h"
#if defined(OS_WIN)
#include "net/base/winsock_init.h"
@@ -26,17 +19,9 @@ void CreateAddressList(net::AddressList* addrlist, int port) {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
- std::string portstr = IntToString(port);
-
- struct addrinfo* result = NULL;
- struct addrinfo hints = {0};
- hints.ai_family = AF_UNSPEC;
- hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
-
- int err = getaddrinfo("192.168.1.1", portstr.c_str(), &hints, &result);
- EXPECT_EQ(0, err);
- addrlist->Adopt(result);
+ int rv = SystemHostResolverProc("192.168.1.1", addrlist);
+ EXPECT_EQ(0, rv);
+ addrlist->SetPort(port);
}
TEST(AddressListTest, GetPort) {
diff --git a/net/base/host_resolver.cc b/net/base/host_resolver.cc
index 4f0ede5..1d17296 100644
--- a/net/base/host_resolver.cc
+++ b/net/base/host_resolver.cc
@@ -4,616 +4,12 @@
#include "net/base/host_resolver.h"
-#if defined(OS_WIN)
-#include <ws2tcpip.h>
-#include <wspiapi.h> // Needed for Win2k compat.
-#elif defined(OS_POSIX)
-#include <netdb.h>
-#include <sys/socket.h>
-#endif
-#if defined(OS_LINUX)
-#include <resolv.h>
-#endif
-
#include "base/compiler_specific.h"
-#include "base/message_loop.h"
-#include "base/stl_util-inl.h"
-#include "base/string_util.h"
-#include "base/time.h"
-#include "base/worker_pool.h"
-#include "net/base/address_list.h"
+#include "base/logging.h"
#include "net/base/net_errors.h"
-#if defined(OS_LINUX)
-#include "base/singleton.h"
-#include "base/thread_local_storage.h"
-#endif
-
-#if defined(OS_WIN)
-#include "net/base/winsock_init.h"
-#endif
-
namespace net {
-//-----------------------------------------------------------------------------
-
-static HostMapper* host_mapper;
-
-std::string HostMapper::MapUsingPrevious(const std::string& host) {
- return previous_mapper_.get() ? previous_mapper_->Map(host) : host;
-}
-
-HostMapper* SetHostMapper(HostMapper* value) {
- std::swap(host_mapper, value);
- return value;
-}
-
-#if defined(OS_LINUX)
-// On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in
-// DNS queries failing either because nameservers are unknown on startup
-// or because nameserver info has changed as a result of e.g. connecting to
-// a new network. Some distributions patch glibc to stat /etc/resolv.conf
-// to try to automatically detect such changes but these patches are not
-// universal and even patched systems such as Jaunty appear to need calls
-// to res_ninit to reload the nameserver information in different threads.
-//
-// We adopt the Mozilla solution here which is to call res_ninit when
-// lookups fail and to rate limit the reloading to once per second per
-// thread.
-
-// Keep a timer per calling thread to rate limit the calling of res_ninit.
-class DnsReloadTimer {
- public:
- DnsReloadTimer() {
- tls_index_.Initialize(SlotReturnFunction);
- }
-
- ~DnsReloadTimer() { }
-
- // Check if the timer for the calling thread has expired. When no
- // timer exists for the calling thread, create one.
- bool Expired() {
- const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
- base::TimeTicks now = base::TimeTicks::Now();
- base::TimeTicks* timer_ptr =
- static_cast<base::TimeTicks*>(tls_index_.Get());
-
- if (!timer_ptr) {
- timer_ptr = new base::TimeTicks();
- *timer_ptr = base::TimeTicks::Now();
- tls_index_.Set(timer_ptr);
- // Return true to reload dns info on the first call for each thread.
- return true;
- } else if (now - *timer_ptr > kRetryTime) {
- *timer_ptr = now;
- return true;
- } else {
- return false;
- }
- }
-
- // Free the allocated timer.
- static void SlotReturnFunction(void* data) {
- base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
- delete tls_data;
- }
-
- private:
- // We use thread local storage to identify which base::TimeTicks to
- // interact with.
- static ThreadLocalStorage::Slot tls_index_ ;
-
- DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
-};
-
-// A TLS slot to the TimeTicks for the current thread.
-// static
-ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
-
-#endif // defined(OS_LINUX)
-
-static int HostResolverProc(const std::string& host, struct addrinfo** out) {
- struct addrinfo hints = {0};
- hints.ai_family = AF_UNSPEC;
-
-#if defined(OS_WIN)
- // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
- //
- // The following comment in <winsock2.h> is the best documentation I found
- // on AI_ADDRCONFIG for Windows:
- // Flags used in "hints" argument to getaddrinfo()
- // - AI_ADDRCONFIG is supported starting with Vista
- // - default is AI_ADDRCONFIG ON whether the flag is set or not
- // because the performance penalty in not having ADDRCONFIG in
- // the multi-protocol stack environment is severe;
- // this defaulting may be disabled by specifying the AI_ALL flag,
- // in that case AI_ADDRCONFIG must be EXPLICITLY specified to
- // enable ADDRCONFIG behavior
- //
- // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful. If the
- // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
- // to fail with WSANO_DATA (11004) for "localhost", probably because of the
- // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
- // The IPv4 or IPv6 loopback address is not considered a valid global
- // address.
- // See http://crbug.com/5234.
- hints.ai_flags = 0;
-#else
- hints.ai_flags = AI_ADDRCONFIG;
-#endif
-
- // Restrict result set to only this socket type to avoid duplicates.
- hints.ai_socktype = SOCK_STREAM;
-
- int err = getaddrinfo(host.c_str(), NULL, &hints, out);
-#if defined(OS_LINUX)
- net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
- // If we fail, re-initialise the resolver just in case there have been any
- // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
- if (err && dns_timer->Expired()) {
- res_nclose(&_res);
- if (!res_ninit(&_res))
- err = getaddrinfo(host.c_str(), NULL, &hints, out);
- }
-#endif
-
- return err ? ERR_NAME_NOT_RESOLVED : OK;
-}
-
-static int ResolveAddrInfo(HostMapper* mapper, const std::string& host,
- struct addrinfo** out) {
- if (mapper) {
- std::string mapped_host = mapper->Map(host);
-
- if (mapped_host.empty())
- return ERR_NAME_NOT_RESOLVED;
-
- return HostResolverProc(mapped_host, out);
- } else {
- return HostResolverProc(host, out);
- }
-}
-
-//-----------------------------------------------------------------------------
-
-class HostResolver::Request {
- public:
- Request(int id, const RequestInfo& info, CompletionCallback* callback,
- AddressList* addresses)
- : id_(id), info_(info), job_(NULL), callback_(callback),
- addresses_(addresses) {}
-
- // Mark the request as cancelled.
- void MarkAsCancelled() {
- job_ = NULL;
- callback_ = NULL;
- addresses_ = NULL;
- }
-
- bool was_cancelled() const {
- return callback_ == NULL;
- }
-
- void set_job(Job* job) {
- DCHECK(job != NULL);
- // Identify which job the request is waiting on.
- job_ = job;
- }
-
- void OnComplete(int error, const AddressList& addrlist) {
- if (error == OK)
- addresses_->SetFrom(addrlist, port());
- callback_->Run(error);
- }
-
- int port() const {
- return info_.port();
- }
-
- Job* job() const {
- return job_;
- }
-
- int id() const {
- return id_;
- }
-
- const RequestInfo& info() const {
- return info_;
- }
-
- private:
- // Unique ID for this request. Used by observers to identify requests.
- int id_;
-
- // The request info that started the request.
- RequestInfo info_;
-
- // The resolve job (running in worker pool) that this request is dependent on.
- Job* job_;
-
- // The user's callback to invoke when the request completes.
- CompletionCallback* callback_;
-
- // The address list to save result into.
- AddressList* addresses_;
-
- DISALLOW_COPY_AND_ASSIGN(Request);
-};
-
-//-----------------------------------------------------------------------------
-
-// This class represents a request to the worker pool for a "getaddrinfo()"
-// call.
-class HostResolver::Job : public base::RefCountedThreadSafe<HostResolver::Job> {
- public:
- Job(HostResolver* resolver, const std::string& host)
- : host_(host),
- resolver_(resolver),
- origin_loop_(MessageLoop::current()),
- host_mapper_(host_mapper),
- error_(OK),
- results_(NULL) {
- }
-
- ~Job() {
- if (results_)
- freeaddrinfo(results_);
-
- // Free the requests attached to this job.
- STLDeleteElements(&requests_);
- }
-
- // Attaches a request to this job. The job takes ownership of |req| and will
- // take care to delete it.
- void AddRequest(HostResolver::Request* req) {
- req->set_job(this);
- requests_.push_back(req);
- }
-
- // Called from origin loop.
- void Start() {
- // Dispatch the job to a worker thread.
- if (!WorkerPool::PostTask(FROM_HERE,
- NewRunnableMethod(this, &Job::DoLookup), true)) {
- NOTREACHED();
-
- // Since we could be running within Resolve() right now, we can't just
- // call OnLookupComplete(). Instead we must wait until Resolve() has
- // returned (IO_PENDING).
- error_ = ERR_UNEXPECTED;
- MessageLoop::current()->PostTask(
- FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
- }
- }
-
- // Cancels the current job. Callable from origin thread.
- void Cancel() {
- HostResolver* resolver = resolver_;
- resolver_ = NULL;
-
- // Mark the job as cancelled, so when worker thread completes it will
- // not try to post completion to origin loop.
- {
- AutoLock locked(origin_loop_lock_);
- origin_loop_ = NULL;
- }
-
- // We don't have to do anything further to actually cancel the requests
- // that were attached to this job (since they are unreachable now).
- // But we will call HostResolver::CancelRequest(Request*) on each one
- // in order to notify any observers.
- for (RequestsList::const_iterator it = requests_.begin();
- it != requests_.end(); ++it) {
- HostResolver::Request* req = *it;
- if (!req->was_cancelled())
- resolver->CancelRequest(req);
- }
- }
-
- // Called from origin thread.
- bool was_cancelled() const {
- return resolver_ == NULL;
- }
-
- // Called from origin thread.
- const std::string& host() const {
- return host_;
- }
-
- // Called from origin thread.
- const RequestsList& requests() const {
- return requests_;
- }
-
- private:
- void DoLookup() {
- // Running on the worker thread
- error_ = ResolveAddrInfo(host_mapper_, host_, &results_);
-
- Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete);
-
- // The origin loop could go away while we are trying to post to it, so we
- // need to call its PostTask method inside a lock. See ~HostResolver.
- {
- AutoLock locked(origin_loop_lock_);
- if (origin_loop_) {
- origin_loop_->PostTask(FROM_HERE, reply);
- reply = NULL;
- }
- }
-
- // Does nothing if it got posted.
- delete reply;
- }
-
- // Callback for when DoLookup() completes (runs on origin thread).
- void OnLookupComplete() {
- // Should be running on origin loop.
- // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
- // because MessageLoop::current() == NULL.
- //DCHECK_EQ(origin_loop_, MessageLoop::current());
- DCHECK(error_ || results_);
-
- if (was_cancelled())
- return;
-
- DCHECK(!requests_.empty());
-
- // Adopt the address list using the port number of the first request.
- AddressList addrlist;
- if (error_ == OK) {
- addrlist.Adopt(results_);
- addrlist.SetPort(requests_[0]->port());
- results_ = NULL;
- }
-
- resolver_->OnJobComplete(this, error_, addrlist);
- }
-
- // Set on the origin thread, read on the worker thread.
- std::string host_;
-
- // Only used on the origin thread (where Resolve was called).
- HostResolver* resolver_;
- RequestsList requests_; // The requests waiting on this job.
-
- // Used to post ourselves onto the origin thread.
- Lock origin_loop_lock_;
- MessageLoop* origin_loop_;
-
- // Hold an owning reference to the host mapper that we are going to use.
- // This may not be the current host mapper by the time we call
- // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
- // reference ensures that it remains valid until we are done.
- scoped_refptr<HostMapper> host_mapper_;
-
- // Assigned on the worker thread, read on the origin thread.
- int error_;
- struct addrinfo* results_;
-
- DISALLOW_COPY_AND_ASSIGN(Job);
-};
-
-//-----------------------------------------------------------------------------
-
-HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms)
- : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0),
- shutdown_(false) {
-#if defined(OS_WIN)
- EnsureWinsockInit();
-#endif
-}
-
-HostResolver::~HostResolver() {
- // Cancel the outstanding jobs. Those jobs may contain several attached
- // requests, which will also be cancelled.
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->Cancel();
-
- // In case we are being deleted during the processing of a callback.
- if (cur_completing_job_)
- cur_completing_job_->Cancel();
-}
-
-// TODO(eroman): Don't create cache entries for hostnames which are simply IP
-// address literals.
-int HostResolver::Resolve(const RequestInfo& info,
- AddressList* addresses,
- CompletionCallback* callback,
- Request** out_req) {
- if (shutdown_)
- return ERR_UNEXPECTED;
-
- // Choose a unique ID number for observers to see.
- int request_id = next_request_id_++;
-
- // Notify registered observers.
- NotifyObserversStartRequest(request_id, info);
-
- // If we have an unexpired cache entry, use it.
- if (info.allow_cached_response()) {
- const HostCache::Entry* cache_entry = cache_.Lookup(
- info.hostname(), base::TimeTicks::Now());
- if (cache_entry) {
- addresses->SetFrom(cache_entry->addrlist, info.port());
- int error = OK;
-
- // Notify registered observers.
- NotifyObserversFinishRequest(request_id, info, error);
-
- return error;
- }
- }
-
- // If no callback was specified, do a synchronous resolution.
- if (!callback) {
- struct addrinfo* results;
- int error = ResolveAddrInfo(host_mapper, info.hostname(), &results);
-
- // Adopt the address list.
- AddressList addrlist;
- if (error == OK) {
- addrlist.Adopt(results);
- addrlist.SetPort(info.port());
- *addresses = addrlist;
- }
-
- // Write to cache.
- cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now());
-
- // Notify registered observers.
- NotifyObserversFinishRequest(request_id, info, error);
-
- return error;
- }
-
- // Create a handle for this request, and pass it back to the user if they
- // asked for it (out_req != NULL).
- Request* req = new Request(request_id, info, callback, addresses);
- if (out_req)
- *out_req = req;
-
- // Next we need to attach our request to a "job". This job is responsible for
- // calling "getaddrinfo(hostname)" on a worker thread.
- scoped_refptr<Job> job;
-
- // If there is already an outstanding job to resolve |info.hostname()|, use
- // it. This prevents starting concurrent resolves for the same hostname.
- job = FindOutstandingJob(info.hostname());
- if (job) {
- job->AddRequest(req);
- } else {
- // Create a new job for this request.
- job = new Job(this, info.hostname());
- job->AddRequest(req);
- AddOutstandingJob(job);
- // TODO(eroman): Bound the total number of concurrent jobs.
- // http://crbug.com/9598
- job->Start();
- }
-
- // Completion happens during OnJobComplete(Job*).
- return ERR_IO_PENDING;
-}
-
-// See OnJobComplete(Job*) for why it is important not to clean out
-// cancelled requests from Job::requests_.
-void HostResolver::CancelRequest(Request* req) {
- DCHECK(req);
- DCHECK(req->job());
- // NULL out the fields of req, to mark it as cancelled.
- req->MarkAsCancelled();
- NotifyObserversCancelRequest(req->id(), req->info());
-}
-
-void HostResolver::AddObserver(Observer* observer) {
- observers_.push_back(observer);
-}
-
-void HostResolver::RemoveObserver(Observer* observer) {
- ObserversList::iterator it =
- std::find(observers_.begin(), observers_.end(), observer);
-
- // Observer must exist.
- DCHECK(it != observers_.end());
-
- observers_.erase(it);
-}
-
-void HostResolver::Shutdown() {
- shutdown_ = true;
-
- // Cancel the outstanding jobs.
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->Cancel();
- jobs_.clear();
-}
-
-void HostResolver::AddOutstandingJob(Job* job) {
- scoped_refptr<Job>& found_job = jobs_[job->host()];
- DCHECK(!found_job);
- found_job = job;
-}
-
-HostResolver::Job* HostResolver::FindOutstandingJob(
- const std::string& hostname) {
- JobMap::iterator it = jobs_.find(hostname);
- if (it != jobs_.end())
- return it->second;
- return NULL;
-}
-
-void HostResolver::RemoveOutstandingJob(Job* job) {
- JobMap::iterator it = jobs_.find(job->host());
- DCHECK(it != jobs_.end());
- DCHECK_EQ(it->second.get(), job);
- jobs_.erase(it);
-}
-
-void HostResolver::OnJobComplete(Job* job,
- int error,
- const AddressList& addrlist) {
- RemoveOutstandingJob(job);
-
- // Write result to the cache.
- cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now());
-
- // Make a note that we are executing within OnJobComplete() in case the
- // HostResolver is deleted by a callback invocation.
- DCHECK(!cur_completing_job_);
- cur_completing_job_ = job;
-
- // Complete all of the requests that were attached to the job.
- for (RequestsList::const_iterator it = job->requests().begin();
- it != job->requests().end(); ++it) {
- Request* req = *it;
- if (!req->was_cancelled()) {
- DCHECK_EQ(job, req->job());
-
- // Notify registered observers.
- NotifyObserversFinishRequest(req->id(), req->info(), error);
-
- req->OnComplete(error, addrlist);
-
- // Check if the job was cancelled as a result of running the callback.
- // (Meaning that |this| was deleted).
- if (job->was_cancelled())
- return;
- }
- }
-
- cur_completing_job_ = NULL;
-}
-
-void HostResolver::NotifyObserversStartRequest(int request_id,
- const RequestInfo& info) {
- for (ObserversList::iterator it = observers_.begin();
- it != observers_.end(); ++it) {
- (*it)->OnStartResolution(request_id, info);
- }
-}
-
-void HostResolver::NotifyObserversFinishRequest(int request_id,
- const RequestInfo& info,
- int error) {
- bool was_resolved = error == OK;
- for (ObserversList::iterator it = observers_.begin();
- it != observers_.end(); ++it) {
- (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
- }
-}
-
-void HostResolver::NotifyObserversCancelRequest(int request_id,
- const RequestInfo& info) {
- for (ObserversList::iterator it = observers_.begin();
- it != observers_.end(); ++it) {
- (*it)->OnCancelResolution(request_id, info);
- }
-}
-
-//-----------------------------------------------------------------------------
-
SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver)
: resolver_(resolver),
cur_request_(NULL),
@@ -634,7 +30,7 @@ int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info,
CompletionCallback* callback) {
DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use";
- HostResolver::Request* request = NULL;
+ HostResolver::RequestHandle request = NULL;
// We need to be notified of completion before |callback| is called, so that
// we can clear out |cur_request_*|.
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index 5a6c548..c1ac13f 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -6,57 +6,26 @@
#define NET_BASE_HOST_RESOLVER_H_
#include <string>
-#include <vector>
-#include "base/basictypes.h"
-#include "base/lock.h"
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
#include "net/base/completion_callback.h"
-#include "net/base/host_cache.h"
class MessageLoop;
namespace net {
class AddressList;
-class HostMapper;
// This class represents the task of resolving hostnames (or IP address
// literal) to an AddressList object.
//
-// HostResolver handles multiple requests at a time, so when cancelling a
-// request the Request* handle that was returned by Resolve() needs to be
+// HostResolver can handle multiple requests at a time, so when cancelling a
+// request the RequestHandle that was returned by Resolve() needs to be
// given. A simpler alternative for consumers that only have 1 outstanding
// request at a time is to create a SingleRequestHostResolver wrapper around
// HostResolver (which will automatically cancel the single request when it
// goes out of scope).
-//
-// For each hostname that is requested, HostResolver creates a
-// HostResolver::Job. This job gets dispatched to a thread in the global
-// WorkerPool, where it runs "getaddrinfo(hostname)". If requests for that same
-// host are made while the job is already outstanding, then they are attached
-// to the existing job rather than creating a new one. This avoids doing
-// parallel resolves for the same host.
-//
-// The way these classes fit together is illustrated by:
-//
-//
-// +------------- HostResolver ---------------+
-// | | |
-// Job Job Job
-// (for host1) (for host2) (for hostX)
-// / | | / | | / | |
-// Request ... Request Request ... Request Request ... Request
-// (port1) (port2) (port3) (port4) (port5) (portX)
-//
-//
-// When a HostResolver::Job finishes its work in the threadpool, the callbacks
-// of each waiting request are run on the origin thread.
-//
-// Thread safety: This class is not threadsafe, and must only be called
-// from one thread!
-//
class HostResolver : public base::RefCounted<HostResolver> {
public:
// The parameters for doing a Resolve(). |hostname| and |port| are required,
@@ -120,20 +89,15 @@ class HostResolver : public base::RefCounted<HostResolver> {
virtual void OnCancelResolution(int id, const RequestInfo& info) = 0;
};
- // Creates a HostResolver that caches up to |max_cache_entries| for
- // |cache_duration_ms| milliseconds.
- //
- // TODO(eroman): Get rid of the default parameters as it violate google
- // style. This is temporary to help with refactoring.
- HostResolver(int max_cache_entries = 100, int cache_duration_ms = 60000);
+ // Opaque type used to cancel a request.
+ typedef void* RequestHandle;
+
+ HostResolver() {}
// If any completion callbacks are pending when the resolver is destroyed,
// the host resolutions are cancelled, and the completion callbacks will not
// be called.
- ~HostResolver();
-
- // Opaque type used to cancel a request.
- class Request;
+ virtual ~HostResolver() {}
// Resolves the given hostname (or IP address literal), filling out the
// |addresses| object upon success. The |info.port| parameter will be set as
@@ -147,74 +111,23 @@ class HostResolver : public base::RefCounted<HostResolver> {
// result code will be passed to the completion callback. If |req| is
// non-NULL, then |*req| will be filled with a handle to the async request.
// This handle is not valid after the request has completed.
- int Resolve(const RequestInfo& info, AddressList* addresses,
- CompletionCallback* callback, Request** req);
+ virtual int Resolve(const RequestInfo& info, AddressList* addresses,
+ CompletionCallback* callback, RequestHandle* out_req) = 0;
// Cancels the specified request. |req| is the handle returned by Resolve().
// After a request is cancelled, its completion callback will not be called.
- void CancelRequest(Request* req);
+ virtual void CancelRequest(RequestHandle req) = 0;
// Adds an observer to this resolver. The observer will be notified of the
// start and completion of all requests (excluding cancellation). |observer|
// must remain valid for the duration of this HostResolver's lifetime.
- void AddObserver(Observer* observer);
+ virtual void AddObserver(Observer* observer) = 0;
// Unregisters an observer previously added by AddObserver().
- void RemoveObserver(Observer* observer);
-
- // TODO(eroman): temp hack for http://crbug.com/15513
- void Shutdown();
-
- private:
- class Job;
- typedef std::vector<Request*> RequestsList;
- typedef base::hash_map<std::string, scoped_refptr<Job> > JobMap;
- typedef std::vector<Observer*> ObserversList;
-
- // Adds a job to outstanding jobs list.
- void AddOutstandingJob(Job* job);
-
- // Returns the outstanding job for |hostname|, or NULL if there is none.
- Job* FindOutstandingJob(const std::string& hostname);
-
- // Removes |job| from the outstanding jobs list.
- void RemoveOutstandingJob(Job* job);
-
- // Callback for when |job| has completed with |error| and |addrlist|.
- void OnJobComplete(Job* job, int error, const AddressList& addrlist);
-
- // Notify all observers of the start of a resolve request.
- void NotifyObserversStartRequest(int request_id,
- const RequestInfo& info);
-
- // Notify all observers of the completion of a resolve request.
- void NotifyObserversFinishRequest(int request_id,
- const RequestInfo& info,
- int error);
-
- // Notify all observers of the cancellation of a resolve request.
- void NotifyObserversCancelRequest(int request_id,
- const RequestInfo& info);
-
- // Cache of host resolution results.
- HostCache cache_;
-
- // Map from hostname to outstanding job.
- JobMap jobs_;
-
- // The job that OnJobComplete() is currently processing (needed in case
- // HostResolver gets deleted from within the callback).
- scoped_refptr<Job> cur_completing_job_;
-
- // The observers to notify when a request starts/ends.
- ObserversList observers_;
-
- // Monotonically increasing ID number to assign to the next request.
- // Observers are the only consumers of this ID number.
- int next_request_id_;
+ virtual void RemoveObserver(Observer* observer) = 0;
// TODO(eroman): temp hack for http://crbug.com/15513
- bool shutdown_;
+ virtual void Shutdown() = 0;
DISALLOW_COPY_AND_ASSIGN(HostResolver);
};
@@ -245,7 +158,7 @@ class SingleRequestHostResolver {
scoped_refptr<HostResolver> resolver_;
// The current request (if any).
- HostResolver::Request* cur_request_;
+ HostResolver::RequestHandle cur_request_;
CompletionCallback* cur_request_callback_;
// Completion callback for when request to |resolver_| completes.
@@ -254,46 +167,10 @@ class SingleRequestHostResolver {
DISALLOW_COPY_AND_ASSIGN(SingleRequestHostResolver);
};
-// A helper class used in unit tests to alter hostname mappings. See
-// SetHostMapper for details.
-class HostMapper : public base::RefCountedThreadSafe<HostMapper> {
- public:
- virtual ~HostMapper() {}
-
- // Returns possibly altered hostname, or empty string to simulate
- // a failed lookup.
- virtual std::string Map(const std::string& host) = 0;
-
- protected:
- // Ask previous host mapper (if set) for mapping of given host.
- std::string MapUsingPrevious(const std::string& host);
-
- private:
- friend class ScopedHostMapper;
-
- // Set mapper to ask when this mapper doesn't want to modify the result.
- void set_previous_mapper(HostMapper* mapper) {
- previous_mapper_ = mapper;
- }
-
- scoped_refptr<HostMapper> previous_mapper_;
-};
-
-#ifdef UNIT_TEST
-// This function is designed to allow unit tests to override the behavior of
-// HostResolver. For example, a HostMapper instance can force all hostnames
-// to map to a fixed IP address such as 127.0.0.1.
-//
-// The previously set HostMapper (or NULL if there was none) is returned.
-//
-// NOTE: This function is not thread-safe, so take care to only call this
-// function while there are no outstanding HostResolver instances.
-//
-// NOTE: In most cases, you should use ScopedHostMapper instead, which is
-// defined in host_resolver_unittest.h
-//
-HostMapper* SetHostMapper(HostMapper* host_mapper);
-#endif
+// Creates a HostResolver implementation that queries the underlying system.
+// (Except if a unit-test has changed the global HostResolverProc using
+// ScopedHostResolverProc to intercept requests to the system).
+HostResolver* CreateSystemHostResolver();
} // namespace net
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
new file mode 100644
index 0000000..2a0eb0f
--- /dev/null
+++ b/net/base/host_resolver_impl.cc
@@ -0,0 +1,483 @@
+// Copyright (c) 2006-2008 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_resolver_impl.h"
+
+#if defined(OS_WIN)
+#include <ws2tcpip.h>
+#include <wspiapi.h> // Needed for Win2k compat.
+#elif defined(OS_POSIX)
+#include <netdb.h>
+#include <sys/socket.h>
+#endif
+#if defined(OS_LINUX)
+#include <resolv.h>
+#endif
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/stl_util-inl.h"
+#include "base/string_util.h"
+#include "base/time.h"
+#include "base/worker_pool.h"
+#include "net/base/address_list.h"
+#include "net/base/host_resolver_proc.h"
+#include "net/base/net_errors.h"
+
+#if defined(OS_WIN)
+#include "net/base/winsock_init.h"
+#endif
+
+namespace net {
+
+HostResolver* CreateSystemHostResolver() {
+ static const size_t kMaxHostCacheEntries = 100;
+ static const size_t kHostCacheExpirationMs = 60000; // 1 minute.
+ return new HostResolverImpl(
+ NULL, kMaxHostCacheEntries, kHostCacheExpirationMs);
+}
+
+static int ResolveAddrInfo(HostResolverProc* resolver_proc,
+ const std::string& host, AddressList* out) {
+ if (resolver_proc) {
+ // Use the custom procedure.
+ return resolver_proc->Resolve(host, out);
+ } else {
+ // Use the system procedure (getaddrinfo).
+ return SystemHostResolverProc(host, out);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+class HostResolverImpl::Request {
+ public:
+ Request(int id, const RequestInfo& info, CompletionCallback* callback,
+ AddressList* addresses)
+ : id_(id), info_(info), job_(NULL), callback_(callback),
+ addresses_(addresses) {}
+
+ // Mark the request as cancelled.
+ void MarkAsCancelled() {
+ job_ = NULL;
+ callback_ = NULL;
+ addresses_ = NULL;
+ }
+
+ bool was_cancelled() const {
+ return callback_ == NULL;
+ }
+
+ void set_job(Job* job) {
+ DCHECK(job != NULL);
+ // Identify which job the request is waiting on.
+ job_ = job;
+ }
+
+ void OnComplete(int error, const AddressList& addrlist) {
+ if (error == OK)
+ addresses_->SetFrom(addrlist, port());
+ callback_->Run(error);
+ }
+
+ int port() const {
+ return info_.port();
+ }
+
+ Job* job() const {
+ return job_;
+ }
+
+ int id() const {
+ return id_;
+ }
+
+ const RequestInfo& info() const {
+ return info_;
+ }
+
+ private:
+ // Unique ID for this request. Used by observers to identify requests.
+ int id_;
+
+ // The request info that started the request.
+ RequestInfo info_;
+
+ // The resolve job (running in worker pool) that this request is dependent on.
+ Job* job_;
+
+ // The user's callback to invoke when the request completes.
+ CompletionCallback* callback_;
+
+ // The address list to save result into.
+ AddressList* addresses_;
+
+ DISALLOW_COPY_AND_ASSIGN(Request);
+};
+
+//-----------------------------------------------------------------------------
+
+// This class represents a request to the worker pool for a "getaddrinfo()"
+// call.
+class HostResolverImpl::Job
+ : public base::RefCountedThreadSafe<HostResolverImpl::Job> {
+ public:
+ Job(HostResolverImpl* resolver, const std::string& host)
+ : host_(host),
+ resolver_(resolver),
+ origin_loop_(MessageLoop::current()),
+ resolver_proc_(resolver->effective_resolver_proc()),
+ error_(OK) {
+ }
+
+ ~Job() {
+ // Free the requests attached to this job.
+ STLDeleteElements(&requests_);
+ }
+
+ // Attaches a request to this job. The job takes ownership of |req| and will
+ // take care to delete it.
+ void AddRequest(Request* req) {
+ req->set_job(this);
+ requests_.push_back(req);
+ }
+
+ // Called from origin loop.
+ void Start() {
+ // Dispatch the job to a worker thread.
+ if (!WorkerPool::PostTask(FROM_HERE,
+ NewRunnableMethod(this, &Job::DoLookup), true)) {
+ NOTREACHED();
+
+ // Since we could be running within Resolve() right now, we can't just
+ // call OnLookupComplete(). Instead we must wait until Resolve() has
+ // returned (IO_PENDING).
+ error_ = ERR_UNEXPECTED;
+ MessageLoop::current()->PostTask(
+ FROM_HERE, NewRunnableMethod(this, &Job::OnLookupComplete));
+ }
+ }
+
+ // Cancels the current job. Callable from origin thread.
+ void Cancel() {
+ HostResolver* resolver = resolver_;
+ resolver_ = NULL;
+
+ // Mark the job as cancelled, so when worker thread completes it will
+ // not try to post completion to origin loop.
+ {
+ AutoLock locked(origin_loop_lock_);
+ origin_loop_ = NULL;
+ }
+
+ // We don't have to do anything further to actually cancel the requests
+ // that were attached to this job (since they are unreachable now).
+ // But we will call HostResolverImpl::CancelRequest(Request*) on each one
+ // in order to notify any observers.
+ for (RequestsList::const_iterator it = requests_.begin();
+ it != requests_.end(); ++it) {
+ HostResolverImpl::Request* req = *it;
+ if (!req->was_cancelled())
+ resolver->CancelRequest(req);
+ }
+ }
+
+ // Called from origin thread.
+ bool was_cancelled() const {
+ return resolver_ == NULL;
+ }
+
+ // Called from origin thread.
+ const std::string& host() const {
+ return host_;
+ }
+
+ // Called from origin thread.
+ const RequestsList& requests() const {
+ return requests_;
+ }
+
+ private:
+ void DoLookup() {
+ // Running on the worker thread
+ error_ = ResolveAddrInfo(resolver_proc_, host_, &results_);
+
+ Task* reply = NewRunnableMethod(this, &Job::OnLookupComplete);
+
+ // The origin loop could go away while we are trying to post to it, so we
+ // need to call its PostTask method inside a lock. See ~HostResolver.
+ {
+ AutoLock locked(origin_loop_lock_);
+ if (origin_loop_) {
+ origin_loop_->PostTask(FROM_HERE, reply);
+ reply = NULL;
+ }
+ }
+
+ // Does nothing if it got posted.
+ delete reply;
+ }
+
+ // Callback for when DoLookup() completes (runs on origin thread).
+ void OnLookupComplete() {
+ // Should be running on origin loop.
+ // TODO(eroman): this is being hit by URLRequestTest.CancelTest*,
+ // because MessageLoop::current() == NULL.
+ //DCHECK_EQ(origin_loop_, MessageLoop::current());
+ DCHECK(error_ || results_.head());
+
+ if (was_cancelled())
+ return;
+
+ DCHECK(!requests_.empty());
+
+ // Use the port number of the first request.
+ if (error_ == OK)
+ results_.SetPort(requests_[0]->port());
+
+ resolver_->OnJobComplete(this, error_, results_);
+ }
+
+ // Set on the origin thread, read on the worker thread.
+ std::string host_;
+
+ // Only used on the origin thread (where Resolve was called).
+ HostResolverImpl* resolver_;
+ RequestsList requests_; // The requests waiting on this job.
+
+ // Used to post ourselves onto the origin thread.
+ Lock origin_loop_lock_;
+ MessageLoop* origin_loop_;
+
+ // Hold an owning reference to the HostResolverProc that we are going to use.
+ // This may not be the current resolver procedure by the time we call
+ // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
+ // reference ensures that it remains valid until we are done.
+ scoped_refptr<HostResolverProc> resolver_proc_;
+
+ // Assigned on the worker thread, read on the origin thread.
+ int error_;
+ AddressList results_;
+
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+//-----------------------------------------------------------------------------
+
+HostResolverImpl::HostResolverImpl(HostResolverProc* resolver_proc,
+ int max_cache_entries,
+ int cache_duration_ms)
+ : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0),
+ resolver_proc_(resolver_proc), shutdown_(false) {
+#if defined(OS_WIN)
+ EnsureWinsockInit();
+#endif
+}
+
+HostResolverImpl::~HostResolverImpl() {
+ // Cancel the outstanding jobs. Those jobs may contain several attached
+ // requests, which will also be cancelled.
+ for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
+ it->second->Cancel();
+
+ // In case we are being deleted during the processing of a callback.
+ if (cur_completing_job_)
+ cur_completing_job_->Cancel();
+}
+
+// TODO(eroman): Don't create cache entries for hostnames which are simply IP
+// address literals.
+int HostResolverImpl::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ CompletionCallback* callback,
+ RequestHandle* out_req) {
+ if (shutdown_)
+ return ERR_UNEXPECTED;
+
+ // Choose a unique ID number for observers to see.
+ int request_id = next_request_id_++;
+
+ // Notify registered observers.
+ NotifyObserversStartRequest(request_id, info);
+
+ // If we have an unexpired cache entry, use it.
+ if (info.allow_cached_response()) {
+ const HostCache::Entry* cache_entry = cache_.Lookup(
+ info.hostname(), base::TimeTicks::Now());
+ if (cache_entry) {
+ addresses->SetFrom(cache_entry->addrlist, info.port());
+ int error = cache_entry->error;
+
+ // Notify registered observers.
+ NotifyObserversFinishRequest(request_id, info, error);
+
+ return error;
+ }
+ }
+
+ // If no callback was specified, do a synchronous resolution.
+ if (!callback) {
+ AddressList addrlist;
+ int error = ResolveAddrInfo(
+ effective_resolver_proc(), info.hostname(), &addrlist);
+ if (error == OK) {
+ addrlist.SetPort(info.port());
+ *addresses = addrlist;
+ }
+
+ // Write to cache.
+ cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now());
+
+ // Notify registered observers.
+ NotifyObserversFinishRequest(request_id, info, error);
+
+ return error;
+ }
+
+ // Create a handle for this request, and pass it back to the user if they
+ // asked for it (out_req != NULL).
+ Request* req = new Request(request_id, info, callback, addresses);
+ if (out_req)
+ *out_req = reinterpret_cast<RequestHandle>(req);
+
+ // Next we need to attach our request to a "job". This job is responsible for
+ // calling "getaddrinfo(hostname)" on a worker thread.
+ scoped_refptr<Job> job;
+
+ // If there is already an outstanding job to resolve |info.hostname()|, use
+ // it. This prevents starting concurrent resolves for the same hostname.
+ job = FindOutstandingJob(info.hostname());
+ if (job) {
+ job->AddRequest(req);
+ } else {
+ // Create a new job for this request.
+ job = new Job(this, info.hostname());
+ job->AddRequest(req);
+ AddOutstandingJob(job);
+ // TODO(eroman): Bound the total number of concurrent jobs.
+ // http://crbug.com/9598
+ job->Start();
+ }
+
+ // Completion happens during OnJobComplete(Job*).
+ return ERR_IO_PENDING;
+}
+
+// See OnJobComplete(Job*) for why it is important not to clean out
+// cancelled requests from Job::requests_.
+void HostResolverImpl::CancelRequest(RequestHandle req_handle) {
+ Request* req = reinterpret_cast<Request*>(req_handle);
+ DCHECK(req);
+ DCHECK(req->job());
+ // NULL out the fields of req, to mark it as cancelled.
+ req->MarkAsCancelled();
+ NotifyObserversCancelRequest(req->id(), req->info());
+}
+
+void HostResolverImpl::AddObserver(Observer* observer) {
+ observers_.push_back(observer);
+}
+
+void HostResolverImpl::RemoveObserver(Observer* observer) {
+ ObserversList::iterator it =
+ std::find(observers_.begin(), observers_.end(), observer);
+
+ // Observer must exist.
+ DCHECK(it != observers_.end());
+
+ observers_.erase(it);
+}
+
+void HostResolverImpl::Shutdown() {
+ shutdown_ = true;
+
+ // Cancel the outstanding jobs.
+ for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
+ it->second->Cancel();
+ jobs_.clear();
+}
+
+void HostResolverImpl::AddOutstandingJob(Job* job) {
+ scoped_refptr<Job>& found_job = jobs_[job->host()];
+ DCHECK(!found_job);
+ found_job = job;
+}
+
+HostResolverImpl::Job* HostResolverImpl::FindOutstandingJob(
+ const std::string& hostname) {
+ JobMap::iterator it = jobs_.find(hostname);
+ if (it != jobs_.end())
+ return it->second;
+ return NULL;
+}
+
+void HostResolverImpl::RemoveOutstandingJob(Job* job) {
+ JobMap::iterator it = jobs_.find(job->host());
+ DCHECK(it != jobs_.end());
+ DCHECK_EQ(it->second.get(), job);
+ jobs_.erase(it);
+}
+
+void HostResolverImpl::OnJobComplete(Job* job,
+ int error,
+ const AddressList& addrlist) {
+ RemoveOutstandingJob(job);
+
+ // Write result to the cache.
+ cache_.Set(job->host(), error, addrlist, base::TimeTicks::Now());
+
+ // Make a note that we are executing within OnJobComplete() in case the
+ // HostResolver is deleted by a callback invocation.
+ DCHECK(!cur_completing_job_);
+ cur_completing_job_ = job;
+
+ // Complete all of the requests that were attached to the job.
+ for (RequestsList::const_iterator it = job->requests().begin();
+ it != job->requests().end(); ++it) {
+ Request* req = *it;
+ if (!req->was_cancelled()) {
+ DCHECK_EQ(job, req->job());
+
+ // Notify registered observers.
+ NotifyObserversFinishRequest(req->id(), req->info(), error);
+
+ req->OnComplete(error, addrlist);
+
+ // Check if the job was cancelled as a result of running the callback.
+ // (Meaning that |this| was deleted).
+ if (job->was_cancelled())
+ return;
+ }
+ }
+
+ cur_completing_job_ = NULL;
+}
+
+void HostResolverImpl::NotifyObserversStartRequest(int request_id,
+ const RequestInfo& info) {
+ for (ObserversList::iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ (*it)->OnStartResolution(request_id, info);
+ }
+}
+
+void HostResolverImpl::NotifyObserversFinishRequest(int request_id,
+ const RequestInfo& info,
+ int error) {
+ bool was_resolved = error == OK;
+ for (ObserversList::iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info);
+ }
+}
+
+void HostResolverImpl::NotifyObserversCancelRequest(int request_id,
+ const RequestInfo& info) {
+ for (ObserversList::iterator it = observers_.begin();
+ it != observers_.end(); ++it) {
+ (*it)->OnCancelResolution(request_id, info);
+ }
+}
+
+} // namespace net
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
new file mode 100644
index 0000000..6ece456
--- /dev/null
+++ b/net/base/host_resolver_impl.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 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_RESOLVER_IMPL_H_
+#define NET_BASE_HOST_RESOLVER_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "net/base/host_cache.h"
+#include "net/base/host_resolver.h"
+#include "net/base/host_resolver_proc.h"
+
+namespace net {
+
+// For each hostname that is requested, HostResolver creates a
+// HostResolverImpl::Job. This job gets dispatched to a thread in the global
+// WorkerPool, where it runs SystemHostResolverProc(). If requests for that same
+// host are made while the job is already outstanding, then they are attached
+// to the existing job rather than creating a new one. This avoids doing
+// parallel resolves for the same host.
+//
+// The way these classes fit together is illustrated by:
+//
+//
+// +----------- HostResolverImpl -------------+
+// | | |
+// Job Job Job
+// (for host1) (for host2) (for hostX)
+// / | | / | | / | |
+// Request ... Request Request ... Request Request ... Request
+// (port1) (port2) (port3) (port4) (port5) (portX)
+//
+//
+// When a HostResolverImpl::Job finishes its work in the threadpool, the
+// callbacks of each waiting request are run on the origin thread.
+//
+// Thread safety: This class is not threadsafe, and must only be called
+// from one thread!
+//
+class HostResolverImpl : public HostResolver {
+ public:
+ // Creates a HostResolver that caches up to |max_cache_entries| for
+ // |cache_duration_ms| milliseconds. |resolver_proc| is used to perform
+ // the actual resolves; it must be thread-safe since it is run from
+ // multiple worker threads. If |resolver_proc| is NULL then the default
+ // host resolver procedure is used (which is SystemHostResolverProc except
+ // if overridden)
+ HostResolverImpl(HostResolverProc* resolver_proc,
+ int max_cache_entries,
+ int cache_duration_ms);
+
+ // If any completion callbacks are pending when the resolver is destroyed,
+ // the host resolutions are cancelled, and the completion callbacks will not
+ // be called.
+ virtual ~HostResolverImpl();
+
+ // HostResolver methods:
+ virtual int Resolve(const RequestInfo& info, AddressList* addresses,
+ CompletionCallback* callback, RequestHandle* out_req);
+ virtual void CancelRequest(RequestHandle req);
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+
+ // TODO(eroman): temp hack for http://crbug.com/15513
+ virtual void Shutdown();
+
+ private:
+ class Job;
+ class Request;
+ typedef std::vector<Request*> RequestsList;
+ typedef base::hash_map<std::string, scoped_refptr<Job> > JobMap;
+ typedef std::vector<Observer*> ObserversList;
+
+ // Returns the HostResolverProc to use for this instance.
+ HostResolverProc* effective_resolver_proc() const {
+ return resolver_proc_ ?
+ resolver_proc_.get() : HostResolverProc::GetDefault();
+ }
+
+ // Adds a job to outstanding jobs list.
+ void AddOutstandingJob(Job* job);
+
+ // Returns the outstanding job for |hostname|, or NULL if there is none.
+ Job* FindOutstandingJob(const std::string& hostname);
+
+ // Removes |job| from the outstanding jobs list.
+ void RemoveOutstandingJob(Job* job);
+
+ // Callback for when |job| has completed with |error| and |addrlist|.
+ void OnJobComplete(Job* job, int error, const AddressList& addrlist);
+
+ // Notify all observers of the start of a resolve request.
+ void NotifyObserversStartRequest(int request_id,
+ const RequestInfo& info);
+
+ // Notify all observers of the completion of a resolve request.
+ void NotifyObserversFinishRequest(int request_id,
+ const RequestInfo& info,
+ int error);
+
+ // Notify all observers of the cancellation of a resolve request.
+ void NotifyObserversCancelRequest(int request_id,
+ const RequestInfo& info);
+
+ // Cache of host resolution results.
+ HostCache cache_;
+
+ // Map from hostname to outstanding job.
+ JobMap jobs_;
+
+ // The job that OnJobComplete() is currently processing (needed in case
+ // HostResolver gets deleted from within the callback).
+ scoped_refptr<Job> cur_completing_job_;
+
+ // The observers to notify when a request starts/ends.
+ ObserversList observers_;
+
+ // Monotonically increasing ID number to assign to the next request.
+ // Observers are the only consumers of this ID number.
+ int next_request_id_;
+
+ // The procedure to use for resolving host names. This will be NULL, except
+ // in the case of unit-tests which inject custom host resolving behaviors.
+ scoped_refptr<HostResolverProc> resolver_proc_;
+
+ // TODO(eroman): temp hack for http://crbug.com/15513
+ bool shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostResolverImpl);
+};
+
+} // namespace net
+
+#endif // NET_BASE_HOST_RESOLVER_IMPL_H_
diff --git a/net/base/host_resolver_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 32b6af6..0ff345c 100644
--- a/net/base/host_resolver_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/host_resolver.h"
+#include "net/base/host_resolver_impl.h"
#if defined(OS_WIN)
#include <ws2tcpip.h>
@@ -18,39 +18,43 @@
#include "base/ref_counted.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "testing/gtest/include/gtest/gtest.h"
-using net::RuleBasedHostMapper;
-using net::ScopedHostMapper;
-using net::WaitingHostMapper;
+using net::HostResolverImpl;
+using net::RuleBasedHostResolverProc;
+using net::WaitingHostResolverProc;
// TODO(eroman):
// - Test mixing async with sync (in particular how does sync update the
// cache while an async is already pending).
namespace {
+static const int kMaxCacheEntries = 100;
+static const int kMaxCacheAgeMs = 60000;
-// A variant of WaitingHostMapper that pushes each host mapped into a list.
+// A variant of WaitingHostResolverProc that pushes each host mapped into a
+// list.
// (and uses a manual-reset event rather than auto-reset).
-class CapturingHostMapper : public net::HostMapper {
+class CapturingHostResolverProc : public net::HostResolverProc {
public:
- CapturingHostMapper() : event_(true, false) {
+ explicit CapturingHostResolverProc(HostResolverProc* previous)
+ : net::HostResolverProc(previous), event_(true, false) {
}
void Signal() {
event_.Signal();
}
- virtual std::string Map(const std::string& host) {
+ virtual int Resolve(const std::string& host, net::AddressList* addrlist) {
event_.Wait();
{
AutoLock l(lock_);
capture_list_.push_back(host);
}
- return MapUsingPrevious(host);
+ return ResolveUsingPrevious(host, addrlist);
}
std::vector<std::string> GetCaptureList() const {
@@ -134,7 +138,7 @@ class ResolveRequest {
// The request details.
net::HostResolver::RequestInfo info_;
- net::HostResolver::Request* req_;
+ net::HostResolver::RequestHandle req_;
// The result of the resolve.
int result_;
@@ -150,18 +154,18 @@ class ResolveRequest {
DISALLOW_COPY_AND_ASSIGN(ResolveRequest);
};
-class HostResolverTest : public testing::Test {
+class HostResolverImplTest : public testing::Test {
public:
- HostResolverTest()
+ HostResolverImplTest()
: callback_called_(false),
ALLOW_THIS_IN_INITIALIZER_LIST(
- callback_(this, &HostResolverTest::OnLookupFinished)) {
+ callback_(this, &HostResolverImplTest::OnLookupFinished)) {
}
protected:
bool callback_called_;
int callback_result_;
- net::CompletionCallbackImpl<HostResolverTest> callback_;
+ net::CompletionCallbackImpl<HostResolverImplTest> callback_;
private:
void OnLookupFinished(int result) {
@@ -171,14 +175,16 @@ class HostResolverTest : public testing::Test {
}
};
-TEST_F(HostResolverTest, SynchronousLookup) {
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+TEST_F(HostResolverImplTest, SynchronousLookup) {
net::AddressList adrlist;
const int kPortnum = 80;
- scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
- mapper->AddRule("just.testing", "192.168.1.42");
- ScopedHostMapper scoped_mapper(mapper.get());
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AddRule("just.testing", "192.168.1.42");
+
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::HostResolver::RequestInfo info("just.testing", kPortnum);
int err = host_resolver->Resolve(info, &adrlist, NULL, NULL);
@@ -194,14 +200,16 @@ TEST_F(HostResolverTest, SynchronousLookup) {
EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
}
-TEST_F(HostResolverTest, AsynchronousLookup) {
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+TEST_F(HostResolverImplTest, AsynchronousLookup) {
net::AddressList adrlist;
const int kPortnum = 80;
- scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
- mapper->AddRule("just.testing", "192.168.1.42");
- ScopedHostMapper scoped_mapper(mapper.get());
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AddRule("just.testing", "192.168.1.42");
+
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::HostResolver::RequestInfo info("just.testing", kPortnum);
int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL);
@@ -222,12 +230,13 @@ TEST_F(HostResolverTest, AsynchronousLookup) {
EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
}
-TEST_F(HostResolverTest, CanceledAsynchronousLookup) {
- scoped_refptr<WaitingHostMapper> mapper = new WaitingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, CanceledAsynchronousLookup) {
+ scoped_refptr<WaitingHostResolverProc> resolver_proc =
+ new WaitingHostResolverProc(NULL);
{
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::AddressList adrlist;
const int kPortnum = 80;
@@ -242,19 +251,20 @@ TEST_F(HostResolverTest, CanceledAsynchronousLookup) {
MessageLoop::current()->Run();
}
- mapper->Signal();
+ resolver_proc->Signal();
EXPECT_FALSE(callback_called_);
}
-TEST_F(HostResolverTest, NumericIPv4Address) {
+TEST_F(HostResolverImplTest, NumericIPv4Address) {
// Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in.
- scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
- mapper->AllowDirectLookup("*");
- ScopedHostMapper scoped_mapper(mapper.get());
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AllowDirectLookup("*");
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::AddressList adrlist;
const int kPortnum = 5555;
net::HostResolver::RequestInfo info("127.1.2.3", kPortnum);
@@ -271,14 +281,15 @@ TEST_F(HostResolverTest, NumericIPv4Address) {
EXPECT_TRUE(htonl(0x7f010203) == sa_in->sin_addr.s_addr);
}
-TEST_F(HostResolverTest, NumericIPv6Address) {
- scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
- mapper->AllowDirectLookup("*");
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, NumericIPv6Address) {
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AllowDirectLookup("*");
// Resolve a plain IPv6 address. Don't worry about [brackets], because
// the caller should have removed them.
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::AddressList adrlist;
const int kPortnum = 5555;
net::HostResolver::RequestInfo info("2001:db8::1", kPortnum);
@@ -307,12 +318,13 @@ TEST_F(HostResolverTest, NumericIPv6Address) {
}
}
-TEST_F(HostResolverTest, EmptyHost) {
- scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper();
- mapper->AllowDirectLookup("*");
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, EmptyHost) {
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc =
+ new RuleBasedHostResolverProc(NULL);
+ resolver_proc->AllowDirectLookup("*");
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
net::AddressList adrlist;
const int kPortnum = 5555;
net::HostResolver::RequestInfo info("", kPortnum);
@@ -320,13 +332,13 @@ TEST_F(HostResolverTest, EmptyHost) {
EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, err);
}
-// Helper class used by HostResolverTest.DeDupeRequests. It receives request
+// Helper class used by HostResolverImplTest.DeDupeRequests. It receives request
// completion notifications for all the resolves, so it can tally up and
// determine when we are done.
class DeDupeRequestsVerifier : public ResolveRequest::Delegate {
public:
- explicit DeDupeRequestsVerifier(CapturingHostMapper* mapper)
- : count_a_(0), count_b_(0), mapper_(mapper) {}
+ explicit DeDupeRequestsVerifier(CapturingHostResolverProc* resolver_proc)
+ : count_a_(0), count_b_(0), resolver_proc_(resolver_proc) {}
// The test does 5 resolves (which can complete in any order).
virtual void OnCompleted(ResolveRequest* resolve) {
@@ -348,9 +360,9 @@ class DeDupeRequestsVerifier : public ResolveRequest::Delegate {
EXPECT_EQ(2, count_a_);
EXPECT_EQ(3, count_b_);
- // The mapper should have been called only twice -- once with "a", once
- // with "b".
- std::vector<std::string> capture_list = mapper_->GetCaptureList();
+ // The resolver_proc should have been called only twice -- once with "a",
+ // once with "b".
+ std::vector<std::string> capture_list = resolver_proc_->GetCaptureList();
EXPECT_EQ(2U, capture_list.size());
// End this test, we are done.
@@ -361,24 +373,25 @@ class DeDupeRequestsVerifier : public ResolveRequest::Delegate {
private:
int count_a_;
int count_b_;
- CapturingHostMapper* mapper_;
+ CapturingHostResolverProc* resolver_proc_;
DISALLOW_COPY_AND_ASSIGN(DeDupeRequestsVerifier);
};
-TEST_F(HostResolverTest, DeDupeRequests) {
- // Use a capturing mapper, since the verifier needs to know what calls
- // reached Map(). Also, the capturing mapper is initially blocked.
- scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, DeDupeRequests) {
+ // Use a capturing resolver_proc, since the verifier needs to know what calls
+ // reached Resolve(). Also, the capturing resolver_proc is initially blocked.
+ scoped_refptr<CapturingHostResolverProc> resolver_proc =
+ new CapturingHostResolverProc(NULL);
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
- DeDupeRequestsVerifier verifier(mapper.get());
+ DeDupeRequestsVerifier verifier(resolver_proc.get());
- // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
+ // Start 5 requests, duplicating hosts "a" and "b". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
ResolveRequest req1(host_resolver, "a", 80, &verifier);
@@ -388,13 +401,13 @@ TEST_F(HostResolverTest, DeDupeRequests) {
ResolveRequest req5(host_resolver, "b", 83, &verifier);
// Ready, Set, GO!!!
- mapper->Signal();
+ resolver_proc->Signal();
// |verifier| will send quit message once all the requests have finished.
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverTest.CancelMultipleRequests.
+// Helper class used by HostResolverImplTest.CancelMultipleRequests.
class CancelMultipleRequestsVerifier : public ResolveRequest::Delegate {
public:
CancelMultipleRequestsVerifier() {}
@@ -415,19 +428,21 @@ class CancelMultipleRequestsVerifier : public ResolveRequest::Delegate {
DISALLOW_COPY_AND_ASSIGN(CancelMultipleRequestsVerifier);
};
-TEST_F(HostResolverTest, CancelMultipleRequests) {
- // Use a capturing mapper, since the verifier needs to know what calls
- // reached Map(). Also, the capturing mapper is initially blocked.
- scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, CancelMultipleRequests) {
+ // Use a capturing resolver_proc, since the verifier needs to know what calls
+ // reached Resolver(). Also, the capturing resolver_proc is initially
+ // blocked.
+ scoped_refptr<CapturingHostResolverProc> resolver_proc =
+ new CapturingHostResolverProc(NULL);
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
CancelMultipleRequestsVerifier verifier;
- // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is
+ // Start 5 requests, duplicating hosts "a" and "b". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
ResolveRequest req1(host_resolver, "a", 80, &verifier);
@@ -443,13 +458,13 @@ TEST_F(HostResolverTest, CancelMultipleRequests) {
req5.Cancel();
// Ready, Set, GO!!!
- mapper->Signal();
+ resolver_proc->Signal();
// |verifier| will send quit message once all the requests have finished.
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverTest.CancelWithinCallback.
+// Helper class used by HostResolverImplTest.CancelWithinCallback.
class CancelWithinCallbackVerifier : public ResolveRequest::Delegate {
public:
CancelWithinCallbackVerifier()
@@ -500,19 +515,21 @@ class CancelWithinCallbackVerifier : public ResolveRequest::Delegate {
DISALLOW_COPY_AND_ASSIGN(CancelWithinCallbackVerifier);
};
-TEST_F(HostResolverTest, CancelWithinCallback) {
- // Use a capturing mapper, since the verifier needs to know what calls
- // reached Map(). Also, the capturing mapper is initially blocked.
- scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, CancelWithinCallback) {
+ // Use a capturing resolver_proc, since the verifier needs to know what calls
+ // reached Resolver(). Also, the capturing resolver_proc is initially
+ // blocked.
+ scoped_refptr<CapturingHostResolverProc> resolver_proc =
+ new CapturingHostResolverProc(NULL);
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
CancelWithinCallbackVerifier verifier;
- // Start 4 requests, duplicating hosts "a". Since the mapper is
+ // Start 4 requests, duplicating hosts "a". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
ResolveRequest req1(host_resolver, "a", 80, &verifier);
@@ -524,13 +541,13 @@ TEST_F(HostResolverTest, CancelWithinCallback) {
verifier.SetRequestsToCancel(&req2, &req3);
// Ready, Set, GO!!!
- mapper->Signal();
+ resolver_proc->Signal();
// |verifier| will send quit message once all the requests have finished.
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverTest.DeleteWithinCallback.
+// Helper class used by HostResolverImplTest.DeleteWithinCallback.
class DeleteWithinCallbackVerifier : public ResolveRequest::Delegate {
public:
// |host_resolver| is the resolver that the the resolve requests were started
@@ -556,19 +573,21 @@ class DeleteWithinCallbackVerifier : public ResolveRequest::Delegate {
DISALLOW_COPY_AND_ASSIGN(DeleteWithinCallbackVerifier);
};
-TEST_F(HostResolverTest, DeleteWithinCallback) {
- // Use a capturing mapper, since the verifier needs to know what calls
- // reached Map(). Also, the capturing mapper is initially blocked.
- scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, DeleteWithinCallback) {
+ // Use a capturing resolver_proc, since the verifier needs to know what calls
+ // reached Resolver(). Also, the capturing resolver_proc is initially
+ // blocked.
+ scoped_refptr<CapturingHostResolverProc> resolver_proc =
+ new CapturingHostResolverProc(NULL);
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened. Note that the verifier holds the
// only reference to |host_resolver|, so it can delete it within callback.
- net::HostResolver* host_resolver = new net::HostResolver;
+ net::HostResolver* host_resolver =
+ new HostResolverImpl(resolver_proc, kMaxCacheEntries, kMaxCacheAgeMs);
DeleteWithinCallbackVerifier verifier(host_resolver);
- // Start 4 requests, duplicating hosts "a". Since the mapper is
+ // Start 4 requests, duplicating hosts "a". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
ResolveRequest req1(host_resolver, "a", 80, &verifier);
@@ -577,13 +596,13 @@ TEST_F(HostResolverTest, DeleteWithinCallback) {
ResolveRequest req4(host_resolver, "a", 83, &verifier);
// Ready, Set, GO!!!
- mapper->Signal();
+ resolver_proc->Signal();
// |verifier| will send quit message once all the requests have finished.
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverTest.StartWithinCallback.
+// Helper class used by HostResolverImplTest.StartWithinCallback.
class StartWithinCallbackVerifier : public ResolveRequest::Delegate {
public:
StartWithinCallbackVerifier() : num_requests_(0) {}
@@ -609,20 +628,22 @@ class StartWithinCallbackVerifier : public ResolveRequest::Delegate {
DISALLOW_COPY_AND_ASSIGN(StartWithinCallbackVerifier);
};
-TEST_F(HostResolverTest, StartWithinCallback) {
- // Use a capturing mapper, since the verifier needs to know what calls
- // reached Map(). Also, the capturing mapper is initially blocked.
- scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper();
- ScopedHostMapper scoped_mapper(mapper.get());
+TEST_F(HostResolverImplTest, StartWithinCallback) {
+ // Use a capturing resolver_proc, since the verifier needs to know what calls
+ // reached Resolver(). Also, the capturing resolver_proc is initially
+ // blocked.
+ scoped_refptr<CapturingHostResolverProc> resolver_proc =
+ new CapturingHostResolverProc(NULL);
// Turn off caching for this host resolver.
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver(0, 0));
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(resolver_proc, 0, 0));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
StartWithinCallbackVerifier verifier;
- // Start 4 requests, duplicating hosts "a". Since the mapper is
+ // Start 4 requests, duplicating hosts "a". Since the resolver_proc is
// blocked, these should all pile up until we signal it.
ResolveRequest req1(host_resolver, "a", 80, &verifier);
@@ -631,13 +652,13 @@ TEST_F(HostResolverTest, StartWithinCallback) {
ResolveRequest req4(host_resolver, "a", 83, &verifier);
// Ready, Set, GO!!!
- mapper->Signal();
+ resolver_proc->Signal();
// |verifier| will send quit message once all the requests have finished.
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverTest.BypassCache.
+// Helper class used by HostResolverImplTest.BypassCache.
class BypassCacheVerifier : public ResolveRequest::Delegate {
public:
BypassCacheVerifier() {}
@@ -679,8 +700,9 @@ class BypassCacheVerifier : public ResolveRequest::Delegate {
DISALLOW_COPY_AND_ASSIGN(BypassCacheVerifier);
};
-TEST_F(HostResolverTest, BypassCache) {
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+TEST_F(HostResolverImplTest, BypassCache) {
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(NULL, kMaxCacheEntries, kMaxCacheAgeMs));
// The class will receive callbacks for when each resolve completes. It
// checks that the right things happened.
@@ -762,8 +784,9 @@ class CapturingObserver : public net::HostResolver::Observer {
// Test that registering, unregistering, and notifying of observers works.
// Does not test the cancellation notification since all resolves are
// synchronous.
-TEST_F(HostResolverTest, Observers) {
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+TEST_F(HostResolverImplTest, Observers) {
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(NULL, kMaxCacheEntries, kMaxCacheAgeMs));
CapturingObserver observer;
@@ -829,11 +852,12 @@ TEST_F(HostResolverTest, Observers) {
// cancelled. There are two ways to cancel a request:
// (1) Delete the HostResolver while job is outstanding.
// (2) Call HostResolver::CancelRequest() while a request is outstanding.
-TEST_F(HostResolverTest, CancellationObserver) {
+TEST_F(HostResolverImplTest, CancellationObserver) {
CapturingObserver observer;
{
// Create a host resolver and attach an observer.
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ new HostResolverImpl(NULL, kMaxCacheEntries, kMaxCacheAgeMs));
host_resolver->AddObserver(&observer);
TestCompletionCallback callback;
@@ -844,7 +868,7 @@ TEST_F(HostResolverTest, CancellationObserver) {
// Start an async resolve for (host1:70).
net::HostResolver::RequestInfo info1("host1", 70);
- net::HostResolver::Request* req = NULL;
+ net::HostResolver::RequestHandle req = NULL;
net::AddressList addrlist;
int rv = host_resolver->Resolve(info1, &addrlist, &callback, &req);
EXPECT_EQ(net::ERR_IO_PENDING, rv);
@@ -857,7 +881,7 @@ TEST_F(HostResolverTest, CancellationObserver) {
EXPECT_TRUE(observer.start_log[0] ==
CapturingObserver::StartOrCancelEntry(0, info1));
- // Cancel the request (host mapper is blocked so it cant be finished yet).
+ // Cancel the request.
host_resolver->CancelRequest(req);
EXPECT_EQ(1U, observer.start_log.size());
diff --git a/net/base/host_resolver_proc.cc b/net/base/host_resolver_proc.cc
new file mode 100644
index 0000000..585a33e
--- /dev/null
+++ b/net/base/host_resolver_proc.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2006-2008 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_resolver_proc.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <ws2tcpip.h>
+#include <wspiapi.h> // Needed for Win2k compat.
+#elif defined(OS_POSIX)
+#include <netdb.h>
+#include <sys/socket.h>
+#endif
+#if defined(OS_LINUX)
+#include <resolv.h>
+#endif
+
+#include "base/logging.h"
+#include "base/time.h"
+#include "net/base/address_list.h"
+#include "net/base/net_errors.h"
+
+#if defined(OS_LINUX)
+#include "base/singleton.h"
+#include "base/thread_local_storage.h"
+#endif
+
+namespace net {
+
+HostResolverProc* HostResolverProc::default_proc_ = NULL;
+
+HostResolverProc::HostResolverProc(HostResolverProc* previous) {
+ set_previous_proc(previous);
+
+ // Implicitly fall-back to the global default procedure.
+ if (!previous)
+ set_previous_proc(default_proc_);
+}
+
+// static
+HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) {
+ HostResolverProc* old = default_proc_;
+ default_proc_ = proc;
+ return old;
+}
+
+// static
+HostResolverProc* HostResolverProc::GetDefault() {
+ return default_proc_;
+}
+
+int HostResolverProc::ResolveUsingPrevious(const std::string& host,
+ AddressList* addrlist) {
+ if (previous_proc_)
+ return previous_proc_->Resolve(host, addrlist);
+
+ // Final fallback is the system resolver.
+ return SystemHostResolverProc(host, addrlist);
+}
+
+#if defined(OS_LINUX)
+// On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in
+// DNS queries failing either because nameservers are unknown on startup
+// or because nameserver info has changed as a result of e.g. connecting to
+// a new network. Some distributions patch glibc to stat /etc/resolv.conf
+// to try to automatically detect such changes but these patches are not
+// universal and even patched systems such as Jaunty appear to need calls
+// to res_ninit to reload the nameserver information in different threads.
+//
+// We adopt the Mozilla solution here which is to call res_ninit when
+// lookups fail and to rate limit the reloading to once per second per
+// thread.
+
+// Keep a timer per calling thread to rate limit the calling of res_ninit.
+class DnsReloadTimer {
+ public:
+ DnsReloadTimer() {
+ tls_index_.Initialize(SlotReturnFunction);
+ }
+
+ ~DnsReloadTimer() { }
+
+ // Check if the timer for the calling thread has expired. When no
+ // timer exists for the calling thread, create one.
+ bool Expired() {
+ const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::TimeTicks* timer_ptr =
+ static_cast<base::TimeTicks*>(tls_index_.Get());
+
+ if (!timer_ptr) {
+ timer_ptr = new base::TimeTicks();
+ *timer_ptr = base::TimeTicks::Now();
+ tls_index_.Set(timer_ptr);
+ // Return true to reload dns info on the first call for each thread.
+ return true;
+ } else if (now - *timer_ptr > kRetryTime) {
+ *timer_ptr = now;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Free the allocated timer.
+ static void SlotReturnFunction(void* data) {
+ base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
+ delete tls_data;
+ }
+
+ private:
+ // We use thread local storage to identify which base::TimeTicks to
+ // interact with.
+ static ThreadLocalStorage::Slot tls_index_ ;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
+};
+
+// A TLS slot to the TimeTicks for the current thread.
+// static
+ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);
+
+#endif // defined(OS_LINUX)
+
+int SystemHostResolverProc(const std::string& host, AddressList* addrlist) {
+ struct addrinfo* ai = NULL;
+ struct addrinfo hints = {0};
+ hints.ai_family = AF_UNSPEC;
+
+#if defined(OS_WIN)
+ // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
+ //
+ // The following comment in <winsock2.h> is the best documentation I found
+ // on AI_ADDRCONFIG for Windows:
+ // Flags used in "hints" argument to getaddrinfo()
+ // - AI_ADDRCONFIG is supported starting with Vista
+ // - default is AI_ADDRCONFIG ON whether the flag is set or not
+ // because the performance penalty in not having ADDRCONFIG in
+ // the multi-protocol stack environment is severe;
+ // this defaulting may be disabled by specifying the AI_ALL flag,
+ // in that case AI_ADDRCONFIG must be EXPLICITLY specified to
+ // enable ADDRCONFIG behavior
+ //
+ // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful. If the
+ // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
+ // to fail with WSANO_DATA (11004) for "localhost", probably because of the
+ // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
+ // The IPv4 or IPv6 loopback address is not considered a valid global
+ // address.
+ // See http://crbug.com/5234.
+ hints.ai_flags = 0;
+#else
+ hints.ai_flags = AI_ADDRCONFIG;
+#endif
+
+ // Restrict result set to only this socket type to avoid duplicates.
+ hints.ai_socktype = SOCK_STREAM;
+
+ int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
+#if defined(OS_LINUX)
+ net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
+ // If we fail, re-initialise the resolver just in case there have been any
+ // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
+ if (err && dns_timer->Expired()) {
+ res_nclose(&_res);
+ if (!res_ninit(&_res))
+ err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
+ }
+#endif
+
+ if (err)
+ return ERR_NAME_NOT_RESOLVED;
+
+ addrlist->Adopt(ai);
+ return OK;
+}
+
+} // namespace net
diff --git a/net/base/host_resolver_proc.h b/net/base/host_resolver_proc.h
new file mode 100644
index 0000000..2690987
--- /dev/null
+++ b/net/base/host_resolver_proc.h
@@ -0,0 +1,69 @@
+// 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_HOST_RESOLVER_PROC_H_
+#define NET_BASE_HOST_RESOLVER_PROC_H_
+
+#include <string>
+
+#include "base/ref_counted.h"
+
+namespace net {
+
+class AddressList;
+
+// Interface for a getaddrinfo()-like procedure. This is used by unit-tests
+// to control the underlying resolutions in HostResolverImpl. HostResolverProcs
+// can be chained together; they fallback to the next procedure in the chain
+// by calling ResolveUsingPrevious().
+//
+// Note that implementations of HostResolverProc *MUST BE THREADSAFE*, since
+// the HostResolver implementation using them can be multi-threaded.
+class HostResolverProc : public base::RefCountedThreadSafe<HostResolverProc> {
+ public:
+ explicit HostResolverProc(HostResolverProc* previous);
+ virtual ~HostResolverProc() {}
+
+ // Resolves |host| to an address list. If successful returns OK and fills
+ // |addrlist| with a list of socket addresses. Otherwise returns a
+ // network error code.
+ virtual int Resolve(const std::string& host, AddressList* addrlist) = 0;
+
+ protected:
+ // Asks the fallback procedure (if set) to do the resolve.
+ int ResolveUsingPrevious(const std::string& host, AddressList* addrlist);
+
+ private:
+ friend class HostResolverImpl;
+ friend class MockHostResolver;
+ friend class ScopedDefaultHostResolverProc;
+
+ // Sets the previous procedure in the chain.
+ void set_previous_proc(HostResolverProc* proc) {
+ previous_proc_ = proc;
+ }
+
+ // Sets the default host resolver procedure that is used by HostResolverImpl.
+ // This can be used through ScopedDefaultHostResolverProc to set a catch-all
+ // DNS block in unit-tests (individual tests should use MockHostResolver to
+ // prevent hitting the network).
+ static HostResolverProc* SetDefault(HostResolverProc* proc);
+ static HostResolverProc* GetDefault();
+
+ private:
+ scoped_refptr<HostResolverProc> previous_proc_;
+ static HostResolverProc* default_proc_;
+
+ DISALLOW_COPY_AND_ASSIGN(HostResolverProc);
+};
+
+// Resolves |host| to an address list, using the system's default host resolver.
+// (i.e. this calls out to getaddrinfo()). If successful returns OK and fills
+// |addrlist| with a list of socket addresses. Otherwise returns a
+// network error code.
+int SystemHostResolverProc(const std::string& host, AddressList* addrlist);
+
+} // namespace net
+
+#endif // NET_BASE_HOST_RESOLVER_PROC_H_
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
new file mode 100644
index 0000000..58ad552
--- /dev/null
+++ b/net/base/mock_host_resolver.cc
@@ -0,0 +1,154 @@
+// 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/mock_host_resolver.h"
+
+#include "base/string_util.h"
+#include "base/platform_thread.h"
+#include "base/ref_counted.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+MockHostResolver::MockHostResolver() {
+ Reset(NULL, 0, 0);
+}
+
+int MockHostResolver::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ CompletionCallback* callback,
+ RequestHandle* out_req) {
+ return impl_->Resolve(info, addresses, callback, out_req);
+}
+
+void MockHostResolver::CancelRequest(RequestHandle req) {
+ impl_->CancelRequest(req);
+}
+
+void MockHostResolver::AddObserver(Observer* observer) {
+ impl_->AddObserver(observer);
+}
+
+void MockHostResolver::RemoveObserver(Observer* observer) {
+ impl_->RemoveObserver(observer);
+}
+
+void MockHostResolver::Shutdown() {
+ impl_->Shutdown();
+}
+
+void MockHostResolver::Reset(HostResolverProc* interceptor,
+ int max_cache_entries,
+ int max_cache_age_ms) {
+ // At the root of the chain, map everything to localhost.
+ scoped_refptr<RuleBasedHostResolverProc> catchall =
+ new RuleBasedHostResolverProc(NULL);
+ catchall->AddRule("*", "127.0.0.1");
+
+ // Next add a rules-based layer the use controls.
+ rules_ = new RuleBasedHostResolverProc(catchall);
+
+ HostResolverProc* proc = rules_;
+
+ // Lastly add the provided interceptor to the front of the chain.
+ if (interceptor) {
+ interceptor->set_previous_proc(proc);
+ proc = interceptor;
+ }
+
+ impl_ = new HostResolverImpl(proc, max_cache_entries, max_cache_age_ms);
+}
+
+//-----------------------------------------------------------------------------
+
+struct RuleBasedHostResolverProc::Rule {
+ std::string host_pattern;
+ std::string replacement;
+ int latency_ms; // In milliseconds.
+ bool direct; // if true, don't mangle hostname and ignore replacement
+ Rule(const std::string& host_pattern, const std::string& replacement)
+ : host_pattern(host_pattern),
+ replacement(replacement),
+ latency_ms(0),
+ direct(false) {}
+ Rule(const std::string& host_pattern, const std::string& replacement,
+ const int latency_ms)
+ : host_pattern(host_pattern),
+ replacement(replacement),
+ latency_ms(latency_ms),
+ direct(false) {}
+ Rule(const std::string& host_pattern, const std::string& replacement,
+ const bool direct)
+ : host_pattern(host_pattern),
+ replacement(replacement),
+ latency_ms(0),
+ direct(direct) {}
+};
+
+RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc* previous)
+ : HostResolverProc(previous) {
+}
+
+RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
+}
+
+void RuleBasedHostResolverProc::AddRule(const std::string& host_pattern,
+ const std::string& replacement) {
+ rules_.push_back(Rule(host_pattern, replacement));
+}
+
+void RuleBasedHostResolverProc::AddRuleWithLatency(
+ const std::string& host_pattern,
+ const std::string& replacement, int latency_ms) {
+ rules_.push_back(Rule(host_pattern, replacement, latency_ms));
+}
+
+void RuleBasedHostResolverProc::AllowDirectLookup(const std::string& host) {
+ rules_.push_back(Rule(host, "", true));
+}
+
+void RuleBasedHostResolverProc::AddSimulatedFailure(const std::string& host) {
+ AddRule(host, "");
+}
+
+int RuleBasedHostResolverProc::Resolve(const std::string& host,
+ AddressList* addrlist) {
+ RuleList::iterator r;
+ for (r = rules_.begin(); r != rules_.end(); ++r) {
+ if (MatchPattern(host, r->host_pattern)) {
+ if (r->latency_ms != 0) {
+ PlatformThread::Sleep(r->latency_ms);
+ // Hmm, this seems unecessary.
+ r->latency_ms = 1;
+ }
+ const std::string& effective_host = r->direct ? host : r->replacement;
+ if (effective_host.empty())
+ return ERR_NAME_NOT_RESOLVED;
+ return SystemHostResolverProc(effective_host, addrlist);
+ }
+ }
+ return ResolveUsingPrevious(host, addrlist);
+}
+
+//-----------------------------------------------------------------------------
+
+ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc(
+ HostResolverProc* proc) : current_proc_(proc) {
+ previous_proc_ = HostResolverProc::SetDefault(current_proc_);
+ current_proc_->set_previous_proc(previous_proc_);
+}
+
+ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() {
+ HostResolverProc* old_proc = HostResolverProc::SetDefault(previous_proc_);
+ // The lifetimes of multiple instances must be nested.
+ CHECK(old_proc == current_proc_);
+}
+
+void ScopedDefaultHostResolverProc::Init(HostResolverProc* proc) {
+ current_proc_ = proc;
+ previous_proc_ = HostResolverProc::SetDefault(current_proc_);
+ current_proc_->set_previous_proc(previous_proc_);
+}
+
+} // namespace net
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
new file mode 100644
index 0000000..ee83105
--- /dev/null
+++ b/net/base/mock_host_resolver.h
@@ -0,0 +1,143 @@
+// 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_MOCK_HOST_RESOLVER_H_
+#define NET_BASE_MOCK_HOST_RESOLVER_H_
+
+#include <list>
+
+#include "base/waitable_event.h"
+#include "net/base/host_resolver_impl.h"
+#include "net/base/host_resolver_proc.h"
+
+namespace net {
+
+class RuleBasedHostResolverProc;
+
+// In most cases, it is important that unit tests avoid making actual DNS
+// queries since the resulting tests can be flaky, especially if the network is
+// unreliable for some reason. To simplify writing tests that avoid making
+// actual DNS queries, pass a MockHostResolver as the HostResolver dependency.
+// The socket addresses returned can be configured using the
+// RuleBasedHostResolverProc:
+//
+// host_resolver->rules()->AddRule("foo.com", "1.2.3.4");
+// host_resolver->rules()->AddRule("bar.com", "2.3.4.5");
+//
+// The above rules define a static mapping from hostnames to IP address
+// literals. The first parameter to AddRule specifies a host pattern to match
+// against, and the second parameter indicates what value should be used to
+// replace the given hostname. So, the following is also supported:
+//
+// host_mapper->AddRule("*.com", "127.0.0.1");
+//
+// Replacement doesn't have to be string representing an IP address. It can
+// re-map one hostname to another as well.
+class MockHostResolver : public HostResolver {
+ public:
+ // Creates a MockHostResolver that does NOT cache entries
+ // (the HostResolverProc will be called for every lookup). If you need
+ // caching behavior, call Reset() with non-zero cache size.
+ MockHostResolver();
+
+ virtual ~MockHostResolver() {}
+
+ // HostResolver methods:
+ virtual int Resolve(const RequestInfo& info, AddressList* addresses,
+ CompletionCallback* callback, RequestHandle* out_req);
+ virtual void CancelRequest(RequestHandle req);
+ virtual void AddObserver(Observer* observer);
+ virtual void RemoveObserver(Observer* observer);
+ // TODO(eroman): temp hack for http://crbug.com/15513
+ virtual void Shutdown();
+
+ RuleBasedHostResolverProc* rules() { return rules_; }
+
+ // Resets the mock.
+ void Reset(HostResolverProc* interceptor,
+ int max_cache_entries,
+ int max_cache_age_ms);
+
+ private:
+ scoped_refptr<HostResolverImpl> impl_;
+ scoped_refptr<RuleBasedHostResolverProc> rules_;
+};
+
+// RuleBasedHostResolverProc applies a set of rules to map a host string to
+// a replacement host string. It then uses the system host resolver to return
+// a socket address. Generally the replacement should be an IPv4 literal so
+// there is no network dependency.
+class RuleBasedHostResolverProc : public HostResolverProc {
+ public:
+ explicit RuleBasedHostResolverProc(HostResolverProc* previous);
+ ~RuleBasedHostResolverProc();
+
+ // Any hostname matching the given pattern will be replaced with the given
+ // replacement value. Usually, replacement should be an IP address literal.
+ void AddRule(const std::string& host_pattern,
+ const std::string& replacement);
+
+ void AddRuleWithLatency(const std::string& host_pattern,
+ const std::string& replacement,
+ int latency_ms);
+
+ // Make sure that |host| will not be re-mapped or even processed by underlying
+ // host resolver procedures. It can also be a pattern.
+ void AllowDirectLookup(const std::string& host);
+
+ // Simulate a lookup failure for |host| (it also can be a pattern).
+ void AddSimulatedFailure(const std::string& host);
+
+ // HostResolverProc methods:
+ virtual int Resolve(const std::string& host, AddressList* addrlist);
+
+ private:
+ struct Rule;
+ typedef std::list<Rule> RuleList;
+ RuleList rules_;
+};
+
+// Using WaitingHostResolverProc you can simulate very long lookups.
+class WaitingHostResolverProc : public HostResolverProc {
+ public:
+ explicit WaitingHostResolverProc(HostResolverProc* previous)
+ : HostResolverProc(previous), event_(false, false) {}
+
+ void Signal() {
+ event_.Signal();
+ }
+
+ // HostResolverProc methods:
+ virtual int Resolve(const std::string& host, AddressList* addrlist) {
+ event_.Wait();
+ return ResolveUsingPrevious(host, addrlist);
+ }
+
+ base::WaitableEvent event_;
+};
+
+// This class sets the HostResolverProc for a particular scope. If there are
+// multiple ScopedDefaultHostResolverProc in existence, then the last one
+// allocated will be used. However, if it does not provide a matching rule,
+// then it should delegate to the previously set HostResolverProc.
+//
+// NOTE: Only use this as a catch-all safety net. Individual tests should use
+// MockHostResolver.
+class ScopedDefaultHostResolverProc {
+ public:
+ ScopedDefaultHostResolverProc() {}
+ explicit ScopedDefaultHostResolverProc(HostResolverProc* proc);
+
+ ~ScopedDefaultHostResolverProc();
+
+ void Init(HostResolverProc* proc);
+
+ private:
+ scoped_refptr<HostResolverProc> current_proc_;
+ scoped_refptr<HostResolverProc> previous_proc_;
+};
+
+} // namespace net
+
+#endif // NET_BASE_MOCK_HOST_RESOLVER_H_
diff --git a/net/base/run_all_unittests.cc b/net/base/run_all_unittests.cc
index 6c60e2d..c4c4df7 100644
--- a/net/base/run_all_unittests.cc
+++ b/net/base/run_all_unittests.cc
@@ -30,7 +30,7 @@
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/test_suite.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
class NetTestSuite : public TestSuite {
public:
@@ -40,12 +40,12 @@ class NetTestSuite : public TestSuite {
virtual void Initialize() {
TestSuite::Initialize();
- host_mapper_ = new net::RuleBasedHostMapper();
- scoped_host_mapper_.Init(host_mapper_.get());
+ host_resolver_proc_ = new net::RuleBasedHostResolverProc(NULL);
+ scoped_host_resolver_proc_.Init(host_resolver_proc_.get());
// In case any attempts are made to resolve host names, force them all to
// be mapped to localhost. This prevents DNS queries from being sent in
// the process of running these unit tests.
- host_mapper_->AddRule("*", "127.0.0.1");
+ host_resolver_proc_->AddRule("*", "127.0.0.1");
message_loop_.reset(new MessageLoopForIO());
}
@@ -60,8 +60,8 @@ class NetTestSuite : public TestSuite {
private:
scoped_ptr<MessageLoop> message_loop_;
- scoped_refptr<net::RuleBasedHostMapper> host_mapper_;
- net::ScopedHostMapper scoped_host_mapper_;
+ scoped_refptr<net::RuleBasedHostResolverProc> host_resolver_proc_;
+ net::ScopedDefaultHostResolverProc scoped_host_resolver_proc_;
};
int main(int argc, char** argv) {
diff --git a/net/ftp/ftp_network_transaction_unittest.cc b/net/ftp/ftp_network_transaction_unittest.cc
index c81fc0f..d549b2f 100644
--- a/net/ftp/ftp_network_transaction_unittest.cc
+++ b/net/ftp/ftp_network_transaction_unittest.cc
@@ -5,9 +5,8 @@
#include "net/ftp/ftp_network_transaction.h"
#include "base/ref_counted.h"
-#include "net/base/host_resolver.h"
-#include "net/base/host_resolver_unittest.h"
#include "net/base/io_buffer.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/test_completion_callback.h"
#include "net/ftp/ftp_network_session.h"
#include "net/ftp/ftp_request_info.h"
@@ -237,7 +236,8 @@ class FtpMockControlSocketFileDownloadRetrFail
class FtpNetworkTransactionTest : public PlatformTest {
public:
FtpNetworkTransactionTest()
- : session_(new FtpNetworkSession(new HostResolver)),
+ : host_resolver_(new MockHostResolver),
+ session_(new FtpNetworkSession(host_resolver_)),
transaction_(session_.get(), &mock_socket_factory_) {
}
@@ -286,6 +286,7 @@ class FtpNetworkTransactionTest : public PlatformTest {
ExecuteTransaction(ctrl_socket, request, expected_result);
}
+ scoped_refptr<MockHostResolver> host_resolver_;
scoped_refptr<FtpNetworkSession> session_;
MockClientSocketFactory mock_socket_factory_;
FtpNetworkTransaction transaction_;
@@ -294,9 +295,7 @@ class FtpNetworkTransactionTest : public PlatformTest {
TEST_F(FtpNetworkTransactionTest, FailedLookup) {
FtpRequestInfo request_info = GetRequestInfo("ftp://badhost");
- scoped_refptr<RuleBasedHostMapper> mapper(new RuleBasedHostMapper());
- mapper->AddSimulatedFailure("badhost");
- ScopedHostMapper scoped_mapper(mapper.get());
+ host_resolver_->rules()->AddSimulatedFailure("badhost");
ASSERT_EQ(ERR_IO_PENDING, transaction_.Start(&request_info, &callback_));
EXPECT_EQ(ERR_FAILED, callback_.WaitForResult());
}
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 9fd35ea..b61ca3d 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/host_resolver.h"
+#include "net/base/mock_host_resolver.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_transaction_unittest.h"
#include "net/proxy/proxy_service.h"
@@ -16,7 +16,7 @@ class HttpNetworkLayerTest : public PlatformTest {
TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull());
net::HttpNetworkLayer factory(
- NULL, new net::HostResolver, proxy_service.get());
+ NULL, new net::MockHostResolver, proxy_service.get());
scoped_ptr<net::HttpTransaction> trans(factory.CreateTransaction());
}
@@ -24,7 +24,7 @@ TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
TEST_F(HttpNetworkLayerTest, Suspend) {
scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull());
net::HttpNetworkLayer factory(
- NULL, new net::HostResolver, proxy_service.get());
+ NULL, new net::MockHostResolver, proxy_service.get());
scoped_ptr<net::HttpTransaction> trans(factory.CreateTransaction());
trans.reset();
@@ -56,7 +56,7 @@ TEST_F(HttpNetworkLayerTest, GET) {
mock_socket_factory.AddMockSocket(&data);
scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull());
- net::HttpNetworkLayer factory(&mock_socket_factory, new net::HostResolver,
+ net::HttpNetworkLayer factory(&mock_socket_factory, new net::MockHostResolver,
proxy_service.get());
TestCompletionCallback callback;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 74764a5..c1510a1 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -6,7 +6,7 @@
#include "base/compiler_specific.h"
#include "net/base/completion_callback.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/ssl_info.h"
#include "net/base/test_completion_callback.h"
#include "net/base/upload_data.h"
@@ -35,14 +35,14 @@ ProxyService* CreateNullProxyService() {
class SessionDependencies {
public:
// Default set of dependencies -- "null" proxy service.
- SessionDependencies() : host_resolver(new HostResolver),
+ SessionDependencies() : host_resolver(new MockHostResolver),
proxy_service(CreateNullProxyService()) {}
// Custom proxy service dependency.
explicit SessionDependencies(ProxyService* proxy_service)
- : host_resolver(new HostResolver), proxy_service(proxy_service) {}
+ : host_resolver(new MockHostResolver), proxy_service(proxy_service) {}
- scoped_refptr<HostResolver> host_resolver;
+ scoped_refptr<MockHostResolver> host_resolver;
scoped_ptr<ProxyService> proxy_service;
MockClientSocketFactory socket_factory;
};
@@ -3351,12 +3351,11 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForProxyConnections) {
}
TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
- scoped_refptr<RuleBasedHostMapper> host_mapper(new RuleBasedHostMapper());
- ScopedHostMapper scoped_host_mapper(host_mapper.get());
- host_mapper->AddSimulatedFailure("*");
-
SessionDependencies session_deps(
CreateFixedProxyService("myproxy:70;foobar:80"));
+
+ session_deps.host_resolver->rules()->AddSimulatedFailure("*");
+
scoped_ptr<HttpTransaction> trans(
new HttpNetworkTransaction(
CreateSession(&session_deps),
@@ -3457,6 +3456,10 @@ TEST_F(HttpNetworkTransactionTest, ResolveMadeWithReferrer) {
// host cache is bypassed.
TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh) {
SessionDependencies session_deps;
+
+ // Enable caching in the mock host resolver (it is off by default).
+ session_deps.host_resolver->Reset(NULL, 100, 60000);
+
scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(
CreateSession(&session_deps), &session_deps.socket_factory));
@@ -3473,14 +3476,12 @@ TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh) {
rv = session_deps.host_resolver->Resolve(
HostResolver::RequestInfo("www.google.com", 80), &addrlist,
&resolve_callback, NULL);
- EXPECT_EQ(OK, rv);
+ ASSERT_EQ(OK, rv);
// Inject a failure the next time that "www.google.com" is resolved. This way
// we can tell if the next lookup hit the cache, or the "network".
// (cache --> success, "network" --> failure).
- scoped_refptr<RuleBasedHostMapper> host_mapper(new RuleBasedHostMapper());
- ScopedHostMapper scoped_host_mapper(host_mapper.get());
- host_mapper->AddSimulatedFailure("www.google.com");
+ session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com");
// Connect up a mock socket which will fail with ERR_UNEXPECTED during the
// first read -- this won't be reached as the host resolution will fail first.
diff --git a/net/net.gyp b/net/net.gyp
index 82b2e63..4f97ec9 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -75,6 +75,10 @@
'base/host_cache.h',
'base/host_resolver.cc',
'base/host_resolver.h',
+ 'base/host_resolver_impl.cc',
+ 'base/host_resolver_impl.h',
+ 'base/host_resolver_proc.cc',
+ 'base/host_resolver_proc.h',
'base/io_buffer.cc',
'base/io_buffer.h',
'base/listen_socket.cc',
@@ -85,6 +89,9 @@
'base/mime_sniffer.h',
'base/mime_util.cc',
'base/mime_util.h',
+ # TODO(eroman): move this into its own test-support target.
+ 'base/mock_host_resolver.cc',
+ 'base/mock_host_resolver.h',
'base/net_error_list.h',
'base/net_errors.cc',
'base/net_errors.h',
@@ -434,8 +441,7 @@
'base/force_tls_state_unittest.cc',
'base/gzip_filter_unittest.cc',
'base/host_cache_unittest.cc',
- 'base/host_resolver_unittest.cc',
- 'base/host_resolver_unittest.h',
+ 'base/host_resolver_impl_unittest.cc',
'base/listen_socket_unittest.cc',
'base/listen_socket_unittest.h',
'base/mime_sniffer_unittest.cc',
diff --git a/net/proxy/proxy_resolver_perftest.cc b/net/proxy/proxy_resolver_perftest.cc
index 22f2350..7c74e72 100644
--- a/net/proxy/proxy_resolver_perftest.cc
+++ b/net/proxy/proxy_resolver_perftest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/perftimer.h"
+#include "net/base/mock_host_resolver.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "net/url_request/url_request_unittest.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -186,7 +187,8 @@ TEST(ProxyResolverPerfTest, ProxyResolverMac) {
TEST(ProxyResolverPerfTest, ProxyResolverV8) {
net::ProxyResolverV8::JSBindings* js_bindings =
- net::ProxyResolverV8::CreateDefaultBindings(new net::HostResolver, NULL);
+ net::ProxyResolverV8::CreateDefaultBindings(
+ new net::MockHostResolver, NULL);
net::ProxyResolverV8 resolver(js_bindings);
PacPerfSuiteRunner runner(&resolver, "ProxyResolverV8");
diff --git a/net/proxy/proxy_resolver_v8.h b/net/proxy/proxy_resolver_v8.h
index 3bf2bec..6fbc968 100644
--- a/net/proxy/proxy_resolver_v8.h
+++ b/net/proxy/proxy_resolver_v8.h
@@ -56,7 +56,7 @@ class ProxyResolverV8 : public ProxyResolver {
// Creates a default javascript bindings implementation that will:
// - Send script error messages to LOG(INFO)
// - Send script alert()s to LOG(INFO)
- // - Use the provided host mapper to service dnsResolve().
+ // - Use the provided host resolver to service dnsResolve().
//
// For clients that need more control (for example, sending the script output
// to a UI widget), use the ProxyResolverV8(JSBindings*) and specify your
diff --git a/net/proxy/proxy_resolver_v8_unittest.cc b/net/proxy/proxy_resolver_v8_unittest.cc
index 7fab7d7..86544d5 100644
--- a/net/proxy/proxy_resolver_v8_unittest.cc
+++ b/net/proxy/proxy_resolver_v8_unittest.cc
@@ -6,7 +6,7 @@
#include "base/string_util.h"
#include "base/path_service.h"
#include "googleurl/src/gurl.h"
-#include "net/base/host_resolver.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_resolver_v8.h"
#include "net/proxy/proxy_info.h"
@@ -379,7 +379,8 @@ TEST(ProxyResolverV8Test, V8Bindings) {
TEST(ProxyResolverV8DefaultBindingsTest, DnsResolve) {
// Get a hold of a DefaultJSBindings* (it is a hidden impl class).
scoped_ptr<net::ProxyResolverV8::JSBindings> bindings(
- net::ProxyResolverV8::CreateDefaultBindings(new net::HostResolver, NULL));
+ net::ProxyResolverV8::CreateDefaultBindings(
+ new net::MockHostResolver, NULL));
// Considered an error.
EXPECT_EQ("", bindings->DnsResolve(""));
@@ -411,7 +412,7 @@ TEST(ProxyResolverV8DefaultBindingsTest, DnsResolve) {
// THIS TEST IS CURRENTLY FLAWED.
//
// Since we are running in unit-test mode, the HostResolve is using a
- // mock HostMapper, which will always return 127.0.0.1, without going
+ // mock HostResolverProc, which will always return 127.0.0.1, without going
// through the real codepaths.
//
// It is important that these tests be run with the real thing, since we
@@ -430,10 +431,11 @@ TEST(ProxyResolverV8DefaultBindingsTest, DnsResolve) {
TEST(ProxyResolverV8DefaultBindingsTest, MyIpAddress) {
// Get a hold of a DefaultJSBindings* (it is a hidden impl class).
scoped_ptr<net::ProxyResolverV8::JSBindings> bindings(
- net::ProxyResolverV8::CreateDefaultBindings(new net::HostResolver, NULL));
+ net::ProxyResolverV8::CreateDefaultBindings(
+ new net::MockHostResolver, NULL));
- // Our ip address is always going to be 127.0.0.1, since we are using a
- // mock host mapper when running in unit-test mode.
+ // Our IP address is always going to be 127.0.0.1, since we are using a
+ // mock host resolver.
std::string my_ip_address = bindings->MyIpAddress();
EXPECT_EQ("127.0.0.1", my_ip_address);
diff --git a/net/proxy/proxy_script_fetcher_unittest.cc b/net/proxy/proxy_script_fetcher_unittest.cc
index 8a7cfb5..8a8030b 100644
--- a/net/proxy/proxy_script_fetcher_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_unittest.cc
@@ -30,7 +30,7 @@ class RequestContext : public URLRequestContext {
public:
RequestContext() {
net::ProxyConfig no_proxy;
- host_resolver_ = new net::HostResolver;
+ host_resolver_ = net::CreateSystemHostResolver();
proxy_service_ = net::ProxyService::CreateFixed(no_proxy);
http_transaction_factory_ =
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 8874686..e4faf5b 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -7,7 +7,6 @@
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/scoped_vector.h"
-#include "net/base/host_resolver_unittest.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/client_socket.h"
@@ -793,7 +792,7 @@ TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
ClientSocketPoolBase::EnableLateBindingOfSockets(false);
// Start job 1 (async OK)
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req1(pool_.get(), &request_order_);
int rv = req1.handle.Init("a", ignored_request_info_, 5, &req1);
@@ -1135,7 +1134,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, ReleaseSockets) {
CreatePool(kDefaultMaxSocketsPerGroup);
// Start job 1 (async OK)
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req1(pool_.get(), &request_order_);
int rv = req1.handle.Init("a", ignored_request_info_, 5, &req1);
@@ -1178,7 +1177,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, ReleaseSockets) {
TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingJobCompletionOrder) {
CreatePool(kDefaultMaxSocketsPerGroup);
// First two jobs are async.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
TestSocketRequest req1(pool_.get(), &request_order_);
int rv = req1.handle.Init("a", ignored_request_info_, 5, &req1);
@@ -1189,7 +1188,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingJobCompletionOrder) {
EXPECT_EQ(ERR_IO_PENDING, rv);
// The pending job is sync.
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
+ connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
TestSocketRequest req3(pool_.get(), &request_order_);
rv = req3.handle.Init("a", ignored_request_info_, 5, &req3);
@@ -1208,7 +1207,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingJobCompletionOrder) {
TEST_F(ClientSocketPoolBaseTest_LateBinding, LoadState) {
CreatePool(kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(
- TestConnectJob::kMockAdvancingLoadStateJob);
+ TestConnectJob::kMockAdvancingLoadStateJob);
TestSocketRequest req1(pool_.get(), &request_order_);
int rv = req1.handle.Init("a", ignored_request_info_, 5, &req1);
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index 8f763c4..b225887 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -12,7 +12,7 @@
#include <netdb.h>
#endif
#include "net/base/address_list.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/test_completion_callback.h"
#include "net/base/winsock_init.h"
#include "net/socket/client_socket_factory.h"
@@ -41,10 +41,8 @@ class SOCKS5ClientSocketTest : public PlatformTest {
scoped_ptr<SOCKS5ClientSocket> user_sock_;
AddressList address_list_;
ClientSocket* tcp_sock_;
- ScopedHostMapper host_mapper_;
TestCompletionCallback callback_;
- scoped_refptr<RuleBasedHostMapper> mapper_;
- scoped_refptr<HostResolver> host_resolver_;
+ scoped_refptr<MockHostResolver> host_resolver_;
scoped_ptr<MockSocket> mock_socket_;
private:
@@ -52,7 +50,7 @@ class SOCKS5ClientSocketTest : public PlatformTest {
};
SOCKS5ClientSocketTest::SOCKS5ClientSocketTest()
- : kNwPort(htons(80)), host_resolver_(new HostResolver(0, 0)) {
+ : kNwPort(htons(80)), host_resolver_(new MockHostResolver) {
}
// Set up platform before every test case
@@ -60,14 +58,9 @@ void SOCKS5ClientSocketTest::SetUp() {
PlatformTest::SetUp();
// Resolve the "localhost" AddressList used by the TCP connection to connect.
- scoped_refptr<HostResolver> resolver = new HostResolver();
HostResolver::RequestInfo info("www.socks-proxy.com", 1080);
- int rv = resolver->Resolve(info, &address_list_, NULL, NULL);
+ int rv = host_resolver_->Resolve(info, &address_list_, NULL, NULL);
ASSERT_EQ(OK, rv);
-
- // Create a new host mapping for the duration of this test case only.
- mapper_ = new RuleBasedHostMapper();
- host_mapper_.Init(mapper_);
}
SOCKS5ClientSocket* SOCKS5ClientSocketTest::BuildMockSocket(
@@ -153,7 +146,7 @@ TEST_F(SOCKS5ClientSocketTest, FailedDNS) {
const std::string hostname = "unresolved.ipv4.address";
const char kSOCKS5DomainRequest[] = { 0x05, 0x01, 0x00, 0x03 };
- mapper_->AddSimulatedFailure(hostname.c_str());
+ host_resolver_->rules()->AddSimulatedFailure(hostname.c_str());
std::string request(kSOCKS5DomainRequest,
arraysize(kSOCKS5DomainRequest));
@@ -186,12 +179,11 @@ TEST_F(SOCKS5ClientSocketTest, IPv6Domain) {
const uint8 ipv6_addr[] = { 0x20, 0x01, 0x0d, 0xb8, 0x87, 0x14, 0x3a, 0x90,
0x00, 0x00, 0x00, 0x00, 0x00, 0x000, 0x00, 0x12 };
- mapper_->AddRule(hostname.c_str(), "2001:db8:8714:3a90::12");
+ host_resolver_->rules()->AddRule(hostname, "2001:db8:8714:3a90::12");
AddressList address_list;
- scoped_refptr<HostResolver> resolver = new HostResolver();
HostResolver::RequestInfo info(hostname, 80);
- int rv = resolver->Resolve(info, &address_list, NULL, NULL);
+ int rv = host_resolver_->Resolve(info, &address_list, NULL, NULL);
if (rv != OK || !address_list.head()) {
// This machine does not support IPv6. We skip this test altogether.
// TODO(arindam): create a MockIPv6HostResolver to manually
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index b2e6627..3d7fa85 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -5,8 +5,8 @@
#include "net/socket/socks_client_socket.h"
#include "net/base/address_list.h"
-#include "net/base/host_resolver_unittest.h"
#include "net/base/listen_socket.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/test_completion_callback.h"
#include "net/base/winsock_init.h"
#include "net/socket/client_socket_factory.h"
@@ -36,10 +36,8 @@ class SOCKSClientSocketTest : public PlatformTest {
scoped_ptr<SOCKSClientSocket> user_sock_;
AddressList address_list_;
ClientSocket* tcp_sock_;
- ScopedHostMapper host_mapper_;
TestCompletionCallback callback_;
- scoped_refptr<RuleBasedHostMapper> mapper_;
- scoped_refptr<HostResolver> host_resolver_;
+ scoped_refptr<MockHostResolver> host_resolver_;
scoped_ptr<MockSocket> mock_socket_;
private:
@@ -47,23 +45,12 @@ class SOCKSClientSocketTest : public PlatformTest {
};
SOCKSClientSocketTest::SOCKSClientSocketTest()
- : host_resolver_(new HostResolver(0, 0)) {
+ : host_resolver_(new MockHostResolver) {
}
// Set up platform before every test case
void SOCKSClientSocketTest::SetUp() {
PlatformTest::SetUp();
-
- // Resolve the "localhost" AddressList used by the tcp_connection to connect.
- scoped_refptr<HostResolver> resolver = new HostResolver();
- HostResolver::RequestInfo info("localhost", 1080);
- int rv = resolver->Resolve(info, &address_list_, NULL, NULL);
- ASSERT_EQ(OK, rv);
-
- // Create a new host mapping for the duration of this test case only.
- mapper_ = new RuleBasedHostMapper();
- host_mapper_.Init(mapper_);
- mapper_->AddRule("www.google.com", "127.0.0.1");
}
SOCKSClientSocket* SOCKSClientSocketTest::BuildMockSocket(
@@ -240,7 +227,7 @@ TEST_F(SOCKSClientSocketTest, FailedSocketRead) {
TEST_F(SOCKSClientSocketTest, SOCKS4AFailedDNS) {
const char hostname[] = "unresolved.ipv4.address";
- mapper_->AddSimulatedFailure(hostname);
+ host_resolver_->rules()->AddSimulatedFailure(hostname);
std::string request(kSOCKS4aInitialRequest,
arraysize(kSOCKS4aInitialRequest));
@@ -266,7 +253,7 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AFailedDNS) {
TEST_F(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6) {
const char hostname[] = "an.ipv6.address";
- mapper_->AddRule(hostname, "2001:db8:8714:3a90::12");
+ host_resolver_->rules()->AddRule(hostname, "2001:db8:8714:3a90::12");
std::string request(kSOCKS4aInitialRequest,
arraysize(kSOCKS4aInitialRequest));
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 1d68bd1..e0520e5 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -23,7 +23,8 @@ const net::SSLConfig kDefaultSSLConfig;
class SSLClientSocketTest : public PlatformTest {
public:
SSLClientSocketTest()
- : socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
+ : resolver_(net::CreateSystemHostResolver()),
+ socket_factory_(net::ClientSocketFactory::GetDefaultFactory()) {
}
void StartOKServer() {
@@ -48,6 +49,7 @@ class SSLClientSocketTest : public PlatformTest {
}
protected:
+ scoped_refptr<net::HostResolver> resolver_;
net::ClientSocketFactory* socket_factory_;
net::TestServerLauncher server_;
};
@@ -86,11 +88,10 @@ TEST_F(SSLClientSocketTest, MAYBE_Connect) {
StartOKServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver->Resolve(info, &addr, NULL, NULL);
+ int rv = resolver_->Resolve(info, &addr, NULL, NULL);
EXPECT_EQ(net::OK, rv);
net::ClientSocket *transport = new net::TCPClientSocket(addr);
@@ -124,11 +125,10 @@ TEST_F(SSLClientSocketTest, MAYBE_ConnectExpired) {
StartExpiredServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kHostName, server_.kBadHTTPSPort);
- int rv = resolver->Resolve(info, &addr, NULL, NULL);
+ int rv = resolver_->Resolve(info, &addr, NULL, NULL);
EXPECT_EQ(net::OK, rv);
net::ClientSocket *transport = new net::TCPClientSocket(addr);
@@ -161,12 +161,11 @@ TEST_F(SSLClientSocketTest, MAYBE_ConnectMismatched) {
StartMismatchedServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kMismatchedHostName,
server_.kOKHTTPSPort);
- int rv = resolver->Resolve(info, &addr, NULL, NULL);
+ int rv = resolver_->Resolve(info, &addr, NULL, NULL);
EXPECT_EQ(net::OK, rv);
net::ClientSocket *transport = new net::TCPClientSocket(addr);
@@ -204,11 +203,10 @@ TEST_F(SSLClientSocketTest, MAYBE_Read) {
StartOKServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver->Resolve(info, &addr, &callback, NULL);
+ int rv = resolver_->Resolve(info, &addr, &callback, NULL);
EXPECT_EQ(net::ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
@@ -265,11 +263,10 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_SmallChunks) {
StartOKServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver->Resolve(info, &addr, NULL, NULL);
+ int rv = resolver_->Resolve(info, &addr, NULL, NULL);
EXPECT_EQ(net::OK, rv);
net::ClientSocket *transport = new net::TCPClientSocket(addr);
@@ -321,11 +318,10 @@ TEST_F(SSLClientSocketTest, MAYBE_Read_Interrupted) {
StartOKServer();
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
TestCompletionCallback callback;
net::HostResolver::RequestInfo info(server_.kHostName, server_.kOKHTTPSPort);
- int rv = resolver->Resolve(info, &addr, NULL, NULL);
+ int rv = resolver_->Resolve(info, &addr, NULL, NULL);
EXPECT_EQ(net::OK, rv);
net::ClientSocket *transport = new net::TCPClientSocket(addr);
diff --git a/net/socket/ssl_test_util.cc b/net/socket/ssl_test_util.cc
index 0f012f5..1acc0b5 100644
--- a/net/socket/ssl_test_util.cc
+++ b/net/socket/ssl_test_util.cc
@@ -246,7 +246,7 @@ bool TestServerLauncher::WaitToStart(const std::string& host_name, int port) {
// Verify that the webserver is actually started.
// Otherwise tests can fail if they run faster than Python can start.
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> resolver(net::CreateSystemHostResolver());
net::HostResolver::RequestInfo info(host_name, port);
int rv = resolver->Resolve(info, &addr, NULL, NULL);
if (rv != net::OK)
diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc
index 5d9e630..b5cce2c 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -6,7 +6,7 @@
#include "base/compiler_specific.h"
#include "base/message_loop.h"
-#include "net/base/host_resolver_unittest.h"
+#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/client_socket.h"
@@ -224,14 +224,16 @@ int TestSocketRequest::completion_count = 0;
class TCPClientSocketPoolTest : public testing::Test {
protected:
TCPClientSocketPoolTest()
- : pool_(new TCPClientSocketPool(kMaxSocketsPerGroup,
- new HostResolver,
- &client_socket_factory_)) {}
+ : host_resolver_(new MockHostResolver),
+ pool_(new TCPClientSocketPool(kMaxSocketsPerGroup,
+ host_resolver_,
+ &client_socket_factory_)) {
+ // We enable caching on the mock host-resolver (it is off by default),
+ // because some of the tests in this file expect it.
+ host_resolver_->Reset(NULL, 100, 60000);
+ }
virtual void SetUp() {
- RuleBasedHostMapper *host_mapper = new RuleBasedHostMapper();
- host_mapper->AddRule("*", "127.0.0.1");
- scoped_host_mapper_.Init(host_mapper);
TestSocketRequest::completion_count = 0;
}
@@ -241,7 +243,7 @@ class TCPClientSocketPoolTest : public testing::Test {
MessageLoop::current()->RunAllPending();
}
- ScopedHostMapper scoped_host_mapper_;
+ scoped_refptr<MockHostResolver> host_resolver_;
MockClientSocketFactory client_socket_factory_;
scoped_refptr<ClientSocketPool> pool_;
std::vector<TestSocketRequest*> request_order_;
@@ -264,9 +266,7 @@ TEST_F(TCPClientSocketPoolTest, Basic) {
}
TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) {
- RuleBasedHostMapper* host_mapper = new RuleBasedHostMapper;
- host_mapper->AddSimulatedFailure("unresolvable.host.name");
- ScopedHostMapper scoped_host_mapper(host_mapper);
+ host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name");
TestSocketRequest req(pool_.get(), &request_order_);
HostResolver::RequestInfo info("unresolvable.host.name", 80);
EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req));
diff --git a/net/socket/tcp_client_socket_unittest.cc b/net/socket/tcp_client_socket_unittest.cc
index 91b0e57..6d14694 100644
--- a/net/socket/tcp_client_socket_unittest.cc
+++ b/net/socket/tcp_client_socket_unittest.cc
@@ -86,7 +86,7 @@ void TCPClientSocketTest::SetUp() {
listen_port_ = port;
AddressList addr;
- scoped_refptr<HostResolver> resolver(new HostResolver);
+ scoped_refptr<HostResolver> resolver(CreateSystemHostResolver());
HostResolver::RequestInfo info("localhost", listen_port_);
int rv = resolver->Resolve(info, &addr, NULL, NULL);
CHECK(rv == OK);
diff --git a/net/socket/tcp_pinger_unittest.cc b/net/socket/tcp_pinger_unittest.cc
index c807007..b1e678f 100644
--- a/net/socket/tcp_pinger_unittest.cc
+++ b/net/socket/tcp_pinger_unittest.cc
@@ -65,7 +65,7 @@ void TCPPingerTest::SetUp() {
TEST_F(TCPPingerTest, Ping) {
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> resolver(net::CreateSystemHostResolver());
net::HostResolver::RequestInfo info("localhost", listen_port_);
int rv = resolver->Resolve(info, &addr, NULL, NULL);
@@ -78,7 +78,7 @@ TEST_F(TCPPingerTest, Ping) {
TEST_F(TCPPingerTest, PingFail) {
net::AddressList addr;
- scoped_refptr<net::HostResolver> resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> resolver(net::CreateSystemHostResolver());
// "Kill" "server"
listen_sock_ = NULL;
diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc
index 783c91d..63083c4 100644
--- a/net/tools/fetch/fetch_client.cc
+++ b/net/tools/fetch/fetch_client.cc
@@ -127,7 +127,9 @@ int main(int argc, char**argv) {
// Do work here.
MessageLoop loop;
- scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver);
+ scoped_refptr<net::HostResolver> host_resolver(
+ net::CreateSystemHostResolver());
+
scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull());
net::HttpTransactionFactory* factory = NULL;
if (use_cache) {
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 220d7e0..2aaac0a 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -45,7 +45,7 @@ namespace {
class URLRequestHttpCacheContext : public URLRequestContext {
public:
URLRequestHttpCacheContext() {
- host_resolver_ = new net::HostResolver;
+ host_resolver_ = net::CreateSystemHostResolver();
proxy_service_ = net::ProxyService::CreateNull();
http_transaction_factory_ =
new net::HttpCache(
diff --git a/net/url_request/url_request_unittest.h b/net/url_request/url_request_unittest.h
index a08d776..61a1712 100644
--- a/net/url_request/url_request_unittest.h
+++ b/net/url_request/url_request_unittest.h
@@ -43,7 +43,7 @@ using base::TimeDelta;
class TestURLRequestContext : public URLRequestContext {
public:
TestURLRequestContext() {
- host_resolver_ = new net::HostResolver;
+ host_resolver_ = net::CreateSystemHostResolver();
proxy_service_ = net::ProxyService::CreateNull();
http_transaction_factory_ =
net::HttpNetworkLayer::CreateFactory(host_resolver_,
@@ -51,7 +51,7 @@ class TestURLRequestContext : public URLRequestContext {
}
explicit TestURLRequestContext(const std::string& proxy) {
- host_resolver_ = new net::HostResolver;
+ host_resolver_ = net::CreateSystemHostResolver();
net::ProxyConfig proxy_config;
proxy_config.proxy_rules.ParseFromString(proxy);
proxy_service_ = net::ProxyService::CreateFixed(proxy_config);
diff --git a/webkit/tools/test_shell/test_shell_request_context.cc b/webkit/tools/test_shell/test_shell_request_context.cc
index cd0f31a..1d1c11c 100644
--- a/webkit/tools/test_shell/test_shell_request_context.cc
+++ b/webkit/tools/test_shell/test_shell_request_context.cc
@@ -45,7 +45,7 @@ void TestShellRequestContext::Init(
// issues.
no_proxy = true;
#endif
- host_resolver_ = new net::HostResolver();
+ host_resolver_ = net::CreateSystemHostResolver();
proxy_service_ = net::ProxyService::Create(no_proxy ? &proxy_config : NULL,
false, NULL, NULL);