// 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/mock_host_resolver.h"
#include "base/memory/ref_counted.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/threading/platform_thread.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/sys_addrinfo.h"
namespace net {
namespace {
char* do_strdup(const char* src) {
#if defined(OS_WIN)
return _strdup(src);
#else
return strdup(src);
#endif
}
// Fills |*addrlist| with a socket address for |host_list| which should be a
// comma-separated list of IPv4 or IPv6 literal(s) without enclosing brackets.
// If |canonical_name| is non-empty it is used as the DNS canonical name for
// the host. Returns OK on success, ERR_UNEXPECTED otherwise.
int CreateIPAddressList(const std::string& host_list,
const std::string& canonical_name,
AddressList* addrlist) {
*addrlist = AddressList();
std::vector<std::string> addresses;
base::SplitString(host_list, ',', &addresses);
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;
}
AddressList result(ip_number, -1, false);
struct addrinfo* ai = const_cast<struct addrinfo*>(result.head());
if (index == 0)
ai->ai_canonname = do_strdup(canonical_name.c_str());
if (!addrlist->head())
addrlist->Copy(result.head(), false);
else
addrlist->Append(result.head());
}
return OK;
}
} // namespace
MockHostResolverBase::~MockHostResolverBase() {}
void MockHostResolverBase::Reset(HostResolverProc* interceptor) {
synchronous_mode_ = false;
// At the root of the chain, map everything to localhost.
scoped_refptr<RuleBasedHostResolverProc> catchall(
new RuleBasedHostResolverProc(NULL));
catchall->AddRule("*", "127.0.0.1");
// Next add a rules-based layer the use controls.
rules_ = new RuleBasedHostResolverProc(catchall);
HostResolverProc* proc = rules_;
// Lastly add the provided interceptor to the front of the chain.
if (interceptor) {
interceptor->SetPreviousProc(proc);
proc = interceptor;
}
HostCache* cache = NULL;
if (use_caching_) {
cache = new HostCache(
100, // max entries.
base::TimeDelta::FromMinutes(1),
base::TimeDelta::FromSeconds(0));
}
impl_.reset(new HostResolverImpl(proc, cache, 50u, NULL));
}
int MockHostResolverBase::Resolve(const RequestInfo& info,
AddressList* addresses,
CompletionCallback* callback,
RequestHandle* out_req,
const BoundNetLog& net_log) {
if (synchronous_mode_) {
callback = NULL;
out_req = NULL;
}
return impl_->Resolve(info, addresses, callback, out_req, net_log);
}
void MockHostResolverBase::CancelRequest(RequestHandle req) {
impl_->CancelRequest(req);
}
void MockHostResolverBase::AddObserver(Observer* observer) {
impl_->AddObserver(observer);
}
void MockHostResolverBase::RemoveObserver(Observer* observer) {
impl_->RemoveObserver(observer);
}
MockHostResolverBase::MockHostResolverBase(bool use_caching)
: use_caching_(use_caching) {
Reset(NULL);
}
//-----------------------------------------------------------------------------
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);
}
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(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:
return SystemHostResolverProc(effective_host,
address_family,
host_resolver_flags,
addrlist, os_error);
case Rule::kResolverTypeIPLiteral:
return CreateIPAddressList(effective_host,
r->canonical_name,
addrlist);
default:
NOTREACHED();
return ERR_UNEXPECTED;
}
}
}
return ResolveUsingPrevious(host, address_family,
host_resolver_flags, addrlist, os_error);
}
RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
}
//-----------------------------------------------------------------------------
WaitingHostResolverProc::WaitingHostResolverProc(HostResolverProc* previous)
: HostResolverProc(previous), event_(false, false) {}
void WaitingHostResolverProc::Signal() {
event_.Signal();
}
int WaitingHostResolverProc::Resolve(const std::string& host,
AddressFamily address_family,
HostResolverFlags host_resolver_flags,
AddressList* addrlist,
int* os_error) {
event_.Wait();
return ResolveUsingPrevious(host, address_family, host_resolver_flags,
addrlist, os_error);
}
WaitingHostResolverProc::~WaitingHostResolverProc() {}
//-----------------------------------------------------------------------------
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