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/memory/ref_counted.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/threading/platform_thread.h"
17 #include "net/base/ip_endpoint.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/net_util.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/dns/host_cache.h"
24 #include "net/base/winsock_init.h"
31 // Cache size for the MockCachingHostResolver.
32 const unsigned kMaxCacheEntries
= 100;
33 // TTL for the successful resolutions. Failures are not cached.
34 const unsigned kCacheEntryTTLSeconds
= 60;
38 int ParseAddressList(const std::string
& host_list
,
39 const std::string
& canonical_name
,
40 AddressList
* addrlist
) {
41 *addrlist
= AddressList();
42 std::vector
<std::string
> addresses
;
43 base::SplitString(host_list
, ',', &addresses
);
44 addrlist
->set_canonical_name(canonical_name
);
45 for (size_t index
= 0; index
< addresses
.size(); ++index
) {
46 IPAddressNumber ip_number
;
47 if (!ParseIPLiteralToNumber(addresses
[index
], &ip_number
)) {
48 LOG(WARNING
) << "Not a supported IP literal: " << addresses
[index
];
49 return ERR_UNEXPECTED
;
51 addrlist
->push_back(IPEndPoint(ip_number
, -1));
56 struct MockHostResolverBase::Request
{
57 Request(const RequestInfo
& req_info
,
59 const CompletionCallback
& cb
)
60 : info(req_info
), addresses(addr
), callback(cb
) {}
62 AddressList
* addresses
;
63 CompletionCallback callback
;
66 MockHostResolverBase::~MockHostResolverBase() {
67 STLDeleteValues(&requests_
);
70 int MockHostResolverBase::Resolve(const RequestInfo
& info
,
71 RequestPriority priority
,
72 AddressList
* addresses
,
73 const CompletionCallback
& callback
,
74 RequestHandle
* handle
,
75 const BoundNetLog
& net_log
) {
76 DCHECK(CalledOnValidThread());
77 last_request_priority_
= priority
;
79 size_t id
= next_request_id_
++;
80 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
81 if (rv
!= ERR_DNS_CACHE_MISS
) {
84 if (synchronous_mode_
) {
85 return ResolveProc(id
, info
, addresses
);
87 // Store the request for asynchronous resolution
88 Request
* req
= new Request(info
, addresses
, callback
);
91 *handle
= reinterpret_cast<RequestHandle
>(id
);
93 if (!ondemand_mode_
) {
94 base::MessageLoop::current()->PostTask(
96 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), id
));
99 return ERR_IO_PENDING
;
102 int MockHostResolverBase::ResolveFromCache(const RequestInfo
& info
,
103 AddressList
* addresses
,
104 const BoundNetLog
& net_log
) {
105 num_resolve_from_cache_
++;
106 DCHECK(CalledOnValidThread());
108 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
112 void MockHostResolverBase::CancelRequest(RequestHandle handle
) {
113 DCHECK(CalledOnValidThread());
114 size_t id
= reinterpret_cast<size_t>(handle
);
115 RequestMap::iterator it
= requests_
.find(id
);
116 if (it
!= requests_
.end()) {
117 scoped_ptr
<Request
> req(it
->second
);
120 NOTREACHED() << "CancelRequest must NOT be called after request is "
121 "complete or canceled.";
125 HostCache
* MockHostResolverBase::GetHostCache() {
129 void MockHostResolverBase::ResolveAllPending() {
130 DCHECK(CalledOnValidThread());
131 DCHECK(ondemand_mode_
);
132 for (RequestMap::iterator i
= requests_
.begin(); i
!= requests_
.end(); ++i
) {
133 base::MessageLoop::current()->PostTask(
135 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), i
->first
));
139 // start id from 1 to distinguish from NULL RequestHandle
140 MockHostResolverBase::MockHostResolverBase(bool use_caching
)
141 : last_request_priority_(DEFAULT_PRIORITY
),
142 synchronous_mode_(false),
143 ondemand_mode_(false),
146 num_resolve_from_cache_(0) {
147 rules_
= CreateCatchAllHostResolverProc();
150 cache_
.reset(new HostCache(kMaxCacheEntries
));
154 int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo
& info
,
155 AddressList
* addresses
) {
157 if (ParseIPLiteralToNumber(info
.hostname(), &ip
)) {
158 // This matches the behavior HostResolverImpl.
159 if (info
.address_family() != ADDRESS_FAMILY_UNSPECIFIED
&&
160 info
.address_family() != GetAddressFamily(ip
)) {
161 return ERR_NAME_NOT_RESOLVED
;
164 *addresses
= AddressList::CreateFromIPAddress(ip
, info
.port());
165 if (info
.host_resolver_flags() & HOST_RESOLVER_CANONNAME
)
166 addresses
->SetDefaultCanonicalName();
169 int rv
= ERR_DNS_CACHE_MISS
;
170 if (cache_
.get() && info
.allow_cached_response()) {
171 HostCache::Key
key(info
.hostname(),
172 info
.address_family(),
173 info
.host_resolver_flags());
174 const HostCache::Entry
* entry
= cache_
->Lookup(key
, base::TimeTicks::Now());
178 *addresses
= AddressList::CopyWithPort(entry
->addrlist
, info
.port());
184 int MockHostResolverBase::ResolveProc(size_t id
,
185 const RequestInfo
& info
,
186 AddressList
* addresses
) {
188 int rv
= rules_
->Resolve(info
.hostname(),
189 info
.address_family(),
190 info
.host_resolver_flags(),
194 HostCache::Key
key(info
.hostname(),
195 info
.address_family(),
196 info
.host_resolver_flags());
197 // Storing a failure with TTL 0 so that it overwrites previous value.
200 ttl
= base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds
);
201 cache_
->Set(key
, HostCache::Entry(rv
, addr
), base::TimeTicks::Now(), ttl
);
204 *addresses
= AddressList::CopyWithPort(addr
, info
.port());
208 void MockHostResolverBase::ResolveNow(size_t id
) {
209 RequestMap::iterator it
= requests_
.find(id
);
210 if (it
== requests_
.end())
211 return; // was canceled
213 scoped_ptr
<Request
> req(it
->second
);
215 int rv
= ResolveProc(id
, req
->info
, req
->addresses
);
216 if (!req
->callback
.is_null())
217 req
->callback
.Run(rv
);
220 //-----------------------------------------------------------------------------
222 struct RuleBasedHostResolverProc::Rule
{
226 kResolverTypeIPLiteral
,
229 ResolverType resolver_type
;
230 std::string host_pattern
;
231 AddressFamily address_family
;
232 HostResolverFlags host_resolver_flags
;
233 std::string replacement
;
234 std::string canonical_name
;
235 int latency_ms
; // In milliseconds.
237 Rule(ResolverType resolver_type
,
238 const std::string
& host_pattern
,
239 AddressFamily address_family
,
240 HostResolverFlags host_resolver_flags
,
241 const std::string
& replacement
,
242 const std::string
& canonical_name
,
244 : resolver_type(resolver_type
),
245 host_pattern(host_pattern
),
246 address_family(address_family
),
247 host_resolver_flags(host_resolver_flags
),
248 replacement(replacement
),
249 canonical_name(canonical_name
),
250 latency_ms(latency_ms
) {}
253 RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc
* previous
)
254 : HostResolverProc(previous
) {
257 void RuleBasedHostResolverProc::AddRule(const std::string
& host_pattern
,
258 const std::string
& replacement
) {
259 AddRuleForAddressFamily(host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
263 void RuleBasedHostResolverProc::AddRuleForAddressFamily(
264 const std::string
& host_pattern
,
265 AddressFamily address_family
,
266 const std::string
& replacement
) {
267 DCHECK(!replacement
.empty());
268 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
269 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
270 Rule
rule(Rule::kResolverTypeSystem
,
277 rules_
.push_back(rule
);
280 void RuleBasedHostResolverProc::AddIPLiteralRule(
281 const std::string
& host_pattern
,
282 const std::string
& ip_literal
,
283 const std::string
& canonical_name
) {
284 // Literals are always resolved to themselves by HostResolverImpl,
285 // consequently we do not support remapping them.
286 IPAddressNumber ip_number
;
287 DCHECK(!ParseIPLiteralToNumber(host_pattern
, &ip_number
));
288 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
289 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
290 if (!canonical_name
.empty())
291 flags
|= HOST_RESOLVER_CANONNAME
;
292 Rule
rule(Rule::kResolverTypeIPLiteral
, host_pattern
,
293 ADDRESS_FAMILY_UNSPECIFIED
, flags
, ip_literal
, canonical_name
,
295 rules_
.push_back(rule
);
298 void RuleBasedHostResolverProc::AddRuleWithLatency(
299 const std::string
& host_pattern
,
300 const std::string
& replacement
,
302 DCHECK(!replacement
.empty());
303 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
304 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
305 Rule
rule(Rule::kResolverTypeSystem
,
307 ADDRESS_FAMILY_UNSPECIFIED
,
312 rules_
.push_back(rule
);
315 void RuleBasedHostResolverProc::AllowDirectLookup(
316 const std::string
& host_pattern
) {
317 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
318 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
319 Rule
rule(Rule::kResolverTypeSystem
,
321 ADDRESS_FAMILY_UNSPECIFIED
,
326 rules_
.push_back(rule
);
329 void RuleBasedHostResolverProc::AddSimulatedFailure(
330 const std::string
& host_pattern
) {
331 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
332 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
333 Rule
rule(Rule::kResolverTypeFail
,
335 ADDRESS_FAMILY_UNSPECIFIED
,
340 rules_
.push_back(rule
);
343 void RuleBasedHostResolverProc::ClearRules() {
347 int RuleBasedHostResolverProc::Resolve(const std::string
& host
,
348 AddressFamily address_family
,
349 HostResolverFlags host_resolver_flags
,
350 AddressList
* addrlist
,
352 RuleList::iterator r
;
353 for (r
= rules_
.begin(); r
!= rules_
.end(); ++r
) {
354 bool matches_address_family
=
355 r
->address_family
== ADDRESS_FAMILY_UNSPECIFIED
||
356 r
->address_family
== address_family
;
357 // Ignore HOST_RESOLVER_SYSTEM_ONLY, since it should have no impact on
358 // whether a rule matches.
359 HostResolverFlags flags
= host_resolver_flags
& ~HOST_RESOLVER_SYSTEM_ONLY
;
360 // Flags match if all of the bitflags in host_resolver_flags are enabled
361 // in the rule's host_resolver_flags. However, the rule may have additional
362 // flags specified, in which case the flags should still be considered a
364 bool matches_flags
= (r
->host_resolver_flags
& flags
) == flags
;
365 if (matches_flags
&& matches_address_family
&&
366 MatchPattern(host
, r
->host_pattern
)) {
367 if (r
->latency_ms
!= 0) {
368 base::PlatformThread::Sleep(
369 base::TimeDelta::FromMilliseconds(r
->latency_ms
));
372 // Remap to a new host.
373 const std::string
& effective_host
=
374 r
->replacement
.empty() ? host
: r
->replacement
;
376 // Apply the resolving function to the remapped hostname.
377 switch (r
->resolver_type
) {
378 case Rule::kResolverTypeFail
:
379 return ERR_NAME_NOT_RESOLVED
;
380 case Rule::kResolverTypeSystem
:
382 net::EnsureWinsockInit();
384 return SystemHostResolverCall(effective_host
,
388 case Rule::kResolverTypeIPLiteral
:
389 return ParseAddressList(effective_host
,
394 return ERR_UNEXPECTED
;
398 return ResolveUsingPrevious(host
, address_family
,
399 host_resolver_flags
, addrlist
, os_error
);
402 RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
405 RuleBasedHostResolverProc
* CreateCatchAllHostResolverProc() {
406 RuleBasedHostResolverProc
* catchall
= new RuleBasedHostResolverProc(NULL
);
407 catchall
->AddIPLiteralRule("*", "127.0.0.1", "localhost");
409 // Next add a rules-based layer the use controls.
410 return new RuleBasedHostResolverProc(catchall
);
413 //-----------------------------------------------------------------------------
415 int HangingHostResolver::Resolve(const RequestInfo
& info
,
416 RequestPriority priority
,
417 AddressList
* addresses
,
418 const CompletionCallback
& callback
,
419 RequestHandle
* out_req
,
420 const BoundNetLog
& net_log
) {
421 return ERR_IO_PENDING
;
424 int HangingHostResolver::ResolveFromCache(const RequestInfo
& info
,
425 AddressList
* addresses
,
426 const BoundNetLog
& net_log
) {
427 return ERR_DNS_CACHE_MISS
;
430 //-----------------------------------------------------------------------------
432 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {}
434 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc(
435 HostResolverProc
* proc
) {
439 ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() {
440 HostResolverProc
* old_proc
=
441 HostResolverProc::SetDefault(previous_proc_
.get());
442 // The lifetimes of multiple instances must be nested.
443 CHECK_EQ(old_proc
, current_proc_
);
446 void ScopedDefaultHostResolverProc::Init(HostResolverProc
* proc
) {
447 current_proc_
= proc
;
448 previous_proc_
= HostResolverProc::SetDefault(current_proc_
.get());
449 current_proc_
->SetLastProc(previous_proc_
.get());