summaryrefslogtreecommitdiffstats
path: root/net/base
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 04:24:16 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 04:24:16 +0000
commitaff93c9850c1d90ba05019e346246acaf56180f1 (patch)
tree53a45871bcd9262ecafd5c0fbca7ec37af1c02ad /net/base
parente4f8181d78bcc220e28a36c626fbbd364d455fd6 (diff)
downloadchromium_src-aff93c9850c1d90ba05019e346246acaf56180f1.zip
chromium_src-aff93c9850c1d90ba05019e346246acaf56180f1.tar.gz
chromium_src-aff93c9850c1d90ba05019e346246acaf56180f1.tar.bz2
[net/dns] Serve requests from HOSTS file if possible.
If the DnsConfig is available, we can serve the requests synchronously in Resolve. However, we might not receive the DnsConfig until the Job is placed in the queue. In that case, we attempt to serve the jobs once DnsConfig is available. BUG=114826 TEST=./net_unittests --gtest_filter=HostResolverImplTest.ServeFromHosts Review URL: http://codereview.chromium.org/9667025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126559 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/base')
-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
5 files changed, 373 insertions, 107 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)