1 // Copyright (c) 2013 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.
5 #include "net/proxy/proxy_resolver_v8_tracing.h"
7 #include "base/files/file_util.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/path_service.h"
10 #include "base/stl_util.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/values.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/net_log.h"
19 #include "net/base/net_log_unittest.h"
20 #include "net/base/test_completion_callback.h"
21 #include "net/dns/host_cache.h"
22 #include "net/dns/mock_host_resolver.h"
23 #include "net/proxy/proxy_info.h"
24 #include "net/proxy/proxy_resolver_error_observer.h"
25 #include "testing/gtest/include/gtest/gtest.h"
32 class ProxyResolverV8TracingTest
: public testing::Test
{
34 virtual void TearDown() OVERRIDE
{
35 // Drain any pending messages, which may be left over from cancellation.
36 // This way they get reliably run as part of the current test, rather than
37 // spilling into the next test's execution.
38 base::MessageLoop::current()->RunUntilIdle();
42 scoped_refptr
<ProxyResolverScriptData
> LoadScriptData(const char* filename
) {
44 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
45 path
= path
.AppendASCII("net");
46 path
= path
.AppendASCII("data");
47 path
= path
.AppendASCII("proxy_resolver_v8_tracing_unittest");
48 path
= path
.AppendASCII(filename
);
50 // Try to read the file from disk.
51 std::string file_contents
;
52 bool ok
= base::ReadFileToString(path
, &file_contents
);
54 // If we can't load the file from disk, something is misconfigured.
55 EXPECT_TRUE(ok
) << "Failed to read file: " << path
.value();
57 // Load the PAC script into the ProxyResolver.
58 return ProxyResolverScriptData::FromUTF8(file_contents
);
61 void InitResolver(ProxyResolverV8Tracing
* resolver
, const char* filename
) {
62 TestCompletionCallback callback
;
64 resolver
->SetPacScript(LoadScriptData(filename
), callback
.callback());
65 EXPECT_EQ(ERR_IO_PENDING
, rv
);
66 EXPECT_EQ(OK
, callback
.WaitForResult());
69 class MockErrorObserver
: public ProxyResolverErrorObserver
{
71 MockErrorObserver() : event_(true, false) {}
73 virtual void OnPACScriptError(int line_number
,
74 const base::string16
& error
) OVERRIDE
{
76 base::AutoLock
l(lock_
);
77 output
+= base::StringPrintf("Error: line %d: %s\n", line_number
,
78 base::UTF16ToASCII(error
).c_str());
83 std::string
GetOutput() {
84 base::AutoLock
l(lock_
);
88 void WaitForOutput() {
96 base::WaitableEvent event_
;
99 TEST_F(ProxyResolverV8TracingTest
, Simple
) {
101 CapturingBoundNetLog request_log
;
102 MockCachingHostResolver host_resolver
;
103 MockErrorObserver
* error_observer
= new MockErrorObserver
;
104 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
106 InitResolver(&resolver
, "simple.js");
108 TestCompletionCallback callback
;
109 ProxyInfo proxy_info
;
111 int rv
= resolver
.GetProxyForURL(
112 GURL("http://foo/"), &proxy_info
, callback
.callback(),
113 NULL
, request_log
.bound());
115 EXPECT_EQ(ERR_IO_PENDING
, rv
);
116 EXPECT_EQ(OK
, callback
.WaitForResult());
118 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
120 EXPECT_EQ(0u, host_resolver
.num_resolve());
122 // There were no errors.
123 EXPECT_EQ("", error_observer
->GetOutput());
125 // Check the NetLogs -- nothing was logged.
126 EXPECT_EQ(0u, log
.GetSize());
127 EXPECT_EQ(0u, request_log
.GetSize());
130 TEST_F(ProxyResolverV8TracingTest
, JavascriptError
) {
132 CapturingBoundNetLog request_log
;
133 MockCachingHostResolver host_resolver
;
134 MockErrorObserver
* error_observer
= new MockErrorObserver
;
135 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
137 InitResolver(&resolver
, "error.js");
139 TestCompletionCallback callback
;
140 ProxyInfo proxy_info
;
142 int rv
= resolver
.GetProxyForURL(
143 GURL("http://throw-an-error/"), &proxy_info
, callback
.callback(), NULL
,
144 request_log
.bound());
146 EXPECT_EQ(ERR_IO_PENDING
, rv
);
147 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
149 EXPECT_EQ(0u, host_resolver
.num_resolve());
151 EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
152 "of null\n", error_observer
->GetOutput());
154 // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
155 // were output to both the global log, and per-request log.
156 CapturingNetLog::CapturedEntryList entries_list
[2];
157 log
.GetEntries(&entries_list
[0]);
158 request_log
.GetEntries(&entries_list
[1]);
160 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
161 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
162 EXPECT_EQ(2u, entries
.size());
164 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
165 NetLog::PHASE_NONE
));
167 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
168 NetLog::PHASE_NONE
));
170 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
171 EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
172 "read property 'split' of null\"}", entries
[1].GetParamsJson());
176 TEST_F(ProxyResolverV8TracingTest
, TooManyAlerts
) {
178 CapturingBoundNetLog request_log
;
179 MockCachingHostResolver host_resolver
;
180 MockErrorObserver
* error_observer
= new MockErrorObserver
;
181 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
183 InitResolver(&resolver
, "too_many_alerts.js");
185 TestCompletionCallback callback
;
186 ProxyInfo proxy_info
;
188 int rv
= resolver
.GetProxyForURL(
193 request_log
.bound());
195 EXPECT_EQ(ERR_IO_PENDING
, rv
);
196 EXPECT_EQ(OK
, callback
.WaitForResult());
198 // Iteration1 does a DNS resolve
199 // Iteration2 exceeds the alert buffer
200 // Iteration3 runs in blocking mode and completes
201 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
203 EXPECT_EQ(1u, host_resolver
.num_resolve());
206 EXPECT_EQ("", error_observer
->GetOutput());
208 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
209 // to both the global and per-request logs.
210 CapturingNetLog::CapturedEntryList entries_list
[2];
211 log
.GetEntries(&entries_list
[0]);
212 request_log
.GetEntries(&entries_list
[1]);
214 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
215 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
216 EXPECT_EQ(50u, entries
.size());
217 for (size_t i
= 0; i
< entries
.size(); ++i
) {
219 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
220 NetLog::PHASE_NONE
));
225 // Verify that buffered alerts cannot grow unboundedly, even when the message is
227 TEST_F(ProxyResolverV8TracingTest
, TooManyEmptyAlerts
) {
229 CapturingBoundNetLog request_log
;
230 MockCachingHostResolver host_resolver
;
231 MockErrorObserver
* error_observer
= new MockErrorObserver
;
232 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
234 InitResolver(&resolver
, "too_many_empty_alerts.js");
236 TestCompletionCallback callback
;
237 ProxyInfo proxy_info
;
239 int rv
= resolver
.GetProxyForURL(
244 request_log
.bound());
246 EXPECT_EQ(ERR_IO_PENDING
, rv
);
247 EXPECT_EQ(OK
, callback
.WaitForResult());
249 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
251 EXPECT_EQ(1u, host_resolver
.num_resolve());
254 EXPECT_EQ("", error_observer
->GetOutput());
256 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
257 // to both the global and per-request logs.
258 CapturingNetLog::CapturedEntryList entries_list
[2];
259 log
.GetEntries(&entries_list
[0]);
260 request_log
.GetEntries(&entries_list
[1]);
262 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
263 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
264 EXPECT_EQ(1000u, entries
.size());
265 for (size_t i
= 0; i
< entries
.size(); ++i
) {
267 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
268 NetLog::PHASE_NONE
));
273 // This test runs a PAC script that issues a sequence of DNS resolves. The test
274 // verifies the final result, and that the underlying DNS resolver received
275 // the correct set of queries.
276 TEST_F(ProxyResolverV8TracingTest
, Dns
) {
278 CapturingBoundNetLog request_log
;
279 MockCachingHostResolver host_resolver
;
280 MockErrorObserver
* error_observer
= new MockErrorObserver
;
281 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
283 host_resolver
.rules()->AddRuleForAddressFamily(
284 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
285 host_resolver
.rules()
286 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
287 host_resolver
.rules()->AddSimulatedFailure("host2");
288 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
289 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
290 host_resolver
.rules()->AddSimulatedFailure("host6");
291 host_resolver
.rules()->AddRuleForAddressFamily(
292 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
293 host_resolver
.rules()->AddRule("*", "133.122.100.200");
295 InitResolver(&resolver
, "dns.js");
297 TestCompletionCallback callback
;
298 ProxyInfo proxy_info
;
300 int rv
= resolver
.GetProxyForURL(
305 request_log
.bound());
307 EXPECT_EQ(ERR_IO_PENDING
, rv
);
308 EXPECT_EQ(OK
, callback
.WaitForResult());
310 // The test does 13 DNS resolution, however only 7 of them are unique.
311 EXPECT_EQ(7u, host_resolver
.num_resolve());
313 const char* kExpectedResult
=
314 "122.133.144.155-" // myIpAddress()
315 "null-" // dnsResolve('')
316 "__1_192.168.1.1-" // dnsResolveEx('host1')
317 "null-" // dnsResolve('host2')
318 "166.155.144.33-" // dnsResolve('host3')
319 "122.133.144.155-" // myIpAddress()
320 "166.155.144.33-" // dnsResolve('host3')
321 "__1_192.168.1.1-" // dnsResolveEx('host1')
322 "122.133.144.155-" // myIpAddress()
323 "null-" // dnsResolve('host2')
324 "-" // dnsResolveEx('host6')
325 "133.122.100.200-" // myIpAddressEx()
326 "166.155.144.44" // dnsResolve('host1')
329 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
332 EXPECT_EQ("", error_observer
->GetOutput());
334 // Check the NetLogs -- the script generated 1 alert, mirrored to both
335 // the per-request and global logs.
336 CapturingNetLog::CapturedEntryList entries_list
[2];
337 log
.GetEntries(&entries_list
[0]);
338 request_log
.GetEntries(&entries_list
[1]);
340 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
341 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
342 EXPECT_EQ(1u, entries
.size());
344 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
345 NetLog::PHASE_NONE
));
346 EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries
[0].GetParamsJson());
350 // This test runs a PAC script that does "myIpAddress()" followed by
351 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
352 // cache is warmed, subsequent calls should take 0 restarts.
353 TEST_F(ProxyResolverV8TracingTest
, DnsChecksCache
) {
355 CapturingBoundNetLog request_log
;
356 MockCachingHostResolver host_resolver
;
357 MockErrorObserver
* error_observer
= new MockErrorObserver
;
358 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
360 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
361 host_resolver
.rules()->AddRule("*", "122.133.144.155");
363 InitResolver(&resolver
, "simple_dns.js");
365 TestCompletionCallback callback1
;
366 TestCompletionCallback callback2
;
367 ProxyInfo proxy_info
;
369 int rv
= resolver
.GetProxyForURL(
370 GURL("http://foopy/req1"),
372 callback1
.callback(),
374 request_log
.bound());
376 EXPECT_EQ(ERR_IO_PENDING
, rv
);
377 EXPECT_EQ(OK
, callback1
.WaitForResult());
379 // The test does 2 DNS resolutions.
380 EXPECT_EQ(2u, host_resolver
.num_resolve());
382 // The first request took 2 restarts, hence on g_iteration=3.
383 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
385 rv
= resolver
.GetProxyForURL(
386 GURL("http://foopy/req2"),
388 callback2
.callback(),
390 request_log
.bound());
392 EXPECT_EQ(ERR_IO_PENDING
, rv
);
393 EXPECT_EQ(OK
, callback2
.WaitForResult());
395 EXPECT_EQ(4u, host_resolver
.num_resolve());
397 // This time no restarts were required, so g_iteration incremented by 1.
398 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
401 EXPECT_EQ("", error_observer
->GetOutput());
403 EXPECT_EQ(0u, log
.GetSize());
404 EXPECT_EQ(0u, request_log
.GetSize());
407 // This test runs a weird PAC script that was designed to defeat the DNS tracing
408 // optimization. The proxy resolver should detect the inconsistency and
409 // fall-back to synchronous mode execution.
410 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous1
) {
412 CapturingBoundNetLog request_log
;
413 MockCachingHostResolver host_resolver
;
414 MockErrorObserver
* error_observer
= new MockErrorObserver
;
415 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
417 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
418 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
419 host_resolver
.rules()->AddRule("*", "122.133.144.155");
421 InitResolver(&resolver
, "global_sideffects1.js");
423 TestCompletionCallback callback
;
424 ProxyInfo proxy_info
;
426 int rv
= resolver
.GetProxyForURL(
427 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
428 request_log
.bound());
429 EXPECT_EQ(ERR_IO_PENDING
, rv
);
430 EXPECT_EQ(OK
, callback
.WaitForResult());
432 // The script itself only does 2 DNS resolves per execution, however it
433 // constructs the hostname using a global counter which changes on each
435 EXPECT_EQ(3u, host_resolver
.num_resolve());
437 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
438 proxy_info
.proxy_server().ToURI());
441 EXPECT_EQ("", error_observer
->GetOutput());
443 // Check the NetLogs -- the script generated 1 alert, mirrored to both
444 // the per-request and global logs.
445 CapturingNetLog::CapturedEntryList entries_list
[2];
446 log
.GetEntries(&entries_list
[0]);
447 request_log
.GetEntries(&entries_list
[1]);
449 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
450 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
451 EXPECT_EQ(1u, entries
.size());
453 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
454 NetLog::PHASE_NONE
));
455 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
459 // This test runs a weird PAC script that was designed to defeat the DNS tracing
460 // optimization. The proxy resolver should detect the inconsistency and
461 // fall-back to synchronous mode execution.
462 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous2
) {
464 CapturingBoundNetLog request_log
;
465 MockCachingHostResolver host_resolver
;
466 MockErrorObserver
* error_observer
= new MockErrorObserver
;
467 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
469 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
470 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
471 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
472 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
473 host_resolver
.rules()->AddRule("*", "122.133.144.155");
475 InitResolver(&resolver
, "global_sideffects2.js");
477 TestCompletionCallback callback
;
478 ProxyInfo proxy_info
;
480 int rv
= resolver
.GetProxyForURL(
481 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
482 request_log
.bound());
483 EXPECT_EQ(ERR_IO_PENDING
, rv
);
484 EXPECT_EQ(OK
, callback
.WaitForResult());
486 EXPECT_EQ(3u, host_resolver
.num_resolve());
488 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
491 EXPECT_EQ("", error_observer
->GetOutput());
493 // Check the NetLogs -- nothing was logged.
494 EXPECT_EQ(0u, log
.GetSize());
495 EXPECT_EQ(0u, request_log
.GetSize());
498 // This test runs a weird PAC script that yields a never ending sequence
499 // of DNS resolves when restarting. Running it will hit the maximum
500 // DNS resolves per request limit (20) after which every DNS resolve will
502 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence
) {
504 CapturingBoundNetLog request_log
;
505 MockCachingHostResolver host_resolver
;
506 MockErrorObserver
* error_observer
= new MockErrorObserver
;
507 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
509 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
510 host_resolver
.rules()->AddRule("*", "122.133.144.155");
512 InitResolver(&resolver
, "global_sideffects3.js");
514 TestCompletionCallback callback
;
515 ProxyInfo proxy_info
;
517 int rv
= resolver
.GetProxyForURL(
518 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
519 request_log
.bound());
520 EXPECT_EQ(ERR_IO_PENDING
, rv
);
521 EXPECT_EQ(OK
, callback
.WaitForResult());
523 EXPECT_EQ(20u, host_resolver
.num_resolve());
526 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
527 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
528 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
529 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
530 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
531 "null:21", proxy_info
.proxy_server().ToURI());
534 EXPECT_EQ("", error_observer
->GetOutput());
536 // Check the NetLogs -- 1 alert was logged.
537 EXPECT_EQ(1u, log
.GetSize());
538 EXPECT_EQ(1u, request_log
.GetSize());
541 // This test runs a weird PAC script that yields a never ending sequence
542 // of DNS resolves when restarting. Running it will hit the maximum
543 // DNS resolves per request limit (20) after which every DNS resolve will
545 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence2
) {
547 CapturingBoundNetLog request_log
;
548 MockCachingHostResolver host_resolver
;
549 MockErrorObserver
* error_observer
= new MockErrorObserver
;
550 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
552 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
553 host_resolver
.rules()->AddRule("*", "122.133.144.155");
555 InitResolver(&resolver
, "global_sideffects4.js");
557 TestCompletionCallback callback
;
558 ProxyInfo proxy_info
;
560 int rv
= resolver
.GetProxyForURL(
561 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
562 request_log
.bound());
563 EXPECT_EQ(ERR_IO_PENDING
, rv
);
564 EXPECT_EQ(OK
, callback
.WaitForResult());
566 EXPECT_EQ(20u, host_resolver
.num_resolve());
568 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
571 EXPECT_EQ("", error_observer
->GetOutput());
573 // Check the NetLogs -- 1 alert was logged.
574 EXPECT_EQ(1u, log
.GetSize());
575 EXPECT_EQ(1u, request_log
.GetSize());
578 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
580 CapturingBoundNetLog request_log
;
581 MockCachingHostResolver host_resolver
;
582 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
583 MockErrorObserver
* error_observer
= new MockErrorObserver
;
584 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
586 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
587 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
589 InitResolver(&resolver
, "dns_during_init.js");
591 // Initialization did 2 dnsResolves.
592 EXPECT_EQ(2u, host_resolver
.num_resolve());
594 host_resolver
.rules()->ClearRules();
595 host_resolver
.GetHostCache()->clear();
597 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
598 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
600 TestCompletionCallback callback
;
601 ProxyInfo proxy_info
;
603 int rv
= resolver
.GetProxyForURL(
604 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
605 request_log
.bound());
606 EXPECT_EQ(ERR_IO_PENDING
, rv
);
607 EXPECT_EQ(OK
, callback
.WaitForResult());
609 // Fetched host1 and host2 again, since the ones done during initialization
610 // should not have been cached.
611 EXPECT_EQ(4u, host_resolver
.num_resolve());
613 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
614 proxy_info
.proxy_server().ToURI());
616 // Check the NetLogs -- the script generated 2 alerts during initialization.
617 EXPECT_EQ(0u, request_log
.GetSize());
618 CapturingNetLog::CapturedEntryList entries
;
619 log
.GetEntries(&entries
);
621 ASSERT_EQ(2u, entries
.size());
623 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
624 NetLog::PHASE_NONE
));
626 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
627 NetLog::PHASE_NONE
));
629 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
630 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
633 // Tests a PAC script which does DNS resolves during initialization.
634 TEST_F(ProxyResolverV8TracingTest
, DnsDuringInit
) {
635 // Test with both both a host resolver that always completes asynchronously,
636 // and then again with one that completes synchronously.
637 DnsDuringInitHelper(false);
638 DnsDuringInitHelper(true);
641 void CrashCallback(int) {
642 // Be extra sure that if the callback ever gets invoked, the test will fail.
646 // Start some requests, cancel them all, and then destroy the resolver.
647 // Note the execution order for this test can vary. Since multiple
648 // threads are involved, the cancellation may be received a different
650 TEST_F(ProxyResolverV8TracingTest
, CancelAll
) {
651 MockCachingHostResolver host_resolver
;
652 MockErrorObserver
* error_observer
= new MockErrorObserver
;
653 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
655 host_resolver
.rules()->AddSimulatedFailure("*");
657 InitResolver(&resolver
, "dns.js");
659 const size_t kNumRequests
= 5;
660 ProxyInfo proxy_info
[kNumRequests
];
661 ProxyResolver::RequestHandle request
[kNumRequests
];
663 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
664 int rv
= resolver
.GetProxyForURL(
665 GURL("http://foo/"), &proxy_info
[i
],
666 base::Bind(&CrashCallback
), &request
[i
], BoundNetLog());
667 EXPECT_EQ(ERR_IO_PENDING
, rv
);
670 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
671 resolver
.CancelRequest(request
[i
]);
675 // Note the execution order for this test can vary. Since multiple
676 // threads are involved, the cancellation may be received a different
678 TEST_F(ProxyResolverV8TracingTest
, CancelSome
) {
679 MockCachingHostResolver host_resolver
;
680 MockErrorObserver
* error_observer
= new MockErrorObserver
;
681 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
683 host_resolver
.rules()->AddSimulatedFailure("*");
685 InitResolver(&resolver
, "dns.js");
687 ProxyInfo proxy_info1
;
688 ProxyInfo proxy_info2
;
689 ProxyResolver::RequestHandle request1
;
690 ProxyResolver::RequestHandle request2
;
691 TestCompletionCallback callback
;
693 int rv
= resolver
.GetProxyForURL(
694 GURL("http://foo/"), &proxy_info1
,
695 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
696 EXPECT_EQ(ERR_IO_PENDING
, rv
);
698 rv
= resolver
.GetProxyForURL(
699 GURL("http://foo/"), &proxy_info2
,
700 callback
.callback(), &request2
, BoundNetLog());
701 EXPECT_EQ(ERR_IO_PENDING
, rv
);
703 resolver
.CancelRequest(request1
);
705 EXPECT_EQ(OK
, callback
.WaitForResult());
708 // Cancel a request after it has finished running on the worker thread, and has
709 // posted a task the completion task back to origin thread.
710 TEST_F(ProxyResolverV8TracingTest
, CancelWhilePendingCompletionTask
) {
711 MockCachingHostResolver host_resolver
;
712 MockErrorObserver
* error_observer
= new MockErrorObserver
;
713 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
715 host_resolver
.rules()->AddSimulatedFailure("*");
717 InitResolver(&resolver
, "error.js");
719 ProxyInfo proxy_info1
;
720 ProxyInfo proxy_info2
;
721 ProxyInfo proxy_info3
;
722 ProxyResolver::RequestHandle request1
;
723 ProxyResolver::RequestHandle request2
;
724 ProxyResolver::RequestHandle request3
;
725 TestCompletionCallback callback
;
727 int rv
= resolver
.GetProxyForURL(
728 GURL("http://foo/"), &proxy_info1
,
729 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
730 EXPECT_EQ(ERR_IO_PENDING
, rv
);
732 rv
= resolver
.GetProxyForURL(
733 GURL("http://throw-an-error/"), &proxy_info2
,
734 callback
.callback(), &request2
, BoundNetLog());
735 EXPECT_EQ(ERR_IO_PENDING
, rv
);
737 // Wait until the first request has finished running on the worker thread.
738 // (The second request will output an error).
739 error_observer
->WaitForOutput();
741 // Cancel the first request, while it has a pending completion task on
742 // the origin thread.
743 resolver
.CancelRequest(request1
);
745 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
747 // Start another request, to make sure it is able to complete.
748 rv
= resolver
.GetProxyForURL(
749 GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3
,
750 callback
.callback(), &request3
, BoundNetLog());
751 EXPECT_EQ(ERR_IO_PENDING
, rv
);
753 EXPECT_EQ(OK
, callback
.WaitForResult());
755 EXPECT_EQ("i-approve-this-message:42",
756 proxy_info3
.proxy_server().ToURI());
759 // This implementation of HostResolver allows blocking until a resolve request
760 // has been received. The resolve requests it receives will never be completed.
761 class BlockableHostResolver
: public HostResolver
{
763 BlockableHostResolver()
764 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
766 virtual int Resolve(const RequestInfo
& info
,
767 RequestPriority priority
,
768 AddressList
* addresses
,
769 const CompletionCallback
& callback
,
770 RequestHandle
* out_req
,
771 const BoundNetLog
& net_log
) OVERRIDE
{
772 EXPECT_FALSE(callback
.is_null());
773 EXPECT_TRUE(out_req
);
775 if (!action_
.is_null())
778 // Indicate to the caller that a request was received.
779 EXPECT_TRUE(waiting_for_resolve_
);
780 base::MessageLoop::current()->Quit();
782 // This line is intentionally after action_.Run(), since one of the
783 // tests does a cancellation inside of Resolve(), and it is more
784 // interesting if *out_req hasn't been written yet at that point.
785 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
787 // Return ERR_IO_PENDING as this request will NEVER be completed.
788 // Expectation is for the caller to later cancel the request.
789 return ERR_IO_PENDING
;
792 virtual int ResolveFromCache(const RequestInfo
& info
,
793 AddressList
* addresses
,
794 const BoundNetLog
& net_log
) OVERRIDE
{
796 return ERR_DNS_CACHE_MISS
;
799 virtual void CancelRequest(RequestHandle req
) OVERRIDE
{
800 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
801 num_cancelled_requests_
++;
804 void SetAction(const base::Callback
<void(void)>& action
) {
808 // Waits until Resolve() has been called.
809 void WaitUntilRequestIsReceived() {
810 waiting_for_resolve_
= true;
811 base::MessageLoop::current()->Run();
812 DCHECK(waiting_for_resolve_
);
813 waiting_for_resolve_
= false;
816 int num_cancelled_requests() const {
817 return num_cancelled_requests_
;
821 int num_cancelled_requests_
;
822 bool waiting_for_resolve_
;
823 base::Callback
<void(void)> action_
;
826 // This cancellation test exercises a more predictable cancellation codepath --
827 // when the request has an outstanding DNS request in flight.
828 TEST_F(ProxyResolverV8TracingTest
, CancelWhileOutstandingNonBlockingDns
) {
829 BlockableHostResolver host_resolver
;
830 MockErrorObserver
* error_observer
= new MockErrorObserver
;
831 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
833 InitResolver(&resolver
, "dns.js");
835 ProxyInfo proxy_info1
;
836 ProxyInfo proxy_info2
;
837 ProxyResolver::RequestHandle request1
;
838 ProxyResolver::RequestHandle request2
;
840 int rv
= resolver
.GetProxyForURL(
841 GURL("http://foo/req1"), &proxy_info1
,
842 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
844 EXPECT_EQ(ERR_IO_PENDING
, rv
);
846 host_resolver
.WaitUntilRequestIsReceived();
848 rv
= resolver
.GetProxyForURL(
849 GURL("http://foo/req2"), &proxy_info2
,
850 base::Bind(&CrashCallback
), &request2
, BoundNetLog());
852 EXPECT_EQ(ERR_IO_PENDING
, rv
);
854 host_resolver
.WaitUntilRequestIsReceived();
856 resolver
.CancelRequest(request1
);
857 resolver
.CancelRequest(request2
);
859 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
861 // After leaving this scope, the ProxyResolver is destroyed.
862 // This should not cause any problems, as the outstanding work
863 // should have been cancelled.
866 void CancelRequestAndPause(ProxyResolverV8Tracing
* resolver
,
867 ProxyResolver::RequestHandle request
) {
868 resolver
->CancelRequest(request
);
870 // Sleep for a little bit. This makes it more likely for the worker
871 // thread to have returned from its call, and serves as a regression
872 // test for http://crbug.com/173373.
873 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
876 // In non-blocking mode, the worker thread actually does block for
877 // a short time to see if the result is in the DNS cache. Test
878 // cancellation while the worker thread is waiting on this event.
879 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns
) {
880 BlockableHostResolver host_resolver
;
881 MockErrorObserver
* error_observer
= new MockErrorObserver
;
882 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
884 InitResolver(&resolver
, "dns.js");
886 ProxyInfo proxy_info
;
887 ProxyResolver::RequestHandle request
;
889 int rv
= resolver
.GetProxyForURL(
890 GURL("http://foo/"), &proxy_info
,
891 base::Bind(&CrashCallback
), &request
, BoundNetLog());
893 EXPECT_EQ(ERR_IO_PENDING
, rv
);
895 host_resolver
.SetAction(
896 base::Bind(CancelRequestAndPause
, &resolver
, request
));
898 host_resolver
.WaitUntilRequestIsReceived();
900 // At this point the host resolver ran Resolve(), and should have cancelled
903 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
906 // Cancel the request while there is a pending DNS request, however before
907 // the request is sent to the host resolver.
908 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns2
) {
909 MockCachingHostResolver host_resolver
;
910 MockErrorObserver
* error_observer
= new MockErrorObserver
;
911 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
913 InitResolver(&resolver
, "dns.js");
915 ProxyInfo proxy_info
;
916 ProxyResolver::RequestHandle request
;
918 int rv
= resolver
.GetProxyForURL(
919 GURL("http://foo/"), &proxy_info
,
920 base::Bind(&CrashCallback
), &request
, BoundNetLog());
922 EXPECT_EQ(ERR_IO_PENDING
, rv
);
924 // Wait a bit, so the DNS task has hopefully been posted. The test will
925 // work whatever the delay is here, but it is most useful if the delay
926 // is large enough to allow a task to be posted back.
927 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
928 resolver
.CancelRequest(request
);
930 EXPECT_EQ(0u, host_resolver
.num_resolve());
933 TEST_F(ProxyResolverV8TracingTest
, CancelSetPacWhileOutstandingBlockingDns
) {
934 BlockableHostResolver host_resolver
;
935 MockErrorObserver
* error_observer
= new MockErrorObserver
;
937 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
940 resolver
.SetPacScript(LoadScriptData("dns_during_init.js"),
941 base::Bind(&CrashCallback
));
942 EXPECT_EQ(ERR_IO_PENDING
, rv
);
944 host_resolver
.WaitUntilRequestIsReceived();
946 resolver
.CancelSetPacScript();
947 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
950 // This tests that the execution of a PAC script is terminated when the DNS
951 // dependencies are missing. If the test fails, then it will hang.
952 TEST_F(ProxyResolverV8TracingTest
, Terminate
) {
954 CapturingBoundNetLog request_log
;
955 MockCachingHostResolver host_resolver
;
956 MockErrorObserver
* error_observer
= new MockErrorObserver
;
957 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
959 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
960 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
962 InitResolver(&resolver
, "terminate.js");
964 TestCompletionCallback callback
;
965 ProxyInfo proxy_info
;
967 int rv
= resolver
.GetProxyForURL(
968 GURL("http://foopy/req1"),
972 request_log
.bound());
974 EXPECT_EQ(ERR_IO_PENDING
, rv
);
975 EXPECT_EQ(OK
, callback
.WaitForResult());
977 // The test does 2 DNS resolutions.
978 EXPECT_EQ(2u, host_resolver
.num_resolve());
980 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
983 EXPECT_EQ("", error_observer
->GetOutput());
985 EXPECT_EQ(0u, log
.GetSize());
986 EXPECT_EQ(0u, request_log
.GetSize());
989 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
990 // correctly at the same time. This is relevant because at the moment (time
991 // this test was written) each ProxyResolverV8Tracing creates its own thread to
992 // run V8 on, however each thread is operating on the same v8::Isolate.
993 TEST_F(ProxyResolverV8TracingTest
, MultipleResolvers
) {
994 // ------------------------
996 // ------------------------
997 MockHostResolver host_resolver0
;
998 host_resolver0
.rules()->AddRuleForAddressFamily(
999 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
1000 host_resolver0
.rules()
1001 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1002 host_resolver0
.rules()->AddSimulatedFailure("host2");
1003 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1004 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1005 host_resolver0
.rules()->AddSimulatedFailure("host6");
1006 host_resolver0
.rules()->AddRuleForAddressFamily(
1007 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
1008 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1009 ProxyResolverV8Tracing
resolver0(
1010 &host_resolver0
, new MockErrorObserver
, NULL
);
1011 InitResolver(&resolver0
, "dns.js");
1013 // ------------------------
1015 // ------------------------
1016 ProxyResolverV8Tracing
resolver1(
1017 &host_resolver0
, new MockErrorObserver
, NULL
);
1018 InitResolver(&resolver1
, "dns.js");
1020 // ------------------------
1022 // ------------------------
1023 ProxyResolverV8Tracing
resolver2(
1024 &host_resolver0
, new MockErrorObserver
, NULL
);
1025 InitResolver(&resolver2
, "simple.js");
1027 // ------------------------
1029 // ------------------------
1030 MockHostResolver host_resolver3
;
1031 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1032 ProxyResolverV8Tracing
resolver3(
1033 &host_resolver3
, new MockErrorObserver
, NULL
);
1034 InitResolver(&resolver3
, "simple_dns.js");
1036 // ------------------------
1037 // Queue up work for each resolver (which will be running in parallel).
1038 // ------------------------
1040 ProxyResolverV8Tracing
* resolver
[] = {
1041 &resolver0
, &resolver1
, &resolver2
, &resolver3
,
1044 const size_t kNumResolvers
= arraysize(resolver
);
1045 const size_t kNumIterations
= 20;
1046 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1047 TestCompletionCallback callback
[kNumResults
];
1048 ProxyInfo proxy_info
[kNumResults
];
1050 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1051 size_t resolver_i
= i
% kNumResolvers
;
1052 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1053 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1055 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1058 // ------------------------
1059 // Verify all of the results.
1060 // ------------------------
1062 const char* kExpectedForDnsJs
=
1063 "122.133.144.155-" // myIpAddress()
1064 "null-" // dnsResolve('')
1065 "__1_192.168.1.1-" // dnsResolveEx('host1')
1066 "null-" // dnsResolve('host2')
1067 "166.155.144.33-" // dnsResolve('host3')
1068 "122.133.144.155-" // myIpAddress()
1069 "166.155.144.33-" // dnsResolve('host3')
1070 "__1_192.168.1.1-" // dnsResolveEx('host1')
1071 "122.133.144.155-" // myIpAddress()
1072 "null-" // dnsResolve('host2')
1073 "-" // dnsResolveEx('host6')
1074 "133.122.100.200-" // myIpAddressEx()
1075 "166.155.144.44" // dnsResolve('host1')
1078 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1079 size_t resolver_i
= i
% kNumResolvers
;
1080 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1082 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1084 if (resolver_i
== 0 || resolver_i
== 1) {
1085 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1086 } else if (resolver_i
== 2) {
1087 EXPECT_EQ("foo:99", proxy_uri
);
1088 } else if (resolver_i
== 3) {
1089 EXPECT_EQ("166.155.144.33:",
1090 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));