summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-21 02:12:25 +0000
committeragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-21 02:12:25 +0000
commitbae82aea7dc5fcf74e4832e0bfb9e365fd3cce3f (patch)
treec9137042423acee6e67b684f5bd2f480b2af8570
parent5a138d8dab2da903a653760c375f0e7dbd2fedfd (diff)
downloadchromium_src-bae82aea7dc5fcf74e4832e0bfb9e365fd3cce3f.zip
chromium_src-bae82aea7dc5fcf74e4832e0bfb9e365fd3cce3f.tar.gz
chromium_src-bae82aea7dc5fcf74e4832e0bfb9e365fd3cce3f.tar.bz2
Implemented AsyncHostResolver -- asynchronous HostResolver.
BUG=60149 TEST=net_unittests --gtest_filter="AsyncHostResolver*" Review URL: http://codereview.chromium.org/7466011 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@93313 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/io_thread.cc19
-rw-r--r--chrome/browser/net/passive_log_collector.cc29
-rw-r--r--chrome/browser/net/passive_log_collector.h16
-rw-r--r--chrome/browser/resources/net_internals/sourceentry.js1
-rw-r--r--net/base/async_host_resolver.cc427
-rw-r--r--net/base/async_host_resolver.h156
-rw-r--r--net/base/async_host_resolver_unittest.cc574
-rw-r--r--net/base/dns_test_util.cc35
-rw-r--r--net/base/dns_test_util.h181
-rw-r--r--net/base/dns_transaction_unittest.cc211
-rw-r--r--net/base/host_resolver.h6
-rw-r--r--net/base/host_resolver_impl_unittest.cc94
-rw-r--r--net/base/net_log_event_type_list.h40
-rw-r--r--net/base/net_log_source_type_list.h3
-rw-r--r--net/net.gyp3
15 files changed, 1583 insertions, 212 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 11d8827..35070e19 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -34,6 +34,7 @@
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/in_process_webkit/indexed_db_key_utility_client.h"
#include "content/common/url_fetcher.h"
+#include "net/base/async_host_resolver.h"
#include "net/base/cert_verifier.h"
#include "net/base/cookie_monster.h"
#include "net/base/dnsrr_resolver.h"
@@ -160,8 +161,24 @@ net::HostResolver* CreateGlobalHostResolver(net::NetLog* net_log) {
}
}
- net::HostResolver* global_host_resolver =
+ net::HostResolver* global_host_resolver = NULL;
+ if (command_line.HasSwitch(switches::kDnsServer)) {
+ std::string dns_ip_string =
+ command_line.GetSwitchValueASCII(switches::kDnsServer);
+ net::IPAddressNumber dns_ip_number;
+ if (net::ParseIPLiteralToNumber(dns_ip_string, &dns_ip_number)) {
+ global_host_resolver =
+ net::CreateAsyncHostResolver(parallelism, dns_ip_number, net_log);
+ } else {
+ LOG(ERROR) << "Invalid IP address specified for --dns-server: "
+ << dns_ip_string;
+ }
+ }
+
+ if (!global_host_resolver) {
+ global_host_resolver =
net::CreateSystemHostResolver(parallelism, retry_attempts, net_log);
+ }
// Determine if we should disable IPv6 support.
if (!command_line.HasSwitch(switches::kEnableIPv6)) {
diff --git a/chrome/browser/net/passive_log_collector.cc b/chrome/browser/net/passive_log_collector.cc
index 6e522a7..ca321dd 100644
--- a/chrome/browser/net/passive_log_collector.cc
+++ b/chrome/browser/net/passive_log_collector.cc
@@ -78,6 +78,8 @@ PassiveLogCollector::PassiveLogCollector()
trackers_[net::NetLog::SOURCE_EXPONENTIAL_BACKOFF_THROTTLING] =
&exponential_backoff_throttling_tracker_;
trackers_[net::NetLog::SOURCE_DNS_TRANSACTION] = &dns_transaction_tracker_;
+ trackers_[net::NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST] =
+ &async_host_resolver_request_tracker_;
// Make sure our mapping is up-to-date.
for (size_t i = 0; i < arraysize(trackers_); ++i)
DCHECK(trackers_[i]) << "Unhandled SourceType: " << i;
@@ -695,3 +697,30 @@ PassiveLogCollector::DnsTransactionTracker::DoAddEntry(
}
return ACTION_NONE;
}
+
+//----------------------------------------------------------------------------
+// AsyncHostResolverRequestTracker
+//----------------------------------------------------------------------------
+
+const size_t
+PassiveLogCollector::AsyncHostResolverRequestTracker::kMaxNumSources = 100;
+
+const size_t
+PassiveLogCollector::AsyncHostResolverRequestTracker::kMaxGraveyardSize = 15;
+
+PassiveLogCollector::
+ AsyncHostResolverRequestTracker::AsyncHostResolverRequestTracker()
+ : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
+}
+
+PassiveLogCollector::SourceTracker::Action
+PassiveLogCollector::AsyncHostResolverRequestTracker::DoAddEntry(
+ const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info) {
+ AddEntryToSourceInfo(entry, out_info);
+ if (entry.type == net::NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST &&
+ entry.phase == net::NetLog::PHASE_END) {
+ return ACTION_MOVE_TO_GRAVEYARD;
+ }
+ return ACTION_NONE;
+}
diff --git a/chrome/browser/net/passive_log_collector.h b/chrome/browser/net/passive_log_collector.h
index 56c60c7..28598b2 100644
--- a/chrome/browser/net/passive_log_collector.h
+++ b/chrome/browser/net/passive_log_collector.h
@@ -369,6 +369,21 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserver {
DISALLOW_COPY_AND_ASSIGN(DnsTransactionTracker);
};
+ // Tracks the log entries for the last seen SOURCE_ASYNC_HOST_RESOLVER_REQUEST
+ class AsyncHostResolverRequestTracker : public SourceTracker {
+ public:
+ static const size_t kMaxNumSources;
+ static const size_t kMaxGraveyardSize;
+
+ AsyncHostResolverRequestTracker();
+
+ private:
+ virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
+ SourceInfo* out_info);
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncHostResolverRequestTracker);
+ };
+
PassiveLogCollector();
virtual ~PassiveLogCollector();
@@ -410,6 +425,7 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserver {
HttpStreamJobTracker http_stream_job_tracker_;
ExponentialBackoffThrottlingTracker exponential_backoff_throttling_tracker_;
DnsTransactionTracker dns_transaction_tracker_;
+ AsyncHostResolverRequestTracker async_host_resolver_request_tracker_;
// This array maps each NetLog::SourceType to one of the tracker instances
// defined above. Use of this array avoid duplicating the list of trackers
diff --git a/chrome/browser/resources/net_internals/sourceentry.js b/chrome/browser/resources/net_internals/sourceentry.js
index 3cb5fd0..1a901ca 100644
--- a/chrome/browser/resources/net_internals/sourceentry.js
+++ b/chrome/browser/resources/net_internals/sourceentry.js
@@ -321,6 +321,7 @@ SourceEntry.prototype.getDescription = function() {
description = connectJobSourceEntry.getDescription();
}
break;
+ case LogSourceType.ASYNC_HOST_RESOLVER_REQUEST:
case LogSourceType.DNS_TRANSACTION:
description = e.params.hostname;
break;
diff --git a/net/base/async_host_resolver.cc b/net/base/async_host_resolver.cc
new file mode 100644
index 0000000..8aa9818
--- /dev/null
+++ b/net/base/async_host_resolver.cc
@@ -0,0 +1,427 @@
+// Copyright (c) 2011 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/async_host_resolver.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "net/base/address_list.h"
+#include "net/base/dns_util.h"
+#include "net/base/net_errors.h"
+#include "net/socket/client_socket_factory.h"
+
+namespace net {
+
+namespace {
+
+// TODO(agayev): fix this when IPv6 support is added.
+uint16 QueryTypeFromAddressFamily(AddressFamily address_family) {
+ return kDNS_A;
+}
+
+int ResolveAsIp(const HostResolver::RequestInfo& info,
+ const IPAddressNumber& ip_number,
+ AddressList* addresses) {
+ if (ip_number.size() != kIPv4AddressSize)
+ return ERR_NAME_NOT_RESOLVED;
+
+ *addresses = AddressList::CreateFromIPAddressWithCname(
+ ip_number,
+ info.port(),
+ info.host_resolver_flags() & HOST_RESOLVER_CANONNAME);
+ return OK;
+}
+
+class RequestParameters : public NetLog::EventParameters {
+ public:
+ RequestParameters(const HostResolver::RequestInfo& info,
+ const NetLog::Source& source)
+ : info_(info), source_(source) {}
+
+ virtual Value* ToValue() const {
+ DictionaryValue* dict = new DictionaryValue();
+ dict->SetString("hostname", info_.host_port_pair().ToString());
+ dict->SetInteger("address_family",
+ static_cast<int>(info_.address_family()));
+ dict->SetBoolean("allow_cached_response", info_.allow_cached_response());
+ dict->SetBoolean("only_use_cached_response",
+ info_.only_use_cached_response());
+ dict->SetBoolean("is_speculative", info_.is_speculative());
+ dict->SetInteger("priority", info_.priority());
+
+ if (source_.is_valid())
+ dict->Set("source_dependency", source_.ToValue());
+
+ return dict;
+ }
+
+ private:
+ const HostResolver::RequestInfo info_;
+ const NetLog::Source source_;
+};
+
+} // namespace
+
+HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
+ const IPAddressNumber& dns_ip,
+ NetLog* net_log) {
+ size_t max_transactions = max_concurrent_resolves;
+ if (max_transactions == 0)
+ max_transactions = 20;
+ size_t max_pending_requests = max_transactions * 100;
+ HostResolver* resolver = new AsyncHostResolver(
+ IPEndPoint(dns_ip, 53),
+ max_transactions,
+ max_pending_requests,
+ base::Bind(&base::RandInt),
+ NULL,
+ net_log);
+ return resolver;
+}
+
+//-----------------------------------------------------------------------------
+class AsyncHostResolver::Request {
+ public:
+ Request(const BoundNetLog& source_net_log,
+ const BoundNetLog& request_net_log,
+ int id,
+ const HostResolver::RequestInfo& info,
+ const Key& key,
+ CompletionCallback* callback,
+ AddressList* addresses)
+ : source_net_log_(source_net_log),
+ request_net_log_(request_net_log),
+ id_(id),
+ info_(info),
+ key_(key),
+ callback_(callback),
+ addresses_(addresses) {
+ DCHECK(addresses_);
+ }
+
+ int id() const { return id_; }
+ const HostResolver::RequestInfo& info() const { return info_; }
+ const Key& key() const { return key_; }
+ RequestPriority priority() const { return info_.priority(); }
+ const BoundNetLog& source_net_log() const { return source_net_log_; }
+ const BoundNetLog& request_net_log() const { return request_net_log_; }
+ const AddressList* addresses() const { return addresses_; }
+
+ void OnComplete(int result, const IPAddressList& ip_addresses) {
+ DCHECK(callback_);
+ if (result == OK)
+ *addresses_ =
+ AddressList::CreateFromIPAddressList(ip_addresses, info_.port());
+ callback_->Run(result);
+ }
+
+ private:
+ BoundNetLog source_net_log_;
+ BoundNetLog request_net_log_;
+ const int id_;
+ const HostResolver::RequestInfo info_;
+ const Key key_;
+ CompletionCallback* callback_;
+ AddressList* addresses_;
+};
+
+//-----------------------------------------------------------------------------
+AsyncHostResolver::AsyncHostResolver(const IPEndPoint& dns_server,
+ size_t max_transactions,
+ size_t max_pending_requests,
+ const RandIntCallback& rand_int_cb,
+ ClientSocketFactory* factory,
+ NetLog* net_log)
+ : max_transactions_(max_transactions),
+ max_pending_requests_(max_pending_requests),
+ dns_server_(dns_server),
+ rand_int_cb_(rand_int_cb),
+ factory_(factory),
+ next_request_id_(0),
+ net_log_(net_log) {
+}
+
+AsyncHostResolver::~AsyncHostResolver() {
+ for (KeyRequestListMap::iterator it = requestlist_map_.begin();
+ it != requestlist_map_.end(); ++it)
+ STLDeleteElements(&it->second);
+ STLDeleteElements(&transactions_);
+}
+
+int AsyncHostResolver::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ CompletionCallback* callback,
+ RequestHandle* out_req,
+ const BoundNetLog& source_net_log) {
+ DCHECK(addresses);
+
+ IPAddressNumber ip_number;
+ std::string dns_name;
+ int rv = ERR_UNEXPECTED;
+ if (info.hostname().empty())
+ rv = ERR_NAME_NOT_RESOLVED;
+ else if (ParseIPLiteralToNumber(info.hostname(), &ip_number))
+ rv = ResolveAsIp(info, ip_number, addresses);
+ else if (!DNSDomainFromDot(info.hostname(), &dns_name))
+ rv = ERR_NAME_NOT_RESOLVED;
+ else if (info.only_use_cached_response()) // TODO(agayev): support caching
+ rv = ERR_NAME_NOT_RESOLVED;
+
+ Request* request = CreateNewRequest(
+ info, dns_name, callback, addresses, source_net_log);
+
+ OnStart(request);
+ if (rv != ERR_UNEXPECTED) {
+ OnFinish(request, rv);
+ delete request;
+ return rv;
+ }
+
+ if (out_req)
+ *out_req = reinterpret_cast<RequestHandle>(request);
+
+ if (AttachToRequestList(request))
+ return ERR_IO_PENDING;
+ if (transactions_.size() < max_transactions_)
+ return StartNewTransactionFor(request);
+ return Enqueue(request);
+}
+
+void AsyncHostResolver::OnStart(Request* request) {
+ DCHECK(request);
+
+ request->source_net_log().BeginEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER,
+ make_scoped_refptr(new NetLogSourceParameter(
+ "source_dependency", request->request_net_log().source())));
+
+ request->request_net_log().BeginEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST,
+ make_scoped_refptr(new RequestParameters(
+ request->info(), request->source_net_log().source())));
+
+ FOR_EACH_OBSERVER(
+ HostResolver::Observer, observers_,
+ OnStartResolution(request->id(), request->info()));
+}
+
+void AsyncHostResolver::OnFinish(Request* request, int result) {
+ DCHECK(request);
+ bool was_resolved = result == OK;
+
+ FOR_EACH_OBSERVER(
+ HostResolver::Observer, observers_,
+ OnFinishResolutionWithStatus(
+ request->id(), was_resolved, request->info()));
+
+ request->request_net_log().EndEventWithNetErrorCode(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, result);
+ request->source_net_log().EndEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
+}
+
+void AsyncHostResolver::OnCancel(Request* request) {
+ DCHECK(request);
+
+ FOR_EACH_OBSERVER(
+ HostResolver::Observer, observers_,
+ OnCancelResolution(request->id(), request->info()));
+
+ request->request_net_log().AddEvent(
+ NetLog::TYPE_CANCELLED, NULL);
+ request->request_net_log().EndEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER_REQUEST, NULL);
+ request->source_net_log().EndEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER, NULL);
+}
+
+void AsyncHostResolver::CancelRequest(RequestHandle req_handle) {
+ scoped_ptr<Request> request(reinterpret_cast<Request*>(req_handle));
+ DCHECK(request.get());
+
+ KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
+ if (it != requestlist_map_.end())
+ it->second.remove(request.get());
+ else
+ pending_requests_[request->priority()].remove(request.get());
+
+ OnCancel(request.get());
+}
+
+void AsyncHostResolver::AddObserver(HostResolver::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void AsyncHostResolver::RemoveObserver(HostResolver::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void AsyncHostResolver::SetDefaultAddressFamily(
+ AddressFamily address_family) {
+ NOTIMPLEMENTED();
+}
+
+AddressFamily AsyncHostResolver::GetDefaultAddressFamily() const {
+ return ADDRESS_FAMILY_IPV4;
+}
+
+HostResolverImpl* AsyncHostResolver::GetAsHostResolverImpl() {
+ return NULL;
+}
+
+void AsyncHostResolver::OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses) {
+
+ DCHECK(std::find(transactions_.begin(), transactions_.end(), transaction)
+ != transactions_.end());
+ DCHECK(requestlist_map_.find(transaction->key()) != requestlist_map_.end());
+
+ // Run callback of every request that was depending on this transaction,
+ // also notify observers.
+ RequestList& requests = requestlist_map_[transaction->key()];
+ for (RequestList::iterator it = requests.begin(); it != requests.end();
+ ++it) {
+ Request* request = *it;
+ OnFinish(request, result);
+ request->OnComplete(result, ip_addresses);
+ }
+
+ // Cleanup requests.
+ STLDeleteElements(&requests);
+ requestlist_map_.erase(transaction->key());
+
+ // Cleanup transaction and start a new one if there are pending requests.
+ delete transaction;
+ transactions_.remove(transaction);
+ ProcessPending();
+}
+
+AsyncHostResolver::Request* AsyncHostResolver::CreateNewRequest(
+ const RequestInfo& info,
+ const std::string& dns_name,
+ CompletionCallback* callback,
+ AddressList* addresses,
+ const BoundNetLog& source_net_log) {
+
+ uint16 query_type = QueryTypeFromAddressFamily(info.address_family());
+ Key key(dns_name, query_type);
+
+ BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
+ NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST);
+
+ int id = next_request_id_++;
+ Request* request = new Request(
+ source_net_log, request_net_log, id, info, key, callback, addresses);
+ return request;
+}
+
+bool AsyncHostResolver::AttachToRequestList(Request* request) {
+ KeyRequestListMap::iterator it = requestlist_map_.find(request->key());
+ if (it == requestlist_map_.end())
+ return false;
+ it->second.push_back(request);
+ return true;
+}
+
+int AsyncHostResolver::StartNewTransactionFor(Request* request) {
+ DCHECK(requestlist_map_.find(request->key()) == requestlist_map_.end());
+ DCHECK(transactions_.size() < max_transactions_);
+
+ request->request_net_log().AddEvent(
+ NetLog::TYPE_ASYNC_HOST_RESOLVER_CREATE_DNS_TRANSACTION, NULL);
+
+ requestlist_map_[request->key()].push_back(request);
+ DnsTransaction* transaction = new DnsTransaction(
+ dns_server_,
+ request->key().first,
+ request->key().second,
+ rand_int_cb_,
+ factory_,
+ request->request_net_log(),
+ net_log_);
+ transaction->SetDelegate(this);
+ transactions_.push_back(transaction);
+ return transaction->Start();
+}
+
+int AsyncHostResolver::Enqueue(Request* request) {
+ scoped_ptr<Request> evicted_request(Insert(request));
+ if (evicted_request != NULL) {
+ int rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
+ if (evicted_request.get() == request)
+ return rv;
+ evicted_request->OnComplete(rv, IPAddressList());
+ }
+ return ERR_IO_PENDING;
+}
+
+AsyncHostResolver::Request* AsyncHostResolver::Insert(Request* request) {
+ pending_requests_[request->priority()].push_back(request);
+ if (GetNumPending() > max_pending_requests_) {
+ Request* req = RemoveLowest();
+ DCHECK(req);
+ return req;
+ }
+ return NULL;
+}
+
+size_t AsyncHostResolver::GetNumPending() {
+ size_t num_pending = 0;
+ for (size_t i = 0; i < arraysize(pending_requests_); ++i)
+ num_pending += pending_requests_[i].size();
+ return num_pending;
+}
+
+AsyncHostResolver::Request* AsyncHostResolver::RemoveLowest() {
+ for (int i = static_cast<int>(arraysize(pending_requests_)) - 1;
+ i >= 0; --i) {
+ RequestList& requests = pending_requests_[i];
+ if (!requests.empty()) {
+ Request* request = requests.front();
+ requests.pop_front();
+ return request;
+ }
+ }
+ return NULL;
+}
+
+AsyncHostResolver::Request* AsyncHostResolver::RemoveHighest() {
+ for (size_t i = 0; i < arraysize(pending_requests_) - 1; ++i) {
+ RequestList& requests = pending_requests_[i];
+ if (!requests.empty()) {
+ Request* request = requests.front();
+ requests.pop_front();
+ return request;
+ }
+ }
+ return NULL;
+}
+
+void AsyncHostResolver::ProcessPending() {
+ Request* request = RemoveHighest();
+ if (!request)
+ return;
+ for (size_t i = 0; i < arraysize(pending_requests_); ++i) {
+ RequestList& requests = pending_requests_[i];
+ RequestList::iterator it = requests.begin();
+ while (it != requests.end()) {
+ if (request->key() == (*it)->key()) {
+ requestlist_map_[request->key()].push_back(*it);
+ it = requests.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ StartNewTransactionFor(request);
+}
+
+} // namespace net
diff --git a/net/base/async_host_resolver.h b/net/base/async_host_resolver.h
new file mode 100644
index 0000000..42ba997
--- /dev/null
+++ b/net/base/async_host_resolver.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2011 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_ASYNC_HOST_RESOLVER_H_
+#define NET_BASE_ASYNC_HOST_RESOLVER_H_
+#pragma once
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include "base/observer_list.h"
+#include "base/threading/non_thread_safe.h"
+#include "net/base/address_family.h"
+#include "net/base/dns_transaction.h"
+#include "net/base/host_resolver.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_log.h"
+#include "net/base/rand_callback.h"
+
+namespace net {
+
+class AddressesList;
+class ClientSocketFactory;
+
+class NET_API AsyncHostResolver : public HostResolver,
+ public DnsTransaction::Delegate,
+ public base::NonThreadSafe {
+ public:
+ AsyncHostResolver(const IPEndPoint& dns_server,
+ size_t max_transactions,
+ size_t max_pending_requests_,
+ const RandIntCallback& rand_int,
+ ClientSocketFactory* factory,
+ NetLog* net_log);
+ virtual ~AsyncHostResolver();
+
+ // HostResolver interface
+ virtual int Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ CompletionCallback* callback,
+ RequestHandle* out_req,
+ const BoundNetLog& source_net_log) OVERRIDE;
+ virtual void CancelRequest(RequestHandle req_handle) OVERRIDE;
+ virtual void AddObserver(HostResolver::Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(HostResolver::Observer* observer) OVERRIDE;
+ virtual void SetDefaultAddressFamily(AddressFamily address_family) OVERRIDE;
+ virtual AddressFamily GetDefaultAddressFamily() const OVERRIDE;
+ virtual HostResolverImpl* GetAsHostResolverImpl() OVERRIDE;
+
+ // DnsTransaction::Delegate interface
+ virtual void OnTransactionComplete(
+ int result,
+ const DnsTransaction* transaction,
+ const IPAddressList& ip_addresses) OVERRIDE;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest, QueuedLookup);
+ FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest, CancelPendingLookup);
+ FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
+ ResolverDestructionCancelsLookups);
+ FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
+ OverflowQueueWithLowPriorityLookup);
+ FRIEND_TEST_ALL_PREFIXES(AsyncHostResolverTest,
+ OverflowQueueWithHighPriorityLookup);
+
+ class Request;
+
+ typedef DnsTransaction::Key Key;
+ typedef std::list<Request*> RequestList;
+ typedef std::list<const DnsTransaction*> TransactionList;
+ typedef std::map<Key, RequestList> KeyRequestListMap;
+
+ // Create a new request for the incoming Resolve() call.
+ Request* CreateNewRequest(const RequestInfo& info,
+ const std::string& dns_name,
+ CompletionCallback* callback,
+ AddressList* addresses,
+ const BoundNetLog& source_net_log);
+
+ // Called when a request has just been started.
+ void OnStart(Request* request);
+
+ // Called when a request has just completed (before its callback is run).
+ void OnFinish(Request* request, int result);
+
+ // Called when a request has been cancelled.
+ void OnCancel(Request* request);
+
+ // If there is an in-progress transaction for Request->key(), this will
+ // attach |request| to the respective list.
+ bool AttachToRequestList(Request* request);
+
+ // Will start a new transaction for |request|, will insert a new key in
+ // |requestlist_map_| and append |request| to the respective list.
+ int StartNewTransactionFor(Request* request);
+
+ // Will enqueue |request| in |pending_requests_|.
+ int Enqueue(Request* request);
+
+ // A helper used by Enqueue to insert |request| into |pending_requests_|.
+ Request* Insert(Request* request);
+
+ // Returns the number of pending requests.
+ size_t GetNumPending();
+
+ // Removes and returns a pointer to the lowest/highest priority request
+ // from |pending_requests_|.
+ Request* RemoveLowest();
+ Request* RemoveHighest();
+
+ // Once a transaction has completed, called to start a new transaction if
+ // there are pending requests.
+ void ProcessPending();
+
+ // Maximum number of concurrent transactions.
+ size_t max_transactions_;
+
+ // List of current transactions.
+ TransactionList transactions_;
+
+ // A map from Key to a list of requests waiting for the Key to resolve.
+ KeyRequestListMap requestlist_map_;
+
+ // Maximum number of pending requests.
+ size_t max_pending_requests_;
+
+ // Queues based on priority for putting pending requests.
+ RequestList pending_requests_[NUM_PRIORITIES];
+
+ // DNS server to which queries will be setn.
+ IPEndPoint dns_server_;
+
+ // Callback to be passed to DnsTransaction for generating DNS query ids.
+ RandIntCallback rand_int_cb_;
+
+ // Also passed to DnsTransaction; it's a dependency injection to aid
+ // testing, outside of unit tests, its value is always NULL.
+ ClientSocketFactory* factory_;
+
+ // The observers to notify when a request starts/ends.
+ ObserverList<HostResolver::Observer> observers_;
+
+ // Monotonically increasing ID number to assign to the next request.
+ // Observers are the only consumers of this ID number.
+ int next_request_id_;
+
+ NetLog* net_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncHostResolver);
+};
+
+} // namespace net
+
+#endif // NET_BASE_ASYNC_HOST_RESOLVER_H_
diff --git a/net/base/async_host_resolver_unittest.cc b/net/base/async_host_resolver_unittest.cc
new file mode 100644
index 0000000..0e92981
--- /dev/null
+++ b/net/base/async_host_resolver_unittest.cc
@@ -0,0 +1,574 @@
+// Copyright (c) 2011 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/async_host_resolver.h"
+
+#include "base/bind.h"
+#include "base/scoped_ptr.h"
+#include "net/base/dns_test_util.h"
+#include "net/base/net_log.h"
+#include "net/base/rand_callback.h"
+#include "net/base/sys_addrinfo.h"
+#include "net/socket/socket_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+void VerifyAddressList(const std::vector<const char*>& ip_addresses,
+ int port,
+ const AddressList& addrlist) {
+ ASSERT_LT(0u, ip_addresses.size());
+ ASSERT_NE(static_cast<addrinfo*>(NULL), addrlist.head());
+
+ IPAddressNumber ip_number;
+ const struct addrinfo* ainfo = addrlist.head();
+ for (std::vector<const char*>::const_iterator i = ip_addresses.begin();
+ i != ip_addresses.end(); ++i, ainfo = ainfo->ai_next) {
+ ASSERT_NE(static_cast<addrinfo*>(NULL), ainfo);
+ EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen);
+
+ const struct sockaddr* sa = ainfo->ai_addr;
+ const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa;
+ EXPECT_TRUE(htons(port) == sa_in->sin_port);
+ EXPECT_STREQ(*i, NetAddressToString(sa, ainfo->ai_addrlen).c_str());
+ }
+ ASSERT_EQ(static_cast<addrinfo*>(NULL), ainfo);
+}
+
+} // namespace
+
+static const int kPortNum = 80;
+static const size_t kMaxTransactions = 2;
+static const size_t kMaxPendingRequests = 1;
+static int transaction_ids[] = {0, 1, 2, 3};
+
+// The following fixture sets up an environment for four different lookups
+// with their data defined in dns_test_util.h. All tests make use of these
+// predefined variables instead of each defining their own, to avoid
+// boilerplate code in every test. Assuming every coming query is for a
+// distinct hostname, as |kMaxTransactions| is set to 2 and
+// |kMaxPendingRequests| is set to 1, first two queries start immediately
+// and the next one is sent to pending queue; as a result, the next query
+// should either fail itself or cause the pending query to fail depending
+// on its priority.
+class AsyncHostResolverTest : public testing::Test {
+ public:
+ AsyncHostResolverTest()
+ : info0_(HostPortPair(kT0HostName, kPortNum)),
+ info1_(HostPortPair(kT1HostName, kPortNum)),
+ info2_(HostPortPair(kT2HostName, kPortNum)),
+ info3_(HostPortPair(kT3HostName, kPortNum)),
+ ip_addresses0_(kT0IpAddresses,
+ kT0IpAddresses + arraysize(kT0IpAddresses)),
+ ip_addresses1_(kT1IpAddresses,
+ kT1IpAddresses + arraysize(kT1IpAddresses)),
+ ip_addresses2_(kT2IpAddresses,
+ kT2IpAddresses + arraysize(kT2IpAddresses)),
+ ip_addresses3_(kT3IpAddresses,
+ kT3IpAddresses + arraysize(kT3IpAddresses)),
+ test_prng_(std::deque<int>(
+ transaction_ids, transaction_ids + arraysize(transaction_ids))) {
+
+ rand_int_cb_ = base::Bind(&TestPrng::GetNext,
+ base::Unretained(&test_prng_));
+ // AF_INET only for now.
+ info0_.set_address_family(ADDRESS_FAMILY_IPV4);
+ info1_.set_address_family(ADDRESS_FAMILY_IPV4);
+ info2_.set_address_family(ADDRESS_FAMILY_IPV4);
+ info3_.set_address_family(ADDRESS_FAMILY_IPV4);
+
+ // Setup socket read/writes for transaction 0.
+ writes0_.push_back(
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram)));
+ reads0_.push_back(
+ MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram)));
+ data0_.reset(new StaticSocketDataProvider(&reads0_[0], reads0_.size(),
+ &writes0_[0], writes0_.size()));
+
+ // Setup socket read/writes for transaction 1.
+ writes1_.push_back(
+ MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
+ arraysize(kT1QueryDatagram)));
+ reads1_.push_back(
+ MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
+ arraysize(kT1ResponseDatagram)));
+ data1_.reset(new StaticSocketDataProvider(&reads1_[0], reads1_.size(),
+ &writes1_[0], writes1_.size()));
+
+ // Setup socket read/writes for transaction 2.
+ writes2_.push_back(
+ MockWrite(true, reinterpret_cast<const char*>(kT2QueryDatagram),
+ arraysize(kT2QueryDatagram)));
+ reads2_.push_back(
+ MockRead(true, reinterpret_cast<const char*>(kT2ResponseDatagram),
+ arraysize(kT2ResponseDatagram)));
+ data2_.reset(new StaticSocketDataProvider(&reads2_[0], reads2_.size(),
+ &writes2_[0], writes2_.size()));
+
+ // Setup socket read/writes for transaction 3.
+ writes3_.push_back(
+ MockWrite(true, reinterpret_cast<const char*>(kT3QueryDatagram),
+ arraysize(kT3QueryDatagram)));
+ reads3_.push_back(
+ MockRead(true, reinterpret_cast<const char*>(kT3ResponseDatagram),
+ arraysize(kT3ResponseDatagram)));
+ data3_.reset(new StaticSocketDataProvider(&reads3_[0], reads3_.size(),
+ &writes3_[0], writes3_.size()));
+
+ factory_.AddSocketDataProvider(data0_.get());
+ factory_.AddSocketDataProvider(data1_.get());
+ factory_.AddSocketDataProvider(data2_.get());
+ factory_.AddSocketDataProvider(data3_.get());
+
+ IPEndPoint dns_server;
+ bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ DCHECK(rv0);
+
+ resolver_.reset(
+ new AsyncHostResolver(
+ dns_server, kMaxTransactions, kMaxPendingRequests, rand_int_cb_,
+ &factory_, NULL));
+ }
+
+ protected:
+ AddressList addrlist0_, addrlist1_, addrlist2_, addrlist3_;
+ HostResolver::RequestInfo info0_, info1_, info2_, info3_;
+ std::vector<MockWrite> writes0_, writes1_, writes2_, writes3_;
+ std::vector<MockRead> reads0_, reads1_, reads2_, reads3_;
+ scoped_ptr<StaticSocketDataProvider> data0_, data1_, data2_, data3_;
+ std::vector<const char*> ip_addresses0_, ip_addresses1_,
+ ip_addresses2_, ip_addresses3_;
+ MockClientSocketFactory factory_;
+ TestPrng test_prng_;
+ RandIntCallback rand_int_cb_;
+ scoped_ptr<HostResolver> resolver_;
+ TestCompletionCallback callback0_, callback1_, callback2_, callback3_;
+};
+
+TEST_F(AsyncHostResolverTest, EmptyHostLookup) {
+ info0_.set_host_port_pair(HostPortPair("", kPortNum));
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+}
+
+TEST_F(AsyncHostResolverTest, IPv4LiteralLookup) {
+ const char* kIPLiteral = "192.168.1.2";
+ info0_.set_host_port_pair(HostPortPair(kIPLiteral, kPortNum));
+ info0_.set_host_resolver_flags(HOST_RESOLVER_CANONNAME);
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(OK, rv);
+ std::vector<const char*> ip_addresses(1, kIPLiteral);
+ VerifyAddressList(ip_addresses, kPortNum, addrlist0_);
+ EXPECT_STREQ(kIPLiteral, addrlist0_.head()->ai_canonname);
+}
+
+TEST_F(AsyncHostResolverTest, IPv6LiteralLookup) {
+ info0_.set_host_port_pair(HostPortPair("2001:db8:0::42", kPortNum));
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ // When support for IPv6 is added, this should succeed.
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+}
+
+TEST_F(AsyncHostResolverTest, CachedOnlyLookup) {
+ info0_.set_only_use_cached_response(true);
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ // When caching is added, this should succeed.
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+}
+
+TEST_F(AsyncHostResolverTest, InvalidHostNameLookup) {
+ const std::string kHostName1(64, 'a');
+ info0_.set_host_port_pair(HostPortPair(kHostName1, kPortNum));
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+
+ const std::string kHostName2(4097, 'b');
+ info0_.set_host_port_pair(HostPortPair(kHostName2, kPortNum));
+ rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
+}
+
+TEST_F(AsyncHostResolverTest, Lookup) {
+ int rv = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+ rv = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+}
+
+TEST_F(AsyncHostResolverTest, ConcurrentLookup) {
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+
+ rv2 = callback2_.WaitForResult();
+ EXPECT_EQ(OK, rv2);
+ VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
+
+ EXPECT_EQ(3u, factory_.udp_client_sockets().size());
+}
+
+TEST_F(AsyncHostResolverTest, SameHostLookupsConsumeSingleTransaction) {
+ // We pass the info0_ to all requests.
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info0_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ int rv2 = resolver_->Resolve(info0_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist1_);
+
+ rv2 = callback2_.WaitForResult();
+ EXPECT_EQ(OK, rv2);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist2_);
+
+ // Although we have three lookups, a single UDP socket was used.
+ EXPECT_EQ(1u, factory_.udp_client_sockets().size());
+}
+
+TEST_F(AsyncHostResolverTest, CancelLookup) {
+ HostResolver::RequestHandle req0 = NULL, req2 = NULL;
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, &req0,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, &req2,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ resolver_->CancelRequest(req0);
+ resolver_->CancelRequest(req2);
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_FALSE(callback0_.have_result());
+ EXPECT_FALSE(callback2_.have_result());
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+}
+
+// Tests the following scenario: start two resolutions for the same host,
+// cancel one of them, make sure that the other one completes.
+TEST_F(AsyncHostResolverTest, CancelSameHostLookup) {
+ HostResolver::RequestHandle req0 = NULL;
+
+ // Pass the info0_ to both requests.
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, &req0,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info0_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+
+ resolver_->CancelRequest(req0);
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(callback0_.have_result());
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist1_);
+
+ EXPECT_EQ(1u, factory_.udp_client_sockets().size());
+}
+
+// Test that a queued lookup completes.
+TEST_F(AsyncHostResolverTest, QueuedLookup) {
+ // kMaxTransactions is 2, thus the following requests consume all
+ // available transactions.
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+
+ // The following request will end up in queue.
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+ EXPECT_EQ(1u,
+ static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
+
+ // Make sure all requests complete.
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+
+ rv2 = callback2_.WaitForResult();
+ EXPECT_EQ(OK, rv2);
+ VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
+}
+
+// Test that cancelling a queued lookup works.
+TEST_F(AsyncHostResolverTest, CancelPendingLookup) {
+ // kMaxTransactions is 2, thus the following requests consume all
+ // available transactions.
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+
+ // The following request will end up in queue.
+ HostResolver::RequestHandle req2 = NULL;
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, &req2,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+ EXPECT_EQ(1u,
+ static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
+
+ resolver_->CancelRequest(req2);
+
+ // Make sure first two requests complete while the cancelled one doesn't.
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(callback2_.have_result());
+
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+}
+
+TEST_F(AsyncHostResolverTest, ResolverDestructionCancelsLookups) {
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ // This one is queued.
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(1u,
+ static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ resolver_.reset();
+
+ MessageLoop::current()->RunAllPending();
+
+ EXPECT_FALSE(callback0_.have_result());
+ EXPECT_FALSE(callback1_.have_result());
+ EXPECT_FALSE(callback2_.have_result());
+}
+
+// Test that when the number of pending lookups is at max, a new lookup
+// with a priority lower than all of those in the queue fails.
+TEST_F(AsyncHostResolverTest, OverflowQueueWithLowPriorityLookup) {
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ // This one is queued and fills up the queue since its size is 1.
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(1u,
+ static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ // This one fails.
+ info3_.set_priority(LOWEST);
+ int rv3 = resolver_->Resolve(info3_, &addrlist3_, &callback3_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, rv3);
+
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(callback3_.have_result());
+}
+
+// Test that when the number of pending lookups is at max, a new lookup
+// with a priority higher than any of those in the queue succeeds and
+// causes the lowest priority lookup in the queue to fail.
+TEST_F(AsyncHostResolverTest, OverflowQueueWithHighPriorityLookup) {
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+
+ // Next lookup is queued. Since this will be ejected from the queue and
+ // will not consume a socket from our factory, we are not passing it
+ // predefined members.
+ HostResolver::RequestInfo info(HostPortPair("cnn.com", 80));
+ info.set_address_family(ADDRESS_FAMILY_IPV4);
+ AddressList addrlist_fail;
+ TestCompletionCallback callback_fail;
+ int rv_fail = resolver_->Resolve(info, &addrlist_fail, &callback_fail, NULL,
+ BoundNetLog());
+ EXPECT_EQ(1u,
+ static_cast<AsyncHostResolver*>(resolver_.get())->GetNumPending());
+
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv_fail);
+
+ // Lookup 2 causes the above to fail, but itself should succeed.
+ info2_.set_priority(HIGHEST);
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+
+ rv_fail = callback_fail.WaitForResult();
+ EXPECT_EQ(ERR_HOST_RESOLVER_QUEUE_TOO_LARGE, rv_fail);
+ EXPECT_EQ(static_cast<addrinfo*>(NULL), addrlist_fail.head());
+
+ rv2 = callback2_.WaitForResult();
+ EXPECT_EQ(OK, rv2);
+ VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
+}
+
+// Test that registering, unregistering, and notifying of observers of
+// resolution start, completion and cancellation (both due to CancelRequest
+// and resolver destruction) work.
+TEST_F(AsyncHostResolverTest, Observers) {
+ TestHostResolverObserver observer;
+ resolver_->AddObserver(&observer);
+
+ int rv0 = resolver_->Resolve(info0_, &addrlist0_, &callback0_, NULL,
+ BoundNetLog());
+ int rv1 = resolver_->Resolve(info1_, &addrlist1_, &callback1_, NULL,
+ BoundNetLog());
+ // We will cancel this one.
+ HostResolver::RequestHandle req2 = NULL;
+ int rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, &req2,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
+ EXPECT_EQ(ERR_IO_PENDING, rv1);
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ // Cancel lookup 2.
+ resolver_->CancelRequest(req2);
+
+ // Lookup 0 and 1 should succeed.
+ rv0 = callback0_.WaitForResult();
+ EXPECT_EQ(OK, rv0);
+ VerifyAddressList(ip_addresses0_, kPortNum, addrlist0_);
+
+ rv1 = callback1_.WaitForResult();
+ EXPECT_EQ(OK, rv1);
+ VerifyAddressList(ip_addresses1_, kPortNum, addrlist1_);
+
+ // Next lookup should not have finished.
+ MessageLoop::current()->RunAllPending();
+ EXPECT_FALSE(callback2_.have_result());
+
+ // Verify observer calls.
+ EXPECT_EQ(3u, observer.start_log.size());
+ EXPECT_EQ(2u, observer.finish_log.size());
+ EXPECT_EQ(1u, observer.cancel_log.size());
+
+ // Lookup 0 started and finished.
+ EXPECT_TRUE(observer.start_log[0] ==
+ TestHostResolverObserver::StartOrCancelEntry(0, info0_));
+ EXPECT_TRUE(observer.finish_log[0] ==
+ TestHostResolverObserver::FinishEntry(0, true, info0_));
+
+ // Ditto for lookup 1.
+ EXPECT_TRUE(observer.start_log[1] ==
+ TestHostResolverObserver::StartOrCancelEntry(1, info1_));
+ EXPECT_TRUE(observer.finish_log[1] ==
+ TestHostResolverObserver::FinishEntry(1, true, info1_));
+
+ // Lookup 2 was cancelled, hence, failed to finish.
+ EXPECT_TRUE(observer.start_log[2] ==
+ TestHostResolverObserver::StartOrCancelEntry(2, info2_));
+ EXPECT_TRUE(observer.cancel_log[0] ==
+ TestHostResolverObserver::StartOrCancelEntry(2, info2_));
+
+ // Unregister observer.
+ resolver_->RemoveObserver(&observer);
+
+ // We will do lookup 2 again but will not be cancel it this time.
+ rv2 = resolver_->Resolve(info2_, &addrlist2_, &callback2_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv2);
+
+ // Run lookup 2 to completion.
+ rv2 = callback2_.WaitForResult();
+ EXPECT_EQ(OK, rv2);
+ VerifyAddressList(ip_addresses2_, kPortNum, addrlist2_);
+
+ // Observer log should stay the same.
+ EXPECT_EQ(3u, observer.start_log.size());
+ EXPECT_EQ(2u, observer.finish_log.size());
+ EXPECT_EQ(1u, observer.cancel_log.size());
+
+ // Re-register observer.
+ resolver_->AddObserver(&observer);
+
+ // Start lookup 3.
+ int rv3 = resolver_->Resolve(info3_, &addrlist3_, &callback3_, NULL,
+ BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv3);
+
+ // Destroy the resolver and make sure that observer was notified of just
+ // the resolution start.
+ resolver_.reset();
+
+ EXPECT_EQ(4u, observer.start_log.size()); // Was incremented by 1.
+ EXPECT_EQ(2u, observer.finish_log.size());
+ EXPECT_EQ(1u, observer.cancel_log.size());
+
+ EXPECT_TRUE(observer.start_log[3] ==
+ TestHostResolverObserver::StartOrCancelEntry(4, info3_));
+}
+
+} // namespace net
diff --git a/net/base/dns_test_util.cc b/net/base/dns_test_util.cc
index f448b6f..d7f6803 100644
--- a/net/base/dns_test_util.cc
+++ b/net/base/dns_test_util.cc
@@ -22,6 +22,41 @@ int TestPrng::GetNext(int min, int max) {
return rv;
}
+bool operator==(const HostResolver::RequestInfo& a,
+ const HostResolver::RequestInfo& b) {
+ return a.hostname() == b.hostname() &&
+ a.port() == b.port() &&
+ a.allow_cached_response() == b.allow_cached_response() &&
+ a.priority() == b.priority() &&
+ a.is_speculative() == b.is_speculative() &&
+ a.referrer() == b.referrer();
+}
+
+TestHostResolverObserver::TestHostResolverObserver() {
+}
+
+TestHostResolverObserver::~TestHostResolverObserver() {
+}
+
+void TestHostResolverObserver::OnStartResolution(
+ int id,
+ const HostResolver::RequestInfo& info) {
+ start_log.push_back(StartOrCancelEntry(id, info));
+}
+
+void TestHostResolverObserver::OnFinishResolutionWithStatus(
+ int id,
+ bool was_resolved,
+ const HostResolver::RequestInfo& info) {
+ finish_log.push_back(FinishEntry(id, was_resolved, info));
+}
+
+void TestHostResolverObserver::OnCancelResolution(
+ int id,
+ const HostResolver::RequestInfo& info) {
+ cancel_log.push_back(StartOrCancelEntry(id, info));
+}
+
bool ConvertStringsToIPAddressList(
const char* const ip_strings[], size_t size, IPAddressList* address_list) {
DCHECK(address_list);
diff --git a/net/base/dns_test_util.h b/net/base/dns_test_util.h
index 96ce38a..04d8652 100644
--- a/net/base/dns_test_util.h
+++ b/net/base/dns_test_util.h
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "net/base/dns_transaction.h"
#include "net/base/dns_util.h"
+#include "net/base/host_resolver.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_util.h"
@@ -34,6 +35,62 @@ class TestPrng {
DISALLOW_COPY_AND_ASSIGN(TestPrng);
};
+bool operator==(const HostResolver::RequestInfo& a,
+ const HostResolver::RequestInfo& b);
+
+// Observer that just makes note of how it was called. The test code can then
+// inspect to make sure it was called with the right parameters. Used by
+// HostResolverImpl and AsyncHostResolver unit tests.
+class TestHostResolverObserver : public HostResolver::Observer {
+ public:
+ TestHostResolverObserver();
+ virtual ~TestHostResolverObserver();
+
+ // HostResolver::Observer methods:
+ virtual void OnStartResolution(int id, const HostResolver::RequestInfo& info);
+ virtual void OnFinishResolutionWithStatus(
+ int id,
+ bool was_resolved,
+ const HostResolver::RequestInfo& info);
+ virtual void OnCancelResolution(
+ int id,
+ const HostResolver::RequestInfo& info);
+
+ // Tuple (id, info).
+ struct StartOrCancelEntry {
+ StartOrCancelEntry(int id, const HostResolver::RequestInfo& info)
+ : id(id), info(info) {}
+
+ bool operator==(const StartOrCancelEntry& other) const {
+ return id == other.id && info == other.info;
+ }
+
+ int id;
+ HostResolver::RequestInfo info;
+ };
+
+ // Tuple (id, was_resolved, info).
+ struct FinishEntry {
+ FinishEntry(int id, bool was_resolved,
+ const HostResolver::RequestInfo& info)
+ : id(id), was_resolved(was_resolved), info(info) {}
+
+ bool operator==(const FinishEntry& other) const {
+ return id == other.id &&
+ was_resolved == other.was_resolved &&
+ info == other.info;
+ }
+
+ int id;
+ bool was_resolved;
+ HostResolver::RequestInfo info;
+ };
+
+ std::vector<StartOrCancelEntry> start_log;
+ std::vector<FinishEntry> finish_log;
+ std::vector<StartOrCancelEntry> cancel_log;
+};
+
// A utility function for tests that given an array of IP literals,
// converts it to an IPAddressList.
bool ConvertStringsToIPAddressList(
@@ -47,29 +104,26 @@ static const char kDnsIp[] = "192.168.1.1";
static const uint16 kDnsPort = 53;
//-----------------------------------------------------------------------------
-// Query/response set for www.google.com, ID is fixed to 1.
-
-static const uint16 kT1Qtype = kDNS_A;
-
-static const char kT1DnsName[] = {
+// Query/response set for www.google.com, ID is fixed to 0.
+static const char kT0HostName[] = "www.google.com";
+static const uint16 kT0Qtype = kDNS_A;
+static const char kT0DnsName[] = {
0x03, 'w', 'w', 'w',
0x06, 'g', 'o', 'o', 'g', 'l', 'e',
0x03, 'c', 'o', 'm',
0x00
};
-
-static const uint8 kT1QueryDatagram[] = {
+static const uint8 kT0QueryDatagram[] = {
// query for www.google.com, type A.
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
};
-
-static const uint8 kT1ResponseDatagram[] = {
+static const uint8 kT0ResponseDatagram[] = {
// response contains one CNAME for www.l.google.com and the following
// IP addresses: 74.125.226.{179,180,176,177,178}
- 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06,
+ 0x00, 0x00, 0x81, 0x80, 0x00, 0x01, 0x00, 0x06,
0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
@@ -87,37 +141,34 @@ static const uint8 kT1ResponseDatagram[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x04,
0x4a, 0x7d, 0xe2, 0xb2
};
-
-static const char* const kT1IpAddresses[] = {
+static const char* const kT0IpAddresses[] = {
"74.125.226.179", "74.125.226.180", "74.125.226.176",
"74.125.226.177", "74.125.226.178"
};
//-----------------------------------------------------------------------------
-// Query/response set for codereview.chromium.org, ID is fixed to 2.
-static const uint16 kT2Qtype = kDNS_A;
-
-static const char kT2DnsName[] = {
+// Query/response set for codereview.chromium.org, ID is fixed to 1.
+static const char kT1HostName[] = "codereview.chromium.org";
+static const uint16 kT1Qtype = kDNS_A;
+static const char kT1DnsName[] = {
0x12, 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w',
0x10, 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm',
0x03, 'o', 'r', 'g',
0x00
};
-
-static const uint8 kT2QueryDatagram[] = {
+static const uint8 kT1QueryDatagram[] = {
// query for codereview.chromium.org, type A.
- 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
0x03, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x01, 0x00,
0x01
};
-
-static const uint8 kT2ResponseDatagram[] = {
+static const uint8 kT1ResponseDatagram[] = {
// response contains one CNAME for ghs.l.google.com and the following
// IP address: 64.233.169.121
- 0x00, 0x02, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, 0x64,
0x65, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x08,
0x63, 0x68, 0x72, 0x6f, 0x6d, 0x69, 0x75, 0x6d,
@@ -129,8 +180,92 @@ static const uint8 kT2ResponseDatagram[] = {
0x35, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01,
0x0b, 0x00, 0x04, 0x40, 0xe9, 0xa9, 0x79
};
+static const char* const kT1IpAddresses[] = {
+ "64.233.169.121"
+};
//-----------------------------------------------------------------------------
+// Query/response set for www.ccs.neu.edu, ID is fixed to 2.
+static const char kT2HostName[] = "www.ccs.neu.edu";
+static const uint16 kT2Qtype = kDNS_A;
+static const char kT2DnsName[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x03, 'c', 'c', 'c',
+ 0x03, 'n', 'e', 'u',
+ 0x03, 'e', 'd', 'u',
+ 0x00
+};
+static const uint8 kT2QueryDatagram[] = {
+ // query for www.ccs.neu.edu, type A.
+ 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x03, 0x63, 0x63, 0x73, 0x03, 0x6e, 0x65, 0x75,
+ 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00,
+ 0x01
+};
+static const uint8 kT2ResponseDatagram[] = {
+ // response contains one CNAME for vulcan.ccs.neu.edu and the following
+ // IP address: 129.10.116.81
+ 0x00, 0x02, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x03, 0x63, 0x63, 0x73, 0x03, 0x6e, 0x65, 0x75,
+ 0x03, 0x65, 0x64, 0x75, 0x00, 0x00, 0x01, 0x00,
+ 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00,
+ 0x00, 0x01, 0x2c, 0x00, 0x09, 0x06, 0x76, 0x75,
+ 0x6c, 0x63, 0x61, 0x6e, 0xc0, 0x10, 0xc0, 0x2d,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c,
+ 0x00, 0x04, 0x81, 0x0a, 0x74, 0x51
+};
+static const char* const kT2IpAddresses[] = {
+ "129.10.116.81"
+};
+
+//-----------------------------------------------------------------------------
+// Query/response set for www.google.az, ID is fixed to 3.
+static const char kT3HostName[] = "www.google.az";
+static const uint16 kT3Qtype = kDNS_A;
+static const char kT3DnsName[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x02, 'a', 'z',
+ 0x00
+};
+static const uint8 kT3QueryDatagram[] = {
+ // query for www.google.az, type A.
+ 0x00, 0x03, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x02,
+ 0x61, 0x7a, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+static const uint8 kT3ResponseDatagram[] = {
+ // response contains www.google.com as CNAME for www.google.az and
+ // www.l.google.com as CNAME for www.google.com and the following
+ // IP addresses: 74.125.226.{178,179,180,176,177}
+ 0x00, 0x03, 0x81, 0x80, 0x00, 0x01, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x02,
+ 0x61, 0x7a, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
+ 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x50,
+ 0x99, 0x00, 0x10, 0x03, 0x77, 0x77, 0x77, 0x06,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
+ 0x6f, 0x6d, 0x00, 0xc0, 0x2b, 0x00, 0x05, 0x00,
+ 0x01, 0x00, 0x01, 0x50, 0x99, 0x00, 0x08, 0x03,
+ 0x77, 0x77, 0x77, 0x01, 0x6c, 0xc0, 0x2f, 0xc0,
+ 0x47, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb2, 0xc0,
+ 0x47, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb3, 0xc0,
+ 0x47, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb4, 0xc0,
+ 0x47, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb0, 0xc0,
+ 0x47, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x15, 0x00, 0x04, 0x4a, 0x7d, 0xe2, 0xb1
+};
+static const char* const kT3IpAddresses[] = {
+ "74.125.226.178", "74.125.226.179", "74.125.226.180",
+ "74.125.226.176", "74.125.226.177"
+};
} // namespace net
diff --git a/net/base/dns_transaction_unittest.cc b/net/base/dns_transaction_unittest.cc
index 6c532f2..2e557e9 100644
--- a/net/base/dns_transaction_unittest.cc
+++ b/net/base/dns_transaction_unittest.cc
@@ -53,48 +53,48 @@ class TestDelegate : public DnsTransaction::Delegate {
TEST(DnsTransactionTest, NormalQueryResponseTest) {
- MockWrite writes1[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
- arraysize(kT1QueryDatagram))
+ MockWrite writes0[] = {
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram))
};
- MockRead reads1[] = {
- MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
- arraysize(kT1ResponseDatagram))
+ MockRead reads0[] = {
+ MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram))
};
- StaticSocketDataProvider data(reads1, arraysize(reads1),
- writes1, arraysize(writes1));
+ StaticSocketDataProvider data(reads0, arraysize(reads0),
+ writes0, arraysize(writes0));
MockClientSocketFactory factory;
factory.AddSocketDataProvider(&data);
- TestPrng test_prng(std::deque<int>(1, 1));
+ TestPrng test_prng(std::deque<int>(1, 0));
RandIntCallback rand_int_cb =
base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
- std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+ std::string t0_dns_name(kT0DnsName, arraysize(kT0DnsName));
IPEndPoint dns_server;
- bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv0);
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv);
- DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory,
+ DnsTransaction t(dns_server, t0_dns_name, kT1Qtype, rand_int_cb, &factory,
BoundNetLog(), NULL);
TestDelegate delegate;
t.SetDelegate(&delegate);
IPAddressList expected_ip_addresses;
- rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
- arraysize(kT1IpAddresses),
- &expected_ip_addresses);
- ASSERT_TRUE(rv0);
+ rv = ConvertStringsToIPAddressList(kT0IpAddresses,
+ arraysize(kT0IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv);
- int rv = t.Start();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv0 = t.Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
MessageLoop::current()->Run();
- EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_TRUE(DnsTransaction::Key(t0_dns_name, kT0Qtype) == t.key());
EXPECT_EQ(OK, delegate.result());
EXPECT_EQ(&t, delegate.transaction());
EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
@@ -104,42 +104,42 @@ TEST(DnsTransactionTest, NormalQueryResponseTest) {
}
TEST(DnsTransactionTest, MismatchedQueryResponseTest) {
- MockWrite writes1[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
- arraysize(kT1QueryDatagram))
+ MockWrite writes0[] = {
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram))
};
- MockRead reads2[] = {
- MockRead(true, reinterpret_cast<const char*>(kT2ResponseDatagram),
- arraysize(kT2ResponseDatagram))
+ MockRead reads1[] = {
+ MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
+ arraysize(kT1ResponseDatagram))
};
- StaticSocketDataProvider data(reads2, arraysize(reads2),
- writes1, arraysize(writes1));
+ StaticSocketDataProvider data(reads1, arraysize(reads1),
+ writes0, arraysize(writes0));
MockClientSocketFactory factory;
factory.AddSocketDataProvider(&data);
- TestPrng test_prng(std::deque<int>(1, 1));
+ TestPrng test_prng(std::deque<int>(1, 0));
RandIntCallback rand_int_cb =
base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
- std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+ std::string t0_dns_name(kT0DnsName, arraysize(kT0DnsName));
IPEndPoint dns_server;
- bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv0);
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv);
- DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory,
+ DnsTransaction t(dns_server, t0_dns_name, kT1Qtype, rand_int_cb, &factory,
BoundNetLog(), NULL);
TestDelegate delegate;
t.SetDelegate(&delegate);
- int rv = t.Start();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv0 = t.Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
MessageLoop::current()->Run();
- EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_TRUE(DnsTransaction::Key(t0_dns_name, kT0Qtype) == t.key());
EXPECT_EQ(ERR_DNS_MALFORMED_RESPONSE, delegate.result());
EXPECT_EQ(0u, delegate.ip_addresses().size());
EXPECT_EQ(&t, delegate.transaction());
@@ -150,35 +150,35 @@ TEST(DnsTransactionTest, MismatchedQueryResponseTest) {
// Test that after the first timeout we do a fresh connection and if we get
// a response on the new connection, we return it.
TEST(DnsTransactionTest, FirstTimeoutTest) {
- MockWrite writes1[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
- arraysize(kT1QueryDatagram))
+ MockWrite writes0[] = {
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram))
};
- MockRead reads1[] = {
- MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
- arraysize(kT1ResponseDatagram))
+ MockRead reads0[] = {
+ MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram))
};
+ scoped_refptr<DelayedSocketData> socket0_data(
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
- scoped_refptr<DelayedSocketData> socket2_data(
- new DelayedSocketData(0, reads1, arraysize(reads1),
- writes1, arraysize(writes1)));
+ new DelayedSocketData(0, reads0, arraysize(reads0),
+ writes0, arraysize(writes0)));
MockClientSocketFactory factory;
+ factory.AddSocketDataProvider(socket0_data.get());
factory.AddSocketDataProvider(socket1_data.get());
- factory.AddSocketDataProvider(socket2_data.get());
- TestPrng test_prng(std::deque<int>(2, 1));
+ TestPrng test_prng(std::deque<int>(2, 0));
RandIntCallback rand_int_cb =
base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
- std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+ std::string t0_dns_name(kT0DnsName, arraysize(kT0DnsName));
IPEndPoint dns_server;
- bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv0);
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv);
- DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory,
+ DnsTransaction t(dns_server, t0_dns_name, kT1Qtype, rand_int_cb, &factory,
BoundNetLog(), NULL);
TestDelegate delegate;
@@ -189,25 +189,26 @@ TEST(DnsTransactionTest, FirstTimeoutTest) {
kTimeoutsMs + arraysize(kTimeoutsMs)));
IPAddressList expected_ip_addresses;
- rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
- arraysize(kT1IpAddresses),
- &expected_ip_addresses);
- ASSERT_TRUE(rv0);
+ rv = ConvertStringsToIPAddressList(kT0IpAddresses,
+ arraysize(kT0IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv);
+
+ int rv0 = t.Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
- int rv = t.Start();
- EXPECT_EQ(ERR_IO_PENDING, rv);
MessageLoop::current()->Run();
- EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_TRUE(DnsTransaction::Key(t0_dns_name, kT0Qtype) == t.key());
EXPECT_EQ(OK, delegate.result());
EXPECT_EQ(&t, delegate.transaction());
EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
+ EXPECT_TRUE(socket0_data->at_read_eof());
+ EXPECT_TRUE(socket0_data->at_write_eof());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
- EXPECT_TRUE(socket2_data->at_read_eof());
- EXPECT_TRUE(socket2_data->at_write_eof());
EXPECT_EQ(2u, factory.udp_client_sockets().size());
}
@@ -215,38 +216,38 @@ TEST(DnsTransactionTest, FirstTimeoutTest) {
// the second timeout we do another fresh connection, and if we get a
// response on the second connection, we return it.
TEST(DnsTransactionTest, SecondTimeoutTest) {
- MockWrite writes1[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
- arraysize(kT1QueryDatagram))
+ MockWrite writes0[] = {
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram))
};
- MockRead reads1[] = {
- MockRead(true, reinterpret_cast<const char*>(kT1ResponseDatagram),
- arraysize(kT1ResponseDatagram))
+ MockRead reads0[] = {
+ MockRead(true, reinterpret_cast<const char*>(kT0ResponseDatagram),
+ arraysize(kT0ResponseDatagram))
};
+ scoped_refptr<DelayedSocketData> socket0_data(
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
scoped_refptr<DelayedSocketData> socket2_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
- scoped_refptr<DelayedSocketData> socket3_data(
- new DelayedSocketData(0, reads1, arraysize(reads1),
- writes1, arraysize(writes1)));
+ new DelayedSocketData(0, reads0, arraysize(reads0),
+ writes0, arraysize(writes0)));
MockClientSocketFactory factory;
+ factory.AddSocketDataProvider(socket0_data.get());
factory.AddSocketDataProvider(socket1_data.get());
factory.AddSocketDataProvider(socket2_data.get());
- factory.AddSocketDataProvider(socket3_data.get());
- TestPrng test_prng(std::deque<int>(3, 1));
+ TestPrng test_prng(std::deque<int>(3, 0));
RandIntCallback rand_int_cb =
base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
- std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+ std::string t0_dns_name(kT0DnsName, arraysize(kT0DnsName));
IPEndPoint dns_server;
- bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv0);
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv);
- DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory,
+ DnsTransaction t(dns_server, t0_dns_name, kT1Qtype, rand_int_cb, &factory,
BoundNetLog(), NULL);
TestDelegate delegate;
@@ -257,27 +258,27 @@ TEST(DnsTransactionTest, SecondTimeoutTest) {
kTimeoutsMs + arraysize(kTimeoutsMs)));
IPAddressList expected_ip_addresses;
- rv0 = ConvertStringsToIPAddressList(kT1IpAddresses,
- arraysize(kT1IpAddresses),
- &expected_ip_addresses);
- ASSERT_TRUE(rv0);
+ rv = ConvertStringsToIPAddressList(kT0IpAddresses,
+ arraysize(kT0IpAddresses),
+ &expected_ip_addresses);
+ ASSERT_TRUE(rv);
- int rv = t.Start();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv0 = t.Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
MessageLoop::current()->Run();
- EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_TRUE(DnsTransaction::Key(t0_dns_name, kT1Qtype) == t.key());
EXPECT_EQ(OK, delegate.result());
EXPECT_EQ(&t, delegate.transaction());
EXPECT_TRUE(expected_ip_addresses == delegate.ip_addresses());
+ EXPECT_TRUE(socket0_data->at_read_eof());
+ EXPECT_TRUE(socket0_data->at_write_eof());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
EXPECT_TRUE(socket2_data->at_read_eof());
EXPECT_TRUE(socket2_data->at_write_eof());
- EXPECT_TRUE(socket3_data->at_read_eof());
- EXPECT_TRUE(socket3_data->at_write_eof());
EXPECT_EQ(3u, factory.udp_client_sockets().size());
}
@@ -285,32 +286,32 @@ TEST(DnsTransactionTest, SecondTimeoutTest) {
// the second timeout we do another fresh connection and after the third
// timeout we give up and return a timeout error.
TEST(DnsTransactionTest, ThirdTimeoutTest) {
- MockWrite writes1[] = {
- MockWrite(true, reinterpret_cast<const char*>(kT1QueryDatagram),
- arraysize(kT1QueryDatagram))
+ MockWrite writes0[] = {
+ MockWrite(true, reinterpret_cast<const char*>(kT0QueryDatagram),
+ arraysize(kT0QueryDatagram))
};
+ scoped_refptr<DelayedSocketData> socket0_data(
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
scoped_refptr<DelayedSocketData> socket1_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
scoped_refptr<DelayedSocketData> socket2_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
- scoped_refptr<DelayedSocketData> socket3_data(
- new DelayedSocketData(2, NULL, 0, writes1, arraysize(writes1)));
+ new DelayedSocketData(2, NULL, 0, writes0, arraysize(writes0)));
MockClientSocketFactory factory;
+ factory.AddSocketDataProvider(socket0_data.get());
factory.AddSocketDataProvider(socket1_data.get());
factory.AddSocketDataProvider(socket2_data.get());
- factory.AddSocketDataProvider(socket3_data.get());
- TestPrng test_prng(std::deque<int>(3, 1));
+ TestPrng test_prng(std::deque<int>(3, 0));
RandIntCallback rand_int_cb =
base::Bind(&TestPrng::GetNext, base::Unretained(&test_prng));
- std::string t1_dns_name(kT1DnsName, arraysize(kT1DnsName));
+ std::string t0_dns_name(kT0DnsName, arraysize(kT0DnsName));
IPEndPoint dns_server;
- bool rv0 = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
- ASSERT_TRUE(rv0);
+ bool rv = CreateDnsAddress(kDnsIp, kDnsPort, &dns_server);
+ ASSERT_TRUE(rv);
- DnsTransaction t(dns_server, t1_dns_name, kT1Qtype, rand_int_cb, &factory,
+ DnsTransaction t(dns_server, t0_dns_name, kT1Qtype, rand_int_cb, &factory,
BoundNetLog(), NULL);
TestDelegate delegate;
@@ -320,21 +321,21 @@ TEST(DnsTransactionTest, ThirdTimeoutTest) {
std::vector<base::TimeDelta>(kTimeoutsMs,
kTimeoutsMs + arraysize(kTimeoutsMs)));
- int rv = t.Start();
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ int rv0 = t.Start();
+ EXPECT_EQ(ERR_IO_PENDING, rv0);
MessageLoop::current()->Run();
- EXPECT_TRUE(DnsTransaction::Key(t1_dns_name, kT1Qtype) == t.key());
+ EXPECT_TRUE(DnsTransaction::Key(t0_dns_name, kT0Qtype) == t.key());
EXPECT_EQ(ERR_DNS_TIMED_OUT, delegate.result());
EXPECT_EQ(&t, delegate.transaction());
+ EXPECT_TRUE(socket0_data->at_read_eof());
+ EXPECT_TRUE(socket0_data->at_write_eof());
EXPECT_TRUE(socket1_data->at_read_eof());
EXPECT_TRUE(socket1_data->at_write_eof());
EXPECT_TRUE(socket2_data->at_read_eof());
EXPECT_TRUE(socket2_data->at_write_eof());
- EXPECT_TRUE(socket3_data->at_read_eof());
- EXPECT_TRUE(socket3_data->at_write_eof());
EXPECT_EQ(3u, factory.udp_client_sockets().size());
}
diff --git a/net/base/host_resolver.h b/net/base/host_resolver.h
index d46fcc3..77977c1 100644
--- a/net/base/host_resolver.h
+++ b/net/base/host_resolver.h
@@ -14,6 +14,7 @@
#include "net/base/completion_callback.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_api.h"
+#include "net/base/net_util.h"
#include "net/base/request_priority.h"
namespace net {
@@ -209,6 +210,11 @@ NET_API HostResolver* CreateSystemHostResolver(size_t max_concurrent_resolves,
size_t max_retry_attempts,
NetLog* net_log);
+// Creates a HostResolver implementation that sends actual DNS queries to
+// the specified DNS server and parses response and returns results.
+NET_API HostResolver* CreateAsyncHostResolver(size_t max_concurrent_resolves,
+ const IPAddressNumber& dns_ip,
+ NetLog* net_log);
} // namespace net
#endif // NET_BASE_HOST_RESOLVER_H_
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index 52b7f89..a833599 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -16,6 +16,7 @@
#include "base/time.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
+#include "net/base/dns_test_util.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/net_log_unittest.h"
@@ -979,73 +980,6 @@ TEST_F(HostResolverImplTest, BypassCache) {
MessageLoop::current()->Run();
}
-bool operator==(const HostResolver::RequestInfo& a,
- const HostResolver::RequestInfo& b) {
- return a.hostname() == b.hostname() &&
- a.port() == b.port() &&
- a.allow_cached_response() == b.allow_cached_response() &&
- a.priority() == b.priority() &&
- a.is_speculative() == b.is_speculative() &&
- a.referrer() == b.referrer();
-}
-
-// Observer that just makes note of how it was called. The test code can then
-// inspect to make sure it was called with the right parameters.
-class CapturingObserver : public HostResolver::Observer {
- public:
- // DnsResolutionObserver methods:
- virtual void OnStartResolution(int id,
- const HostResolver::RequestInfo& info) {
- start_log.push_back(StartOrCancelEntry(id, info));
- }
-
- virtual void OnFinishResolutionWithStatus(
- int id,
- bool was_resolved,
- const HostResolver::RequestInfo& info) {
- finish_log.push_back(FinishEntry(id, was_resolved, info));
- }
-
- virtual void OnCancelResolution(int id,
- const HostResolver::RequestInfo& info) {
- cancel_log.push_back(StartOrCancelEntry(id, info));
- }
-
- // Tuple (id, info).
- struct StartOrCancelEntry {
- StartOrCancelEntry(int id, const HostResolver::RequestInfo& info)
- : id(id), info(info) {}
-
- bool operator==(const StartOrCancelEntry& other) const {
- return id == other.id && info == other.info;
- }
-
- int id;
- HostResolver::RequestInfo info;
- };
-
- // Tuple (id, was_resolved, info).
- struct FinishEntry {
- FinishEntry(int id, bool was_resolved,
- const HostResolver::RequestInfo& info)
- : id(id), was_resolved(was_resolved), info(info) {}
-
- bool operator==(const FinishEntry& other) const {
- return id == other.id &&
- was_resolved == other.was_resolved &&
- info == other.info;
- }
-
- int id;
- bool was_resolved;
- HostResolver::RequestInfo info;
- };
-
- std::vector<StartOrCancelEntry> start_log;
- std::vector<FinishEntry> finish_log;
- std::vector<StartOrCancelEntry> cancel_log;
-};
-
// Test that registering, unregistering, and notifying of observers works.
// Does not test the cancellation notification since all resolves are
// synchronous.
@@ -1053,7 +987,7 @@ TEST_F(HostResolverImplTest, Observers) {
scoped_ptr<HostResolver> host_resolver(
CreateHostResolverImpl(NULL));
- CapturingObserver observer;
+ TestHostResolverObserver observer;
host_resolver->AddObserver(&observer);
@@ -1078,9 +1012,9 @@ TEST_F(HostResolverImplTest, Observers) {
EXPECT_EQ(1U, observer.finish_log.size());
EXPECT_EQ(0U, observer.cancel_log.size());
EXPECT_TRUE(observer.start_log[0] ==
- CapturingObserver::StartOrCancelEntry(0, info1));
+ TestHostResolverObserver::StartOrCancelEntry(0, info1));
EXPECT_TRUE(observer.finish_log[0] ==
- CapturingObserver::FinishEntry(0, true, info1));
+ TestHostResolverObserver::FinishEntry(0, true, info1));
// Resolve "host1" again -- this time it will be served from cache, but it
// should still notify of completion.
@@ -1092,9 +1026,9 @@ TEST_F(HostResolverImplTest, Observers) {
EXPECT_EQ(2U, observer.finish_log.size());
EXPECT_EQ(0U, observer.cancel_log.size());
EXPECT_TRUE(observer.start_log[1] ==
- CapturingObserver::StartOrCancelEntry(1, info1));
+ TestHostResolverObserver::StartOrCancelEntry(1, info1));
EXPECT_TRUE(observer.finish_log[1] ==
- CapturingObserver::FinishEntry(1, true, info1));
+ TestHostResolverObserver::FinishEntry(1, true, info1));
// Resolve "host2", setting referrer to "http://foobar.com"
HostResolver::RequestInfo info2(HostPortPair("host2", 70));
@@ -1106,9 +1040,9 @@ TEST_F(HostResolverImplTest, Observers) {
EXPECT_EQ(3U, observer.finish_log.size());
EXPECT_EQ(0U, observer.cancel_log.size());
EXPECT_TRUE(observer.start_log[2] ==
- CapturingObserver::StartOrCancelEntry(2, info2));
+ TestHostResolverObserver::StartOrCancelEntry(2, info2));
EXPECT_TRUE(observer.finish_log[2] ==
- CapturingObserver::FinishEntry(2, true, info2));
+ TestHostResolverObserver::FinishEntry(2, true, info2));
// Unregister the observer.
host_resolver->RemoveObserver(&observer);
@@ -1128,7 +1062,7 @@ TEST_F(HostResolverImplTest, Observers) {
// (1) Delete the HostResolver while job is outstanding.
// (2) Call HostResolver::CancelRequest() while a request is outstanding.
TEST_F(HostResolverImplTest, CancellationObserver) {
- CapturingObserver observer;
+ TestHostResolverObserver observer;
{
// Create a host resolver and attach an observer.
scoped_ptr<HostResolver> host_resolver(
@@ -1155,7 +1089,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
EXPECT_EQ(0U, observer.cancel_log.size());
EXPECT_TRUE(observer.start_log[0] ==
- CapturingObserver::StartOrCancelEntry(0, info1));
+ TestHostResolverObserver::StartOrCancelEntry(0, info1));
// Cancel the request.
host_resolver->CancelRequest(req);
@@ -1165,7 +1099,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
EXPECT_EQ(1U, observer.cancel_log.size());
EXPECT_TRUE(observer.cancel_log[0] ==
- CapturingObserver::StartOrCancelEntry(0, info1));
+ TestHostResolverObserver::StartOrCancelEntry(0, info1));
// Start an async request for (host2:60)
HostResolver::RequestInfo info2(HostPortPair("host2", 60));
@@ -1179,7 +1113,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
EXPECT_EQ(1U, observer.cancel_log.size());
EXPECT_TRUE(observer.start_log[1] ==
- CapturingObserver::StartOrCancelEntry(1, info2));
+ TestHostResolverObserver::StartOrCancelEntry(1, info2));
// Upon exiting this scope, HostResolver is destroyed, so all requests are
// implicitly cancelled.
@@ -1194,7 +1128,7 @@ TEST_F(HostResolverImplTest, CancellationObserver) {
HostResolver::RequestInfo info(HostPortPair("host2", 60));
EXPECT_TRUE(observer.cancel_log[1] ==
- CapturingObserver::StartOrCancelEntry(1, info));
+ TestHostResolverObserver::StartOrCancelEntry(1, info));
}
// Test that IP address changes flush the cache.
@@ -1364,7 +1298,7 @@ TEST_F(HostResolverImplTest, HigherPriorityRequestsStartedFirst) {
new HostResolverImpl(resolver_proc, CreateDefaultCache(), kMaxJobs,
kRetryAttempts, NULL));
- CapturingObserver observer;
+ TestHostResolverObserver observer;
host_resolver->AddObserver(&observer);
// Note that at this point the CapturingHostResolverProc is blocked, so any
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index f0c2333..8e57c96 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -1077,8 +1077,8 @@ EVENT_TYPE(THROTTLING_GOT_CUSTOM_RETRY_AFTER)
//
// {
// "net_error": <The net error code for the failure>,
-// "ip_address_list": <The result of the resolution process -- list of IP
-// addresses>,
+// "ip_address_list": <The result of the resolution process,
+// an IPAddressList>
// }
EVENT_TYPE(DNS_TRANSACTION)
@@ -1093,3 +1093,39 @@ EVENT_TYPE(DNS_TRANSACTION)
// attempt>,
// }
EVENT_TYPE(DNS_TRANSACTION_ATTEMPT_STARTED)
+
+// ------------------------------------------------------------------------
+// AsyncHostResolver
+// ------------------------------------------------------------------------
+
+// The start/end of waiting on a host resolve (DNS) request.
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "source_dependency": <Source id of the request being waited on>,
+// }
+EVENT_TYPE(ASYNC_HOST_RESOLVER)
+
+// The start/end of a host resolve (DNS) request.
+//
+// The BEGIN phase contains the following parameters:
+//
+// {
+// "hostname": <Hostname associated with the request>,
+// "address_family": <Address family of the request>,
+// "allow_cached_response": <Whether to allow cached response>,
+// "only_use_cached_response": <Use cached results only>,
+// "is_speculative": <Whether the lookup is speculative>,
+// "priority": <Priority of the request>,
+// "source_dependency": <Source id, if any, of what created the request>,
+// }
+//
+// The END phase will contain this parameter:
+// {
+// "net_error": <The net error code integer>,
+// }
+EVENT_TYPE(ASYNC_HOST_RESOLVER_REQUEST)
+
+// This event is created when a new DnsTransaction is about to be created
+// for a request.
+EVENT_TYPE(ASYNC_HOST_RESOLVER_CREATE_DNS_TRANSACTION)
diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h
index 2fcd534..de80d14 100644
--- a/net/base/net_log_source_type_list.h
+++ b/net/base/net_log_source_type_list.h
@@ -21,5 +21,6 @@ SOURCE_TYPE(MEMORY_CACHE_ENTRY, 10)
SOURCE_TYPE(HTTP_STREAM_JOB, 11)
SOURCE_TYPE(EXPONENTIAL_BACKOFF_THROTTLING, 12)
SOURCE_TYPE(DNS_TRANSACTION, 13)
+SOURCE_TYPE(ASYNC_HOST_RESOLVER_REQUEST, 14)
-SOURCE_TYPE(COUNT, 14) // Always keep this as the last entry.
+SOURCE_TYPE(COUNT, 15) // Always keep this as the last entry.
diff --git a/net/net.gyp b/net/net.gyp
index f83cc76..12cfe91 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -31,6 +31,8 @@
'base/address_list_net_log_param.h',
'base/asn1_util.cc',
'base/asn1_util.h',
+ 'base/async_host_resolver.cc',
+ 'base/async_host_resolver.h',
'base/auth.cc',
'base/auth.h',
'base/backoff_entry.cc',
@@ -872,6 +874,7 @@
],
'sources': [
'base/address_list_unittest.cc',
+ 'base/async_host_resolver_unittest.cc',
'base/backoff_entry_unittest.cc',
'base/cert_database_nss_unittest.cc',
'base/cert_verifier_unittest.cc',