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/test_completion_callback.h"
19 #include "net/dns/host_cache.h"
20 #include "net/dns/mock_host_resolver.h"
21 #include "net/log/net_log.h"
22 #include "net/log/test_net_log.h"
23 #include "net/log/test_net_log_entry.h"
24 #include "net/log/test_net_log_util.h"
25 #include "net/proxy/proxy_info.h"
26 #include "net/proxy/proxy_resolver_error_observer.h"
27 #include "testing/gtest/include/gtest/gtest.h"
34 class ProxyResolverV8TracingTest
: public testing::Test
{
36 void TearDown() override
{
37 // Drain any pending messages, which may be left over from cancellation.
38 // This way they get reliably run as part of the current test, rather than
39 // spilling into the next test's execution.
40 base::MessageLoop::current()->RunUntilIdle();
44 scoped_refptr
<ProxyResolverScriptData
> LoadScriptData(const char* filename
) {
46 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
47 path
= path
.AppendASCII("net");
48 path
= path
.AppendASCII("data");
49 path
= path
.AppendASCII("proxy_resolver_v8_tracing_unittest");
50 path
= path
.AppendASCII(filename
);
52 // Try to read the file from disk.
53 std::string file_contents
;
54 bool ok
= base::ReadFileToString(path
, &file_contents
);
56 // If we can't load the file from disk, something is misconfigured.
57 EXPECT_TRUE(ok
) << "Failed to read file: " << path
.value();
59 // Load the PAC script into the ProxyResolver.
60 return ProxyResolverScriptData::FromUTF8(file_contents
);
63 void InitResolver(ProxyResolverV8Tracing
* resolver
, const char* filename
) {
64 TestCompletionCallback callback
;
66 resolver
->SetPacScript(LoadScriptData(filename
), callback
.callback());
67 EXPECT_EQ(ERR_IO_PENDING
, rv
);
68 EXPECT_EQ(OK
, callback
.WaitForResult());
71 class MockErrorObserver
: public ProxyResolverErrorObserver
{
73 MockErrorObserver() : event_(true, false) {}
75 void OnPACScriptError(int line_number
, const base::string16
& error
) override
{
77 base::AutoLock
l(lock_
);
78 output
+= base::StringPrintf("Error: line %d: %s\n", line_number
,
79 base::UTF16ToASCII(error
).c_str());
84 std::string
GetOutput() {
85 base::AutoLock
l(lock_
);
89 void WaitForOutput() {
97 base::WaitableEvent event_
;
100 TEST_F(ProxyResolverV8TracingTest
, Simple
) {
102 BoundTestNetLog request_log
;
103 MockCachingHostResolver host_resolver
;
104 MockErrorObserver
* error_observer
= new MockErrorObserver
;
105 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
107 InitResolver(&resolver
, "simple.js");
109 TestCompletionCallback callback
;
110 ProxyInfo proxy_info
;
112 int rv
= resolver
.GetProxyForURL(
113 GURL("http://foo/"), &proxy_info
, callback
.callback(),
114 NULL
, request_log
.bound());
116 EXPECT_EQ(ERR_IO_PENDING
, rv
);
117 EXPECT_EQ(OK
, callback
.WaitForResult());
119 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
121 EXPECT_EQ(0u, host_resolver
.num_resolve());
123 // There were no errors.
124 EXPECT_EQ("", error_observer
->GetOutput());
126 // Check the NetLogs -- nothing was logged.
127 EXPECT_EQ(0u, log
.GetSize());
128 EXPECT_EQ(0u, request_log
.GetSize());
131 TEST_F(ProxyResolverV8TracingTest
, JavascriptError
) {
133 BoundTestNetLog request_log
;
134 MockCachingHostResolver host_resolver
;
135 MockErrorObserver
* error_observer
= new MockErrorObserver
;
136 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
138 InitResolver(&resolver
, "error.js");
140 TestCompletionCallback callback
;
141 ProxyInfo proxy_info
;
143 int rv
= resolver
.GetProxyForURL(
144 GURL("http://throw-an-error/"), &proxy_info
, callback
.callback(), NULL
,
145 request_log
.bound());
147 EXPECT_EQ(ERR_IO_PENDING
, rv
);
148 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
150 EXPECT_EQ(0u, host_resolver
.num_resolve());
152 EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
153 "of null\n", error_observer
->GetOutput());
155 // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
156 // were output to both the global log, and per-request log.
157 TestNetLogEntry::List entries_list
[2];
158 log
.GetEntries(&entries_list
[0]);
159 request_log
.GetEntries(&entries_list
[1]);
161 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
162 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
163 EXPECT_EQ(2u, entries
.size());
165 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
166 NetLog::PHASE_NONE
));
168 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
169 NetLog::PHASE_NONE
));
171 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
172 EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
173 "read property 'split' of null\"}", entries
[1].GetParamsJson());
177 TEST_F(ProxyResolverV8TracingTest
, TooManyAlerts
) {
179 BoundTestNetLog request_log
;
180 MockCachingHostResolver host_resolver
;
181 MockErrorObserver
* error_observer
= new MockErrorObserver
;
182 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
184 InitResolver(&resolver
, "too_many_alerts.js");
186 TestCompletionCallback callback
;
187 ProxyInfo proxy_info
;
189 int rv
= resolver
.GetProxyForURL(
194 request_log
.bound());
196 EXPECT_EQ(ERR_IO_PENDING
, rv
);
197 EXPECT_EQ(OK
, callback
.WaitForResult());
199 // Iteration1 does a DNS resolve
200 // Iteration2 exceeds the alert buffer
201 // Iteration3 runs in blocking mode and completes
202 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
204 EXPECT_EQ(1u, host_resolver
.num_resolve());
207 EXPECT_EQ("", error_observer
->GetOutput());
209 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
210 // to both the global and per-request logs.
211 TestNetLogEntry::List entries_list
[2];
212 log
.GetEntries(&entries_list
[0]);
213 request_log
.GetEntries(&entries_list
[1]);
215 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
216 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
217 EXPECT_EQ(50u, entries
.size());
218 for (size_t i
= 0; i
< entries
.size(); ++i
) {
220 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
221 NetLog::PHASE_NONE
));
226 // Verify that buffered alerts cannot grow unboundedly, even when the message is
228 TEST_F(ProxyResolverV8TracingTest
, TooManyEmptyAlerts
) {
230 BoundTestNetLog request_log
;
231 MockCachingHostResolver host_resolver
;
232 MockErrorObserver
* error_observer
= new MockErrorObserver
;
233 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
235 InitResolver(&resolver
, "too_many_empty_alerts.js");
237 TestCompletionCallback callback
;
238 ProxyInfo proxy_info
;
240 int rv
= resolver
.GetProxyForURL(
245 request_log
.bound());
247 EXPECT_EQ(ERR_IO_PENDING
, rv
);
248 EXPECT_EQ(OK
, callback
.WaitForResult());
250 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
252 EXPECT_EQ(1u, host_resolver
.num_resolve());
255 EXPECT_EQ("", error_observer
->GetOutput());
257 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
258 // to both the global and per-request logs.
259 TestNetLogEntry::List entries_list
[2];
260 log
.GetEntries(&entries_list
[0]);
261 request_log
.GetEntries(&entries_list
[1]);
263 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
264 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
265 EXPECT_EQ(1000u, entries
.size());
266 for (size_t i
= 0; i
< entries
.size(); ++i
) {
268 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
269 NetLog::PHASE_NONE
));
274 // This test runs a PAC script that issues a sequence of DNS resolves. The test
275 // verifies the final result, and that the underlying DNS resolver received
276 // the correct set of queries.
277 TEST_F(ProxyResolverV8TracingTest
, Dns
) {
279 BoundTestNetLog request_log
;
280 MockCachingHostResolver host_resolver
;
281 MockErrorObserver
* error_observer
= new MockErrorObserver
;
282 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
284 host_resolver
.rules()->AddRuleForAddressFamily(
285 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
286 host_resolver
.rules()
287 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
288 host_resolver
.rules()->AddSimulatedFailure("host2");
289 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
290 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
291 host_resolver
.rules()->AddSimulatedFailure("host6");
292 host_resolver
.rules()->AddRuleForAddressFamily(
293 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
294 host_resolver
.rules()->AddRule("*", "133.122.100.200");
296 InitResolver(&resolver
, "dns.js");
298 TestCompletionCallback callback
;
299 ProxyInfo proxy_info
;
301 int rv
= resolver
.GetProxyForURL(
306 request_log
.bound());
308 EXPECT_EQ(ERR_IO_PENDING
, rv
);
309 EXPECT_EQ(OK
, callback
.WaitForResult());
311 // The test does 13 DNS resolution, however only 7 of them are unique.
312 EXPECT_EQ(7u, host_resolver
.num_resolve());
314 const char* kExpectedResult
=
315 "122.133.144.155-" // myIpAddress()
316 "null-" // dnsResolve('')
317 "__1_192.168.1.1-" // dnsResolveEx('host1')
318 "null-" // dnsResolve('host2')
319 "166.155.144.33-" // dnsResolve('host3')
320 "122.133.144.155-" // myIpAddress()
321 "166.155.144.33-" // dnsResolve('host3')
322 "__1_192.168.1.1-" // dnsResolveEx('host1')
323 "122.133.144.155-" // myIpAddress()
324 "null-" // dnsResolve('host2')
325 "-" // dnsResolveEx('host6')
326 "133.122.100.200-" // myIpAddressEx()
327 "166.155.144.44" // dnsResolve('host1')
330 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
333 EXPECT_EQ("", error_observer
->GetOutput());
335 // Check the NetLogs -- the script generated 1 alert, mirrored to both
336 // the per-request and global logs.
337 TestNetLogEntry::List entries_list
[2];
338 log
.GetEntries(&entries_list
[0]);
339 request_log
.GetEntries(&entries_list
[1]);
341 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
342 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
343 EXPECT_EQ(1u, entries
.size());
345 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
346 NetLog::PHASE_NONE
));
347 EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries
[0].GetParamsJson());
351 // This test runs a PAC script that does "myIpAddress()" followed by
352 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
353 // cache is warmed, subsequent calls should take 0 restarts.
354 TEST_F(ProxyResolverV8TracingTest
, DnsChecksCache
) {
356 BoundTestNetLog request_log
;
357 MockCachingHostResolver host_resolver
;
358 MockErrorObserver
* error_observer
= new MockErrorObserver
;
359 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
361 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
362 host_resolver
.rules()->AddRule("*", "122.133.144.155");
364 InitResolver(&resolver
, "simple_dns.js");
366 TestCompletionCallback callback1
;
367 TestCompletionCallback callback2
;
368 ProxyInfo proxy_info
;
370 int rv
= resolver
.GetProxyForURL(
371 GURL("http://foopy/req1"),
373 callback1
.callback(),
375 request_log
.bound());
377 EXPECT_EQ(ERR_IO_PENDING
, rv
);
378 EXPECT_EQ(OK
, callback1
.WaitForResult());
380 // The test does 2 DNS resolutions.
381 EXPECT_EQ(2u, host_resolver
.num_resolve());
383 // The first request took 2 restarts, hence on g_iteration=3.
384 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
386 rv
= resolver
.GetProxyForURL(
387 GURL("http://foopy/req2"),
389 callback2
.callback(),
391 request_log
.bound());
393 EXPECT_EQ(ERR_IO_PENDING
, rv
);
394 EXPECT_EQ(OK
, callback2
.WaitForResult());
396 EXPECT_EQ(4u, host_resolver
.num_resolve());
398 // This time no restarts were required, so g_iteration incremented by 1.
399 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
402 EXPECT_EQ("", error_observer
->GetOutput());
404 EXPECT_EQ(0u, log
.GetSize());
405 EXPECT_EQ(0u, request_log
.GetSize());
408 // This test runs a weird PAC script that was designed to defeat the DNS tracing
409 // optimization. The proxy resolver should detect the inconsistency and
410 // fall-back to synchronous mode execution.
411 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous1
) {
413 BoundTestNetLog request_log
;
414 MockCachingHostResolver host_resolver
;
415 MockErrorObserver
* error_observer
= new MockErrorObserver
;
416 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
418 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
419 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
420 host_resolver
.rules()->AddRule("*", "122.133.144.155");
422 InitResolver(&resolver
, "global_sideffects1.js");
424 TestCompletionCallback callback
;
425 ProxyInfo proxy_info
;
427 int rv
= resolver
.GetProxyForURL(
428 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
429 request_log
.bound());
430 EXPECT_EQ(ERR_IO_PENDING
, rv
);
431 EXPECT_EQ(OK
, callback
.WaitForResult());
433 // The script itself only does 2 DNS resolves per execution, however it
434 // constructs the hostname using a global counter which changes on each
436 EXPECT_EQ(3u, host_resolver
.num_resolve());
438 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
439 proxy_info
.proxy_server().ToURI());
442 EXPECT_EQ("", error_observer
->GetOutput());
444 // Check the NetLogs -- the script generated 1 alert, mirrored to both
445 // the per-request and global logs.
446 TestNetLogEntry::List entries_list
[2];
447 log
.GetEntries(&entries_list
[0]);
448 request_log
.GetEntries(&entries_list
[1]);
450 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
451 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
452 EXPECT_EQ(1u, entries
.size());
454 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
455 NetLog::PHASE_NONE
));
456 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
460 // This test runs a weird PAC script that was designed to defeat the DNS tracing
461 // optimization. The proxy resolver should detect the inconsistency and
462 // fall-back to synchronous mode execution.
463 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous2
) {
465 BoundTestNetLog request_log
;
466 MockCachingHostResolver host_resolver
;
467 MockErrorObserver
* error_observer
= new MockErrorObserver
;
468 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
470 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
471 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
472 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
473 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
474 host_resolver
.rules()->AddRule("*", "122.133.144.155");
476 InitResolver(&resolver
, "global_sideffects2.js");
478 TestCompletionCallback callback
;
479 ProxyInfo proxy_info
;
481 int rv
= resolver
.GetProxyForURL(
482 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
483 request_log
.bound());
484 EXPECT_EQ(ERR_IO_PENDING
, rv
);
485 EXPECT_EQ(OK
, callback
.WaitForResult());
487 EXPECT_EQ(3u, host_resolver
.num_resolve());
489 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
492 EXPECT_EQ("", error_observer
->GetOutput());
494 // Check the NetLogs -- nothing was logged.
495 EXPECT_EQ(0u, log
.GetSize());
496 EXPECT_EQ(0u, request_log
.GetSize());
499 // This test runs a weird PAC script that yields a never ending sequence
500 // of DNS resolves when restarting. Running it will hit the maximum
501 // DNS resolves per request limit (20) after which every DNS resolve will
503 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence
) {
505 BoundTestNetLog request_log
;
506 MockCachingHostResolver host_resolver
;
507 MockErrorObserver
* error_observer
= new MockErrorObserver
;
508 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
510 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
511 host_resolver
.rules()->AddRule("*", "122.133.144.155");
513 InitResolver(&resolver
, "global_sideffects3.js");
515 TestCompletionCallback callback
;
516 ProxyInfo proxy_info
;
518 int rv
= resolver
.GetProxyForURL(
519 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
520 request_log
.bound());
521 EXPECT_EQ(ERR_IO_PENDING
, rv
);
522 EXPECT_EQ(OK
, callback
.WaitForResult());
524 EXPECT_EQ(20u, host_resolver
.num_resolve());
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 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
532 "null:21", proxy_info
.proxy_server().ToURI());
535 EXPECT_EQ("", error_observer
->GetOutput());
537 // Check the NetLogs -- 1 alert was logged.
538 EXPECT_EQ(1u, log
.GetSize());
539 EXPECT_EQ(1u, request_log
.GetSize());
542 // This test runs a weird PAC script that yields a never ending sequence
543 // of DNS resolves when restarting. Running it will hit the maximum
544 // DNS resolves per request limit (20) after which every DNS resolve will
546 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence2
) {
548 BoundTestNetLog request_log
;
549 MockCachingHostResolver host_resolver
;
550 MockErrorObserver
* error_observer
= new MockErrorObserver
;
551 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
553 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
554 host_resolver
.rules()->AddRule("*", "122.133.144.155");
556 InitResolver(&resolver
, "global_sideffects4.js");
558 TestCompletionCallback callback
;
559 ProxyInfo proxy_info
;
561 int rv
= resolver
.GetProxyForURL(
562 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
563 request_log
.bound());
564 EXPECT_EQ(ERR_IO_PENDING
, rv
);
565 EXPECT_EQ(OK
, callback
.WaitForResult());
567 EXPECT_EQ(20u, host_resolver
.num_resolve());
569 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
572 EXPECT_EQ("", error_observer
->GetOutput());
574 // Check the NetLogs -- 1 alert was logged.
575 EXPECT_EQ(1u, log
.GetSize());
576 EXPECT_EQ(1u, request_log
.GetSize());
579 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
581 BoundTestNetLog request_log
;
582 MockCachingHostResolver host_resolver
;
583 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
584 MockErrorObserver
* error_observer
= new MockErrorObserver
;
585 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
587 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
588 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
590 InitResolver(&resolver
, "dns_during_init.js");
592 // Initialization did 2 dnsResolves.
593 EXPECT_EQ(2u, host_resolver
.num_resolve());
595 host_resolver
.rules()->ClearRules();
596 host_resolver
.GetHostCache()->clear();
598 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
599 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
601 TestCompletionCallback callback
;
602 ProxyInfo proxy_info
;
604 int rv
= resolver
.GetProxyForURL(
605 GURL("http://foo/"), &proxy_info
, callback
.callback(), NULL
,
606 request_log
.bound());
607 EXPECT_EQ(ERR_IO_PENDING
, rv
);
608 EXPECT_EQ(OK
, callback
.WaitForResult());
610 // Fetched host1 and host2 again, since the ones done during initialization
611 // should not have been cached.
612 EXPECT_EQ(4u, host_resolver
.num_resolve());
614 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
615 proxy_info
.proxy_server().ToURI());
617 // Check the NetLogs -- the script generated 2 alerts during initialization.
618 EXPECT_EQ(0u, request_log
.GetSize());
619 TestNetLogEntry::List entries
;
620 log
.GetEntries(&entries
);
622 ASSERT_EQ(2u, entries
.size());
624 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
625 NetLog::PHASE_NONE
));
627 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
628 NetLog::PHASE_NONE
));
630 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
631 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
634 // Tests a PAC script which does DNS resolves during initialization.
635 TEST_F(ProxyResolverV8TracingTest
, DnsDuringInit
) {
636 // Test with both both a host resolver that always completes asynchronously,
637 // and then again with one that completes synchronously.
638 DnsDuringInitHelper(false);
639 DnsDuringInitHelper(true);
642 void CrashCallback(int) {
643 // Be extra sure that if the callback ever gets invoked, the test will fail.
647 // Start some requests, cancel them all, and then destroy the resolver.
648 // Note the execution order for this test can vary. Since multiple
649 // threads are involved, the cancellation may be received a different
651 TEST_F(ProxyResolverV8TracingTest
, CancelAll
) {
652 MockCachingHostResolver host_resolver
;
653 MockErrorObserver
* error_observer
= new MockErrorObserver
;
654 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
656 host_resolver
.rules()->AddSimulatedFailure("*");
658 InitResolver(&resolver
, "dns.js");
660 const size_t kNumRequests
= 5;
661 ProxyInfo proxy_info
[kNumRequests
];
662 ProxyResolver::RequestHandle request
[kNumRequests
];
664 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
665 int rv
= resolver
.GetProxyForURL(
666 GURL("http://foo/"), &proxy_info
[i
],
667 base::Bind(&CrashCallback
), &request
[i
], BoundNetLog());
668 EXPECT_EQ(ERR_IO_PENDING
, rv
);
671 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
672 resolver
.CancelRequest(request
[i
]);
676 // Note the execution order for this test can vary. Since multiple
677 // threads are involved, the cancellation may be received a different
679 TEST_F(ProxyResolverV8TracingTest
, CancelSome
) {
680 MockCachingHostResolver host_resolver
;
681 MockErrorObserver
* error_observer
= new MockErrorObserver
;
682 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
684 host_resolver
.rules()->AddSimulatedFailure("*");
686 InitResolver(&resolver
, "dns.js");
688 ProxyInfo proxy_info1
;
689 ProxyInfo proxy_info2
;
690 ProxyResolver::RequestHandle request1
;
691 ProxyResolver::RequestHandle request2
;
692 TestCompletionCallback callback
;
694 int rv
= resolver
.GetProxyForURL(
695 GURL("http://foo/"), &proxy_info1
,
696 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
697 EXPECT_EQ(ERR_IO_PENDING
, rv
);
699 rv
= resolver
.GetProxyForURL(
700 GURL("http://foo/"), &proxy_info2
,
701 callback
.callback(), &request2
, BoundNetLog());
702 EXPECT_EQ(ERR_IO_PENDING
, rv
);
704 resolver
.CancelRequest(request1
);
706 EXPECT_EQ(OK
, callback
.WaitForResult());
709 // Cancel a request after it has finished running on the worker thread, and has
710 // posted a task the completion task back to origin thread.
711 TEST_F(ProxyResolverV8TracingTest
, CancelWhilePendingCompletionTask
) {
712 MockCachingHostResolver host_resolver
;
713 MockErrorObserver
* error_observer
= new MockErrorObserver
;
714 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
716 host_resolver
.rules()->AddSimulatedFailure("*");
718 InitResolver(&resolver
, "error.js");
720 ProxyInfo proxy_info1
;
721 ProxyInfo proxy_info2
;
722 ProxyInfo proxy_info3
;
723 ProxyResolver::RequestHandle request1
;
724 ProxyResolver::RequestHandle request2
;
725 ProxyResolver::RequestHandle request3
;
726 TestCompletionCallback callback
;
728 int rv
= resolver
.GetProxyForURL(
729 GURL("http://foo/"), &proxy_info1
,
730 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
731 EXPECT_EQ(ERR_IO_PENDING
, rv
);
733 rv
= resolver
.GetProxyForURL(
734 GURL("http://throw-an-error/"), &proxy_info2
,
735 callback
.callback(), &request2
, BoundNetLog());
736 EXPECT_EQ(ERR_IO_PENDING
, rv
);
738 // Wait until the first request has finished running on the worker thread.
739 // (The second request will output an error).
740 error_observer
->WaitForOutput();
742 // Cancel the first request, while it has a pending completion task on
743 // the origin thread.
744 resolver
.CancelRequest(request1
);
746 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
748 // Start another request, to make sure it is able to complete.
749 rv
= resolver
.GetProxyForURL(
750 GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3
,
751 callback
.callback(), &request3
, BoundNetLog());
752 EXPECT_EQ(ERR_IO_PENDING
, rv
);
754 EXPECT_EQ(OK
, callback
.WaitForResult());
756 EXPECT_EQ("i-approve-this-message:42",
757 proxy_info3
.proxy_server().ToURI());
760 // This implementation of HostResolver allows blocking until a resolve request
761 // has been received. The resolve requests it receives will never be completed.
762 class BlockableHostResolver
: public HostResolver
{
764 BlockableHostResolver()
765 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
767 int Resolve(const RequestInfo
& info
,
768 RequestPriority priority
,
769 AddressList
* addresses
,
770 const CompletionCallback
& callback
,
771 RequestHandle
* out_req
,
772 const BoundNetLog
& net_log
) override
{
773 EXPECT_FALSE(callback
.is_null());
774 EXPECT_TRUE(out_req
);
776 if (!action_
.is_null())
779 // Indicate to the caller that a request was received.
780 EXPECT_TRUE(waiting_for_resolve_
);
781 base::MessageLoop::current()->Quit();
783 // This line is intentionally after action_.Run(), since one of the
784 // tests does a cancellation inside of Resolve(), and it is more
785 // interesting if *out_req hasn't been written yet at that point.
786 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
788 // Return ERR_IO_PENDING as this request will NEVER be completed.
789 // Expectation is for the caller to later cancel the request.
790 return ERR_IO_PENDING
;
793 int ResolveFromCache(const RequestInfo
& info
,
794 AddressList
* addresses
,
795 const BoundNetLog
& net_log
) override
{
797 return ERR_DNS_CACHE_MISS
;
800 void CancelRequest(RequestHandle req
) override
{
801 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
802 num_cancelled_requests_
++;
805 void SetAction(const base::Callback
<void(void)>& action
) {
809 // Waits until Resolve() has been called.
810 void WaitUntilRequestIsReceived() {
811 waiting_for_resolve_
= true;
812 base::MessageLoop::current()->Run();
813 DCHECK(waiting_for_resolve_
);
814 waiting_for_resolve_
= false;
817 int num_cancelled_requests() const {
818 return num_cancelled_requests_
;
822 int num_cancelled_requests_
;
823 bool waiting_for_resolve_
;
824 base::Callback
<void(void)> action_
;
827 // This cancellation test exercises a more predictable cancellation codepath --
828 // when the request has an outstanding DNS request in flight.
829 TEST_F(ProxyResolverV8TracingTest
, CancelWhileOutstandingNonBlockingDns
) {
830 BlockableHostResolver host_resolver
;
831 MockErrorObserver
* error_observer
= new MockErrorObserver
;
832 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
834 InitResolver(&resolver
, "dns.js");
836 ProxyInfo proxy_info1
;
837 ProxyInfo proxy_info2
;
838 ProxyResolver::RequestHandle request1
;
839 ProxyResolver::RequestHandle request2
;
841 int rv
= resolver
.GetProxyForURL(
842 GURL("http://foo/req1"), &proxy_info1
,
843 base::Bind(&CrashCallback
), &request1
, BoundNetLog());
845 EXPECT_EQ(ERR_IO_PENDING
, rv
);
847 host_resolver
.WaitUntilRequestIsReceived();
849 rv
= resolver
.GetProxyForURL(
850 GURL("http://foo/req2"), &proxy_info2
,
851 base::Bind(&CrashCallback
), &request2
, BoundNetLog());
853 EXPECT_EQ(ERR_IO_PENDING
, rv
);
855 host_resolver
.WaitUntilRequestIsReceived();
857 resolver
.CancelRequest(request1
);
858 resolver
.CancelRequest(request2
);
860 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
862 // After leaving this scope, the ProxyResolver is destroyed.
863 // This should not cause any problems, as the outstanding work
864 // should have been cancelled.
867 void CancelRequestAndPause(ProxyResolverV8Tracing
* resolver
,
868 ProxyResolver::RequestHandle request
) {
869 resolver
->CancelRequest(request
);
871 // Sleep for a little bit. This makes it more likely for the worker
872 // thread to have returned from its call, and serves as a regression
873 // test for http://crbug.com/173373.
874 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
877 // In non-blocking mode, the worker thread actually does block for
878 // a short time to see if the result is in the DNS cache. Test
879 // cancellation while the worker thread is waiting on this event.
880 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns
) {
881 BlockableHostResolver host_resolver
;
882 MockErrorObserver
* error_observer
= new MockErrorObserver
;
883 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
885 InitResolver(&resolver
, "dns.js");
887 ProxyInfo proxy_info
;
888 ProxyResolver::RequestHandle request
;
890 int rv
= resolver
.GetProxyForURL(
891 GURL("http://foo/"), &proxy_info
,
892 base::Bind(&CrashCallback
), &request
, BoundNetLog());
894 EXPECT_EQ(ERR_IO_PENDING
, rv
);
896 host_resolver
.SetAction(
897 base::Bind(CancelRequestAndPause
, &resolver
, request
));
899 host_resolver
.WaitUntilRequestIsReceived();
901 // At this point the host resolver ran Resolve(), and should have cancelled
904 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
907 // Cancel the request while there is a pending DNS request, however before
908 // the request is sent to the host resolver.
909 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns2
) {
910 MockCachingHostResolver host_resolver
;
911 MockErrorObserver
* error_observer
= new MockErrorObserver
;
912 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
914 InitResolver(&resolver
, "dns.js");
916 ProxyInfo proxy_info
;
917 ProxyResolver::RequestHandle request
;
919 int rv
= resolver
.GetProxyForURL(
920 GURL("http://foo/"), &proxy_info
,
921 base::Bind(&CrashCallback
), &request
, BoundNetLog());
923 EXPECT_EQ(ERR_IO_PENDING
, rv
);
925 // Wait a bit, so the DNS task has hopefully been posted. The test will
926 // work whatever the delay is here, but it is most useful if the delay
927 // is large enough to allow a task to be posted back.
928 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
929 resolver
.CancelRequest(request
);
931 EXPECT_EQ(0u, host_resolver
.num_resolve());
934 TEST_F(ProxyResolverV8TracingTest
, CancelSetPacWhileOutstandingBlockingDns
) {
935 BlockableHostResolver host_resolver
;
936 MockErrorObserver
* error_observer
= new MockErrorObserver
;
938 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, NULL
);
941 resolver
.SetPacScript(LoadScriptData("dns_during_init.js"),
942 base::Bind(&CrashCallback
));
943 EXPECT_EQ(ERR_IO_PENDING
, rv
);
945 host_resolver
.WaitUntilRequestIsReceived();
947 resolver
.CancelSetPacScript();
948 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
951 // This tests that the execution of a PAC script is terminated when the DNS
952 // dependencies are missing. If the test fails, then it will hang.
953 TEST_F(ProxyResolverV8TracingTest
, Terminate
) {
955 BoundTestNetLog request_log
;
956 MockCachingHostResolver host_resolver
;
957 MockErrorObserver
* error_observer
= new MockErrorObserver
;
958 ProxyResolverV8Tracing
resolver(&host_resolver
, error_observer
, &log
);
960 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
961 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
963 InitResolver(&resolver
, "terminate.js");
965 TestCompletionCallback callback
;
966 ProxyInfo proxy_info
;
968 int rv
= resolver
.GetProxyForURL(
969 GURL("http://foopy/req1"),
973 request_log
.bound());
975 EXPECT_EQ(ERR_IO_PENDING
, rv
);
976 EXPECT_EQ(OK
, callback
.WaitForResult());
978 // The test does 2 DNS resolutions.
979 EXPECT_EQ(2u, host_resolver
.num_resolve());
981 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
984 EXPECT_EQ("", error_observer
->GetOutput());
986 EXPECT_EQ(0u, log
.GetSize());
987 EXPECT_EQ(0u, request_log
.GetSize());
990 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
991 // correctly at the same time. This is relevant because at the moment (time
992 // this test was written) each ProxyResolverV8Tracing creates its own thread to
993 // run V8 on, however each thread is operating on the same v8::Isolate.
994 TEST_F(ProxyResolverV8TracingTest
, MultipleResolvers
) {
995 // ------------------------
997 // ------------------------
998 MockHostResolver host_resolver0
;
999 host_resolver0
.rules()->AddRuleForAddressFamily(
1000 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
1001 host_resolver0
.rules()
1002 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1003 host_resolver0
.rules()->AddSimulatedFailure("host2");
1004 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1005 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1006 host_resolver0
.rules()->AddSimulatedFailure("host6");
1007 host_resolver0
.rules()->AddRuleForAddressFamily(
1008 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
1009 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1010 ProxyResolverV8Tracing
resolver0(
1011 &host_resolver0
, new MockErrorObserver
, NULL
);
1012 InitResolver(&resolver0
, "dns.js");
1014 // ------------------------
1016 // ------------------------
1017 ProxyResolverV8Tracing
resolver1(
1018 &host_resolver0
, new MockErrorObserver
, NULL
);
1019 InitResolver(&resolver1
, "dns.js");
1021 // ------------------------
1023 // ------------------------
1024 ProxyResolverV8Tracing
resolver2(
1025 &host_resolver0
, new MockErrorObserver
, NULL
);
1026 InitResolver(&resolver2
, "simple.js");
1028 // ------------------------
1030 // ------------------------
1031 MockHostResolver host_resolver3
;
1032 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1033 ProxyResolverV8Tracing
resolver3(
1034 &host_resolver3
, new MockErrorObserver
, NULL
);
1035 InitResolver(&resolver3
, "simple_dns.js");
1037 // ------------------------
1038 // Queue up work for each resolver (which will be running in parallel).
1039 // ------------------------
1041 ProxyResolverV8Tracing
* resolver
[] = {
1042 &resolver0
, &resolver1
, &resolver2
, &resolver3
,
1045 const size_t kNumResolvers
= arraysize(resolver
);
1046 const size_t kNumIterations
= 20;
1047 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1048 TestCompletionCallback callback
[kNumResults
];
1049 ProxyInfo proxy_info
[kNumResults
];
1051 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1052 size_t resolver_i
= i
% kNumResolvers
;
1053 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1054 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1056 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1059 // ------------------------
1060 // Verify all of the results.
1061 // ------------------------
1063 const char* kExpectedForDnsJs
=
1064 "122.133.144.155-" // myIpAddress()
1065 "null-" // dnsResolve('')
1066 "__1_192.168.1.1-" // dnsResolveEx('host1')
1067 "null-" // dnsResolve('host2')
1068 "166.155.144.33-" // dnsResolve('host3')
1069 "122.133.144.155-" // myIpAddress()
1070 "166.155.144.33-" // dnsResolve('host3')
1071 "__1_192.168.1.1-" // dnsResolveEx('host1')
1072 "122.133.144.155-" // myIpAddress()
1073 "null-" // dnsResolve('host2')
1074 "-" // dnsResolveEx('host6')
1075 "133.122.100.200-" // myIpAddressEx()
1076 "166.155.144.44" // dnsResolve('host1')
1079 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1080 size_t resolver_i
= i
% kNumResolvers
;
1081 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1083 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1085 if (resolver_i
== 0 || resolver_i
== 1) {
1086 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1087 } else if (resolver_i
== 2) {
1088 EXPECT_EQ("foo:99", proxy_uri
);
1089 } else if (resolver_i
== 3) {
1090 EXPECT_EQ("166.155.144.33:",
1091 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));