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 "net/test/event_waiter.h"
30 #include "testing/gtest/include/gtest/gtest.h"
37 class ProxyResolverV8TracingWrapperTest
: public testing::Test
{
39 void TearDown() override
{
40 // Drain any pending messages, which may be left over from cancellation.
41 // This way they get reliably run as part of the current test, rather than
42 // spilling into the next test's execution.
43 base::MessageLoop::current()->RunUntilIdle();
47 scoped_refptr
<ProxyResolverScriptData
> LoadScriptData(const char* filename
) {
49 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
50 path
= path
.AppendASCII("net");
51 path
= path
.AppendASCII("data");
52 path
= path
.AppendASCII("proxy_resolver_v8_tracing_unittest");
53 path
= path
.AppendASCII(filename
);
55 // Try to read the file from disk.
56 std::string file_contents
;
57 bool ok
= base::ReadFileToString(path
, &file_contents
);
59 // If we can't load the file from disk, something is misconfigured.
60 EXPECT_TRUE(ok
) << "Failed to read file: " << path
.value();
62 // Load the PAC script into the ProxyResolver.
63 return ProxyResolverScriptData::FromUTF8(file_contents
);
66 scoped_ptr
<ProxyResolverErrorObserver
> ReturnErrorObserver(
67 scoped_ptr
<ProxyResolverErrorObserver
> error_observer
) {
68 return error_observer
;
71 scoped_ptr
<ProxyResolver
> CreateResolver(
73 HostResolver
* host_resolver
,
74 scoped_ptr
<ProxyResolverErrorObserver
> error_observer
,
75 const char* filename
) {
76 scoped_ptr
<ProxyResolver
> resolver
;
77 ProxyResolverFactoryV8TracingWrapper
factory(
78 host_resolver
, net_log
,
79 base::Bind(&ReturnErrorObserver
, base::Passed(&error_observer
)));
80 TestCompletionCallback callback
;
81 scoped_ptr
<ProxyResolverFactory::Request
> request
;
82 int rv
= factory
.CreateProxyResolver(LoadScriptData(filename
), &resolver
,
83 callback
.callback(), &request
);
84 EXPECT_EQ(ERR_IO_PENDING
, rv
);
85 EXPECT_EQ(OK
, callback
.WaitForResult());
86 EXPECT_TRUE(resolver
);
87 return resolver
.Pass();
90 class MockErrorObserver
: public ProxyResolverErrorObserver
{
92 void OnPACScriptError(int line_number
, const base::string16
& error
) override
{
93 output
+= base::StringPrintf("Error: line %d: %s\n", line_number
,
94 base::UTF16ToASCII(error
).c_str());
95 waiter_
.NotifyEvent(EVENT_ERROR
);
96 if (!error_callback_
.is_null())
97 error_callback_
.Run();
100 std::string
GetOutput() {
104 void RunOnError(const base::Closure
& callback
) {
105 error_callback_
= callback
;
106 waiter_
.WaitForEvent(EVENT_ERROR
);
115 base::Closure error_callback_
;
116 EventWaiter
<Event
> waiter_
;
119 TEST_F(ProxyResolverV8TracingWrapperTest
, Simple
) {
121 BoundTestNetLog request_log
;
122 MockCachingHostResolver host_resolver
;
123 MockErrorObserver
* error_observer
= new MockErrorObserver
;
125 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
126 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "simple.js");
128 TestCompletionCallback callback
;
129 ProxyInfo proxy_info
;
132 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
133 callback
.callback(), NULL
, request_log
.bound());
135 EXPECT_EQ(ERR_IO_PENDING
, rv
);
136 EXPECT_EQ(OK
, callback
.WaitForResult());
138 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
140 EXPECT_EQ(0u, host_resolver
.num_resolve());
142 // There were no errors.
143 EXPECT_EQ("", error_observer
->GetOutput());
145 // Check the NetLogs -- nothing was logged.
146 EXPECT_EQ(0u, log
.GetSize());
147 EXPECT_EQ(0u, request_log
.GetSize());
150 TEST_F(ProxyResolverV8TracingWrapperTest
, JavascriptError
) {
152 BoundTestNetLog request_log
;
153 MockCachingHostResolver host_resolver
;
154 MockErrorObserver
* error_observer
= new MockErrorObserver
;
156 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
157 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
159 TestCompletionCallback callback
;
160 ProxyInfo proxy_info
;
163 resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info
,
164 callback
.callback(), NULL
, request_log
.bound());
166 EXPECT_EQ(ERR_IO_PENDING
, rv
);
167 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
169 EXPECT_EQ(0u, host_resolver
.num_resolve());
172 "Error: line 5: Uncaught TypeError: Cannot read property 'split' "
174 error_observer
->GetOutput());
176 // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
177 // were output to both the global log, and per-request log.
178 TestNetLogEntry::List entries_list
[2];
179 log
.GetEntries(&entries_list
[0]);
180 request_log
.GetEntries(&entries_list
[1]);
182 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
183 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
184 EXPECT_EQ(2u, entries
.size());
185 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
186 NetLog::PHASE_NONE
));
187 EXPECT_TRUE(LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR
,
188 NetLog::PHASE_NONE
));
190 EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries
[0].GetParamsJson());
192 "{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
193 "read property 'split' of null\"}",
194 entries
[1].GetParamsJson());
198 TEST_F(ProxyResolverV8TracingWrapperTest
, TooManyAlerts
) {
200 BoundTestNetLog request_log
;
201 MockCachingHostResolver host_resolver
;
202 MockErrorObserver
* error_observer
= new MockErrorObserver
;
204 scoped_ptr
<ProxyResolver
> resolver
=
205 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
206 "too_many_alerts.js");
208 TestCompletionCallback callback
;
209 ProxyInfo proxy_info
;
212 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
213 callback
.callback(), NULL
, request_log
.bound());
215 EXPECT_EQ(ERR_IO_PENDING
, rv
);
216 EXPECT_EQ(OK
, callback
.WaitForResult());
218 // Iteration1 does a DNS resolve
219 // Iteration2 exceeds the alert buffer
220 // Iteration3 runs in blocking mode and completes
221 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
223 EXPECT_EQ(1u, host_resolver
.num_resolve());
226 EXPECT_EQ("", error_observer
->GetOutput());
228 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
229 // to both the global and per-request logs.
230 TestNetLogEntry::List entries_list
[2];
231 log
.GetEntries(&entries_list
[0]);
232 request_log
.GetEntries(&entries_list
[1]);
234 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
235 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
236 EXPECT_EQ(50u, entries
.size());
237 for (size_t i
= 0; i
< entries
.size(); ++i
) {
238 ASSERT_TRUE(LogContainsEvent(
239 entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
, NetLog::PHASE_NONE
));
244 // Verify that buffered alerts cannot grow unboundedly, even when the message is
246 TEST_F(ProxyResolverV8TracingWrapperTest
, TooManyEmptyAlerts
) {
248 BoundTestNetLog request_log
;
249 MockCachingHostResolver host_resolver
;
250 MockErrorObserver
* error_observer
= new MockErrorObserver
;
252 scoped_ptr
<ProxyResolver
> resolver
=
253 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
254 "too_many_empty_alerts.js");
256 TestCompletionCallback callback
;
257 ProxyInfo proxy_info
;
260 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
261 callback
.callback(), NULL
, request_log
.bound());
263 EXPECT_EQ(ERR_IO_PENDING
, rv
);
264 EXPECT_EQ(OK
, callback
.WaitForResult());
266 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
268 EXPECT_EQ(1u, host_resolver
.num_resolve());
271 EXPECT_EQ("", error_observer
->GetOutput());
273 // Check the NetLogs -- the script generated 50 alerts, which were mirrored
274 // to both the global and per-request logs.
275 TestNetLogEntry::List entries_list
[2];
276 log
.GetEntries(&entries_list
[0]);
277 request_log
.GetEntries(&entries_list
[1]);
279 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
280 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
281 EXPECT_EQ(1000u, entries
.size());
282 for (size_t i
= 0; i
< entries
.size(); ++i
) {
283 ASSERT_TRUE(LogContainsEvent(
284 entries
, i
, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
, NetLog::PHASE_NONE
));
289 // This test runs a PAC script that issues a sequence of DNS resolves. The test
290 // verifies the final result, and that the underlying DNS resolver received
291 // the correct set of queries.
292 TEST_F(ProxyResolverV8TracingWrapperTest
, Dns
) {
294 BoundTestNetLog request_log
;
295 MockCachingHostResolver host_resolver
;
296 MockErrorObserver
* error_observer
= new MockErrorObserver
;
298 host_resolver
.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4
,
300 host_resolver
.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1",
302 host_resolver
.rules()->AddSimulatedFailure("host2");
303 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
304 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
305 host_resolver
.rules()->AddSimulatedFailure("host6");
306 host_resolver
.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4
,
308 host_resolver
.rules()->AddRule("*", "133.122.100.200");
310 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
311 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
313 TestCompletionCallback callback
;
314 ProxyInfo proxy_info
;
317 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
318 callback
.callback(), NULL
, request_log
.bound());
320 EXPECT_EQ(ERR_IO_PENDING
, rv
);
321 EXPECT_EQ(OK
, callback
.WaitForResult());
323 // The test does 13 DNS resolution, however only 7 of them are unique.
324 EXPECT_EQ(7u, host_resolver
.num_resolve());
326 const char* kExpectedResult
=
327 "122.133.144.155-" // myIpAddress()
328 "null-" // dnsResolve('')
329 "__1_192.168.1.1-" // dnsResolveEx('host1')
330 "null-" // dnsResolve('host2')
331 "166.155.144.33-" // dnsResolve('host3')
332 "122.133.144.155-" // myIpAddress()
333 "166.155.144.33-" // dnsResolve('host3')
334 "__1_192.168.1.1-" // dnsResolveEx('host1')
335 "122.133.144.155-" // myIpAddress()
336 "null-" // dnsResolve('host2')
337 "-" // dnsResolveEx('host6')
338 "133.122.100.200-" // myIpAddressEx()
339 "166.155.144.44" // dnsResolve('host1')
342 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
345 EXPECT_EQ("", error_observer
->GetOutput());
347 // Check the NetLogs -- the script generated 1 alert, mirrored to both
348 // the per-request and global logs.
349 TestNetLogEntry::List entries_list
[2];
350 log
.GetEntries(&entries_list
[0]);
351 request_log
.GetEntries(&entries_list
[1]);
353 for (size_t list_i
= 0; list_i
< arraysize(entries_list
); list_i
++) {
354 const TestNetLogEntry::List
& entries
= entries_list
[list_i
];
355 EXPECT_EQ(1u, entries
.size());
356 EXPECT_TRUE(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(ProxyResolverV8TracingWrapperTest
, 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(ProxyResolverV8TracingWrapperTest
, 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());
459 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
460 NetLog::PHASE_NONE
));
461 EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries
[0].GetParamsJson());
465 // This test runs a weird PAC script that was designed to defeat the DNS tracing
466 // optimization. The proxy resolver should detect the inconsistency and
467 // fall-back to synchronous mode execution.
468 TEST_F(ProxyResolverV8TracingWrapperTest
, FallBackToSynchronous2
) {
470 BoundTestNetLog request_log
;
471 MockCachingHostResolver host_resolver
;
472 MockErrorObserver
* error_observer
= new MockErrorObserver
;
474 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
475 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
476 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
477 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
478 host_resolver
.rules()->AddRule("*", "122.133.144.155");
480 scoped_ptr
<ProxyResolver
> resolver
=
481 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
482 "global_sideffects2.js");
484 TestCompletionCallback callback
;
485 ProxyInfo proxy_info
;
488 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
489 callback
.callback(), NULL
, request_log
.bound());
490 EXPECT_EQ(ERR_IO_PENDING
, rv
);
491 EXPECT_EQ(OK
, callback
.WaitForResult());
493 EXPECT_EQ(3u, host_resolver
.num_resolve());
495 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
498 EXPECT_EQ("", error_observer
->GetOutput());
500 // Check the NetLogs -- nothing was logged.
501 EXPECT_EQ(0u, log
.GetSize());
502 EXPECT_EQ(0u, request_log
.GetSize());
505 // This test runs a weird PAC script that yields a never ending sequence
506 // of DNS resolves when restarting. Running it will hit the maximum
507 // DNS resolves per request limit (20) after which every DNS resolve will
509 TEST_F(ProxyResolverV8TracingWrapperTest
, InfiniteDNSSequence
) {
511 BoundTestNetLog request_log
;
512 MockCachingHostResolver host_resolver
;
513 MockErrorObserver
* error_observer
= new MockErrorObserver
;
515 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
516 host_resolver
.rules()->AddRule("*", "122.133.144.155");
518 scoped_ptr
<ProxyResolver
> resolver
=
519 CreateResolver(&log
, &host_resolver
, make_scoped_ptr(error_observer
),
520 "global_sideffects3.js");
522 TestCompletionCallback callback
;
523 ProxyInfo proxy_info
;
526 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
527 callback
.callback(), NULL
, request_log
.bound());
528 EXPECT_EQ(ERR_IO_PENDING
, rv
);
529 EXPECT_EQ(OK
, callback
.WaitForResult());
531 EXPECT_EQ(20u, host_resolver
.num_resolve());
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-"
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-"
540 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(ProxyResolverV8TracingWrapperTest
, 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());
633 EXPECT_TRUE(LogContainsEvent(entries
, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
634 NetLog::PHASE_NONE
));
635 EXPECT_TRUE(LogContainsEvent(entries
, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT
,
636 NetLog::PHASE_NONE
));
638 EXPECT_EQ("{\"message\":\"Watsup\"}", entries
[0].GetParamsJson());
639 EXPECT_EQ("{\"message\":\"Watsup2\"}", entries
[1].GetParamsJson());
642 // Tests a PAC script which does DNS resolves during initialization.
643 TEST_F(ProxyResolverV8TracingWrapperTest
, DnsDuringInit
) {
644 // Test with both both a host resolver that always completes asynchronously,
645 // and then again with one that completes synchronously.
646 DnsDuringInitHelper(false);
647 DnsDuringInitHelper(true);
650 void CrashCallback(int) {
651 // Be extra sure that if the callback ever gets invoked, the test will fail.
655 // Start some requests, cancel them all, and then destroy the resolver.
656 // Note the execution order for this test can vary. Since multiple
657 // threads are involved, the cancellation may be received a different
659 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelAll
) {
660 MockCachingHostResolver host_resolver
;
661 MockErrorObserver
* error_observer
= new MockErrorObserver
;
663 host_resolver
.rules()->AddSimulatedFailure("*");
665 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
666 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
668 const size_t kNumRequests
= 5;
669 ProxyInfo proxy_info
[kNumRequests
];
670 ProxyResolver::RequestHandle request
[kNumRequests
];
672 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
673 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
[i
],
674 base::Bind(&CrashCallback
), &request
[i
],
676 EXPECT_EQ(ERR_IO_PENDING
, rv
);
679 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
680 resolver
->CancelRequest(request
[i
]);
684 // Note the execution order for this test can vary. Since multiple
685 // threads are involved, the cancellation may be received a different
687 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelSome
) {
688 MockCachingHostResolver host_resolver
;
689 MockErrorObserver
* error_observer
= new MockErrorObserver
;
691 host_resolver
.rules()->AddSimulatedFailure("*");
693 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
694 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
696 ProxyInfo proxy_info1
;
697 ProxyInfo proxy_info2
;
698 ProxyResolver::RequestHandle request1
;
699 ProxyResolver::RequestHandle request2
;
700 TestCompletionCallback callback
;
702 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
703 base::Bind(&CrashCallback
), &request1
,
705 EXPECT_EQ(ERR_IO_PENDING
, rv
);
707 rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info2
,
708 callback
.callback(), &request2
, BoundNetLog());
709 EXPECT_EQ(ERR_IO_PENDING
, rv
);
711 resolver
->CancelRequest(request1
);
713 EXPECT_EQ(OK
, callback
.WaitForResult());
716 // Cancel a request after it has finished running on the worker thread, and has
717 // posted a task the completion task back to origin thread.
718 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelWhilePendingCompletionTask
) {
719 MockCachingHostResolver host_resolver
;
720 MockErrorObserver
* error_observer
= new MockErrorObserver
;
722 host_resolver
.rules()->AddSimulatedFailure("*");
724 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
725 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "error.js");
727 ProxyInfo proxy_info1
;
728 ProxyInfo proxy_info2
;
729 ProxyResolver::RequestHandle request1
;
730 ProxyResolver::RequestHandle request2
;
731 TestCompletionCallback callback
;
733 int rv
= resolver
->GetProxyForURL(GURL("http://throw-an-error/"),
734 &proxy_info1
, base::Bind(&CrashCallback
),
735 &request1
, BoundNetLog());
736 EXPECT_EQ(ERR_IO_PENDING
, rv
);
738 // Wait until the first request has finished running on the worker thread.
739 // Cancel the first request, while it has a pending completion task on
740 // the origin thread.
741 error_observer
->RunOnError(base::Bind(&ProxyResolver::CancelRequest
,
742 base::Unretained(resolver
.get()),
745 // Start another request, to make sure it is able to complete.
746 rv
= resolver
->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
747 &proxy_info2
, callback
.callback(), &request2
,
749 EXPECT_EQ(ERR_IO_PENDING
, rv
);
751 EXPECT_EQ(OK
, callback
.WaitForResult());
753 EXPECT_EQ("i-approve-this-message:42", proxy_info2
.proxy_server().ToURI());
756 // This implementation of HostResolver allows blocking until a resolve request
757 // has been received. The resolve requests it receives will never be completed.
758 class BlockableHostResolver
: public HostResolver
{
760 BlockableHostResolver()
761 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
763 int Resolve(const RequestInfo
& info
,
764 RequestPriority priority
,
765 AddressList
* addresses
,
766 const CompletionCallback
& callback
,
767 RequestHandle
* out_req
,
768 const BoundNetLog
& net_log
) override
{
769 EXPECT_FALSE(callback
.is_null());
770 EXPECT_TRUE(out_req
);
772 if (!action_
.is_null())
775 // Indicate to the caller that a request was received.
776 EXPECT_TRUE(waiting_for_resolve_
);
777 base::MessageLoop::current()->Quit();
779 // This line is intentionally after action_.Run(), since one of the
780 // tests does a cancellation inside of Resolve(), and it is more
781 // interesting if *out_req hasn't been written yet at that point.
782 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
784 // Return ERR_IO_PENDING as this request will NEVER be completed.
785 // Expectation is for the caller to later cancel the request.
786 return ERR_IO_PENDING
;
789 int ResolveFromCache(const RequestInfo
& info
,
790 AddressList
* addresses
,
791 const BoundNetLog
& net_log
) override
{
793 return ERR_DNS_CACHE_MISS
;
796 void CancelRequest(RequestHandle req
) override
{
797 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
798 num_cancelled_requests_
++;
801 void SetAction(const base::Callback
<void(void)>& action
) { action_
= action
; }
803 // Waits until Resolve() has been called.
804 void WaitUntilRequestIsReceived() {
805 waiting_for_resolve_
= true;
806 base::MessageLoop::current()->Run();
807 DCHECK(waiting_for_resolve_
);
808 waiting_for_resolve_
= false;
811 int num_cancelled_requests() const { return num_cancelled_requests_
; }
814 int num_cancelled_requests_
;
815 bool waiting_for_resolve_
;
816 base::Callback
<void(void)> action_
;
819 // This cancellation test exercises a more predictable cancellation codepath --
820 // when the request has an outstanding DNS request in flight.
821 TEST_F(ProxyResolverV8TracingWrapperTest
,
822 CancelWhileOutstandingNonBlockingDns
) {
823 BlockableHostResolver host_resolver
;
824 MockErrorObserver
* error_observer
= new MockErrorObserver
;
826 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
827 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
829 ProxyInfo proxy_info1
;
830 ProxyInfo proxy_info2
;
831 ProxyResolver::RequestHandle request1
;
832 ProxyResolver::RequestHandle request2
;
834 int rv
= resolver
->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1
,
835 base::Bind(&CrashCallback
), &request1
,
838 EXPECT_EQ(ERR_IO_PENDING
, rv
);
840 host_resolver
.WaitUntilRequestIsReceived();
842 rv
= resolver
->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2
,
843 base::Bind(&CrashCallback
), &request2
,
846 EXPECT_EQ(ERR_IO_PENDING
, rv
);
848 host_resolver
.WaitUntilRequestIsReceived();
850 resolver
->CancelRequest(request1
);
851 resolver
->CancelRequest(request2
);
853 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
855 // After leaving this scope, the ProxyResolver is destroyed.
856 // This should not cause any problems, as the outstanding work
857 // should have been cancelled.
860 void CancelRequestAndPause(ProxyResolver
* resolver
,
861 ProxyResolver::RequestHandle request
) {
862 resolver
->CancelRequest(request
);
864 // Sleep for a little bit. This makes it more likely for the worker
865 // thread to have returned from its call, and serves as a regression
866 // test for http://crbug.com/173373.
867 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
870 // In non-blocking mode, the worker thread actually does block for
871 // a short time to see if the result is in the DNS cache. Test
872 // cancellation while the worker thread is waiting on this event.
873 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelWhileBlockedInNonBlockingDns
) {
874 BlockableHostResolver host_resolver
;
875 MockErrorObserver
* error_observer
= new MockErrorObserver
;
877 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
878 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
880 ProxyInfo proxy_info
;
881 ProxyResolver::RequestHandle request
;
883 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
884 base::Bind(&CrashCallback
), &request
,
887 EXPECT_EQ(ERR_IO_PENDING
, rv
);
889 host_resolver
.SetAction(
890 base::Bind(CancelRequestAndPause
, resolver
.get(), request
));
892 host_resolver
.WaitUntilRequestIsReceived();
895 // Cancel the request while there is a pending DNS request, however before
896 // the request is sent to the host resolver.
897 TEST_F(ProxyResolverV8TracingWrapperTest
, CancelWhileBlockedInNonBlockingDns2
) {
898 MockCachingHostResolver host_resolver
;
899 MockErrorObserver
* error_observer
= new MockErrorObserver
;
901 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
902 nullptr, &host_resolver
, make_scoped_ptr(error_observer
), "dns.js");
904 ProxyInfo proxy_info
;
905 ProxyResolver::RequestHandle request
;
907 int rv
= resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
908 base::Bind(&CrashCallback
), &request
,
911 EXPECT_EQ(ERR_IO_PENDING
, rv
);
913 // Wait a bit, so the DNS task has hopefully been posted. The test will
914 // work whatever the delay is here, but it is most useful if the delay
915 // is large enough to allow a task to be posted back.
916 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
917 resolver
->CancelRequest(request
);
919 EXPECT_EQ(0u, host_resolver
.num_resolve());
922 TEST_F(ProxyResolverV8TracingWrapperTest
,
923 CancelCreateResolverWhileOutstandingBlockingDns
) {
924 BlockableHostResolver host_resolver
;
925 MockErrorObserver
* error_observer
= new MockErrorObserver
;
927 ProxyResolverFactoryV8TracingWrapper
factory(
928 &host_resolver
, nullptr,
929 base::Bind(&ReturnErrorObserver
,
930 base::Passed(make_scoped_ptr(error_observer
))));
932 scoped_ptr
<ProxyResolver
> resolver
;
933 scoped_ptr
<ProxyResolverFactory::Request
> request
;
934 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
935 &resolver
, base::Bind(&CrashCallback
),
937 EXPECT_EQ(ERR_IO_PENDING
, rv
);
939 host_resolver
.WaitUntilRequestIsReceived();
942 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
945 TEST_F(ProxyResolverV8TracingWrapperTest
,
946 DeleteFactoryWhileOutstandingBlockingDns
) {
947 BlockableHostResolver host_resolver
;
948 MockErrorObserver
* error_observer
= new MockErrorObserver
;
950 scoped_ptr
<ProxyResolver
> resolver
;
951 scoped_ptr
<ProxyResolverFactory::Request
> request
;
953 ProxyResolverFactoryV8TracingWrapper
factory(
954 &host_resolver
, nullptr,
955 base::Bind(&ReturnErrorObserver
,
956 base::Passed(make_scoped_ptr(error_observer
))));
958 int rv
= factory
.CreateProxyResolver(LoadScriptData("dns_during_init.js"),
959 &resolver
, base::Bind(&CrashCallback
),
961 EXPECT_EQ(ERR_IO_PENDING
, rv
);
962 host_resolver
.WaitUntilRequestIsReceived();
964 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
967 TEST_F(ProxyResolverV8TracingWrapperTest
, ErrorLoadingScript
) {
968 BlockableHostResolver host_resolver
;
969 MockErrorObserver
* error_observer
= new MockErrorObserver
;
971 ProxyResolverFactoryV8TracingWrapper
factory(
972 &host_resolver
, nullptr,
973 base::Bind(&ReturnErrorObserver
,
974 base::Passed(make_scoped_ptr(error_observer
))));
976 scoped_ptr
<ProxyResolver
> resolver
;
977 scoped_ptr
<ProxyResolverFactory::Request
> request
;
978 TestCompletionCallback callback
;
980 factory
.CreateProxyResolver(LoadScriptData("error_on_load.js"), &resolver
,
981 callback
.callback(), &request
);
982 EXPECT_EQ(ERR_IO_PENDING
, rv
);
983 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
984 EXPECT_FALSE(resolver
);
987 // This tests that the execution of a PAC script is terminated when the DNS
988 // dependencies are missing. If the test fails, then it will hang.
989 TEST_F(ProxyResolverV8TracingWrapperTest
, Terminate
) {
991 BoundTestNetLog request_log
;
992 MockCachingHostResolver host_resolver
;
993 MockErrorObserver
* error_observer
= new MockErrorObserver
;
995 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
996 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
998 scoped_ptr
<ProxyResolver
> resolver
= CreateResolver(
999 &log
, &host_resolver
, make_scoped_ptr(error_observer
), "terminate.js");
1001 TestCompletionCallback callback
;
1002 ProxyInfo proxy_info
;
1005 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
1006 callback
.callback(), NULL
, request_log
.bound());
1008 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1009 EXPECT_EQ(OK
, callback
.WaitForResult());
1011 // The test does 2 DNS resolutions.
1012 EXPECT_EQ(2u, host_resolver
.num_resolve());
1014 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
1017 EXPECT_EQ("", error_observer
->GetOutput());
1019 EXPECT_EQ(0u, log
.GetSize());
1020 EXPECT_EQ(0u, request_log
.GetSize());
1023 // Tests that multiple instances of ProxyResolverV8TracingWrapper can coexist
1024 // and run correctly at the same time. This is relevant because at the moment
1025 // (time this test was written) each ProxyResolverV8TracingWrapper creates its
1026 // own thread to run V8 on, however each thread is operating on the same
1028 TEST_F(ProxyResolverV8TracingWrapperTest
, MultipleResolvers
) {
1029 // ------------------------
1031 // ------------------------
1032 MockHostResolver host_resolver0
;
1033 host_resolver0
.rules()->AddRuleForAddressFamily("host1", ADDRESS_FAMILY_IPV4
,
1035 host_resolver0
.rules()->AddIPLiteralRule("host1", "::1,192.168.1.1",
1037 host_resolver0
.rules()->AddSimulatedFailure("host2");
1038 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
1039 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
1040 host_resolver0
.rules()->AddSimulatedFailure("host6");
1041 host_resolver0
.rules()->AddRuleForAddressFamily("*", ADDRESS_FAMILY_IPV4
,
1043 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
1044 scoped_ptr
<ProxyResolver
> resolver0
=
1045 CreateResolver(nullptr, &host_resolver0
,
1046 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1048 // ------------------------
1050 // ------------------------
1051 scoped_ptr
<ProxyResolver
> resolver1
=
1052 CreateResolver(nullptr, &host_resolver0
,
1053 make_scoped_ptr(new MockErrorObserver
), "dns.js");
1055 // ------------------------
1057 // ------------------------
1058 scoped_ptr
<ProxyResolver
> resolver2
=
1059 CreateResolver(nullptr, &host_resolver0
,
1060 make_scoped_ptr(new MockErrorObserver
), "simple.js");
1062 // ------------------------
1064 // ------------------------
1065 MockHostResolver host_resolver3
;
1066 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
1067 scoped_ptr
<ProxyResolver
> resolver3
=
1068 CreateResolver(nullptr, &host_resolver3
,
1069 make_scoped_ptr(new MockErrorObserver
), "simple_dns.js");
1071 // ------------------------
1072 // Queue up work for each resolver (which will be running in parallel).
1073 // ------------------------
1075 ProxyResolver
* resolver
[] = {
1076 resolver0
.get(), resolver1
.get(), resolver2
.get(), resolver3
.get(),
1079 const size_t kNumResolvers
= arraysize(resolver
);
1080 const size_t kNumIterations
= 20;
1081 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
1082 TestCompletionCallback callback
[kNumResults
];
1083 ProxyInfo proxy_info
[kNumResults
];
1085 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1086 size_t resolver_i
= i
% kNumResolvers
;
1087 int rv
= resolver
[resolver_i
]->GetProxyForURL(
1088 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
1090 EXPECT_EQ(ERR_IO_PENDING
, rv
);
1093 // ------------------------
1094 // Verify all of the results.
1095 // ------------------------
1097 const char* kExpectedForDnsJs
=
1098 "122.133.144.155-" // myIpAddress()
1099 "null-" // dnsResolve('')
1100 "__1_192.168.1.1-" // dnsResolveEx('host1')
1101 "null-" // dnsResolve('host2')
1102 "166.155.144.33-" // dnsResolve('host3')
1103 "122.133.144.155-" // myIpAddress()
1104 "166.155.144.33-" // dnsResolve('host3')
1105 "__1_192.168.1.1-" // dnsResolveEx('host1')
1106 "122.133.144.155-" // myIpAddress()
1107 "null-" // dnsResolve('host2')
1108 "-" // dnsResolveEx('host6')
1109 "133.122.100.200-" // myIpAddressEx()
1110 "166.155.144.44" // dnsResolve('host1')
1113 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1114 size_t resolver_i
= i
% kNumResolvers
;
1115 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1117 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1119 if (resolver_i
== 0 || resolver_i
== 1) {
1120 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1121 } else if (resolver_i
== 2) {
1122 EXPECT_EQ("foo:99", proxy_uri
);
1123 } else if (resolver_i
== 3) {
1124 EXPECT_EQ("166.155.144.33:",
1125 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));