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"
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 ProxyResolverV8TracingTest
: 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 ProxyResolverFactoryV8Tracing
factory(
77 host_resolver
, net_log
, ProxyResolver::LoadStateChangedCallback(),
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() {
115 base::WaitableEvent event_
;
118 TEST_F(ProxyResolverV8TracingTest
, Simple
) {
120 BoundTestNetLog request_log
;
121 MockCachingHostResolver host_resolver
;
122 MockErrorObserver
* error_observer
= new MockErrorObserver
;
124 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
125 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "simple.js");
127 TestCompletionCallback callback
;
128 ProxyInfo proxy_info
;
131 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
132 callback
.callback(), NULL
, request_log
.bound());
134 EXPECT_EQ(ERR_IO_PENDING
, rv
);
135 EXPECT_EQ(OK
, callback
.WaitForResult());
137 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
139 EXPECT_EQ(0u, host_resolver
.num_resolve());
141 // There were no errors.
142 EXPECT_EQ("", error_observer
->GetOutput());
144 // Check the NetLogs -- nothing was logged.
145 EXPECT_EQ(0u, log
.GetSize());
146 EXPECT_EQ(0u, request_log
.GetSize());
149 TEST_F(ProxyResolverV8TracingTest
, JavascriptError
) {
151 BoundTestNetLog request_log
;
152 MockCachingHostResolver host_resolver
;
153 MockErrorObserver
* error_observer
= new MockErrorObserver
;
155 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
156 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
158 TestCompletionCallback callback
;
159 ProxyInfo proxy_info
;
162 resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info
,
163 callback
.callback(), NULL
, request_log
.bound());
165 EXPECT_EQ(ERR_IO_PENDING
, rv
);
166 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
168 EXPECT_EQ(0u, host_resolver
.num_resolve());
170 EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
171 "of null\n", 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());
183 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
184 NetLog::PHASE_NONE
));
186 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
187 NetLog::PHASE_NONE
));
189 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
190 EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
191 "read property 'split' of null\"}", entries
[1].GetParamsJson());
195 TEST_F(ProxyResolverV8TracingTest
, 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
) {
236 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
237 NetLog::PHASE_NONE
));
242 // Verify that buffered alerts cannot grow unboundedly, even when the message is
244 TEST_F(ProxyResolverV8TracingTest
, TooManyEmptyAlerts
) {
246 BoundTestNetLog request_log
;
247 MockCachingHostResolver host_resolver
;
248 MockErrorObserver
* error_observer
= new MockErrorObserver
;
250 scoped_ptr
<ProxyResolver
> resolver
=
251 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
252 "too_many_empty_alerts.js");
254 TestCompletionCallback callback
;
255 ProxyInfo proxy_info
;
258 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
259 callback
.callback(), NULL
, request_log
.bound());
261 EXPECT_EQ(ERR_IO_PENDING
, rv
);
262 EXPECT_EQ(OK
, callback
.WaitForResult());
264 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
266 EXPECT_EQ(1u, host_resolver
.num_resolve());
269 EXPECT_EQ("", error_observer
->GetOutput());
271 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
272 // to both the global and per-request logs.
273 TestNetLogEntry::List entries_list
[2];
274 log
.GetEntries(&entries_list
[0]);
275 request_log
.GetEntries(&entries_list
[1]);
277 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
278 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
279 EXPECT_EQ(1000u, entries
.size());
280 for (size_t i
= 0; i
< entries
.size(); ++i
) {
282 LogContainsEvent(entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
283 NetLog::PHASE_NONE
));
288 // This test runs a PAC script that issues a sequence of DNS resolves. The test
289 // verifies the final result, and that the underlying DNS resolver received
290 // the correct set of queries.
291 TEST_F(ProxyResolverV8TracingTest
, Dns
) {
293 BoundTestNetLog request_log
;
294 MockCachingHostResolver host_resolver
;
295 MockErrorObserver
* error_observer
= new MockErrorObserver
;
297 host_resolver
.rules()->AddRuleForAddressFamily(
298 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
299 host_resolver
.rules()
300 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
301 host_resolver
.rules()->AddSimulatedFailure("host2");
302 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
303 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
304 host_resolver
.rules()->AddSimulatedFailure("host6");
305 host_resolver
.rules()->AddRuleForAddressFamily(
306 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
307 host_resolver
.rules()->AddRule("*", "133.122.100.200");
309 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
310 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
312 TestCompletionCallback callback
;
313 ProxyInfo proxy_info
;
316 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
317 callback
.callback(), NULL
, request_log
.bound());
319 EXPECT_EQ(ERR_IO_PENDING
, rv
);
320 EXPECT_EQ(OK
, callback
.WaitForResult());
322 // The test does 13 DNS resolution, however only 7 of them are unique.
323 EXPECT_EQ(7u, host_resolver
.num_resolve());
325 const char* kExpectedResult
=
326 "122.133.144.155-" // myIpAddress()
327 "null-" // dnsResolve('')
328 "__1_192.168.1.1-" // dnsResolveEx('host1')
329 "null-" // dnsResolve('host2')
330 "166.155.144.33-" // dnsResolve('host3')
331 "122.133.144.155-" // myIpAddress()
332 "166.155.144.33-" // dnsResolve('host3')
333 "__1_192.168.1.1-" // dnsResolveEx('host1')
334 "122.133.144.155-" // myIpAddress()
335 "null-" // dnsResolve('host2')
336 "-" // dnsResolveEx('host6')
337 "133.122.100.200-" // myIpAddressEx()
338 "166.155.144.44" // dnsResolve('host1')
341 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
344 EXPECT_EQ("", error_observer
->GetOutput());
346 // Check the NetLogs -- the script generated 1 alert, mirrored to both
347 // the per-request and global logs.
348 TestNetLogEntry::List entries_list
[2];
349 log
.GetEntries(&entries_list
[0]);
350 request_log
.GetEntries(&entries_list
[1]);
352 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
353 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
354 EXPECT_EQ(1u, entries
.size());
356 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
357 NetLog::PHASE_NONE
));
358 EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries
[0].GetParamsJson());
362 // This test runs a PAC script that does "myIpAddress()" followed by
363 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
364 // cache is warmed, subsequent calls should take 0 restarts.
365 TEST_F(ProxyResolverV8TracingTest
, DnsChecksCache
) {
367 BoundTestNetLog request_log
;
368 MockCachingHostResolver host_resolver
;
369 MockErrorObserver
* error_observer
= new MockErrorObserver
;
371 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
372 host_resolver
.rules()->AddRule("*", "122.133.144.155");
374 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
375 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "simple_dns.js");
377 TestCompletionCallback callback1
;
378 TestCompletionCallback callback2
;
379 ProxyInfo proxy_info
;
382 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
383 callback1
.callback(), NULL
, request_log
.bound());
385 EXPECT_EQ(ERR_IO_PENDING
, rv
);
386 EXPECT_EQ(OK
, callback1
.WaitForResult());
388 // The test does 2 DNS resolutions.
389 EXPECT_EQ(2u, host_resolver
.num_resolve());
391 // The first request took 2 restarts, hence on g_iteration=3.
392 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
395 resolver
->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info
,
396 callback2
.callback(), NULL
, request_log
.bound());
398 EXPECT_EQ(ERR_IO_PENDING
, rv
);
399 EXPECT_EQ(OK
, callback2
.WaitForResult());
401 EXPECT_EQ(4u, host_resolver
.num_resolve());
403 // This time no restarts were required, so g_iteration incremented by 1.
404 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
407 EXPECT_EQ("", error_observer
->GetOutput());
409 EXPECT_EQ(0u, log
.GetSize());
410 EXPECT_EQ(0u, request_log
.GetSize());
413 // This test runs a weird PAC script that was designed to defeat the DNS tracing
414 // optimization. The proxy resolver should detect the inconsistency and
415 // fall-back to synchronous mode execution.
416 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous1
) {
418 BoundTestNetLog request_log
;
419 MockCachingHostResolver host_resolver
;
420 MockErrorObserver
* error_observer
= new MockErrorObserver
;
422 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
423 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
424 host_resolver
.rules()->AddRule("*", "122.133.144.155");
426 scoped_ptr
<ProxyResolver
> resolver
=
427 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
428 "global_sideffects1.js");
430 TestCompletionCallback callback
;
431 ProxyInfo proxy_info
;
434 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
435 callback
.callback(), NULL
, request_log
.bound());
436 EXPECT_EQ(ERR_IO_PENDING
, rv
);
437 EXPECT_EQ(OK
, callback
.WaitForResult());
439 // The script itself only does 2 DNS resolves per execution, however it
440 // constructs the hostname using a global counter which changes on each
442 EXPECT_EQ(3u, host_resolver
.num_resolve());
444 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
445 proxy_info
.proxy_server().ToURI());
448 EXPECT_EQ("", error_observer
->GetOutput());
450 // Check the NetLogs -- the script generated 1 alert, mirrored to both
451 // the per-request and global logs.
452 TestNetLogEntry::List entries_list
[2];
453 log
.GetEntries(&entries_list
[0]);
454 request_log
.GetEntries(&entries_list
[1]);
456 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
457 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
458 EXPECT_EQ(1u, entries
.size());
460 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
461 NetLog::PHASE_NONE
));
462 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
466 // This test runs a weird PAC script that was designed to defeat the DNS tracing
467 // optimization. The proxy resolver should detect the inconsistency and
468 // fall-back to synchronous mode execution.
469 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous2
) {
471 BoundTestNetLog request_log
;
472 MockCachingHostResolver host_resolver
;
473 MockErrorObserver
* error_observer
= new MockErrorObserver
;
475 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
476 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
477 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
478 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
479 host_resolver
.rules()->AddRule("*", "122.133.144.155");
481 scoped_ptr
<ProxyResolver
> resolver
=
482 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
483 "global_sideffects2.js");
485 TestCompletionCallback callback
;
486 ProxyInfo proxy_info
;
489 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
490 callback
.callback(), NULL
, request_log
.bound());
491 EXPECT_EQ(ERR_IO_PENDING
, rv
);
492 EXPECT_EQ(OK
, callback
.WaitForResult());
494 EXPECT_EQ(3u, host_resolver
.num_resolve());
496 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
499 EXPECT_EQ("", error_observer
->GetOutput());
501 // Check the NetLogs -- nothing was logged.
502 EXPECT_EQ(0u, log
.GetSize());
503 EXPECT_EQ(0u, request_log
.GetSize());
506 // This test runs a weird PAC script that yields a never ending sequence
507 // of DNS resolves when restarting. Running it will hit the maximum
508 // DNS resolves per request limit (20) after which every DNS resolve will
510 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence
) {
512 BoundTestNetLog request_log
;
513 MockCachingHostResolver host_resolver
;
514 MockErrorObserver
* error_observer
= new MockErrorObserver
;
516 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
517 host_resolver
.rules()->AddRule("*", "122.133.144.155");
519 scoped_ptr
<ProxyResolver
> resolver
=
520 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
521 "global_sideffects3.js");
523 TestCompletionCallback callback
;
524 ProxyInfo proxy_info
;
527 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
528 callback
.callback(), NULL
, request_log
.bound());
529 EXPECT_EQ(ERR_IO_PENDING
, rv
);
530 EXPECT_EQ(OK
, callback
.WaitForResult());
532 EXPECT_EQ(20u, host_resolver
.num_resolve());
535 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
536 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
537 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
538 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
539 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
540 "null:21", proxy_info
.proxy_server().ToURI());
543 EXPECT_EQ("", error_observer
->GetOutput());
545 // Check the NetLogs -- 1 alert was logged.
546 EXPECT_EQ(1u, log
.GetSize());
547 EXPECT_EQ(1u, request_log
.GetSize());
550 // This test runs a weird PAC script that yields a never ending sequence
551 // of DNS resolves when restarting. Running it will hit the maximum
552 // DNS resolves per request limit (20) after which every DNS resolve will
554 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence2
) {
556 BoundTestNetLog request_log
;
557 MockCachingHostResolver host_resolver
;
558 MockErrorObserver
* error_observer
= new MockErrorObserver
;
560 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
561 host_resolver
.rules()->AddRule("*", "122.133.144.155");
563 scoped_ptr
<ProxyResolver
> resolver
=
564 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
565 "global_sideffects4.js");
567 TestCompletionCallback callback
;
568 ProxyInfo proxy_info
;
571 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
572 callback
.callback(), NULL
, request_log
.bound());
573 EXPECT_EQ(ERR_IO_PENDING
, rv
);
574 EXPECT_EQ(OK
, callback
.WaitForResult());
576 EXPECT_EQ(20u, host_resolver
.num_resolve());
578 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
581 EXPECT_EQ("", error_observer
->GetOutput());
583 // Check the NetLogs -- 1 alert was logged.
584 EXPECT_EQ(1u, log
.GetSize());
585 EXPECT_EQ(1u, request_log
.GetSize());
588 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
590 BoundTestNetLog request_log
;
591 MockCachingHostResolver host_resolver
;
592 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
593 MockErrorObserver
* error_observer
= new MockErrorObserver
;
595 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
596 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
598 scoped_ptr
<ProxyResolver
> resolver
=
599 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
600 "dns_during_init.js");
602 // Initialization did 2 dnsResolves.
603 EXPECT_EQ(2u, host_resolver
.num_resolve());
605 host_resolver
.rules()->ClearRules();
606 host_resolver
.GetHostCache()->clear();
608 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
609 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
611 TestCompletionCallback callback
;
612 ProxyInfo proxy_info
;
615 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
616 callback
.callback(), NULL
, request_log
.bound());
617 EXPECT_EQ(ERR_IO_PENDING
, rv
);
618 EXPECT_EQ(OK
, callback
.WaitForResult());
620 // Fetched host1 and host2 again, since the ones done during initialization
621 // should not have been cached.
622 EXPECT_EQ(4u, host_resolver
.num_resolve());
624 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
625 proxy_info
.proxy_server().ToURI());
627 // Check the NetLogs -- the script generated 2 alerts during initialization.
628 EXPECT_EQ(0u, request_log
.GetSize());
629 TestNetLogEntry::List entries
;
630 log
.GetEntries(&entries
);
632 ASSERT_EQ(2u, entries
.size());
634 LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
635 NetLog::PHASE_NONE
));
637 LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
638 NetLog::PHASE_NONE
));
640 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
641 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
644 // Tests a PAC script which does DNS resolves during initialization.
645 TEST_F(ProxyResolverV8TracingTest
, DnsDuringInit
) {
646 // Test with both both a host resolver that always completes asynchronously,
647 // and then again with one that completes synchronously.
648 DnsDuringInitHelper(false);
649 DnsDuringInitHelper(true);
652 void CrashCallback(int) {
653 // Be extra sure that if the callback ever gets invoked, the test will fail.
657 // Start some requests, cancel them all, and then destroy the resolver.
658 // Note the execution order for this test can vary. Since multiple
659 // threads are involved, the cancellation may be received a different
661 TEST_F(ProxyResolverV8TracingTest
, CancelAll
) {
662 MockCachingHostResolver host_resolver
;
663 MockErrorObserver
* error_observer
= new MockErrorObserver
;
665 host_resolver
.rules()->AddSimulatedFailure("*");
667 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
668 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
670 const size_t kNumRequests
= 5;
671 ProxyInfo proxy_info
[kNumRequests
];
672 ProxyResolver::RequestHandle request
[kNumRequests
];
674 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
675 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
[i
],
676 base::Bind(&CrashCallback
), &request
[i
],
678 EXPECT_EQ(ERR_IO_PENDING
, rv
);
681 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
682 resolver
->CancelRequest(request
[i
]);
686 // Note the execution order for this test can vary. Since multiple
687 // threads are involved, the cancellation may be received a different
689 TEST_F(ProxyResolverV8TracingTest
, CancelSome
) {
690 MockCachingHostResolver host_resolver
;
691 MockErrorObserver
* error_observer
= new MockErrorObserver
;
693 host_resolver
.rules()->AddSimulatedFailure("*");
695 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
696 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
698 ProxyInfo proxy_info1
;
699 ProxyInfo proxy_info2
;
700 ProxyResolver::RequestHandle request1
;
701 ProxyResolver::RequestHandle request2
;
702 TestCompletionCallback callback
;
704 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
705 base::Bind(&CrashCallback
), &request1
,
707 EXPECT_EQ(ERR_IO_PENDING
, rv
);
709 rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info2
,
710 callback
.callback(), &request2
, BoundNetLog());
711 EXPECT_EQ(ERR_IO_PENDING
, rv
);
713 resolver
->CancelRequest(request1
);
715 EXPECT_EQ(OK
, callback
.WaitForResult());
718 // Cancel a request after it has finished running on the worker thread, and has
719 // posted a task the completion task back to origin thread.
720 TEST_F(ProxyResolverV8TracingTest
, CancelWhilePendingCompletionTask
) {
721 MockCachingHostResolver host_resolver
;
722 MockErrorObserver
* error_observer
= new MockErrorObserver
;
724 host_resolver
.rules()->AddSimulatedFailure("*");
726 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
727 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
729 ProxyInfo proxy_info1
;
730 ProxyInfo proxy_info2
;
731 ProxyInfo proxy_info3
;
732 ProxyResolver::RequestHandle request1
;
733 ProxyResolver::RequestHandle request2
;
734 ProxyResolver::RequestHandle request3
;
735 TestCompletionCallback callback
;
737 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
738 base::Bind(&CrashCallback
), &request1
,
740 EXPECT_EQ(ERR_IO_PENDING
, rv
);
742 rv
= resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info2
,
743 callback
.callback(), &request2
, BoundNetLog());
744 EXPECT_EQ(ERR_IO_PENDING
, rv
);
746 // Wait until the first request has finished running on the worker thread.
747 // (The second request will output an error).
748 error_observer
->WaitForOutput();
750 // Cancel the first request, while it has a pending completion task on
751 // the origin thread.
752 resolver
->CancelRequest(request1
);
754 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
756 // Start another request, to make sure it is able to complete.
757 rv
= resolver
->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
758 &proxy_info3
, callback
.callback(), &request3
,
760 EXPECT_EQ(ERR_IO_PENDING
, rv
);
762 EXPECT_EQ(OK
, callback
.WaitForResult());
764 EXPECT_EQ("i-approve-this-message:42",
765 proxy_info3
.proxy_server().ToURI());
768 // This implementation of HostResolver allows blocking until a resolve request
769 // has been received. The resolve requests it receives will never be completed.
770 class BlockableHostResolver
: public HostResolver
{
772 BlockableHostResolver()
773 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
775 int Resolve(const RequestInfo
& info
,
776 RequestPriority priority
,
777 AddressList
* addresses
,
778 const CompletionCallback
& callback
,
779 RequestHandle
* out_req
,
780 const BoundNetLog
& net_log
) override
{
781 EXPECT_FALSE(callback
.is_null());
782 EXPECT_TRUE(out_req
);
784 if (!action_
.is_null())
787 // Indicate to the caller that a request was received.
788 EXPECT_TRUE(waiting_for_resolve_
);
789 base::MessageLoop::current()->Quit();
791 // This line is intentionally after action_.Run(), since one of the
792 // tests does a cancellation inside of Resolve(), and it is more
793 // interesting if *out_req hasn't been written yet at that point.
794 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
796 // Return ERR_IO_PENDING as this request will NEVER be completed.
797 // Expectation is for the caller to later cancel the request.
798 return ERR_IO_PENDING
;
801 int ResolveFromCache(const RequestInfo
& info
,
802 AddressList
* addresses
,
803 const BoundNetLog
& net_log
) override
{
805 return ERR_DNS_CACHE_MISS
;
808 void CancelRequest(RequestHandle req
) override
{
809 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
810 num_cancelled_requests_
++;
813 void SetAction(const base::Callback
<void(void)>& action
) {
817 // Waits until Resolve() has been called.
818 void WaitUntilRequestIsReceived() {
819 waiting_for_resolve_
= true;
820 base::MessageLoop::current()->Run();
821 DCHECK(waiting_for_resolve_
);
822 waiting_for_resolve_
= false;
825 int num_cancelled_requests() const {
826 return num_cancelled_requests_
;
830 int num_cancelled_requests_
;
831 bool waiting_for_resolve_
;
832 base::Callback
<void(void)> action_
;
835 // This cancellation test exercises a more predictable cancellation codepath --
836 // when the request has an outstanding DNS request in flight.
837 TEST_F(ProxyResolverV8TracingTest
, CancelWhileOutstandingNonBlockingDns
) {
838 BlockableHostResolver host_resolver
;
839 MockErrorObserver
* error_observer
= new MockErrorObserver
;
841 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
842 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
844 ProxyInfo proxy_info1
;
845 ProxyInfo proxy_info2
;
846 ProxyResolver::RequestHandle request1
;
847 ProxyResolver::RequestHandle request2
;
849 int rv
= resolver
->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1
,
850 base::Bind(&CrashCallback
), &request1
,
853 EXPECT_EQ(ERR_IO_PENDING
, rv
);
855 host_resolver
.WaitUntilRequestIsReceived();
857 rv
= resolver
->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2
,
858 base::Bind(&CrashCallback
), &request2
,
861 EXPECT_EQ(ERR_IO_PENDING
, rv
);
863 host_resolver
.WaitUntilRequestIsReceived();
865 resolver
->CancelRequest(request1
);
866 resolver
->CancelRequest(request2
);
868 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
870 // After leaving this scope, the ProxyResolver is destroyed.
871 // This should not cause any problems, as the outstanding work
872 // should have been cancelled.
875 void CancelRequestAndPause(ProxyResolver
* resolver
,
876 ProxyResolver::RequestHandle request
) {
877 resolver
->CancelRequest(request
);
879 // Sleep for a little bit. This makes it more likely for the worker
880 // thread to have returned from its call, and serves as a regression
881 // test for http://crbug.com/173373.
882 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
885 // In non-blocking mode, the worker thread actually does block for
886 // a short time to see if the result is in the DNS cache. Test
887 // cancellation while the worker thread is waiting on this event.
888 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns
) {
889 BlockableHostResolver host_resolver
;
890 MockErrorObserver
* error_observer
= new MockErrorObserver
;
892 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
893 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
895 ProxyInfo proxy_info
;
896 ProxyResolver::RequestHandle request
;
898 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
899 base::Bind(&CrashCallback
), &request
,
902 EXPECT_EQ(ERR_IO_PENDING
, rv
);
904 host_resolver
.SetAction(
905 base::Bind(CancelRequestAndPause
, resolver
.get(), request
));
907 host_resolver
.WaitUntilRequestIsReceived();
909 // At this point the host resolver ran Resolve(), and should have cancelled
912 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
915 // Cancel the request while there is a pending DNS request, however before
916 // the request is sent to the host resolver.
917 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns2
) {
918 MockCachingHostResolver host_resolver
;
919 MockErrorObserver
* error_observer
= new MockErrorObserver
;
921 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
922 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
924 ProxyInfo proxy_info
;
925 ProxyResolver::RequestHandle request
;
927 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
928 base::Bind(&CrashCallback
), &request
,
931 EXPECT_EQ(ERR_IO_PENDING
, rv
);
933 // Wait a bit, so the DNS task has hopefully been posted. The test will
934 // work whatever the delay is here, but it is most useful if the delay
935 // is large enough to allow a task to be posted back.
936 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
937 resolver
->CancelRequest(request
);
939 EXPECT_EQ(0u, host_resolver
.num_resolve());
942 TEST_F(ProxyResolverV8TracingTest
,
943 CancelCreateResolverWhileOutstandingBlockingDns
) {
944 BlockableHostResolver host_resolver
;
945 MockErrorObserver
* error_observer
= new MockErrorObserver
;
947 ProxyResolverFactoryV8Tracing
factory(
948 &host_resolver
, nullptr, ProxyResolver::LoadStateChangedCallback(),
949 base::Bind(&ReturnErrorObserver
,
950 base::Passed(make_scoped_ptr(error_observer
))));
952 scoped_ptr
<ProxyResolver
> resolver
;
953 scoped_ptr
<ProxyResolverFactory::Request
> request
;
954 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
955 &resolver
, base::Bind(&CrashCallback
),
957 EXPECT_EQ(ERR_IO_PENDING
, rv
);
959 host_resolver
.WaitUntilRequestIsReceived();
962 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
965 TEST_F(ProxyResolverV8TracingTest
, DeleteFactoryWhileOutstandingBlockingDns
) {
966 BlockableHostResolver host_resolver
;
967 MockErrorObserver
* error_observer
= new MockErrorObserver
;
969 scoped_ptr
<ProxyResolver
> resolver
;
970 scoped_ptr
<ProxyResolverFactory::Request
> request
;
972 ProxyResolverFactoryV8Tracing
factory(
973 &host_resolver
, nullptr, ProxyResolver::LoadStateChangedCallback(),
974 base::Bind(&ReturnErrorObserver
,
975 base::Passed(make_scoped_ptr(error_observer
))));
977 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
978 &resolver
, base::Bind(&CrashCallback
),
980 EXPECT_EQ(ERR_IO_PENDING
, rv
);
981 host_resolver
.WaitUntilRequestIsReceived();
983 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
986 TEST_F(ProxyResolverV8TracingTest
, ErrorLoadingScript
) {
987 BlockableHostResolver host_resolver
;
988 MockErrorObserver
* error_observer
= new MockErrorObserver
;
990 ProxyResolverFactoryV8Tracing
factory(
991 &host_resolver
, nullptr, ProxyResolver::LoadStateChangedCallback(),
992 base::Bind(&ReturnErrorObserver
,
993 base::Passed(make_scoped_ptr(error_observer
))));
995 scoped_ptr
<ProxyResolver
> resolver
;
996 scoped_ptr
<ProxyResolverFactory::Request
> request
;
997 TestCompletionCallback callback
;
999 factory
.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver
,
1000 callback
.callback(), &request
);
1001 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1002 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
1003 EXPECT_FALSE(resolver
);
1006 // This tests that the execution of a PAC script is terminated when the DNS
1007 // dependencies are missing. If the test fails, then it will hang.
1008 TEST_F(ProxyResolverV8TracingTest
, Terminate
) {
1010 BoundTestNetLog request_log
;
1011 MockCachingHostResolver host_resolver
;
1012 MockErrorObserver
* error_observer
= new MockErrorObserver
;
1014 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
1015 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
1017 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
1018 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "terminate.js");
1020 TestCompletionCallback callback
;
1021 ProxyInfo proxy_info
;
1024 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
1025 callback
.callback(), NULL
, request_log
.bound());
1027 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1028 EXPECT_EQ(OK
, callback
.WaitForResult());
1030 // The test does 2 DNS resolutions.
1031 EXPECT_EQ(2u, host_resolver
.num_resolve());
1033 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
1036 EXPECT_EQ("", error_observer
->GetOutput());
1038 EXPECT_EQ(0u, log
.GetSize());
1039 EXPECT_EQ(0u, request_log
.GetSize());
1042 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
1043 // correctly at the same time. This is relevant because at the moment (time
1044 // this test was written) each ProxyResolverV8Tracing creates its own thread to
1045 // run V8 on, however each thread is operating on the same v8::Isolate.
1046 TEST_F(ProxyResolverV8TracingTest
, MultipleResolvers
) {
1047 // ------------------------
1049 // ------------------------
1050 MockHostResolver host_resolver0
;
1051 host_resolver0
.rules()->AddRuleForAddressFamily(
1052 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
1053 host_resolver0
.rules()
1054 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1055 host_resolver0
.rules()->AddSimulatedFailure("host2");
1056 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1057 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1058 host_resolver0
.rules()->AddSimulatedFailure("host6");
1059 host_resolver0
.rules()->AddRuleForAddressFamily(
1060 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
1061 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1062 scoped_ptr
<ProxyResolver
> resolver0
=
1063 CreateResolver(nullptr, &host_resolver0
,
1064 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1066 // ------------------------
1068 // ------------------------
1069 scoped_ptr
<ProxyResolver
> resolver1
=
1070 CreateResolver(nullptr, &host_resolver0
,
1071 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1073 // ------------------------
1075 // ------------------------
1076 scoped_ptr
<ProxyResolver
> resolver2
=
1077 CreateResolver(nullptr, &host_resolver0
,
1078 make_scoped_ptr(new MockErrorObserver
), "simple.js");
1080 // ------------------------
1082 // ------------------------
1083 MockHostResolver host_resolver3
;
1084 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1085 scoped_ptr
<ProxyResolver
> resolver3
=
1086 CreateResolver(nullptr, &host_resolver3
,
1087 make_scoped_ptr(new MockErrorObserver
), "simple_dns.js");
1089 // ------------------------
1090 // Queue up work for each resolver (which will be running in parallel).
1091 // ------------------------
1093 ProxyResolver
* resolver
[] = {
1094 resolver0
.get(), resolver1
.get(), resolver2
.get(), resolver3
.get(),
1097 const size_t kNumResolvers
= arraysize(resolver
);
1098 const size_t kNumIterations
= 20;
1099 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1100 TestCompletionCallback callback
[kNumResults
];
1101 ProxyInfo proxy_info
[kNumResults
];
1103 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1104 size_t resolver_i
= i
% kNumResolvers
;
1105 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1106 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1108 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1111 // ------------------------
1112 // Verify all of the results.
1113 // ------------------------
1115 const char* kExpectedForDnsJs
=
1116 "122.133.144.155-" // myIpAddress()
1117 "null-" // dnsResolve('')
1118 "__1_192.168.1.1-" // dnsResolveEx('host1')
1119 "null-" // dnsResolve('host2')
1120 "166.155.144.33-" // dnsResolve('host3')
1121 "122.133.144.155-" // myIpAddress()
1122 "166.155.144.33-" // dnsResolve('host3')
1123 "__1_192.168.1.1-" // dnsResolveEx('host1')
1124 "122.133.144.155-" // myIpAddress()
1125 "null-" // dnsResolve('host2')
1126 "-" // dnsResolveEx('host6')
1127 "133.122.100.200-" // myIpAddressEx()
1128 "166.155.144.44" // dnsResolve('host1')
1131 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1132 size_t resolver_i
= i
% kNumResolvers
;
1133 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1135 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1137 if (resolver_i
== 0 || resolver_i
== 1) {
1138 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1139 } else if (resolver_i
== 2) {
1140 EXPECT_EQ("foo:99", proxy_uri
);
1141 } else if (resolver_i
== 3) {
1142 EXPECT_EQ("166.155.144.33:",
1143 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));