| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 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/host_resolver.h" | |
| 6 | |
| 7 #if defined(OS_WIN) | |
| 8 #include <ws2tcpip.h> | |
| 9 #include <wspiapi.h> | |
| 10 #elif defined(OS_POSIX) | |
| 11 #include <netdb.h> | |
| 12 #endif | |
| 13 | |
| 14 #include <string> | |
| 15 | |
| 16 #include "base/compiler_specific.h" | |
| 17 #include "base/message_loop.h" | |
| 18 #include "base/ref_counted.h" | |
| 19 #include "net/base/address_list.h" | |
| 20 #include "net/base/completion_callback.h" | |
| 21 #include "net/base/host_resolver_unittest.h" | |
| 22 #include "net/base/net_errors.h" | |
| 23 #include "net/base/test_completion_callback.h" | |
| 24 #include "testing/gtest/include/gtest/gtest.h" | |
| 25 | |
| 26 using net::RuleBasedHostMapper; | |
| 27 using net::ScopedHostMapper; | |
| 28 using net::WaitingHostMapper; | |
| 29 | |
| 30 // TODO(eroman): | |
| 31 // - Test mixing async with sync (in particular how does sync update the | |
| 32 // cache while an async is already pending). | |
| 33 | |
| 34 namespace { | |
| 35 | |
| 36 // A variant of WaitingHostMapper that pushes each host mapped into a list. | |
| 37 // (and uses a manual-reset event rather than auto-reset). | |
| 38 class CapturingHostMapper : public net::HostMapper { | |
| 39 public: | |
| 40 CapturingHostMapper() : event_(true, false) { | |
| 41 } | |
| 42 | |
| 43 void Signal() { | |
| 44 event_.Signal(); | |
| 45 } | |
| 46 | |
| 47 virtual std::string Map(const std::string& host) { | |
| 48 event_.Wait(); | |
| 49 { | |
| 50 AutoLock l(lock_); | |
| 51 capture_list_.push_back(host); | |
| 52 } | |
| 53 return MapUsingPrevious(host); | |
| 54 } | |
| 55 | |
| 56 std::vector<std::string> GetCaptureList() const { | |
| 57 std::vector<std::string> copy; | |
| 58 { | |
| 59 AutoLock l(lock_); | |
| 60 copy = capture_list_; | |
| 61 } | |
| 62 return copy; | |
| 63 } | |
| 64 | |
| 65 private: | |
| 66 std::vector<std::string> capture_list_; | |
| 67 mutable Lock lock_; | |
| 68 base::WaitableEvent event_; | |
| 69 }; | |
| 70 | |
| 71 // Helper that represents a single Resolve() result, used to inspect all the | |
| 72 // resolve results by forwarding them to Delegate. | |
| 73 class ResolveRequest { | |
| 74 public: | |
| 75 // Delegate interface, for notification when the ResolveRequest completes. | |
| 76 class Delegate { | |
| 77 public: | |
| 78 virtual ~Delegate() {} | |
| 79 virtual void OnCompleted(ResolveRequest* resolve) = 0; | |
| 80 }; | |
| 81 | |
| 82 ResolveRequest(net::HostResolver* resolver, | |
| 83 const std::string& hostname, | |
| 84 int port, | |
| 85 Delegate* delegate) | |
| 86 : info_(hostname, port), resolver_(resolver), delegate_(delegate), | |
| 87 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 88 callback_(this, &ResolveRequest::OnLookupFinished)) { | |
| 89 // Start the request. | |
| 90 int err = resolver->Resolve(info_, &addrlist_, &callback_, &req_); | |
| 91 EXPECT_EQ(net::ERR_IO_PENDING, err); | |
| 92 } | |
| 93 | |
| 94 ResolveRequest(net::HostResolver* resolver, | |
| 95 const net::HostResolver::RequestInfo& info, | |
| 96 Delegate* delegate) | |
| 97 : info_(info), resolver_(resolver), delegate_(delegate), | |
| 98 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 99 callback_(this, &ResolveRequest::OnLookupFinished)) { | |
| 100 // Start the request. | |
| 101 int err = resolver->Resolve(info, &addrlist_, &callback_, &req_); | |
| 102 EXPECT_EQ(net::ERR_IO_PENDING, err); | |
| 103 } | |
| 104 | |
| 105 void Cancel() { | |
| 106 resolver_->CancelRequest(req_); | |
| 107 } | |
| 108 | |
| 109 const std::string& hostname() const { | |
| 110 return info_.hostname(); | |
| 111 } | |
| 112 | |
| 113 int port() const { | |
| 114 return info_.port(); | |
| 115 } | |
| 116 | |
| 117 int result() const { | |
| 118 return result_; | |
| 119 } | |
| 120 | |
| 121 const net::AddressList& addrlist() const { | |
| 122 return addrlist_; | |
| 123 } | |
| 124 | |
| 125 net::HostResolver* resolver() const { | |
| 126 return resolver_; | |
| 127 } | |
| 128 | |
| 129 private: | |
| 130 void OnLookupFinished(int result) { | |
| 131 result_ = result; | |
| 132 delegate_->OnCompleted(this); | |
| 133 } | |
| 134 | |
| 135 // The request details. | |
| 136 net::HostResolver::RequestInfo info_; | |
| 137 net::HostResolver::Request* req_; | |
| 138 | |
| 139 // The result of the resolve. | |
| 140 int result_; | |
| 141 net::AddressList addrlist_; | |
| 142 | |
| 143 // We don't use a scoped_refptr, to simplify deleting shared resolver in | |
| 144 // DeleteWithinCallback test. | |
| 145 net::HostResolver* resolver_; | |
| 146 | |
| 147 Delegate* delegate_; | |
| 148 net::CompletionCallbackImpl<ResolveRequest> callback_; | |
| 149 | |
| 150 DISALLOW_COPY_AND_ASSIGN(ResolveRequest); | |
| 151 }; | |
| 152 | |
| 153 class HostResolverTest : public testing::Test { | |
| 154 public: | |
| 155 HostResolverTest() | |
| 156 : callback_called_(false), | |
| 157 ALLOW_THIS_IN_INITIALIZER_LIST( | |
| 158 callback_(this, &HostResolverTest::OnLookupFinished)) { | |
| 159 } | |
| 160 | |
| 161 protected: | |
| 162 bool callback_called_; | |
| 163 int callback_result_; | |
| 164 net::CompletionCallbackImpl<HostResolverTest> callback_; | |
| 165 | |
| 166 private: | |
| 167 void OnLookupFinished(int result) { | |
| 168 callback_called_ = true; | |
| 169 callback_result_ = result; | |
| 170 MessageLoop::current()->Quit(); | |
| 171 } | |
| 172 }; | |
| 173 | |
| 174 TEST_F(HostResolverTest, SynchronousLookup) { | |
| 175 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 176 net::AddressList adrlist; | |
| 177 const int kPortnum = 80; | |
| 178 | |
| 179 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper(); | |
| 180 mapper->AddRule("just.testing", "192.168.1.42"); | |
| 181 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 182 | |
| 183 net::HostResolver::RequestInfo info("just.testing", kPortnum); | |
| 184 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL); | |
| 185 EXPECT_EQ(net::OK, err); | |
| 186 | |
| 187 const struct addrinfo* ainfo = adrlist.head(); | |
| 188 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next); | |
| 189 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen); | |
| 190 | |
| 191 const struct sockaddr* sa = ainfo->ai_addr; | |
| 192 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa; | |
| 193 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port); | |
| 194 EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr); | |
| 195 } | |
| 196 | |
| 197 TEST_F(HostResolverTest, AsynchronousLookup) { | |
| 198 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 199 net::AddressList adrlist; | |
| 200 const int kPortnum = 80; | |
| 201 | |
| 202 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper(); | |
| 203 mapper->AddRule("just.testing", "192.168.1.42"); | |
| 204 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 205 | |
| 206 net::HostResolver::RequestInfo info("just.testing", kPortnum); | |
| 207 int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL); | |
| 208 EXPECT_EQ(net::ERR_IO_PENDING, err); | |
| 209 | |
| 210 MessageLoop::current()->Run(); | |
| 211 | |
| 212 ASSERT_TRUE(callback_called_); | |
| 213 ASSERT_EQ(net::OK, callback_result_); | |
| 214 | |
| 215 const struct addrinfo* ainfo = adrlist.head(); | |
| 216 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next); | |
| 217 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen); | |
| 218 | |
| 219 const struct sockaddr* sa = ainfo->ai_addr; | |
| 220 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa; | |
| 221 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port); | |
| 222 EXPECT_TRUE(htonl(0xc0a8012a) == sa_in->sin_addr.s_addr); | |
| 223 } | |
| 224 | |
| 225 TEST_F(HostResolverTest, CanceledAsynchronousLookup) { | |
| 226 scoped_refptr<WaitingHostMapper> mapper = new WaitingHostMapper(); | |
| 227 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 228 | |
| 229 { | |
| 230 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 231 net::AddressList adrlist; | |
| 232 const int kPortnum = 80; | |
| 233 | |
| 234 net::HostResolver::RequestInfo info("just.testing", kPortnum); | |
| 235 int err = host_resolver->Resolve(info, &adrlist, &callback_, NULL); | |
| 236 EXPECT_EQ(net::ERR_IO_PENDING, err); | |
| 237 | |
| 238 // Make sure we will exit the queue even when callback is not called. | |
| 239 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 240 new MessageLoop::QuitTask(), | |
| 241 1000); | |
| 242 MessageLoop::current()->Run(); | |
| 243 } | |
| 244 | |
| 245 mapper->Signal(); | |
| 246 | |
| 247 EXPECT_FALSE(callback_called_); | |
| 248 } | |
| 249 | |
| 250 TEST_F(HostResolverTest, NumericIPv4Address) { | |
| 251 // Stevens says dotted quads with AI_UNSPEC resolve to a single sockaddr_in. | |
| 252 | |
| 253 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper(); | |
| 254 mapper->AllowDirectLookup("*"); | |
| 255 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 256 | |
| 257 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 258 net::AddressList adrlist; | |
| 259 const int kPortnum = 5555; | |
| 260 net::HostResolver::RequestInfo info("127.1.2.3", kPortnum); | |
| 261 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL); | |
| 262 EXPECT_EQ(net::OK, err); | |
| 263 | |
| 264 const struct addrinfo* ainfo = adrlist.head(); | |
| 265 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next); | |
| 266 EXPECT_EQ(sizeof(struct sockaddr_in), ainfo->ai_addrlen); | |
| 267 | |
| 268 const struct sockaddr* sa = ainfo->ai_addr; | |
| 269 const struct sockaddr_in* sa_in = (const struct sockaddr_in*) sa; | |
| 270 EXPECT_TRUE(htons(kPortnum) == sa_in->sin_port); | |
| 271 EXPECT_TRUE(htonl(0x7f010203) == sa_in->sin_addr.s_addr); | |
| 272 } | |
| 273 | |
| 274 TEST_F(HostResolverTest, NumericIPv6Address) { | |
| 275 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper(); | |
| 276 mapper->AllowDirectLookup("*"); | |
| 277 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 278 | |
| 279 // Resolve a plain IPv6 address. Don't worry about [brackets], because | |
| 280 // the caller should have removed them. | |
| 281 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 282 net::AddressList adrlist; | |
| 283 const int kPortnum = 5555; | |
| 284 net::HostResolver::RequestInfo info("2001:db8::1", kPortnum); | |
| 285 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL); | |
| 286 // On computers without IPv6 support, getaddrinfo cannot convert IPv6 | |
| 287 // address literals to addresses (getaddrinfo returns EAI_NONAME). So this | |
| 288 // test has to allow host_resolver->Resolve to fail. | |
| 289 if (err == net::ERR_NAME_NOT_RESOLVED) | |
| 290 return; | |
| 291 EXPECT_EQ(net::OK, err); | |
| 292 | |
| 293 const struct addrinfo* ainfo = adrlist.head(); | |
| 294 EXPECT_EQ(static_cast<addrinfo*>(NULL), ainfo->ai_next); | |
| 295 EXPECT_EQ(sizeof(struct sockaddr_in6), ainfo->ai_addrlen); | |
| 296 | |
| 297 const struct sockaddr* sa = ainfo->ai_addr; | |
| 298 const struct sockaddr_in6* sa_in6 = (const struct sockaddr_in6*) sa; | |
| 299 EXPECT_TRUE(htons(kPortnum) == sa_in6->sin6_port); | |
| 300 | |
| 301 const uint8 expect_addr[] = { | |
| 302 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, | |
| 303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 | |
| 304 }; | |
| 305 for (int i = 0; i < 16; i++) { | |
| 306 EXPECT_EQ(expect_addr[i], sa_in6->sin6_addr.s6_addr[i]); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 TEST_F(HostResolverTest, EmptyHost) { | |
| 311 scoped_refptr<RuleBasedHostMapper> mapper = new RuleBasedHostMapper(); | |
| 312 mapper->AllowDirectLookup("*"); | |
| 313 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 314 | |
| 315 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 316 net::AddressList adrlist; | |
| 317 const int kPortnum = 5555; | |
| 318 net::HostResolver::RequestInfo info("", kPortnum); | |
| 319 int err = host_resolver->Resolve(info, &adrlist, NULL, NULL); | |
| 320 EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, err); | |
| 321 } | |
| 322 | |
| 323 // Helper class used by HostResolverTest.DeDupeRequests. It receives request | |
| 324 // completion notifications for all the resolves, so it can tally up and | |
| 325 // determine when we are done. | |
| 326 class DeDupeRequestsVerifier : public ResolveRequest::Delegate { | |
| 327 public: | |
| 328 explicit DeDupeRequestsVerifier(CapturingHostMapper* mapper) | |
| 329 : count_a_(0), count_b_(0), mapper_(mapper) {} | |
| 330 | |
| 331 // The test does 5 resolves (which can complete in any order). | |
| 332 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 333 // Tally up how many requests we have seen. | |
| 334 if (resolve->hostname() == "a") { | |
| 335 count_a_++; | |
| 336 } else if (resolve->hostname() == "b") { | |
| 337 count_b_++; | |
| 338 } else { | |
| 339 FAIL() << "Unexpected hostname: " << resolve->hostname(); | |
| 340 } | |
| 341 | |
| 342 // Check that the port was set correctly. | |
| 343 EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort()); | |
| 344 | |
| 345 // Check whether all the requests have finished yet. | |
| 346 int total_completions = count_a_ + count_b_; | |
| 347 if (total_completions == 5) { | |
| 348 EXPECT_EQ(2, count_a_); | |
| 349 EXPECT_EQ(3, count_b_); | |
| 350 | |
| 351 // The mapper should have been called only twice -- once with "a", once | |
| 352 // with "b". | |
| 353 std::vector<std::string> capture_list = mapper_->GetCaptureList(); | |
| 354 EXPECT_EQ(2U, capture_list.size()); | |
| 355 | |
| 356 // End this test, we are done. | |
| 357 MessageLoop::current()->Quit(); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 private: | |
| 362 int count_a_; | |
| 363 int count_b_; | |
| 364 CapturingHostMapper* mapper_; | |
| 365 | |
| 366 DISALLOW_COPY_AND_ASSIGN(DeDupeRequestsVerifier); | |
| 367 }; | |
| 368 | |
| 369 TEST_F(HostResolverTest, DeDupeRequests) { | |
| 370 // Use a capturing mapper, since the verifier needs to know what calls | |
| 371 // reached Map(). Also, the capturing mapper is initially blocked. | |
| 372 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper(); | |
| 373 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 374 | |
| 375 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 376 | |
| 377 // The class will receive callbacks for when each resolve completes. It | |
| 378 // checks that the right things happened. | |
| 379 DeDupeRequestsVerifier verifier(mapper.get()); | |
| 380 | |
| 381 // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is | |
| 382 // blocked, these should all pile up until we signal it. | |
| 383 | |
| 384 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 385 ResolveRequest req2(host_resolver, "b", 80, &verifier); | |
| 386 ResolveRequest req3(host_resolver, "b", 81, &verifier); | |
| 387 ResolveRequest req4(host_resolver, "a", 82, &verifier); | |
| 388 ResolveRequest req5(host_resolver, "b", 83, &verifier); | |
| 389 | |
| 390 // Ready, Set, GO!!! | |
| 391 mapper->Signal(); | |
| 392 | |
| 393 // |verifier| will send quit message once all the requests have finished. | |
| 394 MessageLoop::current()->Run(); | |
| 395 } | |
| 396 | |
| 397 // Helper class used by HostResolverTest.CancelMultipleRequests. | |
| 398 class CancelMultipleRequestsVerifier : public ResolveRequest::Delegate { | |
| 399 public: | |
| 400 CancelMultipleRequestsVerifier() {} | |
| 401 | |
| 402 // The cancels kill all but one request. | |
| 403 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 404 EXPECT_EQ("a", resolve->hostname()); | |
| 405 EXPECT_EQ(82, resolve->port()); | |
| 406 | |
| 407 // Check that the port was set correctly. | |
| 408 EXPECT_EQ(resolve->port(), resolve->addrlist().GetPort()); | |
| 409 | |
| 410 // End this test, we are done. | |
| 411 MessageLoop::current()->Quit(); | |
| 412 } | |
| 413 | |
| 414 private: | |
| 415 DISALLOW_COPY_AND_ASSIGN(CancelMultipleRequestsVerifier); | |
| 416 }; | |
| 417 | |
| 418 TEST_F(HostResolverTest, CancelMultipleRequests) { | |
| 419 // Use a capturing mapper, since the verifier needs to know what calls | |
| 420 // reached Map(). Also, the capturing mapper is initially blocked. | |
| 421 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper(); | |
| 422 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 423 | |
| 424 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 425 | |
| 426 // The class will receive callbacks for when each resolve completes. It | |
| 427 // checks that the right things happened. | |
| 428 CancelMultipleRequestsVerifier verifier; | |
| 429 | |
| 430 // Start 5 requests, duplicating hosts "a" and "b". Since the mapper is | |
| 431 // blocked, these should all pile up until we signal it. | |
| 432 | |
| 433 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 434 ResolveRequest req2(host_resolver, "b", 80, &verifier); | |
| 435 ResolveRequest req3(host_resolver, "b", 81, &verifier); | |
| 436 ResolveRequest req4(host_resolver, "a", 82, &verifier); | |
| 437 ResolveRequest req5(host_resolver, "b", 83, &verifier); | |
| 438 | |
| 439 // Cancel everything except request 4. | |
| 440 req1.Cancel(); | |
| 441 req2.Cancel(); | |
| 442 req3.Cancel(); | |
| 443 req5.Cancel(); | |
| 444 | |
| 445 // Ready, Set, GO!!! | |
| 446 mapper->Signal(); | |
| 447 | |
| 448 // |verifier| will send quit message once all the requests have finished. | |
| 449 MessageLoop::current()->Run(); | |
| 450 } | |
| 451 | |
| 452 // Helper class used by HostResolverTest.CancelWithinCallback. | |
| 453 class CancelWithinCallbackVerifier : public ResolveRequest::Delegate { | |
| 454 public: | |
| 455 CancelWithinCallbackVerifier() | |
| 456 : req_to_cancel1_(NULL), req_to_cancel2_(NULL), num_completions_(0) { | |
| 457 } | |
| 458 | |
| 459 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 460 num_completions_++; | |
| 461 | |
| 462 // Port 80 is the first request that the callback will be invoked for. | |
| 463 // While we are executing within that callback, cancel the other requests | |
| 464 // in the job and start another request. | |
| 465 if (80 == resolve->port()) { | |
| 466 EXPECT_EQ("a", resolve->hostname()); | |
| 467 | |
| 468 req_to_cancel1_->Cancel(); | |
| 469 req_to_cancel2_->Cancel(); | |
| 470 | |
| 471 // Start a request (so we can make sure the canceled requests don't | |
| 472 // complete before "finalrequest" finishes. | |
| 473 final_request_.reset(new ResolveRequest( | |
| 474 resolve->resolver(), "finalrequest", 70, this)); | |
| 475 | |
| 476 } else if (83 == resolve->port()) { | |
| 477 EXPECT_EQ("a", resolve->hostname()); | |
| 478 } else if (resolve->hostname() == "finalrequest") { | |
| 479 EXPECT_EQ(70, resolve->addrlist().GetPort()); | |
| 480 | |
| 481 // End this test, we are done. | |
| 482 MessageLoop::current()->Quit(); | |
| 483 } else { | |
| 484 FAIL() << "Unexpected completion: " << resolve->hostname() << ", " | |
| 485 << resolve->port(); | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 void SetRequestsToCancel(ResolveRequest* req_to_cancel1, | |
| 490 ResolveRequest* req_to_cancel2) { | |
| 491 req_to_cancel1_ = req_to_cancel1; | |
| 492 req_to_cancel2_ = req_to_cancel2; | |
| 493 } | |
| 494 | |
| 495 private: | |
| 496 scoped_ptr<ResolveRequest> final_request_; | |
| 497 ResolveRequest* req_to_cancel1_; | |
| 498 ResolveRequest* req_to_cancel2_; | |
| 499 int num_completions_; | |
| 500 DISALLOW_COPY_AND_ASSIGN(CancelWithinCallbackVerifier); | |
| 501 }; | |
| 502 | |
| 503 TEST_F(HostResolverTest, CancelWithinCallback) { | |
| 504 // Use a capturing mapper, since the verifier needs to know what calls | |
| 505 // reached Map(). Also, the capturing mapper is initially blocked. | |
| 506 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper(); | |
| 507 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 508 | |
| 509 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 510 | |
| 511 // The class will receive callbacks for when each resolve completes. It | |
| 512 // checks that the right things happened. | |
| 513 CancelWithinCallbackVerifier verifier; | |
| 514 | |
| 515 // Start 4 requests, duplicating hosts "a". Since the mapper is | |
| 516 // blocked, these should all pile up until we signal it. | |
| 517 | |
| 518 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 519 ResolveRequest req2(host_resolver, "a", 81, &verifier); | |
| 520 ResolveRequest req3(host_resolver, "a", 82, &verifier); | |
| 521 ResolveRequest req4(host_resolver, "a", 83, &verifier); | |
| 522 | |
| 523 // Once "a:80" completes, it will cancel "a:81" and "a:82". | |
| 524 verifier.SetRequestsToCancel(&req2, &req3); | |
| 525 | |
| 526 // Ready, Set, GO!!! | |
| 527 mapper->Signal(); | |
| 528 | |
| 529 // |verifier| will send quit message once all the requests have finished. | |
| 530 MessageLoop::current()->Run(); | |
| 531 } | |
| 532 | |
| 533 // Helper class used by HostResolverTest.DeleteWithinCallback. | |
| 534 class DeleteWithinCallbackVerifier : public ResolveRequest::Delegate { | |
| 535 public: | |
| 536 // |host_resolver| is the resolver that the the resolve requests were started | |
| 537 // with. | |
| 538 DeleteWithinCallbackVerifier(net::HostResolver* host_resolver) | |
| 539 : host_resolver_(host_resolver) {} | |
| 540 | |
| 541 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 542 EXPECT_EQ("a", resolve->hostname()); | |
| 543 EXPECT_EQ(80, resolve->port()); | |
| 544 | |
| 545 // Release the last reference to the host resolver that started the | |
| 546 // requests. | |
| 547 host_resolver_ = NULL; | |
| 548 | |
| 549 // Quit after returning from OnCompleted (to give it a chance at | |
| 550 // incorrectly running the cancelled tasks). | |
| 551 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); | |
| 552 } | |
| 553 | |
| 554 private: | |
| 555 scoped_refptr<net::HostResolver> host_resolver_; | |
| 556 DISALLOW_COPY_AND_ASSIGN(DeleteWithinCallbackVerifier); | |
| 557 }; | |
| 558 | |
| 559 TEST_F(HostResolverTest, DeleteWithinCallback) { | |
| 560 // Use a capturing mapper, since the verifier needs to know what calls | |
| 561 // reached Map(). Also, the capturing mapper is initially blocked. | |
| 562 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper(); | |
| 563 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 564 | |
| 565 // The class will receive callbacks for when each resolve completes. It | |
| 566 // checks that the right things happened. Note that the verifier holds the | |
| 567 // only reference to |host_resolver|, so it can delete it within callback. | |
| 568 net::HostResolver* host_resolver = new net::HostResolver; | |
| 569 DeleteWithinCallbackVerifier verifier(host_resolver); | |
| 570 | |
| 571 // Start 4 requests, duplicating hosts "a". Since the mapper is | |
| 572 // blocked, these should all pile up until we signal it. | |
| 573 | |
| 574 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 575 ResolveRequest req2(host_resolver, "a", 81, &verifier); | |
| 576 ResolveRequest req3(host_resolver, "a", 82, &verifier); | |
| 577 ResolveRequest req4(host_resolver, "a", 83, &verifier); | |
| 578 | |
| 579 // Ready, Set, GO!!! | |
| 580 mapper->Signal(); | |
| 581 | |
| 582 // |verifier| will send quit message once all the requests have finished. | |
| 583 MessageLoop::current()->Run(); | |
| 584 } | |
| 585 | |
| 586 // Helper class used by HostResolverTest.StartWithinCallback. | |
| 587 class StartWithinCallbackVerifier : public ResolveRequest::Delegate { | |
| 588 public: | |
| 589 StartWithinCallbackVerifier() : num_requests_(0) {} | |
| 590 | |
| 591 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 592 EXPECT_EQ("a", resolve->hostname()); | |
| 593 | |
| 594 if (80 == resolve->port()) { | |
| 595 // On completing the first request, start another request for "a". | |
| 596 // Since caching is disabled, this will result in another async request. | |
| 597 final_request_.reset(new ResolveRequest( | |
| 598 resolve->resolver(), "a", 70, this)); | |
| 599 } | |
| 600 if (++num_requests_ == 5) { | |
| 601 // Test is done. | |
| 602 MessageLoop::current()->Quit(); | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 private: | |
| 607 int num_requests_; | |
| 608 scoped_ptr<ResolveRequest> final_request_; | |
| 609 DISALLOW_COPY_AND_ASSIGN(StartWithinCallbackVerifier); | |
| 610 }; | |
| 611 | |
| 612 TEST_F(HostResolverTest, StartWithinCallback) { | |
| 613 // Use a capturing mapper, since the verifier needs to know what calls | |
| 614 // reached Map(). Also, the capturing mapper is initially blocked. | |
| 615 scoped_refptr<CapturingHostMapper> mapper = new CapturingHostMapper(); | |
| 616 ScopedHostMapper scoped_mapper(mapper.get()); | |
| 617 | |
| 618 // Turn off caching for this host resolver. | |
| 619 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver(0, 0)); | |
| 620 | |
| 621 // The class will receive callbacks for when each resolve completes. It | |
| 622 // checks that the right things happened. | |
| 623 StartWithinCallbackVerifier verifier; | |
| 624 | |
| 625 // Start 4 requests, duplicating hosts "a". Since the mapper is | |
| 626 // blocked, these should all pile up until we signal it. | |
| 627 | |
| 628 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 629 ResolveRequest req2(host_resolver, "a", 81, &verifier); | |
| 630 ResolveRequest req3(host_resolver, "a", 82, &verifier); | |
| 631 ResolveRequest req4(host_resolver, "a", 83, &verifier); | |
| 632 | |
| 633 // Ready, Set, GO!!! | |
| 634 mapper->Signal(); | |
| 635 | |
| 636 // |verifier| will send quit message once all the requests have finished. | |
| 637 MessageLoop::current()->Run(); | |
| 638 } | |
| 639 | |
| 640 // Helper class used by HostResolverTest.BypassCache. | |
| 641 class BypassCacheVerifier : public ResolveRequest::Delegate { | |
| 642 public: | |
| 643 BypassCacheVerifier() {} | |
| 644 | |
| 645 virtual void OnCompleted(ResolveRequest* resolve) { | |
| 646 EXPECT_EQ("a", resolve->hostname()); | |
| 647 net::HostResolver* resolver = resolve->resolver(); | |
| 648 | |
| 649 if (80 == resolve->port()) { | |
| 650 // On completing the first request, start another request for "a". | |
| 651 // Since caching is enabled, this should complete synchronously. | |
| 652 | |
| 653 // Note that |junk_callback| shouldn't be used since we are going to | |
| 654 // complete synchronously. We can't specify NULL though since that would | |
| 655 // mean synchronous mode so we give it a value of 1. | |
| 656 net::CompletionCallback* junk_callback = | |
| 657 reinterpret_cast<net::CompletionCallback*> (1); | |
| 658 net::AddressList addrlist; | |
| 659 | |
| 660 net::HostResolver::RequestInfo info("a", 70); | |
| 661 int error = resolver->Resolve(info, &addrlist, junk_callback, NULL); | |
| 662 EXPECT_EQ(net::OK, error); | |
| 663 | |
| 664 // Ok good. Now make sure that if we ask to bypass the cache, it can no | |
| 665 // longer service the request synchronously. | |
| 666 info = net::HostResolver::RequestInfo("a", 71); | |
| 667 info.set_allow_cached_response(false); | |
| 668 final_request_.reset(new ResolveRequest(resolver, info, this)); | |
| 669 } else if (71 == resolve->port()) { | |
| 670 // Test is done. | |
| 671 MessageLoop::current()->Quit(); | |
| 672 } else { | |
| 673 FAIL() << "Unexpected port number"; | |
| 674 } | |
| 675 } | |
| 676 | |
| 677 private: | |
| 678 scoped_ptr<ResolveRequest> final_request_; | |
| 679 DISALLOW_COPY_AND_ASSIGN(BypassCacheVerifier); | |
| 680 }; | |
| 681 | |
| 682 TEST_F(HostResolverTest, BypassCache) { | |
| 683 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 684 | |
| 685 // The class will receive callbacks for when each resolve completes. It | |
| 686 // checks that the right things happened. | |
| 687 BypassCacheVerifier verifier; | |
| 688 | |
| 689 // Start a request. | |
| 690 ResolveRequest req1(host_resolver, "a", 80, &verifier); | |
| 691 | |
| 692 // |verifier| will send quit message once all the requests have finished. | |
| 693 MessageLoop::current()->Run(); | |
| 694 } | |
| 695 | |
| 696 bool operator==(const net::HostResolver::RequestInfo& a, | |
| 697 const net::HostResolver::RequestInfo& b) { | |
| 698 return a.hostname() == b.hostname() && | |
| 699 a.port() == b.port() && | |
| 700 a.allow_cached_response() == b.allow_cached_response() && | |
| 701 a.is_speculative() == b.is_speculative() && | |
| 702 a.referrer() == b.referrer(); | |
| 703 } | |
| 704 | |
| 705 // Observer that just makes note of how it was called. The test code can then | |
| 706 // inspect to make sure it was called with the right parameters. | |
| 707 class CapturingObserver : public net::HostResolver::Observer { | |
| 708 public: | |
| 709 // DnsResolutionObserver methods: | |
| 710 virtual void OnStartResolution(int id, | |
| 711 const net::HostResolver::RequestInfo& info) { | |
| 712 start_log.push_back(StartOrCancelEntry(id, info)); | |
| 713 } | |
| 714 | |
| 715 virtual void OnFinishResolutionWithStatus( | |
| 716 int id, | |
| 717 bool was_resolved, | |
| 718 const net::HostResolver::RequestInfo& info) { | |
| 719 finish_log.push_back(FinishEntry(id, was_resolved, info)); | |
| 720 } | |
| 721 | |
| 722 virtual void OnCancelResolution(int id, | |
| 723 const net::HostResolver::RequestInfo& info) { | |
| 724 cancel_log.push_back(StartOrCancelEntry(id, info)); | |
| 725 } | |
| 726 | |
| 727 // Tuple (id, info). | |
| 728 struct StartOrCancelEntry { | |
| 729 StartOrCancelEntry(int id, const net::HostResolver::RequestInfo& info) | |
| 730 : id(id), info(info) {} | |
| 731 | |
| 732 bool operator==(const StartOrCancelEntry& other) const { | |
| 733 return id == other.id && info == other.info; | |
| 734 } | |
| 735 | |
| 736 int id; | |
| 737 net::HostResolver::RequestInfo info; | |
| 738 }; | |
| 739 | |
| 740 // Tuple (id, was_resolved, info). | |
| 741 struct FinishEntry { | |
| 742 FinishEntry(int id, bool was_resolved, | |
| 743 const net::HostResolver::RequestInfo& info) | |
| 744 : id(id), was_resolved(was_resolved), info(info) {} | |
| 745 | |
| 746 bool operator==(const FinishEntry& other) const { | |
| 747 return id == other.id && | |
| 748 was_resolved == other.was_resolved && | |
| 749 info == other.info; | |
| 750 } | |
| 751 | |
| 752 int id; | |
| 753 bool was_resolved; | |
| 754 net::HostResolver::RequestInfo info; | |
| 755 }; | |
| 756 | |
| 757 std::vector<StartOrCancelEntry> start_log; | |
| 758 std::vector<FinishEntry> finish_log; | |
| 759 std::vector<StartOrCancelEntry> cancel_log; | |
| 760 }; | |
| 761 | |
| 762 // Test that registering, unregistering, and notifying of observers works. | |
| 763 // Does not test the cancellation notification since all resolves are | |
| 764 // synchronous. | |
| 765 TEST_F(HostResolverTest, Observers) { | |
| 766 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 767 | |
| 768 CapturingObserver observer; | |
| 769 | |
| 770 host_resolver->AddObserver(&observer); | |
| 771 | |
| 772 net::AddressList addrlist; | |
| 773 | |
| 774 // Resolve "host1". | |
| 775 net::HostResolver::RequestInfo info1("host1", 70); | |
| 776 int rv = host_resolver->Resolve(info1, &addrlist, NULL, NULL); | |
| 777 EXPECT_EQ(net::OK, rv); | |
| 778 | |
| 779 EXPECT_EQ(1U, observer.start_log.size()); | |
| 780 EXPECT_EQ(1U, observer.finish_log.size()); | |
| 781 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 782 EXPECT_TRUE(observer.start_log[0] == | |
| 783 CapturingObserver::StartOrCancelEntry(0, info1)); | |
| 784 EXPECT_TRUE(observer.finish_log[0] == | |
| 785 CapturingObserver::FinishEntry(0, true, info1)); | |
| 786 | |
| 787 // Resolve "host1" again -- this time it will be served from cache, but it | |
| 788 // should still notify of completion. | |
| 789 TestCompletionCallback callback; | |
| 790 rv = host_resolver->Resolve(info1, &addrlist, &callback, NULL); | |
| 791 ASSERT_EQ(net::OK, rv); // Should complete synchronously. | |
| 792 | |
| 793 EXPECT_EQ(2U, observer.start_log.size()); | |
| 794 EXPECT_EQ(2U, observer.finish_log.size()); | |
| 795 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 796 EXPECT_TRUE(observer.start_log[1] == | |
| 797 CapturingObserver::StartOrCancelEntry(1, info1)); | |
| 798 EXPECT_TRUE(observer.finish_log[1] == | |
| 799 CapturingObserver::FinishEntry(1, true, info1)); | |
| 800 | |
| 801 // Resolve "host2", setting referrer to "http://foobar.com" | |
| 802 net::HostResolver::RequestInfo info2("host2", 70); | |
| 803 info2.set_referrer(GURL("http://foobar.com")); | |
| 804 rv = host_resolver->Resolve(info2, &addrlist, NULL, NULL); | |
| 805 EXPECT_EQ(net::OK, rv); | |
| 806 | |
| 807 EXPECT_EQ(3U, observer.start_log.size()); | |
| 808 EXPECT_EQ(3U, observer.finish_log.size()); | |
| 809 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 810 EXPECT_TRUE(observer.start_log[2] == | |
| 811 CapturingObserver::StartOrCancelEntry(2, info2)); | |
| 812 EXPECT_TRUE(observer.finish_log[2] == | |
| 813 CapturingObserver::FinishEntry(2, true, info2)); | |
| 814 | |
| 815 // Unregister the observer. | |
| 816 host_resolver->RemoveObserver(&observer); | |
| 817 | |
| 818 // Resolve "host3" | |
| 819 net::HostResolver::RequestInfo info3("host3", 70); | |
| 820 host_resolver->Resolve(info3, &addrlist, NULL, NULL); | |
| 821 | |
| 822 // No effect this time, since observer was removed. | |
| 823 EXPECT_EQ(3U, observer.start_log.size()); | |
| 824 EXPECT_EQ(3U, observer.finish_log.size()); | |
| 825 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 826 } | |
| 827 | |
| 828 // Tests that observers are sent OnCancelResolution() whenever a request is | |
| 829 // cancelled. There are two ways to cancel a request: | |
| 830 // (1) Delete the HostResolver while job is outstanding. | |
| 831 // (2) Call HostResolver::CancelRequest() while a request is outstanding. | |
| 832 TEST_F(HostResolverTest, CancellationObserver) { | |
| 833 CapturingObserver observer; | |
| 834 { | |
| 835 // Create a host resolver and attach an observer. | |
| 836 scoped_refptr<net::HostResolver> host_resolver(new net::HostResolver); | |
| 837 host_resolver->AddObserver(&observer); | |
| 838 | |
| 839 TestCompletionCallback callback; | |
| 840 | |
| 841 EXPECT_EQ(0U, observer.start_log.size()); | |
| 842 EXPECT_EQ(0U, observer.finish_log.size()); | |
| 843 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 844 | |
| 845 // Start an async resolve for (host1:70). | |
| 846 net::HostResolver::RequestInfo info1("host1", 70); | |
| 847 net::HostResolver::Request* req = NULL; | |
| 848 net::AddressList addrlist; | |
| 849 int rv = host_resolver->Resolve(info1, &addrlist, &callback, &req); | |
| 850 EXPECT_EQ(net::ERR_IO_PENDING, rv); | |
| 851 EXPECT_TRUE(NULL != req); | |
| 852 | |
| 853 EXPECT_EQ(1U, observer.start_log.size()); | |
| 854 EXPECT_EQ(0U, observer.finish_log.size()); | |
| 855 EXPECT_EQ(0U, observer.cancel_log.size()); | |
| 856 | |
| 857 EXPECT_TRUE(observer.start_log[0] == | |
| 858 CapturingObserver::StartOrCancelEntry(0, info1)); | |
| 859 | |
| 860 // Cancel the request (host mapper is blocked so it cant be finished yet). | |
| 861 host_resolver->CancelRequest(req); | |
| 862 | |
| 863 EXPECT_EQ(1U, observer.start_log.size()); | |
| 864 EXPECT_EQ(0U, observer.finish_log.size()); | |
| 865 EXPECT_EQ(1U, observer.cancel_log.size()); | |
| 866 | |
| 867 EXPECT_TRUE(observer.cancel_log[0] == | |
| 868 CapturingObserver::StartOrCancelEntry(0, info1)); | |
| 869 | |
| 870 // Start an async request for (host2:60) | |
| 871 net::HostResolver::RequestInfo info2("host2", 60); | |
| 872 rv = host_resolver->Resolve(info2, &addrlist, &callback, NULL); | |
| 873 EXPECT_EQ(net::ERR_IO_PENDING, rv); | |
| 874 EXPECT_TRUE(NULL != req); | |
| 875 | |
| 876 EXPECT_EQ(2U, observer.start_log.size()); | |
| 877 EXPECT_EQ(0U, observer.finish_log.size()); | |
| 878 EXPECT_EQ(1U, observer.cancel_log.size()); | |
| 879 | |
| 880 EXPECT_TRUE(observer.start_log[1] == | |
| 881 CapturingObserver::StartOrCancelEntry(1, info2)); | |
| 882 | |
| 883 // Upon exiting this scope, HostResolver is destroyed, so all requests are | |
| 884 // implicitly cancelled. | |
| 885 } | |
| 886 | |
| 887 // Check that destroying the HostResolver sent a notification for | |
| 888 // cancellation of host2:60 request. | |
| 889 | |
| 890 EXPECT_EQ(2U, observer.start_log.size()); | |
| 891 EXPECT_EQ(0U, observer.finish_log.size()); | |
| 892 EXPECT_EQ(2U, observer.cancel_log.size()); | |
| 893 | |
| 894 net::HostResolver::RequestInfo info("host2", 60); | |
| 895 EXPECT_TRUE(observer.cancel_log[1] == | |
| 896 CapturingObserver::StartOrCancelEntry(1, info)); | |
| 897 } | |
| 898 | |
| 899 } // namespace | |
| OLD | NEW |