summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/host_resolver.h8
-rw-r--r--net/base/host_resolver_impl.cc131
-rw-r--r--net/base/host_resolver_impl.h29
-rw-r--r--net/base/host_resolver_impl_unittest.cc309
-rw-r--r--net/base/net_log_event_type_list.h3
-rw-r--r--net/dns/dns_client.cc58
-rw-r--r--net/dns/dns_client.h40
-rw-r--r--net/dns/dns_test_util.cc166
-rw-r--r--net/dns/dns_test_util.h21
-rw-r--r--net/dns/dns_transaction_unittest.cc2
-rw-r--r--net/net.gyp3
11 files changed, 662 insertions, 108 deletions
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index e375961..a282701 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -132,10 +132,10 @@ class NET_EXPORT HostResolver {
RequestHandle* out_req,
const BoundNetLog& net_log) = 0;
- // Resolves the given hostname (or IP address literal) out of cache
- // only. This is guaranteed to complete synchronously. This acts like
- // |Resolve()| if the hostname is IP literal or cached value exists.
- // Otherwise, ERR_DNS_CACHE_MISS is returned.
+ // Resolves the given hostname (or IP address literal) out of cache or HOSTS
+ // file (if enabled) only. This is guaranteed to complete synchronously.
+ // This acts like |Resolve()| if the hostname is IP literal, or cached value
+ // or HOSTS entry exists. Otherwise, ERR_DNS_CACHE_MISS is returned.
virtual int ResolveFromCache(const RequestInfo& info,
AddressList* addresses,
const BoundNetLog& net_log) = 0;
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index ecbbd58..2a51153 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -24,7 +24,6 @@
#include "base/message_loop_proxy.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/string_util.h"
#include "base/threading/worker_pool.h"
@@ -40,12 +39,11 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/dns/dns_client.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_response.h"
-#include "net/dns/dns_session.h"
#include "net/dns/dns_transaction.h"
-#include "net/socket/client_socket_factory.h"
#if defined(OS_WIN)
#include "net/base/winsock_init.h"
@@ -755,7 +753,7 @@ class HostResolverImpl::ProcTask
DNS_HISTOGRAM("DNS.ResolveSpeculativeSuccess", duration);
}
- // Log DNS lookups based on address_family. This will help us determine
+ // Log DNS lookups based on |address_family|. This will help us determine
// if IPv4 or IPv4/6 lookups are faster or slower.
switch(key_.address_family) {
case ADDRESS_FAMILY_IPV4:
@@ -776,7 +774,7 @@ class HostResolverImpl::ProcTask
category = RESOLVE_SPECULATIVE_FAIL;
DNS_HISTOGRAM("DNS.ResolveSpeculativeFail", duration);
}
- // Log DNS lookups based on address_family. This will help us determine
+ // Log DNS lookups based on |address_family|. This will help us determine
// if IPv4 or IPv4/6 lookups are faster or slower.
switch(key_.address_family) {
case ADDRESS_FAMILY_IPV4:
@@ -1205,6 +1203,21 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
base::TimeDelta());
}
+ // Attempts to serve the job from HOSTS. Returns true if succeeded and
+ // this Job was destroyed.
+ bool ServeFromHosts() {
+ DCHECK_GT(num_active_requests(), 0u);
+ AddressList addr_list;
+ if (resolver_->ServeFromHosts(key(),
+ requests_.front()->info(),
+ &addr_list)) {
+ // This will destroy the Job.
+ CompleteRequests(OK, addr_list, base::TimeDelta());
+ return true;
+ }
+ return false;
+ }
+
private:
RequestPriority priority() const {
return priority_tracker_.highest_priority();
@@ -1231,7 +1244,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL);
// Job::Start must not complete synchronously.
- if (resolver_->dns_transaction_factory_.get()) {
+ if (resolver_->HaveDnsConfig()) {
StartDnsTask();
} else {
StartProcTask();
@@ -1270,8 +1283,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
}
void StartDnsTask() {
+ DCHECK(resolver_->HaveDnsConfig());
dns_task_.reset(new DnsTask(
- resolver_->dns_transaction_factory_.get(),
+ resolver_->dns_client_->GetTransactionFactory(),
key_,
base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)),
net_log_));
@@ -1292,6 +1306,10 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
if (net_error != OK) {
dns_task_.reset();
+
+ // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so.
+ // http://crbug.com/117655
+
// TODO(szym): Some net errors indicate lack of connectivity. Starting
// ProcTask in that case is a waste of time.
StartProcTask();
@@ -1344,9 +1362,11 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
net_error);
+ DCHECK(!requests_.empty());
+
// We are the only consumer of |list|, so we can safely change the port
// without copy-on-write. This pays off, when job has only one request.
- if (net_error == OK && !requests_.empty())
+ if (net_error == OK)
MutableSetPort(requests_.front()->info().port(), &list);
if ((net_error != ERR_ABORTED) &&
@@ -1424,6 +1444,7 @@ HostResolverImpl::HostResolverImpl(
max_queued_jobs_(job_limits.total_jobs * 100u),
proc_params_(proc_params),
default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
+ dns_client_(NULL),
dns_config_service_(dns_config_service.Pass()),
ipv6_probe_monitoring_(false),
additional_resolver_flags_(0),
@@ -1452,8 +1473,10 @@ HostResolverImpl::HostResolverImpl(
NetworkChangeNotifier::AddDNSObserver(this);
#endif
- if (dns_config_service_.get())
+ if (dns_config_service_.get()) {
dns_config_service_->AddObserver(this);
+ dns_client_ = DnsClient::CreateClient(net_log_);
+ }
}
HostResolverImpl::~HostResolverImpl() {
@@ -1552,9 +1575,17 @@ int HostResolverImpl::ResolveHelper(const Key& key,
int net_error = ERR_UNEXPECTED;
if (ResolveAsIP(key, info, &net_error, addresses))
return net_error;
- net_error = ERR_DNS_CACHE_MISS;
- ServeFromCache(key, info, request_net_log, &net_error, addresses);
- return net_error;
+ if (ServeFromCache(key, info, &net_error, addresses)) {
+ request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
+ return net_error;
+ }
+ // TODO(szym): Do not do this if nsswitch.conf instructs not to.
+ // http://crbug.com/117655
+ if (ServeFromHosts(key, info, addresses)) {
+ request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT, NULL);
+ return OK;
+ }
+ return ERR_DNS_CACHE_MISS;
}
int HostResolverImpl::ResolveFromCache(const RequestInfo& info,
@@ -1637,7 +1668,6 @@ bool HostResolverImpl::ResolveAsIP(const Key& key,
bool HostResolverImpl::ServeFromCache(const Key& key,
const RequestInfo& info,
- const BoundNetLog& request_net_log,
int* net_error,
AddressList* addresses) {
DCHECK(addresses);
@@ -1650,13 +1680,43 @@ bool HostResolverImpl::ServeFromCache(const Key& key,
if (!cache_entry)
return false;
- request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL);
+
*net_error = cache_entry->error;
if (*net_error == OK)
*addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port());
return true;
}
+bool HostResolverImpl::ServeFromHosts(const Key& key,
+ const RequestInfo& info,
+ AddressList* addresses) {
+ DCHECK(addresses);
+ if (!HaveDnsConfig())
+ return false;
+
+ // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
+ // (glibc and c-ares) return the first matching line. We have more
+ // flexibility, but lose implicit ordering.
+ // TODO(szym) http://crbug.com/117850
+ const DnsHosts& hosts = dns_client_->GetConfig()->hosts;
+ DnsHosts::const_iterator it = hosts.find(
+ DnsHostsKey(key.hostname,
+ key.address_family == ADDRESS_FAMILY_UNSPECIFIED ?
+ ADDRESS_FAMILY_IPV4 : key.address_family));
+
+ if (it == hosts.end()) {
+ if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED)
+ return false;
+
+ it = hosts.find(DnsHostsKey(key.hostname, ADDRESS_FAMILY_IPV6));
+ if (it == hosts.end())
+ return false;
+ }
+
+ *addresses = AddressList::CreateFromIPAddress(it->second, info.port());
+ return true;
+}
+
void HostResolverImpl::CacheResult(const Key& key,
int net_error,
const AddressList& addr_list,
@@ -1734,6 +1794,24 @@ void HostResolverImpl::AbortAllInProgressJobs() {
}
}
+void HostResolverImpl::TryServingAllJobsFromHosts() {
+ if (!HaveDnsConfig())
+ return;
+
+ // TODO(szym): Do not do this if nsswitch.conf instructs not to.
+ // http://crbug.com/117655
+
+ // Life check to bail once |this| is deleted.
+ base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
+
+ for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) {
+ Job* job = it->second;
+ ++it;
+ // This could remove |job| from |jobs_|, but iterator will remain valid.
+ job->ServeFromHosts();
+ }
+}
+
void HostResolverImpl::OnIPAddressChanged() {
if (cache_.get())
cache_->clear();
@@ -1769,20 +1847,25 @@ void HostResolverImpl::OnDNSChanged(unsigned detail) {
void HostResolverImpl::OnConfigChanged(const DnsConfig& dns_config) {
// We want a new factory in place, before we Abort running Jobs, so that the
// newly started jobs use the new factory.
- bool had_factory = (dns_transaction_factory_.get() != NULL);
- if (dns_config.IsValid()) {
- dns_transaction_factory_ = DnsTransactionFactory::CreateFactory(
- new DnsSession(dns_config,
- ClientSocketFactory::GetDefaultFactory(),
- base::Bind(&base::RandInt),
- net_log_));
- } else {
- dns_transaction_factory_.reset();
- }
+ DCHECK(dns_client_.get());
+
+ // Life check to bail once |this| is deleted.
+ base::WeakPtr<HostResolverImpl> self = AsWeakPtr();
+
+ bool had_factory = (dns_client_->GetConfig() != NULL);
+ dns_client_->SetConfig(dns_config);
+
// Don't Abort running Jobs unless they were running on DnsTransaction.
// TODO(szym): This will change once http://crbug.com/114827 is fixed.
if (had_factory)
OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS);
+
+ if (self && dns_config.IsValid())
+ TryServingAllJobsFromHosts();
+}
+
+bool HostResolverImpl::HaveDnsConfig() const {
+ return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL);
}
} // namespace net
diff --git a/net/base/host_resolver_impl.h b/net/base/host_resolver_impl.h
index dd8c70e..7b0900f 100644
--- a/net/base/host_resolver_impl.h
+++ b/net/base/host_resolver_impl.h
@@ -23,12 +23,11 @@
#include "net/base/net_log.h"
#include "net/base/network_change_notifier.h"
#include "net/base/prioritized_dispatcher.h"
+#include "net/dns/dns_client.h"
#include "net/dns/dns_config_service.h"
namespace net {
-class DnsTransactionFactory;
-
// For each hostname that is requested, HostResolver creates a
// HostResolverImpl::Job. When this job gets dispatched it creates a ProcTask
// which runs the given HostResolverProc on a WorkerPool thread. If requests for
@@ -154,6 +153,8 @@ class NET_EXPORT HostResolverImpl
}
private:
+ FRIEND_TEST_ALL_PREFIXES(HostResolverImplTest, DnsTask);
+ FRIEND_TEST_ALL_PREFIXES(HostResolverImplTest, ServeFromHosts);
class Job;
class ProcTask;
class IPv6ProbeJob;
@@ -163,10 +164,14 @@ class NET_EXPORT HostResolverImpl
typedef std::map<Key, Job*> JobMap;
typedef std::vector<Request*> RequestsList;
+ void set_dns_client_for_tests(scoped_ptr<DnsClient> client) {
+ dns_client_ = client.Pass();
+ }
+
// Helper used by |Resolve()| and |ResolveFromCache()|. Performs IP
- // literal and cache lookup, returns OK if successful,
+ // literal, cache and HOSTS lookup (if enabled), returns OK if successful,
// ERR_NAME_NOT_RESOLVED if either hostname is invalid or IP literal is
- // incompatible, ERR_DNS_CACHE_MISS if entry was not found in cache.
+ // incompatible, ERR_DNS_CACHE_MISS if entry was not found in cache and HOSTS.
int ResolveHelper(const Key& key,
const RequestInfo& info,
AddressList* addresses,
@@ -184,10 +189,15 @@ class NET_EXPORT HostResolverImpl
// if it is a positive entry.
bool ServeFromCache(const Key& key,
const RequestInfo& info,
- const BoundNetLog& request_net_log,
int* net_error,
AddressList* addresses);
+ // If |key| is not found in the HOSTS file or no HOSTS file known, returns
+ // false, otherwise returns true and fills |addresses|.
+ bool ServeFromHosts(const Key& key,
+ const RequestInfo& info,
+ AddressList* addresses);
+
// Notifies IPv6ProbeJob not to call back, and discard reference to the job.
void DiscardIPv6ProbeJob();
@@ -212,6 +222,9 @@ class NET_EXPORT HostResolverImpl
// Might start new jobs.
void AbortAllInProgressJobs();
+ // Attempts to serve each Job in |jobs_| from the HOSTS file.
+ void TryServingAllJobsFromHosts();
+
// NetworkChangeNotifier::IPAddressObserver:
virtual void OnIPAddressChanged() OVERRIDE;
@@ -221,6 +234,9 @@ class NET_EXPORT HostResolverImpl
// DnsConfigService::Observer:
virtual void OnConfigChanged(const DnsConfig& dns_config) OVERRIDE;
+ // True if have fully configured DNS client.
+ bool HaveDnsConfig() const;
+
// Cache of host resolution results.
scoped_ptr<HostCache> cache_;
@@ -236,11 +252,10 @@ class NET_EXPORT HostResolverImpl
// Parameters for ProcTask.
ProcTaskParams proc_params_;
- scoped_ptr<DnsTransactionFactory> dns_transaction_factory_;
-
// Address family to use when the request doesn't specify one.
AddressFamily default_address_family_;
+ scoped_ptr<DnsClient> dns_client_;
scoped_ptr<DnsConfigService> dns_config_service_;
// Indicate if probing is done after each network change event to set address
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index b99dbf7..7e9606e 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -28,15 +28,18 @@
#include "net/base/net_util.h"
#include "net/base/sys_addrinfo.h"
#include "net/base/test_completion_callback.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
+namespace {
using base::TimeDelta;
using base::TimeTicks;
-static const size_t kMaxJobs = 10u;
-static const size_t kMaxRetryAttempts = 4u;
+const size_t kMaxJobs = 10u;
+const size_t kMaxRetryAttempts = 4u;
PrioritizedDispatcher::Limits DefaultLimits() {
PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, kMaxJobs);
@@ -58,6 +61,17 @@ HostResolverImpl* CreateHostResolverImpl(HostResolverProc* resolver_proc) {
NULL);
}
+HostResolverImpl* CreateHostResolverImplWithDnsConfig(
+ HostResolverProc* resolver_proc,
+ scoped_ptr<DnsConfigService> config_service) {
+ return new HostResolverImpl(
+ HostCache::CreateDefaultCache(),
+ DefaultLimits(),
+ DefaultParams(resolver_proc),
+ config_service.Pass(),
+ NULL);
+}
+
// This HostResolverImpl will only allow 1 outstanding resolve at a time.
HostResolverImpl* CreateSerialHostResolverImpl(
HostResolverProc* resolver_proc) {
@@ -397,6 +411,7 @@ class ResolveRequest {
virtual void OnCompleted(ResolveRequest* resolve) = 0;
};
+ // For asynchronous resolutions.
ResolveRequest(HostResolver* resolver,
const std::string& hostname,
int port,
@@ -412,6 +427,7 @@ class ResolveRequest {
EXPECT_EQ(ERR_IO_PENDING, err);
}
+ // For asynchronous resolutions.
ResolveRequest(HostResolver* resolver,
const HostResolver::RequestInfo& info,
Delegate* delegate)
@@ -421,10 +437,39 @@ class ResolveRequest {
info, &addrlist_,
base::Bind(&ResolveRequest::OnLookupFinished,
base::Unretained(this)),
- &req_, BoundNetLog());
+ &req_, BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, err);
}
+ // For synchronous resolutions.
+ ResolveRequest(HostResolver* resolver,
+ const std::string& hostname,
+ int port)
+ : info_(HostPortPair(hostname, port)),
+ resolver_(resolver),
+ delegate_(NULL) {
+ // Start the request.
+ result_ = resolver->Resolve(
+ info_, &addrlist_,
+ base::Bind(&ResolveRequest::OnLookupFinished, base::Unretained(this)),
+ &req_, BoundNetLog());
+ EXPECT_NE(ERR_IO_PENDING, result_);
+ }
+
+ // For synchronous resolutions.
+ ResolveRequest(HostResolver* resolver,
+ const HostResolver::RequestInfo& info)
+ : info_(info),
+ resolver_(resolver),
+ delegate_(NULL) {
+ // Start the request.
+ result_ = resolver->Resolve(
+ info_, &addrlist_,
+ base::Bind(&ResolveRequest::OnLookupFinished, base::Unretained(this)),
+ &req_, BoundNetLog());
+ EXPECT_NE(ERR_IO_PENDING, result_);
+ }
+
void Cancel() {
resolver_->CancelRequest(req_);
}
@@ -451,6 +496,9 @@ class ResolveRequest {
private:
void OnLookupFinished(int result) {
+ EXPECT_TRUE(delegate_ != NULL);
+ if (delegate_ == NULL)
+ return;
result_ = result;
delegate_->OnCompleted(this);
}
@@ -470,6 +518,7 @@ class ResolveRequest {
DISALLOW_COPY_AND_ASSIGN(ResolveRequest);
};
+// TODO(szym): Make this fixture more useful. http://crbug.com/117830
class HostResolverImplTest : public testing::Test {
public:
HostResolverImplTest()
@@ -491,9 +540,30 @@ class HostResolverImplTest : public testing::Test {
CompletionCallback callback_;
};
+// Returns the first address in |addr_list| in host:port form or empty string if
+// the list is empty.
+std::string FirstAddressToString(const AddressList& addr_list) {
+ const struct addrinfo* ai = addr_list.head();
+ if (!ai)
+ return "";
+ return NetAddressToStringWithPort(ai);
+}
+
+// Returns the number of addresses in |addr_list|.
+unsigned NumberOfAddresses(const AddressList& addr_list) {
+ unsigned count = 0;
+ for (const struct addrinfo* ai = addr_list.head();
+ ai != NULL;
+ ai = ai->ai_next) {
+ ++count;
+ }
+ return count;
+}
+
+} // namespace net
+
TEST_F(HostResolverImplTest, AsynchronousLookup) {
AddressList addrlist;
- const int kPortnum = 80;
scoped_refptr<RuleBasedHostResolverProc> resolver_proc(
new RuleBasedHostResolverProc(NULL));
@@ -502,7 +572,7 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
- HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
int err = host_resolver->Resolve(info, &addrlist, callback_, NULL,
log.bound());
@@ -526,27 +596,19 @@ TEST_F(HostResolverImplTest, AsynchronousLookup) {
EXPECT_TRUE(LogContainsEndEvent(
entries, 1, NetLog::TYPE_HOST_RESOLVER_IMPL));
- const struct addrinfo* ainfo = addrlist.head();
- EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
- EXPECT_EQ(sizeof(struct sockaddr_in), static_cast<size_t>(ainfo->ai_addrlen));
-
- const struct sockaddr* sa = ainfo->ai_addr;
- const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
- EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
- EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
+ EXPECT_EQ("192.168.1.42:80", FirstAddressToString(addrlist));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist));
}
TEST_F(HostResolverImplTest, FailedAsynchronousLookup) {
AddressList addrlist;
- const int kPortnum = 80;
-
scoped_refptr<RuleBasedHostResolverProc> resolver_proc(
new RuleBasedHostResolverProc(NULL));
resolver_proc->AddSimulatedFailure("just.testing");
scoped_ptr<HostResolver> host_resolver(CreateHostResolverImpl(resolver_proc));
- HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
int err = host_resolver->Resolve(info, &addrlist, callback_, NULL,
log.bound());
@@ -590,9 +652,7 @@ TEST_F(HostResolverImplTest, AbortedAsynchronousLookup) {
scoped_ptr<DnsConfigService>(NULL),
&net_log));
AddressList addrlist;
- const int kPortnum = 80;
-
- HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
int err = host_resolver->Resolve(info, &addrlist, callback_, NULL,
log.bound());
EXPECT_EQ(ERR_IO_PENDING, err);
@@ -652,21 +712,14 @@ TEST_F(HostResolverImplTest, NumericIPv4Address) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
AddressList addrlist;
- const int kPortnum = 5555;
TestCompletionCallback callback;
- HostResolver::RequestInfo info(HostPortPair("127.1.2.3", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("127.1.2.3", 5555));
int err = host_resolver->Resolve(info, &addrlist, callback.callback(), NULL,
BoundNetLog());
EXPECT_EQ(OK, err);
- const struct addrinfo* ainfo = addrlist.head();
- EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
- EXPECT_EQ(sizeof(struct sockaddr_in), static_cast<size_t>(ainfo->ai_addrlen));
-
- const struct sockaddr* sa = ainfo->ai_addr;
- const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
- EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
- EXPECT_TRUE(htonl(0x7f010203) == sa_in->sin_addr.s_addr);
+ EXPECT_EQ("127.1.2.3:5555", FirstAddressToString(addrlist));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist));
}
TEST_F(HostResolverImplTest, NumericIPv6Address) {
@@ -679,29 +732,14 @@ TEST_F(HostResolverImplTest, NumericIPv6Address) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
AddressList addrlist;
- const int kPortnum = 5555;
TestCompletionCallback callback;
- HostResolver::RequestInfo info(HostPortPair("2001:db8::1", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("2001:db8::1", 5555));
int err = host_resolver->Resolve(info, &addrlist, callback.callback(), NULL,
BoundNetLog());
EXPECT_EQ(OK, err);
- const struct addrinfo* ainfo = addrlist.head();
- EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
- EXPECT_EQ(sizeof(struct sockaddr_in6),
- static_cast<size_t>(ainfo->ai_addrlen));
-
- const struct sockaddr* sa = ainfo->ai_addr;
- const struct sockaddr_in6* sa_in6 = (const struct sockaddr_in6*) sa;
- EXPECT_TRUE(htons(kPortnum) == sa_in6->sin6_port);
-
- const uint8 expect_addr[] = {
- 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- };
- for (int i = 0; i < 16; i++) {
- EXPECT_EQ(expect_addr[i], sa_in6->sin6_addr.s6_addr[i]);
- }
+ EXPECT_EQ("[2001:db8::1]:5555", FirstAddressToString(addrlist));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist));
}
TEST_F(HostResolverImplTest, EmptyHost) {
@@ -712,9 +750,8 @@ TEST_F(HostResolverImplTest, EmptyHost) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
AddressList addrlist;
- const int kPortnum = 5555;
TestCompletionCallback callback;
- HostResolver::RequestInfo info(HostPortPair("", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("", 5555));
int err = host_resolver->Resolve(info, &addrlist, callback.callback(), NULL,
BoundNetLog());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, err);
@@ -728,10 +765,9 @@ TEST_F(HostResolverImplTest, LongHost) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(resolver_proc));
AddressList addrlist;
- const int kPortnum = 5555;
std::string hostname(4097, 'a');
TestCompletionCallback callback;
- HostResolver::RequestInfo info(HostPortPair(hostname, kPortnum));
+ HostResolver::RequestInfo info(HostPortPair(hostname, 5555));
int err = host_resolver->Resolve(info, &addrlist, callback.callback(), NULL,
BoundNetLog());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, err);
@@ -870,20 +906,30 @@ TEST_F(HostResolverImplTest, CancelMultipleRequests) {
MessageLoop::current()->Run();
}
-// Helper class used by HostResolverImplTest.CanceledRequestsReleaseJobSlots.
+// Delegate which allows to wait for specific number of requests to complete.
+// Used by HostResolverImplTest.CanceledRequestsReleaseJobSlots and .DnsTask.
class CountingDelegate : public ResolveRequest::Delegate {
public:
- CountingDelegate() : num_completions_(0) {}
+ CountingDelegate() : num_completions_(0), awaited_num_completions_(0) {}
virtual void OnCompleted(ResolveRequest* resolve) OVERRIDE {
++num_completions_;
- MessageLoop::current()->Quit();
+ if (num_completions_ == awaited_num_completions_)
+ MessageLoop::current()->Quit();
}
unsigned num_completions() const { return num_completions_; }
+ void WaitForCompletions(unsigned completions) {
+ ASSERT_LT(num_completions_, completions);
+ awaited_num_completions_ = completions;
+ MessageLoop::current()->Run();
+ EXPECT_EQ(completions, num_completions_);
+ }
+
private:
unsigned num_completions_;
+ unsigned awaited_num_completions_;
};
TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
@@ -918,8 +964,7 @@ TEST_F(HostResolverImplTest, CanceledRequestsReleaseJobSlots) {
resolver_proc->SignalAll();
- while (delegate.num_completions() < 2)
- MessageLoop::current()->Run();
+ delegate.WaitForCompletions(2);
EXPECT_EQ(0u, host_resolver->num_running_jobs_for_tests());
}
@@ -1594,9 +1639,12 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) {
// x = length of hostname
// y = ASCII value of hostname[0]
// z = value of address family
- EXPECT_EQ("192.2.104.1", NetAddressToString(addrlist[0].head()));
- EXPECT_EQ("192.2.104.1", NetAddressToString(addrlist[1].head()));
- EXPECT_EQ("192.2.104.2", NetAddressToString(addrlist[2].head()));
+ EXPECT_EQ("192.2.104.1:80", FirstAddressToString(addrlist[0]));
+ EXPECT_EQ("192.2.104.1:80", FirstAddressToString(addrlist[1]));
+ EXPECT_EQ("192.2.104.2:80", FirstAddressToString(addrlist[2]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[0]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[1]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[2]));
}
// This is the exact same test as SetDefaultAddressFamily_IPv4, except the order
@@ -1661,14 +1709,16 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
// x = length of hostname
// y = ASCII value of hostname[0]
// z = value of address family
- EXPECT_EQ("192.2.104.2", NetAddressToString(addrlist[0].head()));
- EXPECT_EQ("192.2.104.2", NetAddressToString(addrlist[1].head()));
- EXPECT_EQ("192.2.104.1", NetAddressToString(addrlist[2].head()));
+ EXPECT_EQ("192.2.104.2:80", FirstAddressToString(addrlist[0]));
+ EXPECT_EQ("192.2.104.2:80", FirstAddressToString(addrlist[1]));
+ EXPECT_EQ("192.2.104.1:80", FirstAddressToString(addrlist[2]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[0]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[1]));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist[2]));
}
TEST_F(HostResolverImplTest, DisallowNonCachedResponses) {
AddressList addrlist;
- const int kPortnum = 80;
scoped_refptr<RuleBasedHostResolverProc> resolver_proc(
new RuleBasedHostResolverProc(NULL));
@@ -1678,7 +1728,7 @@ TEST_F(HostResolverImplTest, DisallowNonCachedResponses) {
CreateHostResolverImpl(resolver_proc));
// First hit will miss the cache.
- HostResolver::RequestInfo info(HostPortPair("just.testing", kPortnum));
+ HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
int err = host_resolver->ResolveFromCache(info, &addrlist, log.bound());
EXPECT_EQ(ERR_DNS_CACHE_MISS, err);
@@ -1695,14 +1745,8 @@ TEST_F(HostResolverImplTest, DisallowNonCachedResponses) {
err = host_resolver->ResolveFromCache(info, &addrlist, log.bound());
EXPECT_EQ(OK, err);
- const struct addrinfo* ainfo = addrlist.head();
- EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next);
- EXPECT_EQ(sizeof(struct sockaddr_in), static_cast<size_t>(ainfo->ai_addrlen));
-
- const struct sockaddr* sa = ainfo->ai_addr;
- const struct sockaddr_in* sa_in = reinterpret_cast<const sockaddr_in*>(sa);
- EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port);
- EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr);
+ EXPECT_EQ("192.168.1.42:80", FirstAddressToString(addrlist));
+ EXPECT_EQ(1u, NumberOfAddresses(addrlist));
}
// Test the retry attempts simulating host resolver proc that takes too long.
@@ -1750,6 +1794,127 @@ TEST_F(HostResolverImplTest, MultipleAttempts) {
EXPECT_EQ(resolver_proc->resolved_attempt_number(), kAttemptNumberToResolve);
}
+DnsConfig CreateValidDnsConfig() {
+ IPAddressNumber dns_ip;
+ bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
+ EXPECT_TRUE(rv);
+
+ DnsConfig config;
+ config.nameservers.push_back(IPEndPoint(dns_ip,
+ dns_protocol::kDefaultPort));
+ EXPECT_TRUE(config.IsValid());
+ return config;
+}
+
+// TODO(szym): Test AbortAllInProgressJobs due to DnsConfig change.
+
// TODO(cbentzel): Test a mix of requests with different HostResolverFlags.
+// Test successful and fallback resolutions in HostResolverImpl::DnsTask.
+TEST_F(HostResolverImplTest, DnsTask) {
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc(
+ new RuleBasedHostResolverProc(NULL));
+ scoped_ptr<HostResolverImpl> host_resolver(CreateHostResolverImpl(
+ resolver_proc));
+
+ resolver_proc->AddRule("er_succeed", "192.168.1.101");
+ resolver_proc->AddRule("nx_succeed", "192.168.1.102");
+ resolver_proc->AddSimulatedFailure("ok_fail");
+ resolver_proc->AddSimulatedFailure("er_fail");
+ resolver_proc->AddSimulatedFailure("nx_fail");
+
+ CountingDelegate delegate;
+
+ // Initially there is no config, so client should not be invoked.
+ ResolveRequest req1(host_resolver.get(), "ok_fail", 80, &delegate);
+
+ delegate.WaitForCompletions(1);
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req1.result());
+
+ host_resolver->set_dns_client_for_tests(
+ CreateMockDnsClient(CreateValidDnsConfig()));
+
+ ResolveRequest req2(host_resolver.get(), "ok_fail", 80, &delegate);
+ ResolveRequest req3(host_resolver.get(), "er_fail", 80, &delegate);
+ ResolveRequest req4(host_resolver.get(), "nx_fail", 80, &delegate);
+ ResolveRequest req5(host_resolver.get(), "er_succeed", 80, &delegate);
+ ResolveRequest req6(host_resolver.get(), "nx_succeed", 80, &delegate);
+
+ delegate.WaitForCompletions(6);
+ EXPECT_EQ(OK, req2.result());
+ // Resolved by MockDnsClient.
+ EXPECT_EQ("127.0.0.1:80", FirstAddressToString(req2.addrlist()));
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req3.result());
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req4.result());
+ EXPECT_EQ(OK, req5.result());
+ EXPECT_EQ("192.168.1.101:80", FirstAddressToString(req5.addrlist()));
+ EXPECT_EQ(OK, req6.result());
+ EXPECT_EQ("192.168.1.102:80", FirstAddressToString(req6.addrlist()));
+}
+
+TEST_F(HostResolverImplTest, ServeFromHosts) {
+ scoped_refptr<RuleBasedHostResolverProc> resolver_proc(
+ new RuleBasedHostResolverProc(NULL));
+ MockDnsConfigService* config_service = new MockDnsConfigService();
+ scoped_ptr<HostResolverImpl> host_resolver(
+ CreateHostResolverImplWithDnsConfig(
+ resolver_proc,
+ scoped_ptr<DnsConfigService>(config_service)));
+
+ resolver_proc->AddSimulatedFailure("*");
+
+ DnsConfig config = CreateValidDnsConfig();
+ host_resolver->set_dns_client_for_tests(CreateMockDnsClient(config));
+
+ CountingDelegate delegate;
+
+ ResolveRequest req1(host_resolver.get(), "er_ipv4", 80, &delegate);
+ delegate.WaitForCompletions(1);
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req1.result());
+
+ IPAddressNumber local_ipv4, local_ipv6;
+ ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &local_ipv4));
+ ASSERT_TRUE(ParseIPLiteralToNumber("::1", &local_ipv6));
+
+ DnsHosts hosts;
+ hosts[DnsHostsKey("er_ipv4", ADDRESS_FAMILY_IPV4)] = local_ipv4;
+ hosts[DnsHostsKey("er_ipv6", ADDRESS_FAMILY_IPV6)] = local_ipv6;
+ hosts[DnsHostsKey("er_both", ADDRESS_FAMILY_IPV4)] = local_ipv4;
+ hosts[DnsHostsKey("er_both", ADDRESS_FAMILY_IPV6)] = local_ipv6;
+
+ config_service->ChangeConfig(config);
+ config_service->ChangeHosts(hosts);
+
+ ResolveRequest req2(host_resolver.get(), "er_ipv4", 80);
+ EXPECT_EQ(OK, req2.result());
+ EXPECT_EQ("127.0.0.1:80", FirstAddressToString(req2.addrlist()));
+
+ ResolveRequest req3(host_resolver.get(), "er_ipv6", 80);
+ EXPECT_EQ(OK, req3.result());
+ EXPECT_EQ("[::1]:80", FirstAddressToString(req3.addrlist()));
+
+ ResolveRequest req4(host_resolver.get(), "er_both", 80);
+ EXPECT_EQ(OK, req4.result());
+ // Either result is satisfactory. http://crbug.com/117850
+ const addrinfo* addr = req4.addrlist().head();
+ if (addr->ai_addrlen == sizeof(struct sockaddr_in))
+ EXPECT_EQ("127.0.0.1", NetAddressToString(addr));
+ else
+ EXPECT_EQ("::1", NetAddressToString(addr));
+
+ // Requests with specified AddressFamily.
+ HostResolver::RequestInfo info(HostPortPair("er_both", 80));
+ info.set_address_family(ADDRESS_FAMILY_IPV4);
+ ResolveRequest req5(host_resolver.get(), info);
+ EXPECT_EQ(OK, req5.result());
+ EXPECT_EQ("127.0.0.1:80", FirstAddressToString(req5.addrlist()));
+ EXPECT_EQ(1u, NumberOfAddresses(req5.addrlist()));
+
+ info.set_address_family(ADDRESS_FAMILY_IPV6);
+ ResolveRequest req6(host_resolver.get(), info);
+ EXPECT_EQ(OK, req6.result());
+ EXPECT_EQ("[::1]:80", FirstAddressToString(req6.addrlist()));
+ EXPECT_EQ(1u, NumberOfAddresses(req6.addrlist()));
+}
+
} // namespace net
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index ceb4a72..68c2b4f 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -62,6 +62,9 @@ EVENT_TYPE(HOST_RESOLVER_IMPL_REQUEST)
// This event is logged when a request is handled by a cache entry.
EVENT_TYPE(HOST_RESOLVER_IMPL_CACHE_HIT)
+// This event is logged when a request is handled by a HOSTS entry.
+EVENT_TYPE(HOST_RESOLVER_IMPL_HOSTS_HIT)
+
// This event is created when a new HostResolverImpl::Job is about to be created
// for a request.
EVENT_TYPE(HOST_RESOLVER_IMPL_CREATE_JOB)
diff --git a/net/dns/dns_client.cc b/net/dns/dns_client.cc
new file mode 100644
index 0000000..5381452
--- /dev/null
+++ b/net/dns/dns_client.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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/dns/dns_client.h"
+
+#include "base/bind.h"
+#include "base/rand_util.h"
+#include "net/base/net_log.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_session.h"
+#include "net/dns/dns_transaction.h"
+#include "net/socket/client_socket_factory.h"
+
+namespace net {
+
+namespace {
+
+class DnsClientImpl : public DnsClient {
+ public:
+ explicit DnsClientImpl(NetLog* net_log) : net_log_(net_log) {}
+
+ virtual void SetConfig(const DnsConfig& config) OVERRIDE {
+ factory_.reset();
+ session_.release();
+ if (config.IsValid()) {
+ session_ = new DnsSession(config,
+ ClientSocketFactory::GetDefaultFactory(),
+ base::Bind(&base::RandInt),
+ net_log_);
+ factory_ = DnsTransactionFactory::CreateFactory(session_);
+ }
+ }
+
+ virtual const DnsConfig* GetConfig() const OVERRIDE {
+ return session_.get() ? &session_->config() : NULL;
+ }
+
+ virtual DnsTransactionFactory* GetTransactionFactory() OVERRIDE {
+ return session_.get() ? factory_.get() : NULL;
+ }
+
+ private:
+ scoped_refptr<DnsSession> session_;
+ scoped_ptr<DnsTransactionFactory> factory_;
+
+ NetLog* net_log_;
+};
+
+} // namespace
+
+// static
+scoped_ptr<DnsClient> DnsClient::CreateClient(NetLog* net_log) {
+ return scoped_ptr<DnsClient>(new DnsClientImpl(net_log));
+}
+
+} // namespace net
+
diff --git a/net/dns/dns_client.h b/net/dns/dns_client.h
new file mode 100644
index 0000000..c5461ec
--- /dev/null
+++ b/net/dns/dns_client.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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_DNS_DNS_CLIENT_H_
+#define NET_DNS_DNS_CLIENT_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+struct DnsConfig;
+class DnsTransactionFactory;
+class NetLog;
+
+// Convenience wrapper allows easy injection of DnsTransaction into
+// HostResolverImpl.
+class NET_EXPORT DnsClient {
+ public:
+ virtual ~DnsClient() {}
+
+ // Creates a new DnsTransactionFactory according to the new |config|.
+ virtual void SetConfig(const DnsConfig& config) = 0;
+
+ // Returns NULL if the current config is not valid.
+ virtual const DnsConfig* GetConfig() const = 0;
+
+ // Returns NULL if the current config is not valid.
+ virtual DnsTransactionFactory* GetTransactionFactory() = 0;
+
+ // Creates default client.
+ static scoped_ptr<DnsClient> CreateClient(NetLog* net_log);
+};
+
+} // namespace net
+
+#endif // NET_DNS_DNS_CLIENT_H_
+
diff --git a/net/dns/dns_test_util.cc b/net/dns/dns_test_util.cc
new file mode 100644
index 0000000..fa1bed1
--- /dev/null
+++ b/net/dns/dns_test_util.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 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/dns/dns_test_util.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop.h"
+#include "base/sys_byteorder.h"
+#include "net/base/big_endian.h"
+#include "net/base/dns_util.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/dns/dns_client.h"
+#include "net/dns/dns_config_service.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_query.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_transaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+
+// A DnsTransaction which responds with loopback to all queries starting with
+// "ok", fails synchronously on all queries starting with "er", and NXDOMAIN to
+// all others.
+class MockTransaction : public DnsTransaction,
+ public base::SupportsWeakPtr<MockTransaction> {
+ public:
+ MockTransaction(const std::string& hostname,
+ uint16 qtype,
+ const DnsTransactionFactory::CallbackType& callback)
+ : hostname_(hostname),
+ qtype_(qtype),
+ callback_(callback),
+ started_(false) {
+ }
+
+ virtual const std::string& GetHostname() const OVERRIDE {
+ return hostname_;
+ }
+
+ virtual uint16 GetType() const OVERRIDE {
+ return qtype_;
+ }
+
+ virtual int Start() OVERRIDE {
+ EXPECT_FALSE(started_);
+ started_ = true;
+ if (hostname_.substr(0, 2) == "er")
+ return ERR_NAME_NOT_RESOLVED;
+ // Using WeakPtr to cleanly cancel when transaction is destroyed.
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockTransaction::Finish, AsWeakPtr()));
+ return ERR_IO_PENDING;
+ }
+
+ private:
+ void Finish() {
+ if (hostname_.substr(0, 2) == "ok") {
+ std::string qname;
+ DNSDomainFromDot(hostname_, &qname);
+ DnsQuery query(0, qname, qtype_);
+
+ DnsResponse response;
+ char* buffer = response.io_buffer()->data();
+ int nbytes = query.io_buffer()->size();
+ memcpy(buffer, query.io_buffer()->data(), nbytes);
+
+ const uint16 kPointerToQueryName =
+ static_cast<uint16>(0xc000 | sizeof(net::dns_protocol::Header));
+
+ const uint32 kTTL = 86400; // One day.
+
+ // Size of RDATA which is a IPv4 or IPv6 address.
+ size_t rdata_size = qtype_ == net::dns_protocol::kTypeA ?
+ net::kIPv4AddressSize : net::kIPv6AddressSize;
+
+ // 12 is the sum of sizes of the compressed name reference, TYPE,
+ // CLASS, TTL and RDLENGTH.
+ size_t answer_size = 12 + rdata_size;
+
+ // Write answer with loopback IP address.
+ reinterpret_cast<dns_protocol::Header*>(buffer)->ancount = htons(1);
+ BigEndianWriter writer(buffer + nbytes, answer_size);
+ writer.WriteU16(kPointerToQueryName);
+ writer.WriteU16(qtype_);
+ writer.WriteU16(net::dns_protocol::kClassIN);
+ writer.WriteU32(kTTL);
+ writer.WriteU16(rdata_size);
+ if (qtype_ == net::dns_protocol::kTypeA) {
+ char kIPv4Loopback[] = { 0x7f, 0, 0, 1 };
+ writer.WriteBytes(kIPv4Loopback, sizeof(kIPv4Loopback));
+ } else {
+ char kIPv6Loopback[] = { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1 };
+ writer.WriteBytes(kIPv6Loopback, sizeof(kIPv6Loopback));
+ }
+
+ EXPECT_TRUE(response.InitParse(nbytes + answer_size, query));
+ callback_.Run(this, OK, &response);
+ } else {
+ callback_.Run(this, ERR_NAME_NOT_RESOLVED, NULL);
+ }
+ }
+
+ const std::string hostname_;
+ const uint16 qtype_;
+ DnsTransactionFactory::CallbackType callback_;
+ bool started_;
+};
+
+
+// A DnsTransactionFactory which creates MockTransaction.
+class MockTransactionFactory : public DnsTransactionFactory {
+ public:
+ MockTransactionFactory() {}
+ virtual ~MockTransactionFactory() {}
+
+ virtual scoped_ptr<DnsTransaction> CreateTransaction(
+ const std::string& hostname,
+ uint16 qtype,
+ const DnsTransactionFactory::CallbackType& callback,
+ const BoundNetLog&) OVERRIDE {
+ return scoped_ptr<DnsTransaction>(
+ new MockTransaction(hostname, qtype, callback));
+ }
+};
+
+// MockDnsClient provides MockTransactionFactory.
+class MockDnsClient : public DnsClient {
+ public:
+ explicit MockDnsClient(const DnsConfig& config) : config_(config) {}
+ virtual ~MockDnsClient() {}
+
+ virtual void SetConfig(const DnsConfig& config) OVERRIDE {
+ config_ = config;
+ }
+
+ virtual const DnsConfig* GetConfig() const OVERRIDE {
+ return config_.IsValid() ? &config_ : NULL;
+ }
+
+ virtual DnsTransactionFactory* GetTransactionFactory() OVERRIDE {
+ return config_.IsValid() ? &factory_ : NULL;
+ }
+
+ private:
+ DnsConfig config_;
+ MockTransactionFactory factory_;
+};
+
+} // namespace
+
+// static
+scoped_ptr<DnsClient> CreateMockDnsClient(const DnsConfig& config) {
+ return scoped_ptr<DnsClient>(new MockDnsClient(config));
+}
+
+} // namespace net
+
diff --git a/net/dns/dns_test_util.h b/net/dns/dns_test_util.h
index 8d8c0a6..e247be0 100644
--- a/net/dns/dns_test_util.h
+++ b/net/dns/dns_test_util.h
@@ -7,6 +7,8 @@
#pragma once
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/dns/dns_config_service.h"
#include "net/dns/dns_protocol.h"
namespace net {
@@ -156,6 +158,25 @@ static const char* const kT3IpAddresses[] = {
static const char kT3CanonName[] = "www.l.google.com";
static const int kT3TTL = 0x00000015;
+class DnsClient;
+// Creates mock DnsClient for testing HostResolverImpl.
+scoped_ptr<DnsClient> CreateMockDnsClient(const DnsConfig& config);
+
+class MockDnsConfigService : public DnsConfigService {
+ public:
+ virtual ~MockDnsConfigService() {}
+
+ // Expose the protected methods for tests.
+ void ChangeConfig(const DnsConfig& config) {
+ DnsConfigService::OnConfigRead(config);
+ }
+
+ void ChangeHosts(const DnsHosts& hosts) {
+ DnsConfigService::OnHostsRead(hosts);
+ }
+};
+
+
} // namespace net
#endif // NET_DNS_DNS_TEST_UTIL_H_
diff --git a/net/dns/dns_transaction_unittest.cc b/net/dns/dns_transaction_unittest.cc
index b865457..063c6ea 100644
--- a/net/dns/dns_transaction_unittest.cc
+++ b/net/dns/dns_transaction_unittest.cc
@@ -202,7 +202,7 @@ class DnsTransactionTest : public testing::Test {
config_.nameservers.clear();
IPAddressNumber dns_ip;
{
- bool rv = ParseIPLiteralToNumber("192.128.1.0", &dns_ip);
+ bool rv = ParseIPLiteralToNumber("192.168.1.0", &dns_ip);
EXPECT_TRUE(rv);
}
for (unsigned i = 0; i < num_servers; ++i) {
diff --git a/net/net.gyp b/net/net.gyp
index a850041..a359eea 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -334,6 +334,8 @@
'disk_cache/stress_support.h',
'disk_cache/trace.cc',
'disk_cache/trace.h',
+ 'dns/dns_client.cc',
+ 'dns/dns_client.h',
'dns/dns_config_service.cc',
'dns/dns_config_service.h',
'dns/dns_config_service_posix.cc',
@@ -1527,6 +1529,7 @@
'disk_cache/disk_cache_test_base.h',
'disk_cache/disk_cache_test_util.cc',
'disk_cache/disk_cache_test_util.h',
+ 'dns/dns_test_util.cc',
'dns/dns_test_util.h',
'proxy/mock_proxy_resolver.cc',
'proxy/mock_proxy_resolver.h',