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 |