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/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/values.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/test_completion_callback.h"
18 #include "net/dns/host_cache.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/log/net_log.h"
21 #include "net/proxy/proxy_info.h"
22 #include "testing/gtest/include/gtest/gtest.h"
29 class ProxyResolverV8TracingTest
: public testing::Test
{
31 void TearDown() override
{
32 // Drain any pending messages, which may be left over from cancellation.
33 // This way they get reliably run as part of the current test, rather than
34 // spilling into the next test's execution.
35 base::RunLoop().RunUntilIdle();
39 scoped_refptr
<ProxyResolverScriptData
> LoadScriptData(const char* filename
) {
41 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
42 path
= path
.AppendASCII("net");
43 path
= path
.AppendASCII("data");
44 path
= path
.AppendASCII("proxy_resolver_v8_tracing_unittest");
45 path
= path
.AppendASCII(filename
);
47 // Try to read the file from disk.
48 std::string file_contents
;
49 bool ok
= base::ReadFileToString(path
, &file_contents
);
51 // If we can't load the file from disk, something is misconfigured.
52 EXPECT_TRUE(ok
) << "Failed to read file: " << path
.value();
54 // Load the PAC script into the ProxyResolver.
55 return ProxyResolverScriptData::FromUTF8(file_contents
);
60 explicit MockBindings(HostResolver
* host_resolver
)
61 : host_resolver_(host_resolver
), event_(true, false) {}
63 void Alert(const base::string16
& message
) {
64 base::AutoLock
l(lock_
);
65 alerts_
.push_back(base::UTF16ToASCII(message
));
67 void OnError(int line_number
, const base::string16
& error
) {
68 base::AutoLock
l(lock_
);
69 errors_
.push_back(std::make_pair(line_number
, base::UTF16ToASCII(error
)));
73 HostResolver
* host_resolver() { return host_resolver_
; }
75 std::vector
<std::string
> GetAlerts() {
76 base::AutoLock
l(lock_
);
80 std::vector
<std::pair
<int, std::string
>> GetErrors() {
81 base::AutoLock
l(lock_
);
85 void WaitForError() { event_
.Wait(); }
87 scoped_ptr
<ProxyResolverV8Tracing::Bindings
> CreateBindings() {
88 return make_scoped_ptr(new ForwardingBindings(this));
92 class ForwardingBindings
: public ProxyResolverV8Tracing::Bindings
{
94 ForwardingBindings(MockBindings
* bindings
) : bindings_(bindings
) {}
96 // ProxyResolverV8Tracing::Bindings overrides.
97 void Alert(const base::string16
& message
) override
{
98 bindings_
->Alert(message
);
101 void OnError(int line_number
, const base::string16
& error
) override
{
102 bindings_
->OnError(line_number
, error
);
105 BoundNetLog
GetBoundNetLog() override
{ return BoundNetLog(); }
107 HostResolver
* GetHostResolver() override
{
108 return bindings_
->host_resolver();
112 MockBindings
* bindings_
;
116 std::vector
<std::string
> alerts_
;
117 std::vector
<std::pair
<int, std::string
>> errors_
;
118 HostResolver
* const host_resolver_
;
120 base::WaitableEvent event_
;
123 scoped_ptr
<ProxyResolverV8Tracing
> CreateResolver(
124 scoped_ptr
<ProxyResolverV8Tracing::Bindings
> bindings
,
125 const char* filename
) {
126 scoped_ptr
<ProxyResolverV8Tracing
> resolver
;
127 scoped_ptr
<ProxyResolverV8TracingFactory
> factory(
128 ProxyResolverV8TracingFactory::Create());
129 TestCompletionCallback callback
;
130 scoped_ptr
<ProxyResolverFactory::Request
> request
;
131 factory
->CreateProxyResolverV8Tracing(LoadScriptData(filename
),
132 bindings
.Pass(), &resolver
,
133 callback
.callback(), &request
);
134 EXPECT_EQ(OK
, callback
.WaitForResult());
135 EXPECT_TRUE(resolver
);
136 return resolver
.Pass();
139 TEST_F(ProxyResolverV8TracingTest
, Simple
) {
140 MockCachingHostResolver host_resolver
;
141 MockBindings
mock_bindings(&host_resolver
);
143 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
144 CreateResolver(mock_bindings
.CreateBindings(), "simple.js");
146 TestCompletionCallback callback
;
147 ProxyInfo proxy_info
;
149 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
150 callback
.callback(), NULL
,
151 mock_bindings
.CreateBindings());
153 EXPECT_EQ(OK
, callback
.WaitForResult());
155 EXPECT_EQ("foo:99", proxy_info
.proxy_server().ToURI());
157 EXPECT_EQ(0u, host_resolver
.num_resolve());
159 // There were no alerts or errors.
160 EXPECT_TRUE(mock_bindings
.GetAlerts().empty());
161 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
164 TEST_F(ProxyResolverV8TracingTest
, JavascriptError
) {
165 MockCachingHostResolver host_resolver
;
166 MockBindings
mock_bindings(&host_resolver
);
168 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
169 CreateResolver(mock_bindings
.CreateBindings(), "error.js");
171 TestCompletionCallback callback
;
172 ProxyInfo proxy_info
;
174 resolver
->GetProxyForURL(GURL("http://throw-an-error/"), &proxy_info
,
175 callback
.callback(), NULL
,
176 mock_bindings
.CreateBindings());
178 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
180 EXPECT_EQ(0u, host_resolver
.num_resolve());
182 // Check the output -- there was 1 alert and 1 javascript error.
183 ASSERT_EQ(1u, mock_bindings
.GetAlerts().size());
184 EXPECT_EQ("Prepare to DIE!", mock_bindings
.GetAlerts()[0]);
185 ASSERT_EQ(1u, mock_bindings
.GetErrors().size());
186 EXPECT_EQ(5, mock_bindings
.GetErrors()[0].first
);
187 EXPECT_EQ("Uncaught TypeError: Cannot read property 'split' of null",
188 mock_bindings
.GetErrors()[0].second
);
191 TEST_F(ProxyResolverV8TracingTest
, TooManyAlerts
) {
192 MockCachingHostResolver host_resolver
;
193 MockBindings
mock_bindings(&host_resolver
);
195 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
196 CreateResolver(mock_bindings
.CreateBindings(), "too_many_alerts.js");
198 TestCompletionCallback callback
;
199 ProxyInfo proxy_info
;
201 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
202 callback
.callback(), NULL
,
203 mock_bindings
.CreateBindings());
205 EXPECT_EQ(OK
, callback
.WaitForResult());
207 // Iteration1 does a DNS resolve
208 // Iteration2 exceeds the alert buffer
209 // Iteration3 runs in blocking mode and completes
210 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
212 EXPECT_EQ(1u, host_resolver
.num_resolve());
215 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
217 // Check the alerts -- the script generated 50 alerts.
218 std::vector
<std::string
> alerts
= mock_bindings
.GetAlerts();
219 ASSERT_EQ(50u, alerts
.size());
220 for (size_t i
= 0; i
< alerts
.size(); i
++) {
221 EXPECT_EQ("Gee, all these alerts are silly!", alerts
[i
]);
225 // Verify that buffered alerts cannot grow unboundedly, even when the message is
227 TEST_F(ProxyResolverV8TracingTest
, TooManyEmptyAlerts
) {
228 MockCachingHostResolver host_resolver
;
229 MockBindings
mock_bindings(&host_resolver
);
231 scoped_ptr
<ProxyResolverV8Tracing
> resolver
= CreateResolver(
232 mock_bindings
.CreateBindings(), "too_many_empty_alerts.js");
234 TestCompletionCallback callback
;
235 ProxyInfo proxy_info
;
237 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
238 callback
.callback(), NULL
,
239 mock_bindings
.CreateBindings());
241 EXPECT_EQ(OK
, callback
.WaitForResult());
243 EXPECT_EQ("foo:3", proxy_info
.proxy_server().ToURI());
245 EXPECT_EQ(1u, host_resolver
.num_resolve());
248 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
250 // Check the alerts -- the script generated 1000 alerts.
251 std::vector
<std::string
> alerts
= mock_bindings
.GetAlerts();
252 ASSERT_EQ(1000u, alerts
.size());
253 for (size_t i
= 0; i
< alerts
.size(); i
++) {
254 EXPECT_EQ("", alerts
[i
]);
258 // This test runs a PAC script that issues a sequence of DNS resolves. The test
259 // verifies the final result, and that the underlying DNS resolver received
260 // the correct set of queries.
261 TEST_F(ProxyResolverV8TracingTest
, Dns
) {
262 MockCachingHostResolver host_resolver
;
263 MockBindings
mock_bindings(&host_resolver
);
265 host_resolver
.rules()->AddRuleForAddressFamily(
266 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
267 host_resolver
.rules()
268 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
269 host_resolver
.rules()->AddSimulatedFailure("host2");
270 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
271 host_resolver
.rules()->AddRule("host5", "166.155.144.55");
272 host_resolver
.rules()->AddSimulatedFailure("host6");
273 host_resolver
.rules()->AddRuleForAddressFamily(
274 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
275 host_resolver
.rules()->AddRule("*", "133.122.100.200");
277 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
278 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
280 TestCompletionCallback callback
;
281 ProxyInfo proxy_info
;
283 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
284 callback
.callback(), NULL
,
285 mock_bindings
.CreateBindings());
287 EXPECT_EQ(OK
, callback
.WaitForResult());
289 // The test does 13 DNS resolution, however only 7 of them are unique.
290 EXPECT_EQ(7u, host_resolver
.num_resolve());
292 const char* kExpectedResult
=
293 "122.133.144.155-" // myIpAddress()
294 "null-" // dnsResolve('')
295 "__1_192.168.1.1-" // dnsResolveEx('host1')
296 "null-" // dnsResolve('host2')
297 "166.155.144.33-" // dnsResolve('host3')
298 "122.133.144.155-" // myIpAddress()
299 "166.155.144.33-" // dnsResolve('host3')
300 "__1_192.168.1.1-" // dnsResolveEx('host1')
301 "122.133.144.155-" // myIpAddress()
302 "null-" // dnsResolve('host2')
303 "-" // dnsResolveEx('host6')
304 "133.122.100.200-" // myIpAddressEx()
305 "166.155.144.44" // dnsResolve('host1')
308 EXPECT_EQ(kExpectedResult
, proxy_info
.proxy_server().ToURI());
311 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
313 // The script generated 1 alert.
314 ASSERT_EQ(1u, mock_bindings
.GetAlerts().size());
315 EXPECT_EQ("iteration: 7", mock_bindings
.GetAlerts()[0]);
318 // This test runs a PAC script that does "myIpAddress()" followed by
319 // "dnsResolve()". This requires 2 restarts. However once the HostResolver's
320 // cache is warmed, subsequent calls should take 0 restarts.
321 TEST_F(ProxyResolverV8TracingTest
, DnsChecksCache
) {
322 MockCachingHostResolver host_resolver
;
323 MockBindings
mock_bindings(&host_resolver
);
325 host_resolver
.rules()->AddRule("foopy", "166.155.144.11");
326 host_resolver
.rules()->AddRule("*", "122.133.144.155");
328 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
329 CreateResolver(mock_bindings
.CreateBindings(), "simple_dns.js");
331 TestCompletionCallback callback1
;
332 TestCompletionCallback callback2
;
333 ProxyInfo proxy_info
;
335 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
336 callback1
.callback(), NULL
,
337 mock_bindings
.CreateBindings());
339 EXPECT_EQ(OK
, callback1
.WaitForResult());
341 // The test does 2 DNS resolutions.
342 EXPECT_EQ(2u, host_resolver
.num_resolve());
344 // The first request took 2 restarts, hence on g_iteration=3.
345 EXPECT_EQ("166.155.144.11:3", proxy_info
.proxy_server().ToURI());
347 resolver
->GetProxyForURL(GURL("http://foopy/req2"), &proxy_info
,
348 callback2
.callback(), NULL
,
349 mock_bindings
.CreateBindings());
351 EXPECT_EQ(OK
, callback2
.WaitForResult());
353 EXPECT_EQ(4u, host_resolver
.num_resolve());
355 // This time no restarts were required, so g_iteration incremented by 1.
356 EXPECT_EQ("166.155.144.11:4", proxy_info
.proxy_server().ToURI());
358 // There were no alerts or errors.
359 EXPECT_TRUE(mock_bindings
.GetAlerts().empty());
360 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
363 // This test runs a weird PAC script that was designed to defeat the DNS tracing
364 // optimization. The proxy resolver should detect the inconsistency and
365 // fall-back to synchronous mode execution.
366 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous1
) {
367 MockCachingHostResolver host_resolver
;
368 MockBindings
mock_bindings(&host_resolver
);
370 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
371 host_resolver
.rules()->AddRule("crazy4", "133.199.111.4");
372 host_resolver
.rules()->AddRule("*", "122.133.144.155");
374 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
375 CreateResolver(mock_bindings
.CreateBindings(), "global_sideffects1.js");
377 TestCompletionCallback callback
;
378 ProxyInfo proxy_info
;
380 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
381 callback
.callback(), NULL
,
382 mock_bindings
.CreateBindings());
383 EXPECT_EQ(OK
, callback
.WaitForResult());
385 // The script itself only does 2 DNS resolves per execution, however it
386 // constructs the hostname using a global counter which changes on each
388 EXPECT_EQ(3u, host_resolver
.num_resolve());
390 EXPECT_EQ("166.155.144.11-133.199.111.4:100",
391 proxy_info
.proxy_server().ToURI());
394 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
396 ASSERT_EQ(1u, mock_bindings
.GetAlerts().size());
397 EXPECT_EQ("iteration: 4", mock_bindings
.GetAlerts()[0]);
400 // This test runs a weird PAC script that was designed to defeat the DNS tracing
401 // optimization. The proxy resolver should detect the inconsistency and
402 // fall-back to synchronous mode execution.
403 TEST_F(ProxyResolverV8TracingTest
, FallBackToSynchronous2
) {
404 MockCachingHostResolver host_resolver
;
405 MockBindings
mock_bindings(&host_resolver
);
407 host_resolver
.rules()->AddRule("host1", "166.155.144.11");
408 host_resolver
.rules()->AddRule("host2", "166.155.144.22");
409 host_resolver
.rules()->AddRule("host3", "166.155.144.33");
410 host_resolver
.rules()->AddRule("host4", "166.155.144.44");
411 host_resolver
.rules()->AddRule("*", "122.133.144.155");
413 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
414 CreateResolver(mock_bindings
.CreateBindings(), "global_sideffects2.js");
416 TestCompletionCallback callback
;
417 ProxyInfo proxy_info
;
419 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
420 callback
.callback(), NULL
,
421 mock_bindings
.CreateBindings());
422 EXPECT_EQ(OK
, callback
.WaitForResult());
424 EXPECT_EQ(3u, host_resolver
.num_resolve());
426 EXPECT_EQ("166.155.144.44:100", proxy_info
.proxy_server().ToURI());
428 // There were no alerts or errors.
429 EXPECT_TRUE(mock_bindings
.GetAlerts().empty());
430 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
433 // This test runs a weird PAC script that yields a never ending sequence
434 // of DNS resolves when restarting. Running it will hit the maximum
435 // DNS resolves per request limit (20) after which every DNS resolve will
437 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence
) {
438 MockCachingHostResolver host_resolver
;
439 MockBindings
mock_bindings(&host_resolver
);
441 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
442 host_resolver
.rules()->AddRule("*", "122.133.144.155");
444 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
445 CreateResolver(mock_bindings
.CreateBindings(), "global_sideffects3.js");
447 TestCompletionCallback callback
;
448 ProxyInfo proxy_info
;
450 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
451 callback
.callback(), NULL
,
452 mock_bindings
.CreateBindings());
453 EXPECT_EQ(OK
, callback
.WaitForResult());
455 EXPECT_EQ(20u, host_resolver
.num_resolve());
458 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
459 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
460 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
461 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
462 "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
463 "null:21", proxy_info
.proxy_server().ToURI());
466 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
469 EXPECT_EQ(1u, mock_bindings
.GetAlerts().size());
470 EXPECT_EQ("iteration: 21", mock_bindings
.GetAlerts()[0]);
473 // This test runs a weird PAC script that yields a never ending sequence
474 // of DNS resolves when restarting. Running it will hit the maximum
475 // DNS resolves per request limit (20) after which every DNS resolve will
477 TEST_F(ProxyResolverV8TracingTest
, InfiniteDNSSequence2
) {
478 MockCachingHostResolver host_resolver
;
479 MockBindings
mock_bindings(&host_resolver
);
481 host_resolver
.rules()->AddRule("host*", "166.155.144.11");
482 host_resolver
.rules()->AddRule("*", "122.133.144.155");
484 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
485 CreateResolver(mock_bindings
.CreateBindings(), "global_sideffects4.js");
487 TestCompletionCallback callback
;
488 ProxyInfo proxy_info
;
490 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
491 callback
.callback(), NULL
,
492 mock_bindings
.CreateBindings());
493 EXPECT_EQ(OK
, callback
.WaitForResult());
495 EXPECT_EQ(20u, host_resolver
.num_resolve());
497 EXPECT_EQ("null21:34", proxy_info
.proxy_server().ToURI());
500 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
503 EXPECT_EQ(1u, mock_bindings
.GetAlerts().size());
504 EXPECT_EQ("iteration: 21", mock_bindings
.GetAlerts()[0]);
507 void DnsDuringInitHelper(bool synchronous_host_resolver
) {
508 MockCachingHostResolver host_resolver
;
509 MockBindings
mock_bindings(&host_resolver
);
510 host_resolver
.set_synchronous_mode(synchronous_host_resolver
);
512 host_resolver
.rules()->AddRule("host1", "91.13.12.1");
513 host_resolver
.rules()->AddRule("host2", "91.13.12.2");
515 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
516 CreateResolver(mock_bindings
.CreateBindings(), "dns_during_init.js");
518 // Initialization did 2 dnsResolves.
519 EXPECT_EQ(2u, host_resolver
.num_resolve());
521 host_resolver
.rules()->ClearRules();
522 host_resolver
.GetHostCache()->clear();
524 host_resolver
.rules()->AddRule("host1", "145.88.13.3");
525 host_resolver
.rules()->AddRule("host2", "137.89.8.45");
527 TestCompletionCallback callback
;
528 ProxyInfo proxy_info
;
530 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
531 callback
.callback(), NULL
,
532 mock_bindings
.CreateBindings());
533 EXPECT_EQ(OK
, callback
.WaitForResult());
535 // Fetched host1 and host2 again, since the ones done during initialization
536 // should not have been cached.
537 EXPECT_EQ(4u, host_resolver
.num_resolve());
539 EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
540 proxy_info
.proxy_server().ToURI());
543 ASSERT_EQ(2u, mock_bindings
.GetAlerts().size());
544 EXPECT_EQ("Watsup", mock_bindings
.GetAlerts()[0]);
545 EXPECT_EQ("Watsup2", mock_bindings
.GetAlerts()[1]);
548 // Tests a PAC script which does DNS resolves during initialization.
549 TEST_F(ProxyResolverV8TracingTest
, DnsDuringInit
) {
550 // Test with both both a host resolver that always completes asynchronously,
551 // and then again with one that completes synchronously.
552 DnsDuringInitHelper(false);
553 DnsDuringInitHelper(true);
556 void CrashCallback(int) {
557 // Be extra sure that if the callback ever gets invoked, the test will fail.
561 // Start some requests, cancel them all, and then destroy the resolver.
562 // Note the execution order for this test can vary. Since multiple
563 // threads are involved, the cancellation may be received a different
565 TEST_F(ProxyResolverV8TracingTest
, CancelAll
) {
566 MockCachingHostResolver host_resolver
;
567 MockBindings
mock_bindings(&host_resolver
);
569 host_resolver
.rules()->AddSimulatedFailure("*");
571 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
572 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
574 const size_t kNumRequests
= 5;
575 ProxyInfo proxy_info
[kNumRequests
];
576 ProxyResolver::RequestHandle request
[kNumRequests
];
578 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
579 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
[i
],
580 base::Bind(&CrashCallback
), &request
[i
],
581 mock_bindings
.CreateBindings());
584 for (size_t i
= 0; i
< kNumRequests
; ++i
) {
585 resolver
->CancelRequest(request
[i
]);
589 // Note the execution order for this test can vary. Since multiple
590 // threads are involved, the cancellation may be received a different
592 TEST_F(ProxyResolverV8TracingTest
, CancelSome
) {
593 MockCachingHostResolver host_resolver
;
594 MockBindings
mock_bindings(&host_resolver
);
596 host_resolver
.rules()->AddSimulatedFailure("*");
598 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
599 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
601 ProxyInfo proxy_info1
;
602 ProxyInfo proxy_info2
;
603 ProxyResolver::RequestHandle request1
;
604 ProxyResolver::RequestHandle request2
;
605 TestCompletionCallback callback
;
607 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
608 base::Bind(&CrashCallback
), &request1
,
609 mock_bindings
.CreateBindings());
610 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info2
,
611 callback
.callback(), &request2
,
612 mock_bindings
.CreateBindings());
614 resolver
->CancelRequest(request1
);
616 EXPECT_EQ(OK
, callback
.WaitForResult());
619 // Cancel a request after it has finished running on the worker thread, and has
620 // posted a task the completion task back to origin thread.
621 TEST_F(ProxyResolverV8TracingTest
, CancelWhilePendingCompletionTask
) {
622 MockCachingHostResolver host_resolver
;
623 MockBindings
mock_bindings(&host_resolver
);
625 host_resolver
.rules()->AddSimulatedFailure("*");
627 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
628 CreateResolver(mock_bindings
.CreateBindings(), "error.js");
630 ProxyInfo proxy_info1
;
631 ProxyInfo proxy_info2
;
632 ProxyInfo proxy_info3
;
633 ProxyResolver::RequestHandle request1
;
634 ProxyResolver::RequestHandle request2
;
635 ProxyResolver::RequestHandle request3
;
636 TestCompletionCallback callback
;
638 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info1
,
639 base::Bind(&CrashCallback
), &request1
,
640 mock_bindings
.CreateBindings());
642 resolver
->GetProxyForURL(GURL("http://throw-an-error"), &proxy_info2
,
643 callback
.callback(), &request2
,
644 mock_bindings
.CreateBindings());
646 // Wait until the first request has finished running on the worker thread.
647 // (The second request will output an error).
648 mock_bindings
.WaitForError();
650 // Cancel the first request, while it has a pending completion task on
651 // the origin thread.
652 resolver
->CancelRequest(request1
);
654 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
656 // Start another request, to make sure it is able to complete.
657 resolver
->GetProxyForURL(GURL("http://i-have-no-idea-what-im-doing/"),
658 &proxy_info3
, callback
.callback(), &request3
,
659 mock_bindings
.CreateBindings());
661 EXPECT_EQ(OK
, callback
.WaitForResult());
663 EXPECT_EQ("i-approve-this-message:42",
664 proxy_info3
.proxy_server().ToURI());
667 // This implementation of HostResolver allows blocking until a resolve request
668 // has been received. The resolve requests it receives will never be completed.
669 class BlockableHostResolver
: public HostResolver
{
671 BlockableHostResolver()
672 : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
674 int Resolve(const RequestInfo
& info
,
675 RequestPriority priority
,
676 AddressList
* addresses
,
677 const CompletionCallback
& callback
,
678 RequestHandle
* out_req
,
679 const BoundNetLog
& net_log
) override
{
680 EXPECT_FALSE(callback
.is_null());
681 EXPECT_TRUE(out_req
);
683 if (!action_
.is_null())
686 // Indicate to the caller that a request was received.
687 EXPECT_TRUE(waiting_for_resolve_
);
688 base::MessageLoop::current()->Quit();
690 // This line is intentionally after action_.Run(), since one of the
691 // tests does a cancellation inside of Resolve(), and it is more
692 // interesting if *out_req hasn't been written yet at that point.
693 *out_req
= reinterpret_cast<RequestHandle
*>(1); // Magic value.
695 // Return ERR_IO_PENDING as this request will NEVER be completed.
696 // Expectation is for the caller to later cancel the request.
697 return ERR_IO_PENDING
;
700 int ResolveFromCache(const RequestInfo
& info
,
701 AddressList
* addresses
,
702 const BoundNetLog
& net_log
) override
{
704 return ERR_DNS_CACHE_MISS
;
707 void CancelRequest(RequestHandle req
) override
{
708 EXPECT_EQ(reinterpret_cast<RequestHandle
*>(1), req
);
709 num_cancelled_requests_
++;
712 void SetAction(const base::Callback
<void(void)>& action
) {
716 // Waits until Resolve() has been called.
717 void WaitUntilRequestIsReceived() {
718 waiting_for_resolve_
= true;
719 base::MessageLoop::current()->Run();
720 DCHECK(waiting_for_resolve_
);
721 waiting_for_resolve_
= false;
724 int num_cancelled_requests() const {
725 return num_cancelled_requests_
;
729 int num_cancelled_requests_
;
730 bool waiting_for_resolve_
;
731 base::Callback
<void(void)> action_
;
734 // This cancellation test exercises a more predictable cancellation codepath --
735 // when the request has an outstanding DNS request in flight.
736 TEST_F(ProxyResolverV8TracingTest
, CancelWhileOutstandingNonBlockingDns
) {
737 BlockableHostResolver host_resolver
;
738 MockBindings
mock_bindings(&host_resolver
);
740 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
741 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
743 ProxyInfo proxy_info1
;
744 ProxyInfo proxy_info2
;
745 ProxyResolver::RequestHandle request1
;
746 ProxyResolver::RequestHandle request2
;
748 resolver
->GetProxyForURL(GURL("http://foo/req1"), &proxy_info1
,
749 base::Bind(&CrashCallback
), &request1
,
750 mock_bindings
.CreateBindings());
752 host_resolver
.WaitUntilRequestIsReceived();
754 resolver
->GetProxyForURL(GURL("http://foo/req2"), &proxy_info2
,
755 base::Bind(&CrashCallback
), &request2
,
756 mock_bindings
.CreateBindings());
758 host_resolver
.WaitUntilRequestIsReceived();
760 resolver
->CancelRequest(request1
);
761 resolver
->CancelRequest(request2
);
763 EXPECT_EQ(2, host_resolver
.num_cancelled_requests());
765 // After leaving this scope, the ProxyResolver is destroyed.
766 // This should not cause any problems, as the outstanding work
767 // should have been cancelled.
770 void CancelRequestAndPause(ProxyResolverV8Tracing
* resolver
,
771 ProxyResolver::RequestHandle request
) {
772 resolver
->CancelRequest(request
);
774 // Sleep for a little bit. This makes it more likely for the worker
775 // thread to have returned from its call, and serves as a regression
776 // test for http://crbug.com/173373.
777 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
780 // In non-blocking mode, the worker thread actually does block for
781 // a short time to see if the result is in the DNS cache. Test
782 // cancellation while the worker thread is waiting on this event.
783 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns
) {
784 BlockableHostResolver host_resolver
;
785 MockBindings
mock_bindings(&host_resolver
);
787 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
788 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
790 ProxyInfo proxy_info
;
791 ProxyResolver::RequestHandle request
;
793 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
794 base::Bind(&CrashCallback
), &request
,
795 mock_bindings
.CreateBindings());
797 host_resolver
.SetAction(
798 base::Bind(CancelRequestAndPause
, resolver
.get(), request
));
800 host_resolver
.WaitUntilRequestIsReceived();
802 // At this point the host resolver ran Resolve(), and should have cancelled
805 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
808 // Cancel the request while there is a pending DNS request, however before
809 // the request is sent to the host resolver.
810 TEST_F(ProxyResolverV8TracingTest
, CancelWhileBlockedInNonBlockingDns2
) {
811 MockCachingHostResolver host_resolver
;
812 MockBindings
mock_bindings(&host_resolver
);
814 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
815 CreateResolver(mock_bindings
.CreateBindings(), "dns.js");
817 ProxyInfo proxy_info
;
818 ProxyResolver::RequestHandle request
;
820 resolver
->GetProxyForURL(GURL("http://foo/"), &proxy_info
,
821 base::Bind(&CrashCallback
), &request
,
822 mock_bindings
.CreateBindings());
824 // Wait a bit, so the DNS task has hopefully been posted. The test will
825 // work whatever the delay is here, but it is most useful if the delay
826 // is large enough to allow a task to be posted back.
827 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
828 resolver
->CancelRequest(request
);
830 EXPECT_EQ(0u, host_resolver
.num_resolve());
833 TEST_F(ProxyResolverV8TracingTest
,
834 CancelCreateResolverWhileOutstandingBlockingDns
) {
835 BlockableHostResolver host_resolver
;
836 MockBindings
mock_bindings(&host_resolver
);
838 scoped_ptr
<ProxyResolverV8TracingFactory
> factory(
839 ProxyResolverV8TracingFactory::Create());
840 scoped_ptr
<ProxyResolverV8Tracing
> resolver
;
841 scoped_ptr
<ProxyResolverFactory::Request
> request
;
842 factory
->CreateProxyResolverV8Tracing(
843 LoadScriptData("dns_during_init.js"), mock_bindings
.CreateBindings(),
844 &resolver
, base::Bind(&CrashCallback
), &request
);
846 host_resolver
.WaitUntilRequestIsReceived();
849 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
852 TEST_F(ProxyResolverV8TracingTest
, DeleteFactoryWhileOutstandingBlockingDns
) {
853 BlockableHostResolver host_resolver
;
854 MockBindings
mock_bindings(&host_resolver
);
856 scoped_ptr
<ProxyResolverV8Tracing
> resolver
;
857 scoped_ptr
<ProxyResolverFactory::Request
> request
;
859 scoped_ptr
<ProxyResolverV8TracingFactory
> factory(
860 ProxyResolverV8TracingFactory::Create());
862 factory
->CreateProxyResolverV8Tracing(
863 LoadScriptData("dns_during_init.js"), mock_bindings
.CreateBindings(),
864 &resolver
, base::Bind(&CrashCallback
), &request
);
865 host_resolver
.WaitUntilRequestIsReceived();
867 EXPECT_EQ(1, host_resolver
.num_cancelled_requests());
870 TEST_F(ProxyResolverV8TracingTest
, ErrorLoadingScript
) {
871 BlockableHostResolver host_resolver
;
872 MockBindings
mock_bindings(&host_resolver
);
874 scoped_ptr
<ProxyResolverV8TracingFactory
> factory(
875 ProxyResolverV8TracingFactory::Create());
876 scoped_ptr
<ProxyResolverV8Tracing
> resolver
;
877 scoped_ptr
<ProxyResolverFactory::Request
> request
;
878 TestCompletionCallback callback
;
879 factory
->CreateProxyResolverV8Tracing(
880 LoadScriptData("error_on_load.js"), mock_bindings
.CreateBindings(),
881 &resolver
, callback
.callback(), &request
);
883 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, callback
.WaitForResult());
884 EXPECT_FALSE(resolver
);
887 // This tests that the execution of a PAC script is terminated when the DNS
888 // dependencies are missing. If the test fails, then it will hang.
889 TEST_F(ProxyResolverV8TracingTest
, Terminate
) {
890 MockCachingHostResolver host_resolver
;
891 MockBindings
mock_bindings(&host_resolver
);
893 host_resolver
.rules()->AddRule("host1", "182.111.0.222");
894 host_resolver
.rules()->AddRule("host2", "111.33.44.55");
896 scoped_ptr
<ProxyResolverV8Tracing
> resolver
=
897 CreateResolver(mock_bindings
.CreateBindings(), "terminate.js");
899 TestCompletionCallback callback
;
900 ProxyInfo proxy_info
;
902 resolver
->GetProxyForURL(GURL("http://foopy/req1"), &proxy_info
,
903 callback
.callback(), NULL
,
904 mock_bindings
.CreateBindings());
905 EXPECT_EQ(OK
, callback
.WaitForResult());
907 // The test does 2 DNS resolutions.
908 EXPECT_EQ(2u, host_resolver
.num_resolve());
910 EXPECT_EQ("foopy:3", proxy_info
.proxy_server().ToURI());
912 // No errors or alerts.
913 EXPECT_TRUE(mock_bindings
.GetErrors().empty());
914 EXPECT_TRUE(mock_bindings
.GetAlerts().empty());
917 // Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
918 // correctly at the same time. This is relevant because at the moment (time
919 // this test was written) each ProxyResolverV8Tracing creates its own thread to
920 // run V8 on, however each thread is operating on the same v8::Isolate.
921 TEST_F(ProxyResolverV8TracingTest
, MultipleResolvers
) {
922 // ------------------------
924 // ------------------------
925 MockHostResolver host_resolver0
;
926 MockBindings
mock_bindings0(&host_resolver0
);
927 host_resolver0
.rules()->AddRuleForAddressFamily(
928 "host1", ADDRESS_FAMILY_IPV4
, "166.155.144.44");
929 host_resolver0
.rules()
930 ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
931 host_resolver0
.rules()->AddSimulatedFailure("host2");
932 host_resolver0
.rules()->AddRule("host3", "166.155.144.33");
933 host_resolver0
.rules()->AddRule("host5", "166.155.144.55");
934 host_resolver0
.rules()->AddSimulatedFailure("host6");
935 host_resolver0
.rules()->AddRuleForAddressFamily(
936 "*", ADDRESS_FAMILY_IPV4
, "122.133.144.155");
937 host_resolver0
.rules()->AddRule("*", "133.122.100.200");
938 scoped_ptr
<ProxyResolverV8Tracing
> resolver0
=
939 CreateResolver(mock_bindings0
.CreateBindings(), "dns.js");
941 // ------------------------
943 // ------------------------
944 scoped_ptr
<ProxyResolverV8Tracing
> resolver1
=
945 CreateResolver(mock_bindings0
.CreateBindings(), "dns.js");
947 // ------------------------
949 // ------------------------
950 scoped_ptr
<ProxyResolverV8Tracing
> resolver2
=
951 CreateResolver(mock_bindings0
.CreateBindings(), "simple.js");
953 // ------------------------
955 // ------------------------
956 MockHostResolver host_resolver3
;
957 MockBindings
mock_bindings3(&host_resolver3
);
958 host_resolver3
.rules()->AddRule("foo", "166.155.144.33");
959 scoped_ptr
<ProxyResolverV8Tracing
> resolver3
=
960 CreateResolver(mock_bindings3
.CreateBindings(), "simple_dns.js");
962 // ------------------------
963 // Queue up work for each resolver (which will be running in parallel).
964 // ------------------------
966 ProxyResolverV8Tracing
* resolver
[] = {
967 resolver0
.get(), resolver1
.get(), resolver2
.get(), resolver3
.get(),
970 const size_t kNumResolvers
= arraysize(resolver
);
971 const size_t kNumIterations
= 20;
972 const size_t kNumResults
= kNumResolvers
* kNumIterations
;
973 TestCompletionCallback callback
[kNumResults
];
974 ProxyInfo proxy_info
[kNumResults
];
976 for (size_t i
= 0; i
< kNumResults
; ++i
) {
977 size_t resolver_i
= i
% kNumResolvers
;
978 resolver
[resolver_i
]->GetProxyForURL(
979 GURL("http://foo/"), &proxy_info
[i
], callback
[i
].callback(), NULL
,
980 resolver_i
== 3 ? mock_bindings3
.CreateBindings()
981 : mock_bindings0
.CreateBindings());
984 // ------------------------
985 // Verify all of the results.
986 // ------------------------
988 const char* kExpectedForDnsJs
=
989 "122.133.144.155-" // myIpAddress()
990 "null-" // dnsResolve('')
991 "__1_192.168.1.1-" // dnsResolveEx('host1')
992 "null-" // dnsResolve('host2')
993 "166.155.144.33-" // dnsResolve('host3')
994 "122.133.144.155-" // myIpAddress()
995 "166.155.144.33-" // dnsResolve('host3')
996 "__1_192.168.1.1-" // dnsResolveEx('host1')
997 "122.133.144.155-" // myIpAddress()
998 "null-" // dnsResolve('host2')
999 "-" // dnsResolveEx('host6')
1000 "133.122.100.200-" // myIpAddressEx()
1001 "166.155.144.44" // dnsResolve('host1')
1004 for (size_t i
= 0; i
< kNumResults
; ++i
) {
1005 size_t resolver_i
= i
% kNumResolvers
;
1006 EXPECT_EQ(OK
, callback
[i
].WaitForResult());
1008 std::string proxy_uri
= proxy_info
[i
].proxy_server().ToURI();
1010 if (resolver_i
== 0 || resolver_i
== 1) {
1011 EXPECT_EQ(kExpectedForDnsJs
, proxy_uri
);
1012 } else if (resolver_i
== 2) {
1013 EXPECT_EQ("foo:99", proxy_uri
);
1014 } else if (resolver_i
== 3) {
1015 EXPECT_EQ("166.155.144.33:",
1016 proxy_uri
.substr(0, proxy_uri
.find(':') + 1));