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 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 void OnPACScriptError(int line_number
, const base::string16
& error
) override
{
75 base::AutoLock
l(lock_
);
76 output
+= base::StringPrintf("Error: line %d: %s\n", line_number
,
77 base::UTF16ToASCII(error
).c_str());
82 std::string
GetOutput() {
83 base::AutoLock
l(lock_
);
87 void WaitForOutput() {
95 base::WaitableEvent event_
;
98 TEST_F(ProxyResolverV8TracingTest
, Simple
) {
100 CapturingBoundNetLog request_log
;
101 MockCachingHostResolver host_resolver
;
102 MockErrorObserver
* error_observer
= new MockErrorObserver
;
103 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
105 InitResolver(&resolver
, "simple.js");
107 TestCompletionCallback callback
;
108 ProxyInfo proxy_info
;
110 int rv
= resolver
.GetProxyForURL(
111 GURL("http://foo/"), &proxy_info
, callback
.callback(),
112 NULL
, request_log
.bound());
114 EXPECT_EQ(ERR_IO_PENDING
, rv
);
115 EXPECT_EQ(OK
, callback
.WaitForResult());
117 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
119 EXPECT_EQ(0u, host_resolver
.num_resolve());
121 // There were no errors.
122 EXPECT_EQ("", error_observer
->GetOutput());
124 // Check the NetLogs -- nothing was logged.
125 EXPECT_EQ(0u, log
.GetSize());
126 EXPECT_EQ(0u, request_log
.GetSize());
129 TEST_F(ProxyResolverV8TracingTest
, JavascriptError
) {
131 CapturingBoundNetLog request_log
;
132 MockCachingHostResolver host_resolver
;
133 MockErrorObserver
* error_observer
= new MockErrorObserver
;
134 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
136 InitResolver(&resolver
, "error.js");
138 TestCompletionCallback callback
;
139 ProxyInfo proxy_info
;
141 int rv
= resolver
.GetProxyForURL(
142 GURL("http://throw-an-error/"), &proxy_info
, callback
.callback(), NULL
,
143 request_log
.bound());
145 EXPECT_EQ(ERR_IO_PENDING
, rv
);
146 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
148 EXPECT_EQ(0u, host_resolver
.num_resolve());
150 EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
151 "of null\n", error_observer
->GetOutput());
153 // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
154 // were output to both the global log, and per-request log.
155 CapturingNetLog::CapturedEntryList entries_list
[2];
156 log
.GetEntries(&entries_list
[0]);
157 request_log
.GetEntries(&entries_list
[1]);
159 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
160 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
161 EXPECT_EQ(2u, entries
.size());
163 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
164 NetLog::PHASE_NONE
));
166 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
167 NetLog::PHASE_NONE
));
169 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
170 EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
171 "read property 'split' of null\"}", entries
[1].GetParamsJson());
175 TEST_F(ProxyResolverV8TracingTest
, TooManyAlerts
) {
177 CapturingBoundNetLog request_log
;
178 MockCachingHostResolver host_resolver
;
179 MockErrorObserver
* error_observer
= new MockErrorObserver
;
180 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
182 InitResolver(&resolver
, "too_many_alerts.js");
184 TestCompletionCallback callback
;
185 ProxyInfo proxy_info
;
187 int rv
= resolver
.GetProxyForURL(
192 request_log
.bound());
194 EXPECT_EQ(ERR_IO_PENDING
, rv
);
195 EXPECT_EQ(OK
, callback
.WaitForResult());
197 // Iteration1 does a DNS resolve
198 // Iteration2 exceeds the alert buffer
199 // Iteration3 runs in blocking mode and completes
200 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
202 EXPECT_EQ(1u, host_resolver
.num_resolve());
205 EXPECT_EQ("", error_observer
->GetOutput());
207 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
208 // to both the global and per-request logs.
209 CapturingNetLog::CapturedEntryList entries_list
[2];
210 log
.GetEntries(&entries_list
[0]);
211 request_log
.GetEntries(&entries_list
[1]);
213 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
214 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
215 EXPECT_EQ(50u, entries
.size());
216 for (size_t i
= 0; i
< entries
.size(); ++i
) {
218 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
219 NetLog::PHASE_NONE
));
224 // Verify that buffered alerts cannot grow unboundedly, even when the message is
226 TEST_F(ProxyResolverV8TracingTest
, TooManyEmptyAlerts
) {
228 CapturingBoundNetLog request_log
;
229 MockCachingHostResolver host_resolver
;
230 MockErrorObserver
* error_observer
= new MockErrorObserver
;
231 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
233 InitResolver(&resolver
, "too_many_empty_alerts.js");
235 TestCompletionCallback callback
;
236 ProxyInfo proxy_info
;
238 int rv
= resolver
.GetProxyForURL(
243 request_log
.bound());
245 EXPECT_EQ(ERR_IO_PENDING
, rv
);
246 EXPECT_EQ(OK
, callback
.WaitForResult());
248 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
250 EXPECT_EQ(1u, host_resolver
.num_resolve());
253 EXPECT_EQ("", error_observer
->GetOutput());
255 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
256 // to both the global and per-request logs.
257 CapturingNetLog::CapturedEntryList entries_list
[2];
258 log
.GetEntries(&entries_list
[0]);
259 request_log
.GetEntries(&entries_list
[1]);
261 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
262 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
263 EXPECT_EQ(1000u, entries
.size());
264 for (size_t i
= 0; i
< entries
.size(); ++i
) {
266 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
267 NetLog::PHASE_NONE
));
272 // This test runs a PAC script that issues a sequence of DNS resolves. The test
273 // verifies the final result, and that the underlying DNS resolver received
274 // the correct set of queries.
275 TEST_F(ProxyResolverV8TracingTest
, Dns
) {
277 CapturingBoundNetLog request_log
;
278 MockCachingHostResolver host_resolver
;
279 MockErrorObserver
* error_observer
= new MockErrorObserver
;
280 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
282 host_resolver
.rules()->AddRuleForAddressFamily(
283 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
284 host_resolver
.rules()
285 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
286 host_resolver
.rules()->AddSimulatedFailure("host2");
287 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
288 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
289 host_resolver
.rules()->AddSimulatedFailure("host6");
290 host_resolver
.rules()->AddRuleForAddressFamily(
291 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
292 host_resolver
.rules()->AddRule("*", "133.122.100.200");
294 InitResolver(&resolver
, "dns.js");
296 TestCompletionCallback callback
;
297 ProxyInfo proxy_info
;
299 int rv
= resolver
.GetProxyForURL(
304 request_log
.bound());
306 EXPECT_EQ(ERR_IO_PENDING
, rv
);
307 EXPECT_EQ(OK
, callback
.WaitForResult());
309 // The test does 13 DNS resolution, however only 7 of them are unique.
310 EXPECT_EQ(7u, host_resolver
.num_resolve());
312 const char* kExpectedResult
=
313 "122.133.144.155-" // myIpAddress()
314 "null-" // dnsResolve('')
315 "__1_192.168.1.1-" // dnsResolveEx('host1')
316 "null-" // dnsResolve('host2')
317 "166.155.144.33-" // dnsResolve('host3')
318 "122.133.144.155-" // myIpAddress()
319 "166.155.144.33-" // dnsResolve('host3')
320 "__1_192.168.1.1-" // dnsResolveEx('host1')
321 "122.133.144.155-" // myIpAddress()
322 "null-" // dnsResolve('host2')
323 "-" // dnsResolveEx('host6')
324 "133.122.100.200-" // myIpAddressEx()
325 "166.155.144.44" // dnsResolve('host1')
328 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
331 EXPECT_EQ("", error_observer
->GetOutput());
333 // Check the NetLogs -- the script generated 1 alert, mirrored to both
334 // the per-request and global logs.
335 CapturingNetLog::CapturedEntryList entries_list
[2];
336 log
.GetEntries(&entries_list
[0]);
337 request_log
.GetEntries(&entries_list
[1]);
339 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
340 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
341 EXPECT_EQ(1u, entries
.size());
343 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
344 NetLog::PHASE_NONE
));
345 EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries
[0].GetParamsJson());
349 // This test runs a PAC script that does "myIpAddress()" followed by
350 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
351 // cache is warmed, subsequent calls should take 0 restarts.
352 TEST_F(ProxyResolverV8TracingTest
, DnsChecksCache
) {
354 CapturingBoundNetLog request_log
;
355 MockCachingHostResolver host_resolver
;
356 MockErrorObserver
* error_observer
= new MockErrorObserver
;
357 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
359 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
360 host_resolver
.rules()->AddRule("*", "122.133.144.155");
362 InitResolver(&resolver
, "simple_dns.js");
364 TestCompletionCallback callback1
;
365 TestCompletionCallback callback2
;
366 ProxyInfo proxy_info
;
368 int rv
= resolver
.GetProxyForURL(
369 GURL("http://foopy/req1"),
371 callback1
.callback(),
373 request_log
.bound());
375 EXPECT_EQ(ERR_IO_PENDING
, rv
);
376 EXPECT_EQ(OK
, callback1
.WaitForResult());
378 // The test does 2 DNS resolutions.
379 EXPECT_EQ(2u, host_resolver
.num_resolve());
381 // The first request took 2 restarts, hence on g_iteration=3.
382 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
384 rv
= resolver
.GetProxyForURL(
385 GURL("http://foopy/req2"),
387 callback2
.callback(),
389 request_log
.bound());
391 EXPECT_EQ(ERR_IO_PENDING
, rv
);
392 EXPECT_EQ(OK
, callback2
.WaitForResult());
394 EXPECT_EQ(4u, host_resolver
.num_resolve());
396 // This time no restarts were required, so g_iteration incremented by 1.
397 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
400 EXPECT_EQ("", error_observer
->GetOutput());
402 EXPECT_EQ(0u, log
.GetSize());
403 EXPECT_EQ(0u, request_log
.GetSize());
406 // This test runs a weird PAC script that was designed to defeat the DNS tracing
407 // optimization. The proxy resolver should detect the inconsistency and
408 // fall-back to synchronous mode execution.
409 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous1
) {
411 CapturingBoundNetLog request_log
;
412 MockCachingHostResolver host_resolver
;
413 MockErrorObserver
* error_observer
= new MockErrorObserver
;
414 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
416 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
417 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
418 host_resolver
.rules()->AddRule("*", "122.133.144.155");
420 InitResolver(&resolver
, "global_sideffects1.js");
422 TestCompletionCallback callback
;
423 ProxyInfo proxy_info
;
425 int rv
= resolver
.GetProxyForURL(
426 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
427 request_log
.bound());
428 EXPECT_EQ(ERR_IO_PENDING
, rv
);
429 EXPECT_EQ(OK
, callback
.WaitForResult());
431 // The script itself only does 2 DNS resolves per execution, however it
432 // constructs the hostname using a global counter which changes on each
434 EXPECT_EQ(3u, host_resolver
.num_resolve());
436 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
437 proxy_info
.proxy_server().ToURI());
440 EXPECT_EQ("", error_observer
->GetOutput());
442 // Check the NetLogs -- the script generated 1 alert, mirrored to both
443 // the per-request and global logs.
444 CapturingNetLog::CapturedEntryList entries_list
[2];
445 log
.GetEntries(&entries_list
[0]);
446 request_log
.GetEntries(&entries_list
[1]);
448 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
449 const CapturingNetLog::CapturedEntryList
& entries
= entries_list
[list_i
];
450 EXPECT_EQ(1u, entries
.size());
452 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
453 NetLog::PHASE_NONE
));
454 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
458 // This test runs a weird PAC script that was designed to defeat the DNS tracing
459 // optimization. The proxy resolver should detect the inconsistency and
460 // fall-back to synchronous mode execution.
461 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous2
) {
463 CapturingBoundNetLog request_log
;
464 MockCachingHostResolver host_resolver
;
465 MockErrorObserver
* error_observer
= new MockErrorObserver
;
466 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
468 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
469 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
470 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
471 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
472 host_resolver
.rules()->AddRule("*", "122.133.144.155");
474 InitResolver(&resolver
, "global_sideffects2.js");
476 TestCompletionCallback callback
;
477 ProxyInfo proxy_info
;
479 int rv
= resolver
.GetProxyForURL(
480 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
481 request_log
.bound());
482 EXPECT_EQ(ERR_IO_PENDING
, rv
);
483 EXPECT_EQ(OK
, callback
.WaitForResult());
485 EXPECT_EQ(3u, host_resolver
.num_resolve());
487 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
490 EXPECT_EQ("", error_observer
->GetOutput());
492 // Check the NetLogs -- nothing was logged.
493 EXPECT_EQ(0u, log
.GetSize());
494 EXPECT_EQ(0u, request_log
.GetSize());
497 // This test runs a weird PAC script that yields a never ending sequence
498 // of DNS resolves when restarting. Running it will hit the maximum
499 // DNS resolves per request limit (20) after which every DNS resolve will
501 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence
) {
503 CapturingBoundNetLog request_log
;
504 MockCachingHostResolver host_resolver
;
505 MockErrorObserver
* error_observer
= new MockErrorObserver
;
506 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
508 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
509 host_resolver
.rules()->AddRule("*", "122.133.144.155");
511 InitResolver(&resolver
, "global_sideffects3.js");
513 TestCompletionCallback callback
;
514 ProxyInfo proxy_info
;
516 int rv
= resolver
.GetProxyForURL(
517 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
518 request_log
.bound());
519 EXPECT_EQ(ERR_IO_PENDING
, rv
);
520 EXPECT_EQ(OK
, callback
.WaitForResult());
522 EXPECT_EQ(20u, host_resolver
.num_resolve());
525 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
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 "null:21", proxy_info
.proxy_server().ToURI());
533 EXPECT_EQ("", error_observer
->GetOutput());
535 // Check the NetLogs -- 1 alert was logged.
536 EXPECT_EQ(1u, log
.GetSize());
537 EXPECT_EQ(1u, request_log
.GetSize());
540 // This test runs a weird PAC script that yields a never ending sequence
541 // of DNS resolves when restarting. Running it will hit the maximum
542 // DNS resolves per request limit (20) after which every DNS resolve will
544 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence2
) {
546 CapturingBoundNetLog request_log
;
547 MockCachingHostResolver host_resolver
;
548 MockErrorObserver
* error_observer
= new MockErrorObserver
;
549 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
551 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
552 host_resolver
.rules()->AddRule("*", "122.133.144.155");
554 InitResolver(&resolver
, "global_sideffects4.js");
556 TestCompletionCallback callback
;
557 ProxyInfo proxy_info
;
559 int rv
= resolver
.GetProxyForURL(
560 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
561 request_log
.bound());
562 EXPECT_EQ(ERR_IO_PENDING
, rv
);
563 EXPECT_EQ(OK
, callback
.WaitForResult());
565 EXPECT_EQ(20u, host_resolver
.num_resolve());
567 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
570 EXPECT_EQ("", error_observer
->GetOutput());
572 // Check the NetLogs -- 1 alert was logged.
573 EXPECT_EQ(1u, log
.GetSize());
574 EXPECT_EQ(1u, request_log
.GetSize());
577 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
579 CapturingBoundNetLog request_log
;
580 MockCachingHostResolver host_resolver
;
581 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
582 MockErrorObserver
* error_observer
= new MockErrorObserver
;
583 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
585 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
586 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
588 InitResolver(&resolver
, "dns_during_init.js");
590 // Initialization did 2 dnsResolves.
591 EXPECT_EQ(2u, host_resolver
.num_resolve());
593 host_resolver
.rules()->ClearRules();
594 host_resolver
.GetHostCache()->clear();
596 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
597 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
599 TestCompletionCallback callback
;
600 ProxyInfo proxy_info
;
602 int rv
= resolver
.GetProxyForURL(
603 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
604 request_log
.bound());
605 EXPECT_EQ(ERR_IO_PENDING
, rv
);
606 EXPECT_EQ(OK
, callback
.WaitForResult());
608 // Fetched host1 and host2 again, since the ones done during initialization
609 // should not have been cached.
610 EXPECT_EQ(4u, host_resolver
.num_resolve());
612 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
613 proxy_info
.proxy_server().ToURI());
615 // Check the NetLogs -- the script generated 2 alerts during initialization.
616 EXPECT_EQ(0u, request_log
.GetSize());
617 CapturingNetLog::CapturedEntryList entries
;
618 log
.GetEntries(&entries
);
620 ASSERT_EQ(2u, entries
.size());
622 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
623 NetLog::PHASE_NONE
));
625 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
626 NetLog::PHASE_NONE
));
628 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
629 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
632 // Tests a PAC script which does DNS resolves during initialization.
633 TEST_F(ProxyResolverV8TracingTest
, DnsDuringInit
) {
634 // Test with both both a host resolver that always completes asynchronously,
635 // and then again with one that completes synchronously.
636 DnsDuringInitHelper(false);
637 DnsDuringInitHelper(true);
640 void CrashCallback(int) {
641 // Be extra sure that if the callback ever gets invoked, the test will fail.
645 // Start some requests, cancel them all, and then destroy the resolver.
646 // Note the execution order for this test can vary. Since multiple
647 // threads are involved, the cancellation may be received a different
649 TEST_F(ProxyResolverV8TracingTest
, CancelAll
) {
650 MockCachingHostResolver host_resolver
;
651 MockErrorObserver
* error_observer
= new MockErrorObserver
;
652 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
654 host_resolver
.rules()->AddSimulatedFailure("*");
656 InitResolver(&resolver
, "dns.js");
658 const size_t kNumRequests
= 5;
659 ProxyInfo proxy_info
[kNumRequests
];
660 ProxyResolver::RequestHandle request
[kNumRequests
];
662 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
663 int rv
= resolver
.GetProxyForURL(
664 GURL("http://foo/"), &proxy_info
[i
],
665 base::Bind(&CrashCallback
), &request
[i
], BoundNetLog());
666 EXPECT_EQ(ERR_IO_PENDING
, rv
);
669 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
670 resolver
.CancelRequest(request
[i
]);
674 // Note the execution order for this test can vary. Since multiple
675 // threads are involved, the cancellation may be received a different
677 TEST_F(ProxyResolverV8TracingTest
, CancelSome
) {
678 MockCachingHostResolver host_resolver
;
679 MockErrorObserver
* error_observer
= new MockErrorObserver
;
680 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
682 host_resolver
.rules()->AddSimulatedFailure("*");
684 InitResolver(&resolver
, "dns.js");
686 ProxyInfo proxy_info1
;
687 ProxyInfo proxy_info2
;
688 ProxyResolver::RequestHandle request1
;
689 ProxyResolver::RequestHandle request2
;
690 TestCompletionCallback callback
;
692 int rv
= resolver
.GetProxyForURL(
693 GURL("http://foo/"), &proxy_info1
,
694 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
695 EXPECT_EQ(ERR_IO_PENDING
, rv
);
697 rv
= resolver
.GetProxyForURL(
698 GURL("http://foo/"), &proxy_info2
,
699 callback
.callback(), &request2
, BoundNetLog());
700 EXPECT_EQ(ERR_IO_PENDING
, rv
);
702 resolver
.CancelRequest(request1
);
704 EXPECT_EQ(OK
, callback
.WaitForResult());
707 // Cancel a request after it has finished running on the worker thread, and has
708 // posted a task the completion task back to origin thread.
709 TEST_F(ProxyResolverV8TracingTest
, CancelWhilePendingCompletionTask
) {
710 MockCachingHostResolver host_resolver
;
711 MockErrorObserver
* error_observer
= new MockErrorObserver
;
712 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
714 host_resolver
.rules()->AddSimulatedFailure("*");
716 InitResolver(&resolver
, "error.js");
718 ProxyInfo proxy_info1
;
719 ProxyInfo proxy_info2
;
720 ProxyInfo proxy_info3
;
721 ProxyResolver::RequestHandle request1
;
722 ProxyResolver::RequestHandle request2
;
723 ProxyResolver::RequestHandle request3
;
724 TestCompletionCallback callback
;
726 int rv
= resolver
.GetProxyForURL(
727 GURL("http://foo/"), &proxy_info1
,
728 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
729 EXPECT_EQ(ERR_IO_PENDING
, rv
);
731 rv
= resolver
.GetProxyForURL(
732 GURL("http://throw-an-error/"), &proxy_info2
,
733 callback
.callback(), &request2
, BoundNetLog());
734 EXPECT_EQ(ERR_IO_PENDING
, rv
);
736 // Wait until the first request has finished running on the worker thread.
737 // (The second request will output an error).
738 error_observer
->WaitForOutput();
740 // Cancel the first request, while it has a pending completion task on
741 // the origin thread.
742 resolver
.CancelRequest(request1
);
744 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
746 // Start another request, to make sure it is able to complete.
747 rv
= resolver
.GetProxyForURL(
748 GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3
,
749 callback
.callback(), &request3
, BoundNetLog());
750 EXPECT_EQ(ERR_IO_PENDING
, rv
);
752 EXPECT_EQ(OK
, callback
.WaitForResult());
754 EXPECT_EQ("i-approve-this-message:42",
755 proxy_info3
.proxy_server().ToURI());
758 // This implementation of HostResolver allows blocking until a resolve request
759 // has been received. The resolve requests it receives will never be completed.
760 class BlockableHostResolver
: public HostResolver
{
762 BlockableHostResolver()
763 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
765 int Resolve(const RequestInfo
& info
,
766 RequestPriority priority
,
767 AddressList
* addresses
,
768 const CompletionCallback
& callback
,
769 RequestHandle
* out_req
,
770 const BoundNetLog
& net_log
) override
{
771 EXPECT_FALSE(callback
.is_null());
772 EXPECT_TRUE(out_req
);
774 if (!action_
.is_null())
777 // Indicate to the caller that a request was received.
778 EXPECT_TRUE(waiting_for_resolve_
);
779 base::MessageLoop::current()->Quit();
781 // This line is intentionally after action_.Run(), since one of the
782 // tests does a cancellation inside of Resolve(), and it is more
783 // interesting if *out_req hasn't been written yet at that point.
784 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
786 // Return ERR_IO_PENDING as this request will NEVER be completed.
787 // Expectation is for the caller to later cancel the request.
788 return ERR_IO_PENDING
;
791 int ResolveFromCache(const RequestInfo
& info
,
792 AddressList
* addresses
,
793 const BoundNetLog
& net_log
) override
{
795 return ERR_DNS_CACHE_MISS
;
798 void CancelRequest(RequestHandle req
) override
{
799 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
800 num_cancelled_requests_
++;
803 void SetAction(const base::Callback
<void(void)>& action
) {
807 // Waits until Resolve() has been called.
808 void WaitUntilRequestIsReceived() {
809 waiting_for_resolve_
= true;
810 base::MessageLoop::current()->Run();
811 DCHECK(waiting_for_resolve_
);
812 waiting_for_resolve_
= false;
815 int num_cancelled_requests() const {
816 return num_cancelled_requests_
;
820 int num_cancelled_requests_
;
821 bool waiting_for_resolve_
;
822 base::Callback
<void(void)> action_
;
825 // This cancellation test exercises a more predictable cancellation codepath --
826 // when the request has an outstanding DNS request in flight.
827 TEST_F(ProxyResolverV8TracingTest
, CancelWhileOutstandingNonBlockingDns
) {
828 BlockableHostResolver host_resolver
;
829 MockErrorObserver
* error_observer
= new MockErrorObserver
;
830 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
832 InitResolver(&resolver
, "dns.js");
834 ProxyInfo proxy_info1
;
835 ProxyInfo proxy_info2
;
836 ProxyResolver::RequestHandle request1
;
837 ProxyResolver::RequestHandle request2
;
839 int rv
= resolver
.GetProxyForURL(
840 GURL("http://foo/req1"), &proxy_info1
,
841 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
843 EXPECT_EQ(ERR_IO_PENDING
, rv
);
845 host_resolver
.WaitUntilRequestIsReceived();
847 rv
= resolver
.GetProxyForURL(
848 GURL("http://foo/req2"), &proxy_info2
,
849 base::Bind(&CrashCallback
), &request2
, BoundNetLog());
851 EXPECT_EQ(ERR_IO_PENDING
, rv
);
853 host_resolver
.WaitUntilRequestIsReceived();
855 resolver
.CancelRequest(request1
);
856 resolver
.CancelRequest(request2
);
858 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
860 // After leaving this scope, the ProxyResolver is destroyed.
861 // This should not cause any problems, as the outstanding work
862 // should have been cancelled.
865 void CancelRequestAndPause(ProxyResolverV8Tracing
* resolver
,
866 ProxyResolver::RequestHandle request
) {
867 resolver
->CancelRequest(request
);
869 // Sleep for a little bit. This makes it more likely for the worker
870 // thread to have returned from its call, and serves as a regression
871 // test for http://crbug.com/173373.
872 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
875 // In non-blocking mode, the worker thread actually does block for
876 // a short time to see if the result is in the DNS cache. Test
877 // cancellation while the worker thread is waiting on this event.
878 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns
) {
879 BlockableHostResolver host_resolver
;
880 MockErrorObserver
* error_observer
= new MockErrorObserver
;
881 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
883 InitResolver(&resolver
, "dns.js");
885 ProxyInfo proxy_info
;
886 ProxyResolver::RequestHandle request
;
888 int rv
= resolver
.GetProxyForURL(
889 GURL("http://foo/"), &proxy_info
,
890 base::Bind(&CrashCallback
), &request
, BoundNetLog());
892 EXPECT_EQ(ERR_IO_PENDING
, rv
);
894 host_resolver
.SetAction(
895 base::Bind(CancelRequestAndPause
, &resolver
, request
));
897 host_resolver
.WaitUntilRequestIsReceived();
899 // At this point the host resolver ran Resolve(), and should have cancelled
902 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
905 // Cancel the request while there is a pending DNS request, however before
906 // the request is sent to the host resolver.
907 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns2
) {
908 MockCachingHostResolver host_resolver
;
909 MockErrorObserver
* error_observer
= new MockErrorObserver
;
910 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
912 InitResolver(&resolver
, "dns.js");
914 ProxyInfo proxy_info
;
915 ProxyResolver::RequestHandle request
;
917 int rv
= resolver
.GetProxyForURL(
918 GURL("http://foo/"), &proxy_info
,
919 base::Bind(&CrashCallback
), &request
, BoundNetLog());
921 EXPECT_EQ(ERR_IO_PENDING
, rv
);
923 // Wait a bit, so the DNS task has hopefully been posted. The test will
924 // work whatever the delay is here, but it is most useful if the delay
925 // is large enough to allow a task to be posted back.
926 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
927 resolver
.CancelRequest(request
);
929 EXPECT_EQ(0u, host_resolver
.num_resolve());
932 TEST_F(ProxyResolverV8TracingTest
, CancelSetPacWhileOutstandingBlockingDns
) {
933 BlockableHostResolver host_resolver
;
934 MockErrorObserver
* error_observer
= new MockErrorObserver
;
936 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
939 resolver
.SetPacScript(LoadScriptData("dns_during_init.js"),
940 base::Bind(&CrashCallback
));
941 EXPECT_EQ(ERR_IO_PENDING
, rv
);
943 host_resolver
.WaitUntilRequestIsReceived();
945 resolver
.CancelSetPacScript();
946 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
949 // This tests that the execution of a PAC script is terminated when the DNS
950 // dependencies are missing. If the test fails, then it will hang.
951 TEST_F(ProxyResolverV8TracingTest
, Terminate
) {
953 CapturingBoundNetLog request_log
;
954 MockCachingHostResolver host_resolver
;
955 MockErrorObserver
* error_observer
= new MockErrorObserver
;
956 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
958 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
959 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
961 InitResolver(&resolver
, "terminate.js");
963 TestCompletionCallback callback
;
964 ProxyInfo proxy_info
;
966 int rv
= resolver
.GetProxyForURL(
967 GURL("http://foopy/req1"),
971 request_log
.bound());
973 EXPECT_EQ(ERR_IO_PENDING
, rv
);
974 EXPECT_EQ(OK
, callback
.WaitForResult());
976 // The test does 2 DNS resolutions.
977 EXPECT_EQ(2u, host_resolver
.num_resolve());
979 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
982 EXPECT_EQ("", error_observer
->GetOutput());
984 EXPECT_EQ(0u, log
.GetSize());
985 EXPECT_EQ(0u, request_log
.GetSize());
988 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
989 // correctly at the same time. This is relevant because at the moment (time
990 // this test was written) each ProxyResolverV8Tracing creates its own thread to
991 // run V8 on, however each thread is operating on the same v8::Isolate.
992 TEST_F(ProxyResolverV8TracingTest
, MultipleResolvers
) {
993 // ------------------------
995 // ------------------------
996 MockHostResolver host_resolver0
;
997 host_resolver0
.rules()->AddRuleForAddressFamily(
998 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
999 host_resolver0
.rules()
1000 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1001 host_resolver0
.rules()->AddSimulatedFailure("host2");
1002 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1003 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1004 host_resolver0
.rules()->AddSimulatedFailure("host6");
1005 host_resolver0
.rules()->AddRuleForAddressFamily(
1006 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
1007 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1008 ProxyResolverV8Tracing
resolver0(
1009 &host_resolver0
, new MockErrorObserver
, NULL
);
1010 InitResolver(&resolver0
, "dns.js");
1012 // ------------------------
1014 // ------------------------
1015 ProxyResolverV8Tracing
resolver1(
1016 &host_resolver0
, new MockErrorObserver
, NULL
);
1017 InitResolver(&resolver1
, "dns.js");
1019 // ------------------------
1021 // ------------------------
1022 ProxyResolverV8Tracing
resolver2(
1023 &host_resolver0
, new MockErrorObserver
, NULL
);
1024 InitResolver(&resolver2
, "simple.js");
1026 // ------------------------
1028 // ------------------------
1029 MockHostResolver host_resolver3
;
1030 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1031 ProxyResolverV8Tracing
resolver3(
1032 &host_resolver3
, new MockErrorObserver
, NULL
);
1033 InitResolver(&resolver3
, "simple_dns.js");
1035 // ------------------------
1036 // Queue up work for each resolver (which will be running in parallel).
1037 // ------------------------
1039 ProxyResolverV8Tracing
* resolver
[] = {
1040 &resolver0
, &resolver1
, &resolver2
, &resolver3
,
1043 const size_t kNumResolvers
= arraysize(resolver
);
1044 const size_t kNumIterations
= 20;
1045 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1046 TestCompletionCallback callback
[kNumResults
];
1047 ProxyInfo proxy_info
[kNumResults
];
1049 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1050 size_t resolver_i
= i
% kNumResolvers
;
1051 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1052 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1054 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1057 // ------------------------
1058 // Verify all of the results.
1059 // ------------------------
1061 const char* kExpectedForDnsJs
=
1062 "122.133.144.155-" // myIpAddress()
1063 "null-" // dnsResolve('')
1064 "__1_192.168.1.1-" // dnsResolveEx('host1')
1065 "null-" // dnsResolve('host2')
1066 "166.155.144.33-" // dnsResolve('host3')
1067 "122.133.144.155-" // myIpAddress()
1068 "166.155.144.33-" // dnsResolve('host3')
1069 "__1_192.168.1.1-" // dnsResolveEx('host1')
1070 "122.133.144.155-" // myIpAddress()
1071 "null-" // dnsResolve('host2')
1072 "-" // dnsResolveEx('host6')
1073 "133.122.100.200-" // myIpAddressEx()
1074 "166.155.144.44" // dnsResolve('host1')
1077 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1078 size_t resolver_i
= i
% kNumResolvers
;
1079 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1081 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1083 if (resolver_i
== 0 || resolver_i
== 1) {
1084 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1085 } else if (resolver_i
== 2) {
1086 EXPECT_EQ("foo:99", proxy_uri
);
1087 } else if (resolver_i
== 3) {
1088 EXPECT_EQ("166.155.144.33:",
1089 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));