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/base/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.h" | |
13 #include "base/stl_util.h" | |
14 #include "base/string_util.h" | |
15 #include "base/strings/string_split.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" | |
21 #if defined(OS_WIN) | |
22 #include "net/base/winsock_init.h" | |
23 #endif | |
24 | |
25 namespace net { | |
26 | |
27 namespace { | |
28 | |
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; | |
33 | |
34 } // namespace | |
35 | |
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; | |
48 } | |
49 addrlist->push_back(IPEndPoint(ip_number, -1)); | |
50 } | |
51 return OK; | |
52 } | |
53 | |
54 struct MockHostResolverBase::Request { | |
55 Request(const RequestInfo& req_info, | |
56 AddressList* addr, | |
57 const CompletionCallback& cb) | |
58 : info(req_info), addresses(addr), callback(cb) {} | |
59 RequestInfo info; | |
60 AddressList* addresses; | |
61 CompletionCallback callback; | |
62 }; | |
63 | |
64 MockHostResolverBase::~MockHostResolverBase() { | |
65 STLDeleteValues(&requests_); | |
66 } | |
67 | |
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 num_resolve_++; | |
75 size_t id = next_request_id_++; | |
76 int rv = ResolveFromIPLiteralOrCache(info, addresses); | |
77 if (rv != ERR_DNS_CACHE_MISS) { | |
78 return rv; | |
79 } | |
80 if (synchronous_mode_) { | |
81 return ResolveProc(id, info, addresses); | |
82 } | |
83 // Store the request for asynchronous resolution | |
84 Request* req = new Request(info, addresses, callback); | |
85 requests_[id] = req; | |
86 if (handle) | |
87 *handle = reinterpret_cast<RequestHandle>(id); | |
88 | |
89 if (!ondemand_mode_) { | |
90 MessageLoop::current()->PostTask( | |
91 FROM_HERE, | |
92 base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), id)); | |
93 } | |
94 | |
95 return ERR_IO_PENDING; | |
96 } | |
97 | |
98 int MockHostResolverBase::ResolveFromCache(const RequestInfo& info, | |
99 AddressList* addresses, | |
100 const BoundNetLog& net_log) { | |
101 num_resolve_from_cache_++; | |
102 DCHECK(CalledOnValidThread()); | |
103 next_request_id_++; | |
104 int rv = ResolveFromIPLiteralOrCache(info, addresses); | |
105 return rv; | |
106 } | |
107 | |
108 void MockHostResolverBase::CancelRequest(RequestHandle handle) { | |
109 DCHECK(CalledOnValidThread()); | |
110 size_t id = reinterpret_cast<size_t>(handle); | |
111 RequestMap::iterator it = requests_.find(id); | |
112 if (it != requests_.end()) { | |
113 scoped_ptr<Request> req(it->second); | |
114 requests_.erase(it); | |
115 } else { | |
116 NOTREACHED() << "CancelRequest must NOT be called after request is " | |
117 "complete or canceled."; | |
118 } | |
119 } | |
120 | |
121 HostCache* MockHostResolverBase::GetHostCache() { | |
122 return cache_.get(); | |
123 } | |
124 | |
125 void MockHostResolverBase::ResolveAllPending() { | |
126 DCHECK(CalledOnValidThread()); | |
127 DCHECK(ondemand_mode_); | |
128 for (RequestMap::iterator i = requests_.begin(); i != requests_.end(); ++i) { | |
129 MessageLoop::current()->PostTask( | |
130 FROM_HERE, | |
131 base::Bind(&MockHostResolverBase::ResolveNow, AsWeakPtr(), i->first)); | |
132 } | |
133 } | |
134 | |
135 // start id from 1 to distinguish from NULL RequestHandle | |
136 MockHostResolverBase::MockHostResolverBase(bool use_caching) | |
137 : synchronous_mode_(false), | |
138 ondemand_mode_(false), | |
139 next_request_id_(1), | |
140 num_resolve_(0), | |
141 num_resolve_from_cache_(0) { | |
142 rules_ = CreateCatchAllHostResolverProc(); | |
143 | |
144 if (use_caching) { | |
145 cache_.reset(new HostCache(kMaxCacheEntries)); | |
146 } | |
147 } | |
148 | |
149 int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info, | |
150 AddressList* addresses) { | |
151 IPAddressNumber ip; | |
152 if (ParseIPLiteralToNumber(info.hostname(), &ip)) { | |
153 *addresses = AddressList::CreateFromIPAddress(ip, info.port()); | |
154 if (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME) | |
155 addresses->SetDefaultCanonicalName(); | |
156 return OK; | |
157 } | |
158 int rv = ERR_DNS_CACHE_MISS; | |
159 if (cache_.get() && info.allow_cached_response()) { | |
160 HostCache::Key key(info.hostname(), | |
161 info.address_family(), | |
162 info.host_resolver_flags()); | |
163 const HostCache::Entry* entry = cache_->Lookup(key, base::TimeTicks::Now()); | |
164 if (entry) { | |
165 rv = entry->error; | |
166 if (rv == OK) | |
167 *addresses = AddressList::CopyWithPort(entry->addrlist, info.port()); | |
168 } | |
169 } | |
170 return rv; | |
171 } | |
172 | |
173 int MockHostResolverBase::ResolveProc(size_t id, | |
174 const RequestInfo& info, | |
175 AddressList* addresses) { | |
176 AddressList addr; | |
177 int rv = rules_->Resolve(info.hostname(), | |
178 info.address_family(), | |
179 info.host_resolver_flags(), | |
180 &addr, | |
181 NULL); | |
182 if (cache_.get()) { | |
183 HostCache::Key key(info.hostname(), | |
184 info.address_family(), | |
185 info.host_resolver_flags()); | |
186 // Storing a failure with TTL 0 so that it overwrites previous value. | |
187 base::TimeDelta ttl; | |
188 if (rv == OK) | |
189 ttl = base::TimeDelta::FromSeconds(kCacheEntryTTLSeconds); | |
190 cache_->Set(key, HostCache::Entry(rv, addr), base::TimeTicks::Now(), ttl); | |
191 } | |
192 if (rv == OK) | |
193 *addresses = AddressList::CopyWithPort(addr, info.port()); | |
194 return rv; | |
195 } | |
196 | |
197 void MockHostResolverBase::ResolveNow(size_t id) { | |
198 RequestMap::iterator it = requests_.find(id); | |
199 if (it == requests_.end()) | |
200 return; // was canceled | |
201 | |
202 scoped_ptr<Request> req(it->second); | |
203 requests_.erase(it); | |
204 int rv = ResolveProc(id, req->info, req->addresses); | |
205 if (!req->callback.is_null()) | |
206 req->callback.Run(rv); | |
207 } | |
208 | |
209 //----------------------------------------------------------------------------- | |
210 | |
211 struct RuleBasedHostResolverProc::Rule { | |
212 enum ResolverType { | |
213 kResolverTypeFail, | |
214 kResolverTypeSystem, | |
215 kResolverTypeIPLiteral, | |
216 }; | |
217 | |
218 ResolverType resolver_type; | |
219 std::string host_pattern; | |
220 AddressFamily address_family; | |
221 HostResolverFlags host_resolver_flags; | |
222 std::string replacement; | |
223 std::string canonical_name; | |
224 int latency_ms; // In milliseconds. | |
225 | |
226 Rule(ResolverType resolver_type, | |
227 const std::string& host_pattern, | |
228 AddressFamily address_family, | |
229 HostResolverFlags host_resolver_flags, | |
230 const std::string& replacement, | |
231 const std::string& canonical_name, | |
232 int latency_ms) | |
233 : resolver_type(resolver_type), | |
234 host_pattern(host_pattern), | |
235 address_family(address_family), | |
236 host_resolver_flags(host_resolver_flags), | |
237 replacement(replacement), | |
238 canonical_name(canonical_name), | |
239 latency_ms(latency_ms) {} | |
240 }; | |
241 | |
242 RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc* previous) | |
243 : HostResolverProc(previous) { | |
244 } | |
245 | |
246 void RuleBasedHostResolverProc::AddRule(const std::string& host_pattern, | |
247 const std::string& replacement) { | |
248 AddRuleForAddressFamily(host_pattern, ADDRESS_FAMILY_UNSPECIFIED, | |
249 replacement); | |
250 } | |
251 | |
252 void RuleBasedHostResolverProc::AddRuleForAddressFamily( | |
253 const std::string& host_pattern, | |
254 AddressFamily address_family, | |
255 const std::string& replacement) { | |
256 DCHECK(!replacement.empty()); | |
257 HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | | |
258 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
259 Rule rule(Rule::kResolverTypeSystem, host_pattern, address_family, flags, | |
260 replacement, "", 0); | |
261 rules_.push_back(rule); | |
262 } | |
263 | |
264 void RuleBasedHostResolverProc::AddIPLiteralRule( | |
265 const std::string& host_pattern, | |
266 const std::string& ip_literal, | |
267 const std::string& canonical_name) { | |
268 // Literals are always resolved to themselves by HostResolverImpl, | |
269 // consequently we do not support remapping them. | |
270 IPAddressNumber ip_number; | |
271 DCHECK(!ParseIPLiteralToNumber(host_pattern, &ip_number)); | |
272 HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | | |
273 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
274 if (!canonical_name.empty()) | |
275 flags |= HOST_RESOLVER_CANONNAME; | |
276 Rule rule(Rule::kResolverTypeIPLiteral, host_pattern, | |
277 ADDRESS_FAMILY_UNSPECIFIED, flags, ip_literal, canonical_name, | |
278 0); | |
279 rules_.push_back(rule); | |
280 } | |
281 | |
282 void RuleBasedHostResolverProc::AddRuleWithLatency( | |
283 const std::string& host_pattern, | |
284 const std::string& replacement, | |
285 int latency_ms) { | |
286 DCHECK(!replacement.empty()); | |
287 HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | | |
288 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
289 Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, | |
290 flags, replacement, "", latency_ms); | |
291 rules_.push_back(rule); | |
292 } | |
293 | |
294 void RuleBasedHostResolverProc::AllowDirectLookup( | |
295 const std::string& host_pattern) { | |
296 HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | | |
297 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
298 Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, | |
299 flags, "", "", 0); | |
300 rules_.push_back(rule); | |
301 } | |
302 | |
303 void RuleBasedHostResolverProc::AddSimulatedFailure( | |
304 const std::string& host_pattern) { | |
305 HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | | |
306 HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; | |
307 Rule rule(Rule::kResolverTypeFail, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, | |
308 flags, "", "", 0); | |
309 rules_.push_back(rule); | |
310 } | |
311 | |
312 void RuleBasedHostResolverProc::ClearRules() { | |
313 rules_.clear(); | |
314 } | |
315 | |
316 int RuleBasedHostResolverProc::Resolve(const std::string& host, | |
317 AddressFamily address_family, | |
318 HostResolverFlags host_resolver_flags, | |
319 AddressList* addrlist, | |
320 int* os_error) { | |
321 RuleList::iterator r; | |
322 for (r = rules_.begin(); r != rules_.end(); ++r) { | |
323 bool matches_address_family = | |
324 r->address_family == ADDRESS_FAMILY_UNSPECIFIED || | |
325 r->address_family == address_family; | |
326 // Flags match if all of the bitflags in host_resolver_flags are enabled | |
327 // in the rule's host_resolver_flags. However, the rule may have additional | |
328 // flags specified, in which case the flags should still be considered a | |
329 // match. | |
330 bool matches_flags = (r->host_resolver_flags & host_resolver_flags) == | |
331 host_resolver_flags; | |
332 if (matches_flags && matches_address_family && | |
333 MatchPattern(host, r->host_pattern)) { | |
334 if (r->latency_ms != 0) { | |
335 base::PlatformThread::Sleep( | |
336 base::TimeDelta::FromMilliseconds(r->latency_ms)); | |
337 } | |
338 | |
339 // Remap to a new host. | |
340 const std::string& effective_host = | |
341 r->replacement.empty() ? host : r->replacement; | |
342 | |
343 // Apply the resolving function to the remapped hostname. | |
344 switch (r->resolver_type) { | |
345 case Rule::kResolverTypeFail: | |
346 return ERR_NAME_NOT_RESOLVED; | |
347 case Rule::kResolverTypeSystem: | |
348 #if defined(OS_WIN) | |
349 net::EnsureWinsockInit(); | |
350 #endif | |
351 return SystemHostResolverProc(effective_host, | |
352 address_family, | |
353 host_resolver_flags, | |
354 addrlist, os_error); | |
355 case Rule::kResolverTypeIPLiteral: | |
356 return ParseAddressList(effective_host, | |
357 r->canonical_name, | |
358 addrlist); | |
359 default: | |
360 NOTREACHED(); | |
361 return ERR_UNEXPECTED; | |
362 } | |
363 } | |
364 } | |
365 return ResolveUsingPrevious(host, address_family, | |
366 host_resolver_flags, addrlist, os_error); | |
367 } | |
368 | |
369 RuleBasedHostResolverProc::~RuleBasedHostResolverProc() { | |
370 } | |
371 | |
372 RuleBasedHostResolverProc* CreateCatchAllHostResolverProc() { | |
373 RuleBasedHostResolverProc* catchall = new RuleBasedHostResolverProc(NULL); | |
374 catchall->AddIPLiteralRule("*", "127.0.0.1", "localhost"); | |
375 | |
376 // Next add a rules-based layer the use controls. | |
377 return new RuleBasedHostResolverProc(catchall); | |
378 } | |
379 | |
380 //----------------------------------------------------------------------------- | |
381 | |
382 int HangingHostResolver::Resolve(const RequestInfo& info, | |
383 AddressList* addresses, | |
384 const CompletionCallback& callback, | |
385 RequestHandle* out_req, | |
386 const BoundNetLog& net_log) { | |
387 return ERR_IO_PENDING; | |
388 } | |
389 | |
390 int HangingHostResolver::ResolveFromCache(const RequestInfo& info, | |
391 AddressList* addresses, | |
392 const BoundNetLog& net_log) { | |
393 return ERR_DNS_CACHE_MISS; | |
394 } | |
395 | |
396 //----------------------------------------------------------------------------- | |
397 | |
398 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {} | |
399 | |
400 ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc( | |
401 HostResolverProc* proc) { | |
402 Init(proc); | |
403 } | |
404 | |
405 ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() { | |
406 HostResolverProc* old_proc = HostResolverProc::SetDefault(previous_proc_); | |
407 // The lifetimes of multiple instances must be nested. | |
408 CHECK_EQ(old_proc, current_proc_); | |
409 } | |
410 | |
411 void ScopedDefaultHostResolverProc::Init(HostResolverProc* proc) { | |
412 current_proc_ = proc; | |
413 previous_proc_ = HostResolverProc::SetDefault(current_proc_); | |
414 current_proc_->SetLastProc(previous_proc_); | |
415 } | |
416 | |
417 } // namespace net | |
OLD | NEW |