summaryrefslogtreecommitdiffstats
path: root/net/dns/mock_host_resolver.cc
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-21 01:40:53 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-21 01:40:53 +0000
commitf2cb3cf86e4217581443d93e863c891a05066e60 (patch)
treec62110d2347d17e1b1a1f57fa758cf8bba72548b /net/dns/mock_host_resolver.cc
parentb8512263f9556ac705394e9da03d364980f0eadf (diff)
downloadchromium_src-f2cb3cf86e4217581443d93e863c891a05066e60.zip
chromium_src-f2cb3cf86e4217581443d93e863c891a05066e60.tar.gz
chromium_src-f2cb3cf86e4217581443d93e863c891a05066e60.tar.bz2
net: move host_resolver files from net/base to net/dns
BUG=70818 Review URL: https://codereview.chromium.org/12518036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@189485 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/dns/mock_host_resolver.cc')
-rw-r--r--net/dns/mock_host_resolver.cc417
1 files changed, 417 insertions, 0 deletions
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
new file mode 100644
index 0000000..fb03836
--- /dev/null
+++ b/net/dns/mock_host_resolver.cc
@@ -0,0 +1,417 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/dns/mock_host_resolver.h"
+
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/strings/string_split.h"
+#include "base/threading/platform_thread.h"
+#include "net/base/host_cache.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util.h"
+#include "net/base/test_completion_callback.h"
+#if defined(OS_WIN)
+#include "net/base/winsock_init.h"
+#endif
+
+namespace net {
+
+namespace {
+
+// Cache size for the MockCachingHostResolver.
+const unsigned kMaxCacheEntries = 100;
+// TTL for the successful resolutions. Failures are not cached.
+const unsigned kCacheEntryTTLSeconds = 60;
+
+} // namespace
+
+int ParseAddressList(const std::string& host_list,
+ const std::string& canonical_name,
+ AddressList* addrlist) {
+ *addrlist = AddressList();
+ std::vector<std::string> addresses;
+ base::SplitString(host_list, ',', &addresses);
+ addrlist->set_canonical_name(canonical_name);
+ for (size_t index = 0; index < addresses.size(); ++index) {
+ IPAddressNumber ip_number;
+ if (!ParseIPLiteralToNumber(addresses[index], &ip_number)) {
+ LOG(WARNING) << "Not a supported IP literal: " << addresses[index];
+ return ERR_UNEXPECTED;
+ }
+ addrlist->push_back(IPEndPoint(ip_number, -1));
+ }
+ return OK;
+}
+
+struct MockHostResolverBase::Request {
+ Request(const RequestInfo& req_info,
+ AddressList* addr,
+ const CompletionCallback& cb)
+ : info(req_info), addresses(addr), callback(cb) {}
+ RequestInfo info;
+ AddressList* addresses;
+ CompletionCallback callback;
+};
+
+MockHostResolverBase::~MockHostResolverBase() {
+ STLDeleteValues(&requests_);
+}
+
+int MockHostResolverBase::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ RequestHandle* handle,
+ const BoundNetLog& net_log) {
+ DCHECK(CalledOnValidThread());
+ num_resolve_++;
+ size_t id = next_request_id_++;
+ int rv = ResolveFromIPLiteralOrCache(info, addresses);
+ if (rv != ERR_DNS_CACHE_MISS) {
+ return rv;
+ }
+ if (synchronous_mode_) {
+ return ResolveProc(id, info, addresses);
+ }
+ // Store the request for asynchronous resolution
+ Request* req = new Request(info, addresses, callback);
+ requests_[id] = req;
+ if (handle)
+ *handle = reinterpret_cast<RequestHandle>(id);
+
+ if (!ondemand_mode_) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), id));
+ }
+
+ return ERR_IO_PENDING;
+}
+
+int MockHostResolverBase::ResolveFromCache(const RequestInfo& info,
+ AddressList* addresses,
+ const BoundNetLog& net_log) {
+ num_resolve_from_cache_++;
+ DCHECK(CalledOnValidThread());
+ next_request_id_++;
+ int rv = ResolveFromIPLiteralOrCache(info, addresses);
+ return rv;
+}
+
+void MockHostResolverBase::CancelRequest(RequestHandle handle) {
+ DCHECK(CalledOnValidThread());
+ size_t id = reinterpret_cast<size_t>(handle);
+ RequestMap::iterator it = requests_.find(id);
+ if (it != requests_.end()) {
+ scoped_ptr<Request> req(it->second);
+ requests_.erase(it);
+ } else {
+ NOTREACHED() << "CancelRequest must NOT be called after request is "
+ "complete or canceled.";
+ }
+}
+
+HostCache* MockHostResolverBase::GetHostCache() {
+ return cache_.get();
+}
+
+void MockHostResolverBase::ResolveAllPending() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(ondemand_mode_);
+ for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i) {
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), i->first));
+ }
+}
+
+// start id from 1 to distinguish from NULL RequestHandle
+MockHostResolverBase::MockHostResolverBase(bool use_caching)
+ : synchronous_mode_(false),
+ ondemand_mode_(false),
+ next_request_id_(1),
+ num_resolve_(0),
+ num_resolve_from_cache_(0) {
+ rules_ = CreateCatchAllHostResolverProc();
+
+ if (use_caching) {
+ cache_.reset(new HostCache(kMaxCacheEntries));
+ }
+}
+
+int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info,
+ AddressList* addresses) {
+ IPAddressNumber ip;
+ if (ParseIPLiteralToNumber(info.hostname(), &ip)) {
+ *addresses = AddressList::CreateFromIPAddress(ip, info.port());
+ if (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME)
+ addresses->SetDefaultCanonicalName();
+ return OK;
+ }
+ int rv = ERR_DNS_CACHE_MISS;
+ if (cache_.get() && info.allow_cached_response()) {
+ HostCache::Key key(info.hostname(),
+ info.address_family(),
+ info.host_resolver_flags());
+ const HostCache::Entry* entry = cache_->Lookup(key, base::TimeTicks::Now());
+ if (entry) {
+ rv = entry->error;
+ if (rv == OK)
+ *addresses = AddressList::CopyWithPort(entry->addrlist, info.port());
+ }
+ }
+ return rv;
+}
+
+int MockHostResolverBase::ResolveProc(size_t id,
+ const RequestInfo& info,
+ AddressList* addresses) {
+ AddressList addr;
+ int rv = rules_->Resolve(info.hostname(),
+ info.address_family(),
+ info.host_resolver_flags(),
+ &addr,
+ NULL);
+ if (cache_.get()) {
+ HostCache::Key key(info.hostname(),
+ info.address_family(),
+ info.host_resolver_flags());
+ // Storing a failure with TTL 0 so that it overwrites previous value.
+ base::TimeDelta ttl;
+ if (rv == OK)
+ ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds);
+ cache_->Set(key, HostCache::Entry(rv, addr), base::TimeTicks::Now(), ttl);
+ }
+ if (rv == OK)
+ *addresses = AddressList::CopyWithPort(addr, info.port());
+ return rv;
+}
+
+void MockHostResolverBase::ResolveNow(size_t id) {
+ RequestMap::iterator it = requests_.find(id);
+ if (it == requests_.end())
+ return; // was canceled
+
+ scoped_ptr<Request> req(it->second);
+ requests_.erase(it);
+ int rv = ResolveProc(id, req->info, req->addresses);
+ if (!req->callback.is_null())
+ req->callback.Run(rv);
+}
+
+//-----------------------------------------------------------------------------
+
+struct RuleBasedHostResolverProc::Rule {
+ enum ResolverType {
+ kResolverTypeFail,
+ kResolverTypeSystem,
+ kResolverTypeIPLiteral,
+ };
+
+ ResolverType resolver_type;
+ std::string host_pattern;
+ AddressFamily address_family;
+ HostResolverFlags host_resolver_flags;
+ std::string replacement;
+ std::string canonical_name;
+ int latency_ms; // In milliseconds.
+
+ Rule(ResolverType resolver_type,
+ const std::string& host_pattern,
+ AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
+ const std::string& replacement,
+ const std::string& canonical_name,
+ int latency_ms)
+ : resolver_type(resolver_type),
+ host_pattern(host_pattern),
+ address_family(address_family),
+ host_resolver_flags(host_resolver_flags),
+ replacement(replacement),
+ canonical_name(canonical_name),
+ latency_ms(latency_ms) {}
+};
+
+RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc* previous)
+ : HostResolverProc(previous) {
+}
+
+void RuleBasedHostResolverProc::AddRule(const std::string& host_pattern,
+ const std::string& replacement) {
+ AddRuleForAddressFamily(host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ replacement);
+}
+
+void RuleBasedHostResolverProc::AddRuleForAddressFamily(
+ const std::string& host_pattern,
+ AddressFamily address_family,
+ const std::string& replacement) {
+ DCHECK(!replacement.empty());
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, address_family, flags,
+ replacement, "", 0);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::AddIPLiteralRule(
+ const std::string& host_pattern,
+ const std::string& ip_literal,
+ const std::string& canonical_name) {
+ // Literals are always resolved to themselves by HostResolverImpl,
+ // consequently we do not support remapping them.
+ IPAddressNumber ip_number;
+ DCHECK(!ParseIPLiteralToNumber(host_pattern, &ip_number));
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ if (!canonical_name.empty())
+ flags |= HOST_RESOLVER_CANONNAME;
+ Rule rule(Rule::kResolverTypeIPLiteral, host_pattern,
+ ADDRESS_FAMILY_UNSPECIFIED, flags, ip_literal, canonical_name,
+ 0);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::AddRuleWithLatency(
+ const std::string& host_pattern,
+ const std::string& replacement,
+ int latency_ms) {
+ DCHECK(!replacement.empty());
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, replacement, "", latency_ms);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::AllowDirectLookup(
+ const std::string& host_pattern) {
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, "", "", 0);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::AddSimulatedFailure(
+ const std::string& host_pattern) {
+ HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY |
+ HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ Rule rule(Rule::kResolverTypeFail, host_pattern, ADDRESS_FAMILY_UNSPECIFIED,
+ flags, "", "", 0);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::ClearRules() {
+ rules_.clear();
+}
+
+int RuleBasedHostResolverProc::Resolve(const std::string& host,
+ AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
+ AddressList* addrlist,
+ int* os_error) {
+ RuleList::iterator r;
+ for (r = rules_.begin(); r != rules_.end(); ++r) {
+ bool matches_address_family =
+ r->address_family == ADDRESS_FAMILY_UNSPECIFIED ||
+ r->address_family == address_family;
+ // Flags match if all of the bitflags in host_resolver_flags are enabled
+ // in the rule's host_resolver_flags. However, the rule may have additional
+ // flags specified, in which case the flags should still be considered a
+ // match.
+ bool matches_flags = (r->host_resolver_flags & host_resolver_flags) ==
+ host_resolver_flags;
+ if (matches_flags && matches_address_family &&
+ MatchPattern(host, r->host_pattern)) {
+ if (r->latency_ms != 0) {
+ base::PlatformThread::Sleep(
+ base::TimeDelta::FromMilliseconds(r->latency_ms));
+ }
+
+ // Remap to a new host.
+ const std::string& effective_host =
+ r->replacement.empty() ? host : r->replacement;
+
+ // Apply the resolving function to the remapped hostname.
+ switch (r->resolver_type) {
+ case Rule::kResolverTypeFail:
+ return ERR_NAME_NOT_RESOLVED;
+ case Rule::kResolverTypeSystem:
+#if defined(OS_WIN)
+ net::EnsureWinsockInit();
+#endif
+ return SystemHostResolverProc(effective_host,
+ address_family,
+ host_resolver_flags,
+ addrlist, os_error);
+ case Rule::kResolverTypeIPLiteral:
+ return ParseAddressList(effective_host,
+ r->canonical_name,
+ addrlist);
+ default:
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+ }
+ }
+ }
+ return ResolveUsingPrevious(host, address_family,
+ host_resolver_flags, addrlist, os_error);
+}
+
+RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
+}
+
+RuleBasedHostResolverProc* CreateCatchAllHostResolverProc() {
+ RuleBasedHostResolverProc* catchall = new RuleBasedHostResolverProc(NULL);
+ catchall->AddIPLiteralRule("*", "127.0.0.1", "localhost");
+
+ // Next add a rules-based layer the use controls.
+ return new RuleBasedHostResolverProc(catchall);
+}
+
+//-----------------------------------------------------------------------------
+
+int HangingHostResolver::Resolve(const RequestInfo& info,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ RequestHandle* out_req,
+ const BoundNetLog& net_log) {
+ return ERR_IO_PENDING;
+}
+
+int HangingHostResolver::ResolveFromCache(const RequestInfo& info,
+ AddressList* addresses,
+ const BoundNetLog& net_log) {
+ return ERR_DNS_CACHE_MISS;
+}
+
+//-----------------------------------------------------------------------------
+
+ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {}
+
+ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc(
+ HostResolverProc* proc) {
+ Init(proc);
+}
+
+ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() {
+ HostResolverProc* old_proc = HostResolverProc::SetDefault(previous_proc_);
+ // The lifetimes of multiple instances must be nested.
+ CHECK_EQ(old_proc, current_proc_);
+}
+
+void ScopedDefaultHostResolverProc::Init(HostResolverProc* proc) {
+ current_proc_ = proc;
+ previous_proc_ = HostResolverProc::SetDefault(current_proc_);
+ current_proc_->SetLastProc(previous_proc_);
+}
+
+} // namespace net