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/base/mock_host_resolver.h"
10 #include "base/bind.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/message_loop.h"
13 #include "base/stl_util.h"
14 #include "base/string_split.h"
15 #include "base/string_util.h"
16 #include "base/threading/platform_thread.h"
17 #include "net/base/host_cache.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/net_util.h"
20 #include "net/base/test_completion_callback.h"
22 #include "net/base/winsock_init.h"
29 // Cache size for the MockCachingHostResolver.
30 const unsigned kMaxCacheEntries
= 100;
31 // TTL for the successful resolutions. Failures are not cached.
32 const unsigned kCacheEntryTTLSeconds
= 60;
36 int ParseAddressList(const std::string
& host_list
,
37 const std::string
& canonical_name
,
38 AddressList
* addrlist
) {
39 *addrlist
= AddressList();
40 std::vector
<std::string
> addresses
;
41 base::SplitString(host_list
, ',', &addresses
);
42 addrlist
->set_canonical_name(canonical_name
);
43 for (size_t index
= 0; index
< addresses
.size(); ++index
) {
44 IPAddressNumber ip_number
;
45 if (!ParseIPLiteralToNumber(addresses
[index
], &ip_number
)) {
46 LOG(WARNING
) << "Not a supported IP literal: " << addresses
[index
];
47 return ERR_UNEXPECTED
;
49 addrlist
->push_back(IPEndPoint(ip_number
, -1));
54 struct MockHostResolverBase::Request
{
55 Request(const RequestInfo
& req_info
,
57 const CompletionCallback
& cb
)
58 : info(req_info
), addresses(addr
), callback(cb
) {}
60 AddressList
* addresses
;
61 CompletionCallback callback
;
64 MockHostResolverBase::~MockHostResolverBase() {
65 STLDeleteValues(&requests_
);
68 int MockHostResolverBase::Resolve(const RequestInfo
& info
,
69 AddressList
* addresses
,
70 const CompletionCallback
& callback
,
71 RequestHandle
* handle
,
72 const BoundNetLog
& net_log
) {
73 DCHECK(CalledOnValidThread());
74 size_t id
= next_request_id_
++;
75 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
76 if (rv
!= ERR_DNS_CACHE_MISS
) {
79 if (synchronous_mode_
) {
80 return ResolveProc(id
, info
, addresses
);
82 // Store the request for asynchronous resolution
83 Request
* req
= new Request(info
, addresses
, callback
);
86 *handle
= reinterpret_cast<RequestHandle
>(id
);
88 if (!ondemand_mode_
) {
89 MessageLoop::current()->PostTask(
91 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), id
));
94 return ERR_IO_PENDING
;
97 int MockHostResolverBase::ResolveFromCache(const RequestInfo
& info
,
98 AddressList
* addresses
,
99 const BoundNetLog
& net_log
) {
100 DCHECK(CalledOnValidThread());
102 int rv
= ResolveFromIPLiteralOrCache(info
, addresses
);
106 void MockHostResolverBase::CancelRequest(RequestHandle handle
) {
107 DCHECK(CalledOnValidThread());
108 size_t id
= reinterpret_cast<size_t>(handle
);
109 RequestMap::iterator it
= requests_
.find(id
);
110 if (it
!= requests_
.end()) {
111 scoped_ptr
<Request
> req(it
->second
);
114 NOTREACHED() << "CancelRequest must NOT be called after request is "
115 "complete or canceled.";
119 HostCache
* MockHostResolverBase::GetHostCache() {
123 void MockHostResolverBase::ResolveAllPending() {
124 DCHECK(CalledOnValidThread());
125 DCHECK(ondemand_mode_
);
126 for (RequestMap::iterator i
= requests_
.begin(); i
!= requests_
.end(); ++i
) {
127 MessageLoop::current()->PostTask(
129 base::Bind(&MockHostResolverBase::ResolveNow
, AsWeakPtr(), i
->first
));
133 // start id from 1 to distinguish from NULL RequestHandle
134 MockHostResolverBase::MockHostResolverBase(bool use_caching
)
135 : synchronous_mode_(false),
136 ondemand_mode_(false),
137 next_request_id_(1) {
138 rules_
= CreateCatchAllHostResolverProc();
141 cache_
.reset(new HostCache(kMaxCacheEntries
));
145 int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo
& info
,
146 AddressList
* addresses
) {
148 if (ParseIPLiteralToNumber(info
.hostname(), &ip
)) {
149 *addresses
= AddressList::CreateFromIPAddress(ip
, info
.port());
150 if (info
.host_resolver_flags() & HOST_RESOLVER_CANONNAME
)
151 addresses
->SetDefaultCanonicalName();
154 int rv
= ERR_DNS_CACHE_MISS
;
155 if (cache_
.get() && info
.allow_cached_response()) {
156 HostCache::Key
key(info
.hostname(),
157 info
.address_family(),
158 info
.host_resolver_flags());
159 const HostCache::Entry
* entry
= cache_
->Lookup(key
, base::TimeTicks::Now());
163 *addresses
= AddressList::CopyWithPort(entry
->addrlist
, info
.port());
169 int MockHostResolverBase::ResolveProc(size_t id
,
170 const RequestInfo
& info
,
171 AddressList
* addresses
) {
173 int rv
= rules_
->Resolve(info
.hostname(),
174 info
.address_family(),
175 info
.host_resolver_flags(),
179 HostCache::Key
key(info
.hostname(),
180 info
.address_family(),
181 info
.host_resolver_flags());
182 // Storing a failure with TTL 0 so that it overwrites previous value.
185 ttl
= base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds
);
186 cache_
->Set(key
, HostCache::Entry(rv
, addr
), base::TimeTicks::Now(), ttl
);
189 *addresses
= AddressList::CopyWithPort(addr
, info
.port());
193 void MockHostResolverBase::ResolveNow(size_t id
) {
194 RequestMap::iterator it
= requests_
.find(id
);
195 if (it
== requests_
.end())
196 return; // was canceled
198 scoped_ptr
<Request
> req(it
->second
);
200 int rv
= ResolveProc(id
, req
->info
, req
->addresses
);
201 if (!req
->callback
.is_null())
202 req
->callback
.Run(rv
);
205 //-----------------------------------------------------------------------------
207 struct RuleBasedHostResolverProc::Rule
{
211 kResolverTypeIPLiteral
,
214 ResolverType resolver_type
;
215 std::string host_pattern
;
216 AddressFamily address_family
;
217 HostResolverFlags host_resolver_flags
;
218 std::string replacement
;
219 std::string canonical_name
;
220 int latency_ms
; // In milliseconds.
222 Rule(ResolverType resolver_type
,
223 const std::string
& host_pattern
,
224 AddressFamily address_family
,
225 HostResolverFlags host_resolver_flags
,
226 const std::string
& replacement
,
227 const std::string
& canonical_name
,
229 : resolver_type(resolver_type
),
230 host_pattern(host_pattern
),
231 address_family(address_family
),
232 host_resolver_flags(host_resolver_flags
),
233 replacement(replacement
),
234 canonical_name(canonical_name
),
235 latency_ms(latency_ms
) {}
238 RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc
* previous
)
239 : HostResolverProc(previous
) {
242 void RuleBasedHostResolverProc::AddRule(const std::string
& host_pattern
,
243 const std::string
& replacement
) {
244 AddRuleForAddressFamily(host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
248 void RuleBasedHostResolverProc::AddRuleForAddressFamily(
249 const std::string
& host_pattern
,
250 AddressFamily address_family
,
251 const std::string
& replacement
) {
252 DCHECK(!replacement
.empty());
253 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
254 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
255 Rule
rule(Rule::kResolverTypeSystem
, host_pattern
, address_family
, flags
,
257 rules_
.push_back(rule
);
260 void RuleBasedHostResolverProc::AddIPLiteralRule(
261 const std::string
& host_pattern
,
262 const std::string
& ip_literal
,
263 const std::string
& canonical_name
) {
264 // Literals are always resolved to themselves by HostResolverImpl,
265 // consequently we do not support remapping them.
266 IPAddressNumber ip_number
;
267 DCHECK(!ParseIPLiteralToNumber(host_pattern
, &ip_number
));
268 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
269 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
270 if (!canonical_name
.empty())
271 flags
|= HOST_RESOLVER_CANONNAME
;
272 Rule
rule(Rule::kResolverTypeIPLiteral
, host_pattern
,
273 ADDRESS_FAMILY_UNSPECIFIED
, flags
, ip_literal
, canonical_name
,
275 rules_
.push_back(rule
);
278 void RuleBasedHostResolverProc::AddRuleWithLatency(
279 const std::string
& host_pattern
,
280 const std::string
& replacement
,
282 DCHECK(!replacement
.empty());
283 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
284 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
285 Rule
rule(Rule::kResolverTypeSystem
, host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
286 flags
, replacement
, "", latency_ms
);
287 rules_
.push_back(rule
);
290 void RuleBasedHostResolverProc::AllowDirectLookup(
291 const std::string
& host_pattern
) {
292 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
293 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
294 Rule
rule(Rule::kResolverTypeSystem
, host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
296 rules_
.push_back(rule
);
299 void RuleBasedHostResolverProc::AddSimulatedFailure(
300 const std::string
& host_pattern
) {
301 HostResolverFlags flags
= HOST_RESOLVER_LOOPBACK_ONLY
|
302 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6
;
303 Rule
rule(Rule::kResolverTypeFail
, host_pattern
, ADDRESS_FAMILY_UNSPECIFIED
,
305 rules_
.push_back(rule
);
308 int RuleBasedHostResolverProc::Resolve(const std::string
& host
,
309 AddressFamily address_family
,
310 HostResolverFlags host_resolver_flags
,
311 AddressList
* addrlist
,
313 RuleList::iterator r
;
314 for (r
= rules_
.begin(); r
!= rules_
.end(); ++r
) {
315 bool matches_address_family
=
316 r
->address_family
== ADDRESS_FAMILY_UNSPECIFIED
||
317 r
->address_family
== address_family
;
318 // Flags match if all of the bitflags in host_resolver_flags are enabled
319 // in the rule's host_resolver_flags. However, the rule may have additional
320 // flags specified, in which case the flags should still be considered a
322 bool matches_flags
= (r
->host_resolver_flags
& host_resolver_flags
) ==
324 if (matches_flags
&& matches_address_family
&&
325 MatchPattern(host
, r
->host_pattern
)) {
326 if (r
->latency_ms
!= 0) {
327 base::PlatformThread::Sleep(
328 base::TimeDelta::FromMilliseconds(r
->latency_ms
));
331 // Remap to a new host.
332 const std::string
& effective_host
=
333 r
->replacement
.empty() ? host
: r
->replacement
;
335 // Apply the resolving function to the remapped hostname.
336 switch (r
->resolver_type
) {
337 case Rule::kResolverTypeFail
:
338 return ERR_NAME_NOT_RESOLVED
;
339 case Rule::kResolverTypeSystem
:
341 net::EnsureWinsockInit();
343 return SystemHostResolverProc(effective_host
,
347 case Rule::kResolverTypeIPLiteral
:
348 return ParseAddressList(effective_host
,
353 return ERR_UNEXPECTED
;
357 return ResolveUsingPrevious(host
, address_family
,
358 host_resolver_flags
, addrlist
, os_error
);
361 RuleBasedHostResolverProc::~RuleBasedHostResolverProc() {
364 RuleBasedHostResolverProc
* CreateCatchAllHostResolverProc() {
365 RuleBasedHostResolverProc
* catchall
= new RuleBasedHostResolverProc(NULL
);
366 catchall
->AddIPLiteralRule("*", "127.0.0.1", "localhost");
368 // Next add a rules-based layer the use controls.
369 return new RuleBasedHostResolverProc(catchall
);
372 //-----------------------------------------------------------------------------
374 int HangingHostResolver::Resolve(const RequestInfo
& info
,
375 AddressList
* addresses
,
376 const CompletionCallback
& callback
,
377 RequestHandle
* out_req
,
378 const BoundNetLog
& net_log
) {
379 return ERR_IO_PENDING
;
382 int HangingHostResolver::ResolveFromCache(const RequestInfo
& info
,
383 AddressList
* addresses
,
384 const BoundNetLog
& net_log
) {
385 return ERR_DNS_CACHE_MISS
;
388 //-----------------------------------------------------------------------------
390 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {}
392 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc(
393 HostResolverProc
* proc
) {
397 ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() {
398 HostResolverProc
* old_proc
= HostResolverProc::SetDefault(previous_proc_
);
399 // The lifetimes of multiple instances must be nested.
400 CHECK_EQ(old_proc
, current_proc_
);
403 void ScopedDefaultHostResolverProc::Init(HostResolverProc
* proc
) {
404 current_proc_
= proc
;
405 previous_proc_
= HostResolverProc::SetDefault(current_proc_
);
406 current_proc_
->SetLastProc(previous_proc_
);