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_wrapper.h"
9 #include "base/files/file_util.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/path_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/platform_thread.h"
18 #include "base/values.h"
19 #include "net/base/net_errors.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/log/net_log.h"
24 #include "net/log/test_net_log.h"
25 #include "net/log/test_net_log_entry.h"
26 #include "net/log/test_net_log_util.h"
27 #include "net/proxy/proxy_info.h"
28 #include "net/proxy/proxy_resolver_error_observer.h"
29 #include "testing/gtest/include/gtest/gtest.h"
36 class ProxyResolverV8TracingWrapperTest
: public testing::Test
{
38 void TearDown() override
{
39 // Drain any pending messages, which may be left over from cancellation.
40 // This way they get reliably run as part of the current test, rather than
41 // spilling into the next test's execution.
42 base::MessageLoop::current()->RunUntilIdle();
46 scoped_refptr
<ProxyResolverScriptData
> LoadScriptData(const char* filename
) {
48 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
49 path
= path
.AppendASCII("net");
50 path
= path
.AppendASCII("data");
51 path
= path
.AppendASCII("proxy_resolver_v8_tracing_unittest");
52 path
= path
.AppendASCII(filename
);
54 // Try to read the file from disk.
55 std::string file_contents
;
56 bool ok
= base::ReadFileToString(path
, &file_contents
);
58 // If we can't load the file from disk, something is misconfigured.
59 EXPECT_TRUE(ok
) << "Failed to read file: " << path
.value();
61 // Load the PAC script into the ProxyResolver.
62 return ProxyResolverScriptData::FromUTF8(file_contents
);
65 scoped_ptr
<ProxyResolverErrorObserver
> ReturnErrorObserver(
66 scoped_ptr
<ProxyResolverErrorObserver
> error_observer
) {
67 return error_observer
;
70 scoped_ptr
<ProxyResolver
> CreateResolver(
72 HostResolver
* host_resolver
,
73 scoped_ptr
<ProxyResolverErrorObserver
> error_observer
,
74 const char* filename
) {
75 scoped_ptr
<ProxyResolver
> resolver
;
76 ProxyResolverFactoryV8TracingWrapper
factory(
77 host_resolver
, net_log
,
78 base::Bind(&ReturnErrorObserver
, base::Passed(&error_observer
)));
79 TestCompletionCallback callback
;
80 scoped_ptr
<ProxyResolverFactory::Request
> request
;
81 int rv
= factory
.CreateProxyResolver(LoadScriptData(filename
), &resolver
,
82 callback
.callback(), &request
);
83 EXPECT_EQ(ERR_IO_PENDING
, rv
);
84 EXPECT_EQ(OK
, callback
.WaitForResult());
85 EXPECT_TRUE(resolver
);
86 return resolver
.Pass();
89 class MockErrorObserver
: public ProxyResolverErrorObserver
{
91 MockErrorObserver() : event_(true, false) {}
93 void OnPACScriptError(int line_number
, const base::string16
& error
) override
{
95 base::AutoLock
l(lock_
);
96 output
+= base::StringPrintf("Error: line %d: %s\n", line_number
,
97 base::UTF16ToASCII(error
).c_str());
102 std::string
GetOutput() {
103 base::AutoLock
l(lock_
);
107 void WaitForOutput() { event_
.Wait(); }
113 base::WaitableEvent event_
;
116 TEST_F(ProxyResolverV8TracingWrapperTest
, Simple
) {
118 BoundTestNetLog request_log
;
119 MockCachingHostResolver host_resolver
;
120 MockErrorObserver
* error_observer
= new MockErrorObserver
;
122 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
123 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "simple.js");
125 TestCompletionCallback callback
;
126 ProxyInfo proxy_info
;
129 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
130 callback
.callback(), NULL
, request_log
.bound());
132 EXPECT_EQ(ERR_IO_PENDING
, rv
);
133 EXPECT_EQ(OK
, callback
.WaitForResult());
135 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
137 EXPECT_EQ(0u, host_resolver
.num_resolve());
139 // There were no errors.
140 EXPECT_EQ("", error_observer
->GetOutput());
142 // Check the NetLogs -- nothing was logged.
143 EXPECT_EQ(0u, log
.GetSize());
144 EXPECT_EQ(0u, request_log
.GetSize());
147 TEST_F(ProxyResolverV8TracingWrapperTest
, JavascriptError
) {
149 BoundTestNetLog request_log
;
150 MockCachingHostResolver host_resolver
;
151 MockErrorObserver
* error_observer
= new MockErrorObserver
;
153 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
154 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
156 TestCompletionCallback callback
;
157 ProxyInfo proxy_info
;
160 resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info
,
161 callback
.callback(), NULL
, request_log
.bound());
163 EXPECT_EQ(ERR_IO_PENDING
, rv
);
164 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
166 EXPECT_EQ(0u, host_resolver
.num_resolve());
169 "Error: line 5: Uncaught TypeError: Cannot read property 'split' "
171 error_observer
->GetOutput());
173 // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
174 // were output to both the global log, and per-request log.
175 TestNetLogEntry::List entries_list
[2];
176 log
.GetEntries(&entries_list
[0]);
177 request_log
.GetEntries(&entries_list
[1]);
179 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
180 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
181 EXPECT_EQ(2u, entries
.size());
182 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
183 NetLog::PHASE_NONE
));
184 EXPECT_TRUE(LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
185 NetLog::PHASE_NONE
));
187 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
189 "{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
190 "read property 'split' of null\"}",
191 entries
[1].GetParamsJson());
195 TEST_F(ProxyResolverV8TracingWrapperTest
, TooManyAlerts
) {
197 BoundTestNetLog request_log
;
198 MockCachingHostResolver host_resolver
;
199 MockErrorObserver
* error_observer
= new MockErrorObserver
;
201 scoped_ptr
<ProxyResolver
> resolver
=
202 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
203 "too_many_alerts.js");
205 TestCompletionCallback callback
;
206 ProxyInfo proxy_info
;
209 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
210 callback
.callback(), NULL
, request_log
.bound());
212 EXPECT_EQ(ERR_IO_PENDING
, rv
);
213 EXPECT_EQ(OK
, callback
.WaitForResult());
215 // Iteration1 does a DNS resolve
216 // Iteration2 exceeds the alert buffer
217 // Iteration3 runs in blocking mode and completes
218 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
220 EXPECT_EQ(1u, host_resolver
.num_resolve());
223 EXPECT_EQ("", error_observer
->GetOutput());
225 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
226 // to both the global and per-request logs.
227 TestNetLogEntry::List entries_list
[2];
228 log
.GetEntries(&entries_list
[0]);
229 request_log
.GetEntries(&entries_list
[1]);
231 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
232 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
233 EXPECT_EQ(50u, entries
.size());
234 for (size_t i
= 0; i
< entries
.size(); ++i
) {
235 ASSERT_TRUE(LogContainsEvent(
236 entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
, NetLog::PHASE_NONE
));
241 // Verify that buffered alerts cannot grow unboundedly, even when the message is
243 TEST_F(ProxyResolverV8TracingWrapperTest
, TooManyEmptyAlerts
) {
245 BoundTestNetLog request_log
;
246 MockCachingHostResolver host_resolver
;
247 MockErrorObserver
* error_observer
= new MockErrorObserver
;
249 scoped_ptr
<ProxyResolver
> resolver
=
250 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
251 "too_many_empty_alerts.js");
253 TestCompletionCallback callback
;
254 ProxyInfo proxy_info
;
257 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
258 callback
.callback(), NULL
, request_log
.bound());
260 EXPECT_EQ(ERR_IO_PENDING
, rv
);
261 EXPECT_EQ(OK
, callback
.WaitForResult());
263 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
265 EXPECT_EQ(1u, host_resolver
.num_resolve());
268 EXPECT_EQ("", error_observer
->GetOutput());
270 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
271 // to both the global and per-request logs.
272 TestNetLogEntry::List entries_list
[2];
273 log
.GetEntries(&entries_list
[0]);
274 request_log
.GetEntries(&entries_list
[1]);
276 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
277 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
278 EXPECT_EQ(1000u, entries
.size());
279 for (size_t i
= 0; i
< entries
.size(); ++i
) {
280 ASSERT_TRUE(LogContainsEvent(
281 entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
, NetLog::PHASE_NONE
));
286 // This test runs a PAC script that issues a sequence of DNS resolves. The test
287 // verifies the final result, and that the underlying DNS resolver received
288 // the correct set of queries.
289 TEST_F(ProxyResolverV8TracingWrapperTest
, Dns
) {
291 BoundTestNetLog request_log
;
292 MockCachingHostResolver host_resolver
;
293 MockErrorObserver
* error_observer
= new MockErrorObserver
;
295 host_resolver
.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4
,
297 host_resolver
.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1",
299 host_resolver
.rules()->AddSimulatedFailure("host2");
300 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
301 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
302 host_resolver
.rules()->AddSimulatedFailure("host6");
303 host_resolver
.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4
,
305 host_resolver
.rules()->AddRule("*", "133.122.100.200");
307 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
308 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
310 TestCompletionCallback callback
;
311 ProxyInfo proxy_info
;
314 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
315 callback
.callback(), NULL
, request_log
.bound());
317 EXPECT_EQ(ERR_IO_PENDING
, rv
);
318 EXPECT_EQ(OK
, callback
.WaitForResult());
320 // The test does 13 DNS resolution, however only 7 of them are unique.
321 EXPECT_EQ(7u, host_resolver
.num_resolve());
323 const char* kExpectedResult
=
324 "122.133.144.155-" // myIpAddress()
325 "null-" // dnsResolve('')
326 "__1_192.168.1.1-" // dnsResolveEx('host1')
327 "null-" // dnsResolve('host2')
328 "166.155.144.33-" // dnsResolve('host3')
329 "122.133.144.155-" // myIpAddress()
330 "166.155.144.33-" // dnsResolve('host3')
331 "__1_192.168.1.1-" // dnsResolveEx('host1')
332 "122.133.144.155-" // myIpAddress()
333 "null-" // dnsResolve('host2')
334 "-" // dnsResolveEx('host6')
335 "133.122.100.200-" // myIpAddressEx()
336 "166.155.144.44" // dnsResolve('host1')
339 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
342 EXPECT_EQ("", error_observer
->GetOutput());
344 // Check the NetLogs -- the script generated 1 alert, mirrored to both
345 // the per-request and global logs.
346 TestNetLogEntry::List entries_list
[2];
347 log
.GetEntries(&entries_list
[0]);
348 request_log
.GetEntries(&entries_list
[1]);
350 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
351 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
352 EXPECT_EQ(1u, entries
.size());
353 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
354 NetLog::PHASE_NONE
));
355 EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries
[0].GetParamsJson());
359 // This test runs a PAC script that does "myIpAddress()" followed by
360 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
361 // cache is warmed, subsequent calls should take 0 restarts.
362 TEST_F(ProxyResolverV8TracingWrapperTest
, DnsChecksCache
) {
364 BoundTestNetLog request_log
;
365 MockCachingHostResolver host_resolver
;
366 MockErrorObserver
* error_observer
= new MockErrorObserver
;
368 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
369 host_resolver
.rules()->AddRule("*", "122.133.144.155");
371 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
372 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "simple_dns.js");
374 TestCompletionCallback callback1
;
375 TestCompletionCallback callback2
;
376 ProxyInfo proxy_info
;
379 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
380 callback1
.callback(), NULL
, request_log
.bound());
382 EXPECT_EQ(ERR_IO_PENDING
, rv
);
383 EXPECT_EQ(OK
, callback1
.WaitForResult());
385 // The test does 2 DNS resolutions.
386 EXPECT_EQ(2u, host_resolver
.num_resolve());
388 // The first request took 2 restarts, hence on g_iteration=3.
389 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
392 resolver
->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info
,
393 callback2
.callback(), NULL
, request_log
.bound());
395 EXPECT_EQ(ERR_IO_PENDING
, rv
);
396 EXPECT_EQ(OK
, callback2
.WaitForResult());
398 EXPECT_EQ(4u, host_resolver
.num_resolve());
400 // This time no restarts were required, so g_iteration incremented by 1.
401 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
404 EXPECT_EQ("", error_observer
->GetOutput());
406 EXPECT_EQ(0u, log
.GetSize());
407 EXPECT_EQ(0u, request_log
.GetSize());
410 // This test runs a weird PAC script that was designed to defeat the DNS tracing
411 // optimization. The proxy resolver should detect the inconsistency and
412 // fall-back to synchronous mode execution.
413 TEST_F(ProxyResolverV8TracingWrapperTest
, FallBackToSynchronous1
) {
415 BoundTestNetLog request_log
;
416 MockCachingHostResolver host_resolver
;
417 MockErrorObserver
* error_observer
= new MockErrorObserver
;
419 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
420 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
421 host_resolver
.rules()->AddRule("*", "122.133.144.155");
423 scoped_ptr
<ProxyResolver
> resolver
=
424 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
425 "global_sideffects1.js");
427 TestCompletionCallback callback
;
428 ProxyInfo proxy_info
;
431 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
432 callback
.callback(), NULL
, request_log
.bound());
433 EXPECT_EQ(ERR_IO_PENDING
, rv
);
434 EXPECT_EQ(OK
, callback
.WaitForResult());
436 // The script itself only does 2 DNS resolves per execution, however it
437 // constructs the hostname using a global counter which changes on each
439 EXPECT_EQ(3u, host_resolver
.num_resolve());
441 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
442 proxy_info
.proxy_server().ToURI());
445 EXPECT_EQ("", error_observer
->GetOutput());
447 // Check the NetLogs -- the script generated 1 alert, mirrored to both
448 // the per-request and global logs.
449 TestNetLogEntry::List entries_list
[2];
450 log
.GetEntries(&entries_list
[0]);
451 request_log
.GetEntries(&entries_list
[1]);
453 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
454 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
455 EXPECT_EQ(1u, entries
.size());
456 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
457 NetLog::PHASE_NONE
));
458 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
462 // This test runs a weird PAC script that was designed to defeat the DNS tracing
463 // optimization. The proxy resolver should detect the inconsistency and
464 // fall-back to synchronous mode execution.
465 TEST_F(ProxyResolverV8TracingWrapperTest
, FallBackToSynchronous2
) {
467 BoundTestNetLog request_log
;
468 MockCachingHostResolver host_resolver
;
469 MockErrorObserver
* error_observer
= new MockErrorObserver
;
471 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
472 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
473 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
474 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
475 host_resolver
.rules()->AddRule("*", "122.133.144.155");
477 scoped_ptr
<ProxyResolver
> resolver
=
478 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
479 "global_sideffects2.js");
481 TestCompletionCallback callback
;
482 ProxyInfo proxy_info
;
485 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
486 callback
.callback(), NULL
, request_log
.bound());
487 EXPECT_EQ(ERR_IO_PENDING
, rv
);
488 EXPECT_EQ(OK
, callback
.WaitForResult());
490 EXPECT_EQ(3u, host_resolver
.num_resolve());
492 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
495 EXPECT_EQ("", error_observer
->GetOutput());
497 // Check the NetLogs -- nothing was logged.
498 EXPECT_EQ(0u, log
.GetSize());
499 EXPECT_EQ(0u, request_log
.GetSize());
502 // This test runs a weird PAC script that yields a never ending sequence
503 // of DNS resolves when restarting. Running it will hit the maximum
504 // DNS resolves per request limit (20) after which every DNS resolve will
506 TEST_F(ProxyResolverV8TracingWrapperTest
, InfiniteDNSSequence
) {
508 BoundTestNetLog request_log
;
509 MockCachingHostResolver host_resolver
;
510 MockErrorObserver
* error_observer
= new MockErrorObserver
;
512 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
513 host_resolver
.rules()->AddRule("*", "122.133.144.155");
515 scoped_ptr
<ProxyResolver
> resolver
=
516 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
517 "global_sideffects3.js");
519 TestCompletionCallback callback
;
520 ProxyInfo proxy_info
;
523 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
524 callback
.callback(), NULL
, request_log
.bound());
525 EXPECT_EQ(ERR_IO_PENDING
, rv
);
526 EXPECT_EQ(OK
, callback
.WaitForResult());
528 EXPECT_EQ(20u, host_resolver
.num_resolve());
531 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
532 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
533 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
534 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
535 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
537 proxy_info
.proxy_server().ToURI());
540 EXPECT_EQ("", error_observer
->GetOutput());
542 // Check the NetLogs -- 1 alert was logged.
543 EXPECT_EQ(1u, log
.GetSize());
544 EXPECT_EQ(1u, request_log
.GetSize());
547 // This test runs a weird PAC script that yields a never ending sequence
548 // of DNS resolves when restarting. Running it will hit the maximum
549 // DNS resolves per request limit (20) after which every DNS resolve will
551 TEST_F(ProxyResolverV8TracingWrapperTest
, InfiniteDNSSequence2
) {
553 BoundTestNetLog request_log
;
554 MockCachingHostResolver host_resolver
;
555 MockErrorObserver
* error_observer
= new MockErrorObserver
;
557 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
558 host_resolver
.rules()->AddRule("*", "122.133.144.155");
560 scoped_ptr
<ProxyResolver
> resolver
=
561 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
562 "global_sideffects4.js");
564 TestCompletionCallback callback
;
565 ProxyInfo proxy_info
;
568 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
569 callback
.callback(), NULL
, request_log
.bound());
570 EXPECT_EQ(ERR_IO_PENDING
, rv
);
571 EXPECT_EQ(OK
, callback
.WaitForResult());
573 EXPECT_EQ(20u, host_resolver
.num_resolve());
575 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
578 EXPECT_EQ("", error_observer
->GetOutput());
580 // Check the NetLogs -- 1 alert was logged.
581 EXPECT_EQ(1u, log
.GetSize());
582 EXPECT_EQ(1u, request_log
.GetSize());
585 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
587 BoundTestNetLog request_log
;
588 MockCachingHostResolver host_resolver
;
589 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
590 MockErrorObserver
* error_observer
= new MockErrorObserver
;
592 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
593 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
595 scoped_ptr
<ProxyResolver
> resolver
=
596 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
597 "dns_during_init.js");
599 // Initialization did 2 dnsResolves.
600 EXPECT_EQ(2u, host_resolver
.num_resolve());
602 host_resolver
.rules()->ClearRules();
603 host_resolver
.GetHostCache()->clear();
605 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
606 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
608 TestCompletionCallback callback
;
609 ProxyInfo proxy_info
;
612 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
613 callback
.callback(), NULL
, request_log
.bound());
614 EXPECT_EQ(ERR_IO_PENDING
, rv
);
615 EXPECT_EQ(OK
, callback
.WaitForResult());
617 // Fetched host1 and host2 again, since the ones done during initialization
618 // should not have been cached.
619 EXPECT_EQ(4u, host_resolver
.num_resolve());
621 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
622 proxy_info
.proxy_server().ToURI());
624 // Check the NetLogs -- the script generated 2 alerts during initialization.
625 EXPECT_EQ(0u, request_log
.GetSize());
626 TestNetLogEntry::List entries
;
627 log
.GetEntries(&entries
);
629 ASSERT_EQ(2u, entries
.size());
630 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
631 NetLog::PHASE_NONE
));
632 EXPECT_TRUE(LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
633 NetLog::PHASE_NONE
));
635 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
636 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
639 // Tests a PAC script which does DNS resolves during initialization.
640 TEST_F(ProxyResolverV8TracingWrapperTest
, DnsDuringInit
) {
641 // Test with both both a host resolver that always completes asynchronously,
642 // and then again with one that completes synchronously.
643 DnsDuringInitHelper(false);
644 DnsDuringInitHelper(true);
647 void CrashCallback(int) {
648 // Be extra sure that if the callback ever gets invoked, the test will fail.
652 // Start some requests, cancel them all, and then destroy the resolver.
653 // Note the execution order for this test can vary. Since multiple
654 // threads are involved, the cancellation may be received a different
656 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelAll
) {
657 MockCachingHostResolver host_resolver
;
658 MockErrorObserver
* error_observer
= new MockErrorObserver
;
660 host_resolver
.rules()->AddSimulatedFailure("*");
662 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
663 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
665 const size_t kNumRequests
= 5;
666 ProxyInfo proxy_info
[kNumRequests
];
667 ProxyResolver::RequestHandle request
[kNumRequests
];
669 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
670 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
[i
],
671 base::Bind(&CrashCallback
), &request
[i
],
673 EXPECT_EQ(ERR_IO_PENDING
, rv
);
676 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
677 resolver
->CancelRequest(request
[i
]);
681 // Note the execution order for this test can vary. Since multiple
682 // threads are involved, the cancellation may be received a different
684 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelSome
) {
685 MockCachingHostResolver host_resolver
;
686 MockErrorObserver
* error_observer
= new MockErrorObserver
;
688 host_resolver
.rules()->AddSimulatedFailure("*");
690 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
691 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
693 ProxyInfo proxy_info1
;
694 ProxyInfo proxy_info2
;
695 ProxyResolver::RequestHandle request1
;
696 ProxyResolver::RequestHandle request2
;
697 TestCompletionCallback callback
;
699 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
700 base::Bind(&CrashCallback
), &request1
,
702 EXPECT_EQ(ERR_IO_PENDING
, rv
);
704 rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info2
,
705 callback
.callback(), &request2
, BoundNetLog());
706 EXPECT_EQ(ERR_IO_PENDING
, rv
);
708 resolver
->CancelRequest(request1
);
710 EXPECT_EQ(OK
, callback
.WaitForResult());
713 // Cancel a request after it has finished running on the worker thread, and has
714 // posted a task the completion task back to origin thread.
715 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelWhilePendingCompletionTask
) {
716 MockCachingHostResolver host_resolver
;
717 MockErrorObserver
* error_observer
= new MockErrorObserver
;
719 host_resolver
.rules()->AddSimulatedFailure("*");
721 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
722 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
724 ProxyInfo proxy_info1
;
725 ProxyInfo proxy_info2
;
726 ProxyInfo proxy_info3
;
727 ProxyResolver::RequestHandle request1
;
728 ProxyResolver::RequestHandle request2
;
729 ProxyResolver::RequestHandle request3
;
730 TestCompletionCallback callback
;
732 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
733 base::Bind(&CrashCallback
), &request1
,
735 EXPECT_EQ(ERR_IO_PENDING
, rv
);
737 rv
= resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2
,
738 callback
.callback(), &request2
, BoundNetLog());
739 EXPECT_EQ(ERR_IO_PENDING
, rv
);
741 // Wait until the first request has finished running on the worker thread.
742 // (The second request will output an error).
743 error_observer
->WaitForOutput();
745 // Cancel the first request, while it has a pending completion task on
746 // the origin thread.
747 resolver
->CancelRequest(request1
);
749 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
751 // Start another request, to make sure it is able to complete.
752 rv
= resolver
->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
753 &proxy_info3
, callback
.callback(), &request3
,
755 EXPECT_EQ(ERR_IO_PENDING
, rv
);
757 EXPECT_EQ(OK
, callback
.WaitForResult());
759 EXPECT_EQ("i-approve-this-message:42", proxy_info3
.proxy_server().ToURI());
762 // This implementation of HostResolver allows blocking until a resolve request
763 // has been received. The resolve requests it receives will never be completed.
764 class BlockableHostResolver
: public HostResolver
{
766 BlockableHostResolver()
767 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
769 int Resolve(const RequestInfo
& info
,
770 RequestPriority priority
,
771 AddressList
* addresses
,
772 const CompletionCallback
& callback
,
773 RequestHandle
* out_req
,
774 const BoundNetLog
& net_log
) override
{
775 EXPECT_FALSE(callback
.is_null());
776 EXPECT_TRUE(out_req
);
778 if (!action_
.is_null())
781 // Indicate to the caller that a request was received.
782 EXPECT_TRUE(waiting_for_resolve_
);
783 base::MessageLoop::current()->Quit();
785 // This line is intentionally after action_.Run(), since one of the
786 // tests does a cancellation inside of Resolve(), and it is more
787 // interesting if *out_req hasn't been written yet at that point.
788 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
790 // Return ERR_IO_PENDING as this request will NEVER be completed.
791 // Expectation is for the caller to later cancel the request.
792 return ERR_IO_PENDING
;
795 int ResolveFromCache(const RequestInfo
& info
,
796 AddressList
* addresses
,
797 const BoundNetLog
& net_log
) override
{
799 return ERR_DNS_CACHE_MISS
;
802 void CancelRequest(RequestHandle req
) override
{
803 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
804 num_cancelled_requests_
++;
807 void SetAction(const base::Callback
<void(void)>& action
) { action_
= 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 { 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(ProxyResolverV8TracingWrapperTest
,
828 CancelWhileOutstandingNonBlockingDns
) {
829 BlockableHostResolver host_resolver
;
830 MockErrorObserver
* error_observer
= new MockErrorObserver
;
832 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
833 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
835 ProxyInfo proxy_info1
;
836 ProxyInfo proxy_info2
;
837 ProxyResolver::RequestHandle request1
;
838 ProxyResolver::RequestHandle request2
;
840 int rv
= resolver
->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1
,
841 base::Bind(&CrashCallback
), &request1
,
844 EXPECT_EQ(ERR_IO_PENDING
, rv
);
846 host_resolver
.WaitUntilRequestIsReceived();
848 rv
= resolver
->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2
,
849 base::Bind(&CrashCallback
), &request2
,
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(ProxyResolver
* 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(ProxyResolverV8TracingWrapperTest
, CancelWhileBlockedInNonBlockingDns
) {
880 BlockableHostResolver host_resolver
;
881 MockErrorObserver
* error_observer
= new MockErrorObserver
;
883 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
884 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
886 ProxyInfo proxy_info
;
887 ProxyResolver::RequestHandle request
;
889 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
890 base::Bind(&CrashCallback
), &request
,
893 EXPECT_EQ(ERR_IO_PENDING
, rv
);
895 host_resolver
.SetAction(
896 base::Bind(CancelRequestAndPause
, resolver
.get(), 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(ProxyResolverV8TracingWrapperTest
, CancelWhileBlockedInNonBlockingDns2
) {
909 MockCachingHostResolver host_resolver
;
910 MockErrorObserver
* error_observer
= new MockErrorObserver
;
912 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
913 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
915 ProxyInfo proxy_info
;
916 ProxyResolver::RequestHandle request
;
918 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
919 base::Bind(&CrashCallback
), &request
,
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(ProxyResolverV8TracingWrapperTest
,
934 CancelCreateResolverWhileOutstandingBlockingDns
) {
935 BlockableHostResolver host_resolver
;
936 MockErrorObserver
* error_observer
= new MockErrorObserver
;
938 ProxyResolverFactoryV8TracingWrapper
factory(
939 &host_resolver
, nullptr,
940 base::Bind(&ReturnErrorObserver
,
941 base::Passed(make_scoped_ptr(error_observer
))));
943 scoped_ptr
<ProxyResolver
> resolver
;
944 scoped_ptr
<ProxyResolverFactory::Request
> request
;
945 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
946 &resolver
, base::Bind(&CrashCallback
),
948 EXPECT_EQ(ERR_IO_PENDING
, rv
);
950 host_resolver
.WaitUntilRequestIsReceived();
953 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
956 TEST_F(ProxyResolverV8TracingWrapperTest
,
957 DeleteFactoryWhileOutstandingBlockingDns
) {
958 BlockableHostResolver host_resolver
;
959 MockErrorObserver
* error_observer
= new MockErrorObserver
;
961 scoped_ptr
<ProxyResolver
> resolver
;
962 scoped_ptr
<ProxyResolverFactory::Request
> request
;
964 ProxyResolverFactoryV8TracingWrapper
factory(
965 &host_resolver
, nullptr,
966 base::Bind(&ReturnErrorObserver
,
967 base::Passed(make_scoped_ptr(error_observer
))));
969 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
970 &resolver
, base::Bind(&CrashCallback
),
972 EXPECT_EQ(ERR_IO_PENDING
, rv
);
973 host_resolver
.WaitUntilRequestIsReceived();
975 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
978 TEST_F(ProxyResolverV8TracingWrapperTest
, ErrorLoadingScript
) {
979 BlockableHostResolver host_resolver
;
980 MockErrorObserver
* error_observer
= new MockErrorObserver
;
982 ProxyResolverFactoryV8TracingWrapper
factory(
983 &host_resolver
, nullptr,
984 base::Bind(&ReturnErrorObserver
,
985 base::Passed(make_scoped_ptr(error_observer
))));
987 scoped_ptr
<ProxyResolver
> resolver
;
988 scoped_ptr
<ProxyResolverFactory::Request
> request
;
989 TestCompletionCallback callback
;
991 factory
.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver
,
992 callback
.callback(), &request
);
993 EXPECT_EQ(ERR_IO_PENDING
, rv
);
994 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
995 EXPECT_FALSE(resolver
);
998 // This tests that the execution of a PAC script is terminated when the DNS
999 // dependencies are missing. If the test fails, then it will hang.
1000 TEST_F(ProxyResolverV8TracingWrapperTest
, Terminate
) {
1002 BoundTestNetLog request_log
;
1003 MockCachingHostResolver host_resolver
;
1004 MockErrorObserver
* error_observer
= new MockErrorObserver
;
1006 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
1007 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
1009 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
1010 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "terminate.js");
1012 TestCompletionCallback callback
;
1013 ProxyInfo proxy_info
;
1016 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
1017 callback
.callback(), NULL
, request_log
.bound());
1019 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1020 EXPECT_EQ(OK
, callback
.WaitForResult());
1022 // The test does 2 DNS resolutions.
1023 EXPECT_EQ(2u, host_resolver
.num_resolve());
1025 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
1028 EXPECT_EQ("", error_observer
->GetOutput());
1030 EXPECT_EQ(0u, log
.GetSize());
1031 EXPECT_EQ(0u, request_log
.GetSize());
1034 // Tests that multiple instances of ProxyResolverV8TracingWrapper can coexist
1035 // and run correctly at the same time. This is relevant because at the moment
1036 // (time this test was written) each ProxyResolverV8TracingWrapper creates its
1037 // own thread to run V8 on, however each thread is operating on the same
1039 TEST_F(ProxyResolverV8TracingWrapperTest
, MultipleResolvers
) {
1040 // ------------------------
1042 // ------------------------
1043 MockHostResolver host_resolver0
;
1044 host_resolver0
.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4
,
1046 host_resolver0
.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1",
1048 host_resolver0
.rules()->AddSimulatedFailure("host2");
1049 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1050 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1051 host_resolver0
.rules()->AddSimulatedFailure("host6");
1052 host_resolver0
.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4
,
1054 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1055 scoped_ptr
<ProxyResolver
> resolver0
=
1056 CreateResolver(nullptr, &host_resolver0
,
1057 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1059 // ------------------------
1061 // ------------------------
1062 scoped_ptr
<ProxyResolver
> resolver1
=
1063 CreateResolver(nullptr, &host_resolver0
,
1064 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1066 // ------------------------
1068 // ------------------------
1069 scoped_ptr
<ProxyResolver
> resolver2
=
1070 CreateResolver(nullptr, &host_resolver0
,
1071 make_scoped_ptr(new MockErrorObserver
), "simple.js");
1073 // ------------------------
1075 // ------------------------
1076 MockHostResolver host_resolver3
;
1077 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1078 scoped_ptr
<ProxyResolver
> resolver3
=
1079 CreateResolver(nullptr, &host_resolver3
,
1080 make_scoped_ptr(new MockErrorObserver
), "simple_dns.js");
1082 // ------------------------
1083 // Queue up work for each resolver (which will be running in parallel).
1084 // ------------------------
1086 ProxyResolver
* resolver
[] = {
1087 resolver0
.get(), resolver1
.get(), resolver2
.get(), resolver3
.get(),
1090 const size_t kNumResolvers
= arraysize(resolver
);
1091 const size_t kNumIterations
= 20;
1092 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1093 TestCompletionCallback callback
[kNumResults
];
1094 ProxyInfo proxy_info
[kNumResults
];
1096 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1097 size_t resolver_i
= i
% kNumResolvers
;
1098 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1099 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1101 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1104 // ------------------------
1105 // Verify all of the results.
1106 // ------------------------
1108 const char* kExpectedForDnsJs
=
1109 "122.133.144.155-" // myIpAddress()
1110 "null-" // dnsResolve('')
1111 "__1_192.168.1.1-" // dnsResolveEx('host1')
1112 "null-" // dnsResolve('host2')
1113 "166.155.144.33-" // dnsResolve('host3')
1114 "122.133.144.155-" // myIpAddress()
1115 "166.155.144.33-" // dnsResolve('host3')
1116 "__1_192.168.1.1-" // dnsResolveEx('host1')
1117 "122.133.144.155-" // myIpAddress()
1118 "null-" // dnsResolve('host2')
1119 "-" // dnsResolveEx('host6')
1120 "133.122.100.200-" // myIpAddressEx()
1121 "166.155.144.44" // dnsResolve('host1')
1124 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1125 size_t resolver_i
= i
% kNumResolvers
;
1126 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1128 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1130 if (resolver_i
== 0 || resolver_i
== 1) {
1131 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1132 } else if (resolver_i
== 2) {
1133 EXPECT_EQ("foo:99", proxy_uri
);
1134 } else if (resolver_i
== 3) {
1135 EXPECT_EQ("166.155.144.33:",
1136 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));