OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "net/dns/mock_host_resolver.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
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" | |
22 | |
23 #if defined(OS_WIN) | |
24 #include "net/base/winsock_init.h" | |
25 #endif | |
26 | |
27 namespace net { | |
28 | |
29 namespace { | |
30 | |
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; | |
35 | |
36 } // namespace | |
37 | |
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; | |
50 } | |
51 addrlist->push_back(IPEndPoint(ip_number, 0)); | |
52 } | |
53 return OK; | |
54 } | |
55 | |
56 struct MockHostResolverBase::Request { | |
57 Request(const RequestInfo& req_info, | |
58 AddressList* addr, | |
59 const CompletionCallback& cb) | |
60 : info(req_info), addresses(addr), callback(cb) {} | |
61 RequestInfo info; | |
62 AddressList* addresses; | |
63 CompletionCallback callback; | |
64 }; | |
65 | |
66 MockHostResolverBase::~MockHostResolverBase() { | |
67 STLDeleteValues(&requests_); | |
68 } | |
69 | |
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; | |
78 num_resolve_++; | |
79 size_t id = next_request_id_++; | |
80 int rv = ResolveFromIPLiteralOrCache(info, addresses); | |
81 if (rv != ERR_DNS_CACHE_MISS) { | |
82 return rv; | |
83 } | |
84 if (synchronous_mode_) { | |
85 return ResolveProc(id, info, addresses); | |
86 } | |
87 // Store the request for asynchronous resolution | |
88 Request* req = new Request(info, addresses, callback); | |
89 requests_[id] = req; | |
90 if (handle) | |
91 *handle = reinterpret_cast<RequestHandle>(id); | |
92 | |
93 if (!ondemand_mode_) { | |
94 base::MessageLoop::current()->PostTask( | |
95 FROM_HERE, | |
96 base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), id)); | |
97 } | |
98 | |
99 return ERR_IO_PENDING; | |
100 } | |
101 | |
102 int MockHostResolverBase::ResolveFromCache(const RequestInfo& info, | |
103 AddressList* addresses, | |
104 const BoundNetLog& net_log) { | |
105 num_resolve_from_cache_++; | |
106 DCHECK(CalledOnValidThread()); | |
107 next_request_id_++; | |
108 int rv = ResolveFromIPLiteralOrCache(info, addresses); | |
109 return rv; | |
110 } | |
111 | |
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); | |
118 requests_.erase(it); | |
119 } else { | |
120 NOTREACHED() << "CancelRequest must NOT be called after request is " | |
121 "complete or canceled."; | |
122 } | |
123 } | |
124 | |
125 HostCache* MockHostResolverBase::GetHostCache() { | |
126 return cache_.get(); | |
127 } | |
128 | |
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( | |
134 FROM_HERE, | |
135 base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), i->first)); | |
136 } | |
137 } | |
138 | |
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), | |
144 next_request_id_(1), | |
145 num_resolve_(0), | |
146 num_resolve_from_cache_(0) { | |
147 rules_ = CreateCatchAllHostResolverProc(); | |
148 | |
149 if (use_caching) { | |
150 cache_.reset(new HostCache(kMaxCacheEntries)); | |
151 } | |
152 } | |
153 | |
154 int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info, | |
155 AddressList* addresses) { | |
156 IPAddressNumber ip; | |
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; | |
162 } | |
163 | |
164 *addresses = AddressList::CreateFromIPAddress(ip, info.port()); | |
165 if (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME) | |
166 addresses->SetDefaultCanonicalName(); | |
167 return OK; | |
168 } | |
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()); | |
175 if (entry) { | |
176 rv = entry->error; | |
177 if (rv == OK) | |
178 *addresses = AddressList::CopyWithPort(entry->addrlist, info.port()); | |
179 } | |
180 } | |
181 return rv; | |
182 } | |
183 | |
184 int MockHostResolverBase::ResolveProc(size_t id, | |
185 const RequestInfo& info, | |
186 AddressList* addresses) { | |
187 AddressList addr; | |
188 int rv = rules_->Resolve(info.hostname(), | |
189 info.address_family(), | |
190 info.host_resolver_flags(), | |
191 &addr, | |
192 NULL); | |
193 if (cache_.get()) { | |
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. | |
198 base::TimeDelta ttl; | |
199 if (rv == OK) | |
200 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | |
201 cache_->Set(key, HostCache::Entry(rv, addr), base::TimeTicks::Now(), ttl); | |
202 } | |
203 if (rv == OK) | |
204 *addresses = AddressList::CopyWithPort(addr, info.port()); | |
205 return rv; | |
206 } | |
207 | |
208 void MockHostResolverBase::ResolveNow(size_t id) { | |
209 RequestMap::iterator it = requests_.find(id); | |
210 if (it == requests_.end()) | |
211 return; // was canceled | |
212 | |
213 scoped_ptr<Request> req(it->second); | |
214 requests_.erase(it); | |
215 int rv = ResolveProc(id, req->info, req->addresses); | |
216 if (!req->callback.is_null()) | |
217 req->callback.Run(rv); | |
218 } | |
219 | |
220 //----------------------------------------------------------------------------- | |
221 | |
222 struct RuleBasedHostResolverProc::Rule { | |
223 enum ResolverType { | |
224 kResolverTypeFail, | |
225 kResolverTypeSystem, | |
226 kResolverTypeIPLiteral, | |
227 }; | |
228 | |
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. | |
236 | |
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, | |
243 int latency_ms) | |
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) {} | |
251 }; | |
252 | |
253 RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc* previous) | |
254 : HostResolverProc(previous) { | |
255 } | |
256 | |
257 void RuleBasedHostResolverProc::AddRule(const std::string& host_pattern, | |
258 const std::string& replacement) { | |
259 AddRuleForAddressFamily(host_pattern, ADDRESS_FAMILY_UNSPECIFIED, | |
260 replacement); | |
261 } | |
262 | |
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, | |
271 host_pattern, | |
272 address_family, | |
273 flags, | |
274 replacement, | |
275 std::string(), | |
276 0); | |
277 rules_.push_back(rule); | |
278 } | |
279 | |
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, | |
294 0); | |
295 rules_.push_back(rule); | |
296 } | |
297 | |
298 void RuleBasedHostResolverProc::AddRuleWithLatency( | |
299 const std::string& host_pattern, | |
300 const std::string& replacement, | |
301 int latency_ms) { | |
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, | |
306 host_pattern, | |
307 ADDRESS_FAMILY_UNSPECIFIED, | |
308 flags, | |
309 replacement, | |
310 std::string(), | |
311 latency_ms); | |
312 rules_.push_back(rule); | |
313 } | |
314 | |
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, | |
320 host_pattern, | |
321 ADDRESS_FAMILY_UNSPECIFIED, | |
322 flags, | |
323 std::string(), | |
324 std::string(), | |
325 0); | |
326 rules_.push_back(rule); | |
327 } | |
328 | |
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, | |
334 host_pattern, | |
335 ADDRESS_FAMILY_UNSPECIFIED, | |
336 flags, | |
337 std::string(), | |
338 std::string(), | |
339 0); | |
340 rules_.push_back(rule); | |
341 } | |
342 | |
343 void RuleBasedHostResolverProc::ClearRules() { | |
344 rules_.clear(); | |
345 } | |
346 | |
347 int RuleBasedHostResolverProc::Resolve(const std::string& host, | |
348 AddressFamily address_family, | |
349 HostResolverFlags host_resolver_flags, | |
350 AddressList* addrlist, | |
351 int* os_error) { | |
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 | |
363 // match. | |
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)); | |
370 } | |
371 | |
372 // Remap to a new host. | |
373 const std::string& effective_host = | |
374 r->replacement.empty() ? host : r->replacement; | |
375 | |
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: | |
381 #if defined(OS_WIN) | |
382 net::EnsureWinsockInit(); | |
383 #endif | |
384 return SystemHostResolverCall(effective_host, | |
385 address_family, | |
386 host_resolver_flags, | |
387 addrlist, os_error); | |
388 case Rule::kResolverTypeIPLiteral: | |
389 return ParseAddressList(effective_host, | |
390 r->canonical_name, | |
391 addrlist); | |
392 default: | |
393 NOTREACHED(); | |
394 return ERR_UNEXPECTED; | |
395 } | |
396 } | |
397 } | |
398 return ResolveUsingPrevious(host, address_family, | |
399 host_resolver_flags, addrlist, os_error); | |
400 } | |
401 | |
402 RuleBasedHostResolverProc::~RuleBasedHostResolverProc() { | |
403 } | |
404 | |
405 RuleBasedHostResolverProc* CreateCatchAllHostResolverProc() { | |
406 RuleBasedHostResolverProc* catchall = new RuleBasedHostResolverProc(NULL); | |
407 catchall->AddIPLiteralRule("*", "127.0.0.1", "localhost"); | |
408 | |
409 // Next add a rules-based layer the use controls. | |
410 return new RuleBasedHostResolverProc(catchall); | |
411 } | |
412 | |
413 //----------------------------------------------------------------------------- | |
414 | |
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; | |
422 } | |
423 | |
424 int HangingHostResolver::ResolveFromCache(const RequestInfo& info, | |
425 AddressList* addresses, | |
426 const BoundNetLog& net_log) { | |
427 return ERR_DNS_CACHE_MISS; | |
428 } | |
429 | |
430 //----------------------------------------------------------------------------- | |
431 | |
432 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {} | |
433 | |
434 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc( | |
435 HostResolverProc* proc) { | |
436 Init(proc); | |
437 } | |
438 | |
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_.get()); | |
444 } | |
445 | |
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()); | |
450 } | |
451 | |
452 } // namespace net | |
OLD | NEW |