1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/dns/mock_host_resolver.h"
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/pattern.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/platform_thread.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h"
23 #include "net/base/test_completion_callback.h"
24 #include "net/dns/host_cache.h"
27 #include "net/base/winsock_init.h"
34 // Cache size for the MockCachingHostResolver.
35 const unsigned kMaxCacheEntries
= 100;
36 // TTL for the successful resolutions. Failures are not cached.
37 const unsigned kCacheEntryTTLSeconds
= 60;
41 int ParseAddressList(const std::string
& host_list
,
42 const std::string
& canonical_name
,
43 AddressList
* addrlist
) {
44 *addrlist
= AddressList();
45 addrlist
->set_canonical_name(canonical_name
);
46 for (const base::StringPiece
& address
: base::SplitStringPiece(
47 host_list
, ",", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
)) {
48 IPAddressNumber ip_number
;
49 if (!ParseIPLiteralToNumber(address
, &ip_number
)) {
50 LOG(WARNING
) << "Not a supported IP literal: " << address
.as_string();
51 return ERR_UNEXPECTED
;
53 addrlist
->push_back(IPEndPoint(ip_number
, 0));
58 struct MockHostResolverBase::Request
{
59 Request(const RequestInfo
& req_info
,
61 const CompletionCallback
& cb
)
62 : info(req_info
), addresses(addr
), callback(cb
) {}
64 AddressList
* addresses
;
65 CompletionCallback callback
;
68 MockHostResolverBase::~MockHostResolverBase() {
69 STLDeleteValues(&requests_
);
72 int MockHostResolverBase::Resolve(const RequestInfo
& info
,
73 RequestPriority priority
,
74 AddressList
* addresses
,
75 const CompletionCallback
& callback
,
76 RequestHandle
* handle
,
77 const BoundNetLog
& net_log
) {
78 DCHECK(CalledOnValidThread());
79 last_request_priority_
= priority
;
81 size_t id
= next_request_id_
++;
82 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
83 if (rv
!= ERR_DNS_CACHE_MISS
) {
86 if (synchronous_mode_
) {
87 return ResolveProc(id
, info
, addresses
);
89 // Store the request for asynchronous resolution
90 Request
* req
= new Request(info
, addresses
, callback
);
93 *handle
= reinterpret_cast<RequestHandle
>(id
);
95 if (!ondemand_mode_
) {
96 base::ThreadTaskRunnerHandle::Get()->PostTask(
98 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), id
));
101 return ERR_IO_PENDING
;
104 int MockHostResolverBase::ResolveFromCache(const RequestInfo
& info
,
105 AddressList
* addresses
,
106 const BoundNetLog
& net_log
) {
107 num_resolve_from_cache_
++;
108 DCHECK(CalledOnValidThread());
110 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
114 void MockHostResolverBase::CancelRequest(RequestHandle handle
) {
115 DCHECK(CalledOnValidThread());
116 size_t id
= reinterpret_cast<size_t>(handle
);
117 RequestMap::iterator it
= requests_
.find(id
);
118 if (it
!= requests_
.end()) {
119 scoped_ptr
<Request
> req(it
->second
);
122 NOTREACHED() << "CancelRequest must NOT be called after request is "
123 "complete or canceled.";
127 HostCache
* MockHostResolverBase::GetHostCache() {
131 void MockHostResolverBase::ResolveAllPending() {
132 DCHECK(CalledOnValidThread());
133 DCHECK(ondemand_mode_
);
134 for (RequestMap::iterator i
= requests_
.begin(); i
!= requests_
.end(); ++i
) {
135 base::ThreadTaskRunnerHandle::Get()->PostTask(
137 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), i
->first
));
141 // start id from 1 to distinguish from NULL RequestHandle
142 MockHostResolverBase::MockHostResolverBase(bool use_caching
)
143 : last_request_priority_(DEFAULT_PRIORITY
),
144 synchronous_mode_(false),
145 ondemand_mode_(false),
148 num_resolve_from_cache_(0) {
149 rules_
= CreateCatchAllHostResolverProc();
152 cache_
.reset(new HostCache(kMaxCacheEntries
));
156 int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo
& info
,
157 AddressList
* addresses
) {
159 if (ParseIPLiteralToNumber(info
.hostname(), &ip
)) {
160 // This matches the behavior HostResolverImpl.
161 if (info
.address_family() != ADDRESS_FAMILY_UNSPECIFIED
&&
162 info
.address_family() != GetAddressFamily(ip
)) {
163 return ERR_NAME_NOT_RESOLVED
;
166 *addresses
= AddressList::CreateFromIPAddress(ip
, info
.port());
167 if (info
.host_resolver_flags() & HOST_RESOLVER_CANONNAME
)
168 addresses
->SetDefaultCanonicalName();
171 int rv
= ERR_DNS_CACHE_MISS
;
172 if (cache_
.get() && info
.allow_cached_response()) {
173 HostCache::Key
key(info
.hostname(),
174 info
.address_family(),
175 info
.host_resolver_flags());
176 const HostCache::Entry
* entry
= cache_
->Lookup(key
, base::TimeTicks::Now());
180 *addresses
= AddressList::CopyWithPort(entry
->addrlist
, info
.port());
186 int MockHostResolverBase::ResolveProc(size_t id
,
187 const RequestInfo
& info
,
188 AddressList
* addresses
) {
190 int rv
= rules_
->Resolve(info
.hostname(),
191 info
.address_family(),
192 info
.host_resolver_flags(),
196 HostCache::Key
key(info
.hostname(),
197 info
.address_family(),
198 info
.host_resolver_flags());
199 // Storing a failure with TTL 0 so that it overwrites previous value.
202 ttl
= base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds
);
203 cache_
->Set(key
, HostCache::Entry(rv
, addr
), base::TimeTicks::Now(), ttl
);
206 *addresses
= AddressList::CopyWithPort(addr
, info
.port());
210 void MockHostResolverBase::ResolveNow(size_t id
) {
211 RequestMap::iterator it
= requests_
.find(id
);
212 if (it
== requests_
.end())
213 return; // was canceled
215 scoped_ptr
<Request
> req(it
->second
);
217 int rv
= ResolveProc(id
, req
->info
, req
->addresses
);
218 if (!req
->callback
.is_null())
219 req
->callback
.Run(rv
);
222 //-----------------------------------------------------------------------------
224 struct RuleBasedHostResolverProc::Rule
{
228 kResolverTypeIPLiteral
,
231 ResolverType resolver_type
;
232 std::string host_pattern
;
233 AddressFamily address_family
;
234 HostResolverFlags host_resolver_flags
;
235 std::string replacement
;
236 std::string canonical_name
;
237 int latency_ms
; // In milliseconds.
239 Rule(ResolverType resolver_type
,
240 const std::string
& host_pattern
,
241 AddressFamily address_family
,
242 HostResolverFlags host_resolver_flags
,
243 const std::string
& replacement
,
244 const std::string
& canonical_name
,
246 : resolver_type(resolver_type
),
247 host_pattern(host_pattern
),
248 address_family(address_family
),
249 host_resolver_flags(host_resolver_flags
),
250 replacement(replacement
),
251 canonical_name(canonical_name
),
252 latency_ms(latency_ms
) {}
255 RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc
* previous
)
256 : HostResolverProc(previous
) {
259 void RuleBasedHostResolverProc::AddRule(const std::string
& host_pattern
,
260 const std::string
& replacement
) {
261 AddRuleForAddressFamily(host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
265 void RuleBasedHostResolverProc::AddRuleForAddressFamily(
266 const std::string
& host_pattern
,
267 AddressFamily address_family
,
268 const std::string
& replacement
) {
269 DCHECK(!replacement
.empty());
270 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
271 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
272 Rule
rule(Rule::kResolverTypeSystem
,
279 rules_
.push_back(rule
);
282 void RuleBasedHostResolverProc::AddIPLiteralRule(
283 const std::string
& host_pattern
,
284 const std::string
& ip_literal
,
285 const std::string
& canonical_name
) {
286 // Literals are always resolved to themselves by HostResolverImpl,
287 // consequently we do not support remapping them.
288 IPAddressNumber ip_number
;
289 DCHECK(!ParseIPLiteralToNumber(host_pattern
, &ip_number
));
290 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
291 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
292 if (!canonical_name
.empty())
293 flags
|= HOST_RESOLVER_CANONNAME
;
294 Rule
rule(Rule::kResolverTypeIPLiteral
, host_pattern
,
295 ADDRESS_FAMILY_UNSPECIFIED
, flags
, ip_literal
, canonical_name
,
297 rules_
.push_back(rule
);
300 void RuleBasedHostResolverProc::AddRuleWithLatency(
301 const std::string
& host_pattern
,
302 const std::string
& replacement
,
304 DCHECK(!replacement
.empty());
305 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
306 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
307 Rule
rule(Rule::kResolverTypeSystem
,
309 ADDRESS_FAMILY_UNSPECIFIED
,
314 rules_
.push_back(rule
);
317 void RuleBasedHostResolverProc::AllowDirectLookup(
318 const std::string
& host_pattern
) {
319 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
320 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
321 Rule
rule(Rule::kResolverTypeSystem
,
323 ADDRESS_FAMILY_UNSPECIFIED
,
328 rules_
.push_back(rule
);
331 void RuleBasedHostResolverProc::AddSimulatedFailure(
332 const std::string
& host_pattern
) {
333 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
334 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
335 Rule
rule(Rule::kResolverTypeFail
,
337 ADDRESS_FAMILY_UNSPECIFIED
,
342 rules_
.push_back(rule
);
345 void RuleBasedHostResolverProc::ClearRules() {
349 int RuleBasedHostResolverProc::Resolve(const std::string
& host
,
350 AddressFamily address_family
,
351 HostResolverFlags host_resolver_flags
,
352 AddressList
* addrlist
,
354 RuleList::iterator r
;
355 for (r
= rules_
.begin(); r
!= rules_
.end(); ++r
) {
356 bool matches_address_family
=
357 r
->address_family
== ADDRESS_FAMILY_UNSPECIFIED
||
358 r
->address_family
== address_family
;
359 // Ignore HOST_RESOLVER_SYSTEM_ONLY, since it should have no impact on
360 // whether a rule matches.
361 HostResolverFlags flags
= host_resolver_flags
& ~HOST_RESOLVER_SYSTEM_ONLY
;
362 // Flags match if all of the bitflags in host_resolver_flags are enabled
363 // in the rule's host_resolver_flags. However, the rule may have additional
364 // flags specified, in which case the flags should still be considered a
366 bool matches_flags
= (r
->host_resolver_flags
& flags
) == flags
;
367 if (matches_flags
&& matches_address_family
&&
368 base::MatchPattern(host
, r
->host_pattern
)) {
369 if (r
->latency_ms
!= 0) {
370 base::PlatformThread::Sleep(
371 base::TimeDelta::FromMilliseconds(r
->latency_ms
));
374 // Remap to a new host.
375 const std::string
& effective_host
=
376 r
->replacement
.empty() ? host
: r
->replacement
;
378 // Apply the resolving function to the remapped hostname.
379 switch (r
->resolver_type
) {
380 case Rule::kResolverTypeFail
:
381 return ERR_NAME_NOT_RESOLVED
;
382 case Rule::kResolverTypeSystem
:
386 return SystemHostResolverCall(effective_host
,
390 case Rule::kResolverTypeIPLiteral
:
391 return ParseAddressList(effective_host
,
396 return ERR_UNEXPECTED
;
400 return ResolveUsingPrevious(host
, address_family
,
401 host_resolver_flags
, addrlist
, os_error
);
404 RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
407 RuleBasedHostResolverProc
* CreateCatchAllHostResolverProc() {
408 RuleBasedHostResolverProc
* catchall
= new RuleBasedHostResolverProc(NULL
);
409 catchall
->AddIPLiteralRule("*", "127.0.0.1", "localhost");
411 // Next add a rules-based layer the use controls.
412 return new RuleBasedHostResolverProc(catchall
);
415 //-----------------------------------------------------------------------------
417 int HangingHostResolver::Resolve(const RequestInfo
& info
,
418 RequestPriority priority
,
419 AddressList
* addresses
,
420 const CompletionCallback
& callback
,
421 RequestHandle
* out_req
,
422 const BoundNetLog
& net_log
) {
423 return ERR_IO_PENDING
;
426 int HangingHostResolver::ResolveFromCache(const RequestInfo
& info
,
427 AddressList
* addresses
,
428 const BoundNetLog
& net_log
) {
429 return ERR_DNS_CACHE_MISS
;
432 //-----------------------------------------------------------------------------
434 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {}
436 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc(
437 HostResolverProc
* proc
) {
441 ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() {
442 HostResolverProc
* old_proc
=
443 HostResolverProc::SetDefault(previous_proc_
.get());
444 // The lifetimes of multiple instances must be nested.
445 CHECK_EQ(old_proc
, current_proc_
.get());
448 void ScopedDefaultHostResolverProc::Init(HostResolverProc
* proc
) {
449 current_proc_
= proc
;
450 previous_proc_
= HostResolverProc::SetDefault(current_proc_
.get());
451 current_proc_
->SetLastProc(previous_proc_
.get());