| 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 |