1 // Copyright (c) 2012 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 "base/compiler_specific.h"
6 #include "base/files/file_util.h"
7 #include "base/path_service.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/net_log_unittest.h"
13 #include "net/proxy/proxy_info.h"
14 #include "net/proxy/proxy_resolver_v8.h"
15 #include "testing/gtest/include/gtest/gtest.h"
21 // Javascript bindings for ProxyResolverV8, which returns mock values.
22 // Each time one of the bindings is called into, we push the input into a
23 // list, for later verification.
24 class MockJSBindings
: public ProxyResolverV8::JSBindings
{
26 MockJSBindings() : my_ip_address_count(0), my_ip_address_ex_count(0),
27 should_terminate(false) {}
29 void Alert(const base::string16
& message
) override
{
30 VLOG(1) << "PAC-alert: " << message
; // Helpful when debugging.
31 alerts
.push_back(base::UTF16ToUTF8(message
));
34 bool ResolveDns(const std::string
& host
,
35 ResolveDnsOperation op
,
37 bool* terminate
) override
{
38 *terminate
= should_terminate
;
40 if (op
== MY_IP_ADDRESS
) {
41 my_ip_address_count
++;
42 *output
= my_ip_address_result
;
43 return !my_ip_address_result
.empty();
46 if (op
== MY_IP_ADDRESS_EX
) {
47 my_ip_address_ex_count
++;
48 *output
= my_ip_address_ex_result
;
49 return !my_ip_address_ex_result
.empty();
52 if (op
== DNS_RESOLVE
) {
53 dns_resolves
.push_back(host
);
54 *output
= dns_resolve_result
;
55 return !dns_resolve_result
.empty();
58 if (op
== DNS_RESOLVE_EX
) {
59 dns_resolves_ex
.push_back(host
);
60 *output
= dns_resolve_ex_result
;
61 return !dns_resolve_ex_result
.empty();
68 void OnError(int line_number
, const base::string16
& message
) override
{
69 // Helpful when debugging.
70 VLOG(1) << "PAC-error: [" << line_number
<< "] " << message
;
72 errors
.push_back(base::UTF16ToUTF8(message
));
73 errors_line_number
.push_back(line_number
);
76 // Mock values to return.
77 std::string my_ip_address_result
;
78 std::string my_ip_address_ex_result
;
79 std::string dns_resolve_result
;
80 std::string dns_resolve_ex_result
;
82 // Inputs we got called with.
83 std::vector
<std::string
> alerts
;
84 std::vector
<std::string
> errors
;
85 std::vector
<int> errors_line_number
;
86 std::vector
<std::string
> dns_resolves
;
87 std::vector
<std::string
> dns_resolves_ex
;
88 int my_ip_address_count
;
89 int my_ip_address_ex_count
;
91 // Whether ResolveDns() should terminate script execution.
92 bool should_terminate
;
95 // This is the same as ProxyResolverV8, but it uses mock bindings in place of
96 // the default bindings, and has a helper function to load PAC scripts from
98 class ProxyResolverV8WithMockBindings
: public ProxyResolverV8
{
100 ProxyResolverV8WithMockBindings() {
101 set_js_bindings(&mock_js_bindings_
);
104 ~ProxyResolverV8WithMockBindings() override
{}
106 MockJSBindings
* mock_js_bindings() {
107 return &mock_js_bindings_
;
110 // Initialize with the PAC script data at |filename|.
111 int SetPacScriptFromDisk(const char* filename
) {
113 PathService::Get(base::DIR_SOURCE_ROOT
, &path
);
114 path
= path
.AppendASCII("net");
115 path
= path
.AppendASCII("data");
116 path
= path
.AppendASCII("proxy_resolver_v8_unittest");
117 path
= path
.AppendASCII(filename
);
119 // Try to read the file from disk.
120 std::string file_contents
;
121 bool ok
= base::ReadFileToString(path
, &file_contents
);
123 // If we can't load the file from disk, something is misconfigured.
125 LOG(ERROR
) << "Failed to read file: " << path
.value();
126 return ERR_UNEXPECTED
;
129 // Load the PAC script into the ProxyResolver.
130 return SetPacScript(ProxyResolverScriptData::FromUTF8(file_contents
),
131 CompletionCallback());
135 MockJSBindings mock_js_bindings_
;
138 // Doesn't really matter what these values are for many of the tests.
139 const GURL
kQueryUrl("http://www.google.com");
142 TEST(ProxyResolverV8Test
, Direct
) {
143 ProxyResolverV8WithMockBindings resolver
;
144 int result
= resolver
.SetPacScriptFromDisk("direct.js");
145 EXPECT_EQ(OK
, result
);
147 ProxyInfo proxy_info
;
148 CapturingBoundNetLog log
;
149 result
= resolver
.GetProxyForURL(
150 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, log
.bound());
152 EXPECT_EQ(OK
, result
);
153 EXPECT_TRUE(proxy_info
.is_direct());
155 EXPECT_EQ(0U, resolver
.mock_js_bindings()->alerts
.size());
156 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
158 net::CapturingNetLog::CapturedEntryList entries
;
159 log
.GetEntries(&entries
);
160 // No bindings were called, so no log entries.
161 EXPECT_EQ(0u, entries
.size());
164 TEST(ProxyResolverV8Test
, ReturnEmptyString
) {
165 ProxyResolverV8WithMockBindings resolver
;
166 int result
= resolver
.SetPacScriptFromDisk("return_empty_string.js");
167 EXPECT_EQ(OK
, result
);
169 ProxyInfo proxy_info
;
170 result
= resolver
.GetProxyForURL(
171 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
173 EXPECT_EQ(OK
, result
);
174 EXPECT_TRUE(proxy_info
.is_direct());
176 EXPECT_EQ(0U, resolver
.mock_js_bindings()->alerts
.size());
177 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
180 TEST(ProxyResolverV8Test
, Basic
) {
181 ProxyResolverV8WithMockBindings resolver
;
182 int result
= resolver
.SetPacScriptFromDisk("passthrough.js");
183 EXPECT_EQ(OK
, result
);
185 // The "FindProxyForURL" of this PAC script simply concatenates all of the
186 // arguments into a pseudo-host. The purpose of this test is to verify that
187 // the correct arguments are being passed to FindProxyForURL().
189 ProxyInfo proxy_info
;
190 result
= resolver
.GetProxyForURL(GURL("http://query.com/path"), &proxy_info
,
191 CompletionCallback(), NULL
, BoundNetLog());
192 EXPECT_EQ(OK
, result
);
193 EXPECT_EQ("http.query.com.path.query.com:80",
194 proxy_info
.proxy_server().ToURI());
197 ProxyInfo proxy_info
;
198 int result
= resolver
.GetProxyForURL(
199 GURL("ftp://query.com:90/path"), &proxy_info
, CompletionCallback(),
200 NULL
, BoundNetLog());
201 EXPECT_EQ(OK
, result
);
202 // Note that FindProxyForURL(url, host) does not expect |host| to contain
204 EXPECT_EQ("ftp.query.com.90.path.query.com:80",
205 proxy_info
.proxy_server().ToURI());
207 EXPECT_EQ(0U, resolver
.mock_js_bindings()->alerts
.size());
208 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
212 TEST(ProxyResolverV8Test
, BadReturnType
) {
213 // These are the filenames of PAC scripts which each return a non-string
214 // types for FindProxyForURL(). They should all fail with
215 // ERR_PAC_SCRIPT_FAILED.
216 static const char* const filenames
[] = {
217 "return_undefined.js",
219 "return_function.js",
221 // TODO(eroman): Should 'null' be considered equivalent to "DIRECT" ?
225 for (size_t i
= 0; i
< arraysize(filenames
); ++i
) {
226 ProxyResolverV8WithMockBindings resolver
;
227 int result
= resolver
.SetPacScriptFromDisk(filenames
[i
]);
228 EXPECT_EQ(OK
, result
);
230 ProxyInfo proxy_info
;
231 result
= resolver
.GetProxyForURL(
232 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
234 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
236 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
237 EXPECT_EQ(0U, bindings
->alerts
.size());
238 ASSERT_EQ(1U, bindings
->errors
.size());
239 EXPECT_EQ("FindProxyForURL() did not return a string.",
240 bindings
->errors
[0]);
241 EXPECT_EQ(-1, bindings
->errors_line_number
[0]);
245 // Try using a PAC script which defines no "FindProxyForURL" function.
246 TEST(ProxyResolverV8Test
, NoEntryPoint
) {
247 ProxyResolverV8WithMockBindings resolver
;
248 int result
= resolver
.SetPacScriptFromDisk("no_entrypoint.js");
249 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
251 ProxyInfo proxy_info
;
252 result
= resolver
.GetProxyForURL(
253 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
255 EXPECT_EQ(ERR_FAILED
, result
);
258 // Try loading a malformed PAC script.
259 TEST(ProxyResolverV8Test
, ParseError
) {
260 ProxyResolverV8WithMockBindings resolver
;
261 int result
= resolver
.SetPacScriptFromDisk("missing_close_brace.js");
262 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
264 ProxyInfo proxy_info
;
265 result
= resolver
.GetProxyForURL(
266 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
268 EXPECT_EQ(ERR_FAILED
, result
);
270 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
271 EXPECT_EQ(0U, bindings
->alerts
.size());
273 // We get one error during compilation.
274 ASSERT_EQ(1U, bindings
->errors
.size());
276 EXPECT_EQ("Uncaught SyntaxError: Unexpected end of input",
277 bindings
->errors
[0]);
278 EXPECT_EQ(0, bindings
->errors_line_number
[0]);
281 // Run a PAC script several times, which has side-effects.
282 TEST(ProxyResolverV8Test
, SideEffects
) {
283 ProxyResolverV8WithMockBindings resolver
;
284 int result
= resolver
.SetPacScriptFromDisk("side_effects.js");
286 // The PAC script increments a counter each time we invoke it.
287 for (int i
= 0; i
< 3; ++i
) {
288 ProxyInfo proxy_info
;
289 result
= resolver
.GetProxyForURL(
290 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
291 EXPECT_EQ(OK
, result
);
292 EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i
),
293 proxy_info
.proxy_server().ToURI());
296 // Reload the script -- the javascript environment should be reset, hence
297 // the counter starts over.
298 result
= resolver
.SetPacScriptFromDisk("side_effects.js");
299 EXPECT_EQ(OK
, result
);
301 for (int i
= 0; i
< 3; ++i
) {
302 ProxyInfo proxy_info
;
303 result
= resolver
.GetProxyForURL(
304 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
305 EXPECT_EQ(OK
, result
);
306 EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i
),
307 proxy_info
.proxy_server().ToURI());
311 // Execute a PAC script which throws an exception in FindProxyForURL.
312 TEST(ProxyResolverV8Test
, UnhandledException
) {
313 ProxyResolverV8WithMockBindings resolver
;
314 int result
= resolver
.SetPacScriptFromDisk("unhandled_exception.js");
315 EXPECT_EQ(OK
, result
);
317 ProxyInfo proxy_info
;
318 result
= resolver
.GetProxyForURL(
319 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
321 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
323 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
324 EXPECT_EQ(0U, bindings
->alerts
.size());
325 ASSERT_EQ(1U, bindings
->errors
.size());
326 EXPECT_EQ("Uncaught ReferenceError: undefined_variable is not defined",
327 bindings
->errors
[0]);
328 EXPECT_EQ(3, bindings
->errors_line_number
[0]);
331 TEST(ProxyResolverV8Test
, ReturnUnicode
) {
332 ProxyResolverV8WithMockBindings resolver
;
333 int result
= resolver
.SetPacScriptFromDisk("return_unicode.js");
334 EXPECT_EQ(OK
, result
);
336 ProxyInfo proxy_info
;
337 result
= resolver
.GetProxyForURL(
338 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
340 // The result from this resolve was unparseable, because it
342 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
345 // Test the PAC library functions that we expose in the JS environment.
346 TEST(ProxyResolverV8Test
, JavascriptLibrary
) {
347 ProxyResolverV8WithMockBindings resolver
;
348 int result
= resolver
.SetPacScriptFromDisk("pac_library_unittest.js");
349 EXPECT_EQ(OK
, result
);
351 ProxyInfo proxy_info
;
352 result
= resolver
.GetProxyForURL(
353 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
355 // If the javascript side of this unit-test fails, it will throw a javascript
356 // exception. Otherwise it will return "PROXY success:80".
357 EXPECT_EQ(OK
, result
);
358 EXPECT_EQ("success:80", proxy_info
.proxy_server().ToURI());
360 EXPECT_EQ(0U, resolver
.mock_js_bindings()->alerts
.size());
361 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
364 // Try resolving when SetPacScriptByData() has not been called.
365 TEST(ProxyResolverV8Test
, NoSetPacScript
) {
366 ProxyResolverV8WithMockBindings resolver
;
368 ProxyInfo proxy_info
;
370 // Resolve should fail, as we are not yet initialized with a script.
371 int result
= resolver
.GetProxyForURL(
372 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
373 EXPECT_EQ(ERR_FAILED
, result
);
376 result
= resolver
.SetPacScriptFromDisk("direct.js");
377 EXPECT_EQ(OK
, result
);
379 // Resolve should now succeed.
380 result
= resolver
.GetProxyForURL(
381 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
382 EXPECT_EQ(OK
, result
);
384 // Clear it, by initializing with an empty string.
385 resolver
.SetPacScript(
386 ProxyResolverScriptData::FromUTF16(base::string16()),
387 CompletionCallback());
389 // Resolve should fail again now.
390 result
= resolver
.GetProxyForURL(
391 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
392 EXPECT_EQ(ERR_FAILED
, result
);
394 // Load a good script once more.
395 result
= resolver
.SetPacScriptFromDisk("direct.js");
396 EXPECT_EQ(OK
, result
);
397 result
= resolver
.GetProxyForURL(
398 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
399 EXPECT_EQ(OK
, result
);
401 EXPECT_EQ(0U, resolver
.mock_js_bindings()->alerts
.size());
402 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
405 // Test marshalling/un-marshalling of values between C++/V8.
406 TEST(ProxyResolverV8Test
, V8Bindings
) {
407 ProxyResolverV8WithMockBindings resolver
;
408 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
409 bindings
->dns_resolve_result
= "127.0.0.1";
410 int result
= resolver
.SetPacScriptFromDisk("bindings.js");
411 EXPECT_EQ(OK
, result
);
413 ProxyInfo proxy_info
;
414 result
= resolver
.GetProxyForURL(
415 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
417 EXPECT_EQ(OK
, result
);
418 EXPECT_TRUE(proxy_info
.is_direct());
420 EXPECT_EQ(0U, resolver
.mock_js_bindings()->errors
.size());
422 // Alert was called 5 times.
423 ASSERT_EQ(5U, bindings
->alerts
.size());
424 EXPECT_EQ("undefined", bindings
->alerts
[0]);
425 EXPECT_EQ("null", bindings
->alerts
[1]);
426 EXPECT_EQ("undefined", bindings
->alerts
[2]);
427 EXPECT_EQ("[object Object]", bindings
->alerts
[3]);
428 EXPECT_EQ("exception from calling toString()", bindings
->alerts
[4]);
430 // DnsResolve was called 8 times, however only 2 of those were string
431 // parameters. (so 6 of them failed immediately).
432 ASSERT_EQ(2U, bindings
->dns_resolves
.size());
433 EXPECT_EQ("", bindings
->dns_resolves
[0]);
434 EXPECT_EQ("arg1", bindings
->dns_resolves
[1]);
436 // MyIpAddress was called two times.
437 EXPECT_EQ(2, bindings
->my_ip_address_count
);
439 // MyIpAddressEx was called once.
440 EXPECT_EQ(1, bindings
->my_ip_address_ex_count
);
442 // DnsResolveEx was called 2 times.
443 ASSERT_EQ(2U, bindings
->dns_resolves_ex
.size());
444 EXPECT_EQ("is_resolvable", bindings
->dns_resolves_ex
[0]);
445 EXPECT_EQ("foobar", bindings
->dns_resolves_ex
[1]);
448 // Test calling a binding (myIpAddress()) from the script's global scope.
449 // http://crbug.com/40026
450 TEST(ProxyResolverV8Test
, BindingCalledDuringInitialization
) {
451 ProxyResolverV8WithMockBindings resolver
;
453 int result
= resolver
.SetPacScriptFromDisk("binding_from_global.js");
454 EXPECT_EQ(OK
, result
);
456 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
458 // myIpAddress() got called during initialization of the script.
459 EXPECT_EQ(1, bindings
->my_ip_address_count
);
461 ProxyInfo proxy_info
;
462 result
= resolver
.GetProxyForURL(
463 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
465 EXPECT_EQ(OK
, result
);
466 EXPECT_FALSE(proxy_info
.is_direct());
467 EXPECT_EQ("127.0.0.1:80", proxy_info
.proxy_server().ToURI());
469 // Check that no other bindings were called.
470 EXPECT_EQ(0U, bindings
->errors
.size());
471 ASSERT_EQ(0U, bindings
->alerts
.size());
472 ASSERT_EQ(0U, bindings
->dns_resolves
.size());
473 EXPECT_EQ(0, bindings
->my_ip_address_ex_count
);
474 ASSERT_EQ(0U, bindings
->dns_resolves_ex
.size());
477 // Try loading a PAC script that ends with a comment and has no terminal
478 // newline. This should not cause problems with the PAC utility functions
479 // that we add to the script's environment.
480 // http://crbug.com/22864
481 TEST(ProxyResolverV8Test
, EndsWithCommentNoNewline
) {
482 ProxyResolverV8WithMockBindings resolver
;
483 int result
= resolver
.SetPacScriptFromDisk("ends_with_comment.js");
484 EXPECT_EQ(OK
, result
);
486 ProxyInfo proxy_info
;
487 result
= resolver
.GetProxyForURL(
488 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
490 EXPECT_EQ(OK
, result
);
491 EXPECT_FALSE(proxy_info
.is_direct());
492 EXPECT_EQ("success:80", proxy_info
.proxy_server().ToURI());
495 // Try loading a PAC script that ends with a statement and has no terminal
496 // newline. This should not cause problems with the PAC utility functions
497 // that we add to the script's environment.
498 // http://crbug.com/22864
499 TEST(ProxyResolverV8Test
, EndsWithStatementNoNewline
) {
500 ProxyResolverV8WithMockBindings resolver
;
501 int result
= resolver
.SetPacScriptFromDisk(
502 "ends_with_statement_no_semicolon.js");
503 EXPECT_EQ(OK
, result
);
505 ProxyInfo proxy_info
;
506 result
= resolver
.GetProxyForURL(
507 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
509 EXPECT_EQ(OK
, result
);
510 EXPECT_FALSE(proxy_info
.is_direct());
511 EXPECT_EQ("success:3", proxy_info
.proxy_server().ToURI());
514 // Test the return values from myIpAddress(), myIpAddressEx(), dnsResolve(),
515 // dnsResolveEx(), isResolvable(), isResolvableEx(), when the the binding
516 // returns empty string (failure). This simulates the return values from
517 // those functions when the underlying DNS resolution fails.
518 TEST(ProxyResolverV8Test
, DNSResolutionFailure
) {
519 ProxyResolverV8WithMockBindings resolver
;
520 int result
= resolver
.SetPacScriptFromDisk("dns_fail.js");
521 EXPECT_EQ(OK
, result
);
523 ProxyInfo proxy_info
;
524 result
= resolver
.GetProxyForURL(
525 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
527 EXPECT_EQ(OK
, result
);
528 EXPECT_FALSE(proxy_info
.is_direct());
529 EXPECT_EQ("success:80", proxy_info
.proxy_server().ToURI());
532 TEST(ProxyResolverV8Test
, DNSResolutionOfInternationDomainName
) {
533 ProxyResolverV8WithMockBindings resolver
;
534 int result
= resolver
.SetPacScriptFromDisk("international_domain_names.js");
535 EXPECT_EQ(OK
, result
);
537 // Execute FindProxyForURL().
538 ProxyInfo proxy_info
;
539 result
= resolver
.GetProxyForURL(
540 kQueryUrl
, &proxy_info
, CompletionCallback(), NULL
, BoundNetLog());
542 EXPECT_EQ(OK
, result
);
543 EXPECT_TRUE(proxy_info
.is_direct());
545 // Check that the international domain name was converted to punycode
546 // before passing it onto the bindings layer.
547 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
549 ASSERT_EQ(1u, bindings
->dns_resolves
.size());
550 EXPECT_EQ("xn--bcher-kva.ch", bindings
->dns_resolves
[0]);
552 ASSERT_EQ(1u, bindings
->dns_resolves_ex
.size());
553 EXPECT_EQ("xn--bcher-kva.ch", bindings
->dns_resolves_ex
[0]);
556 // Test that when resolving a URL which contains an IPv6 string literal, the
557 // brackets are removed from the host before passing it down to the PAC script.
558 // If we don't do this, then subsequent calls to dnsResolveEx(host) will be
559 // doomed to fail since it won't correspond with a valid name.
560 TEST(ProxyResolverV8Test
, IPv6HostnamesNotBracketed
) {
561 ProxyResolverV8WithMockBindings resolver
;
562 int result
= resolver
.SetPacScriptFromDisk("resolve_host.js");
563 EXPECT_EQ(OK
, result
);
565 ProxyInfo proxy_info
;
566 result
= resolver
.GetProxyForURL(
567 GURL("http://[abcd::efff]:99/watsupdawg"), &proxy_info
,
568 CompletionCallback(), NULL
, BoundNetLog());
570 EXPECT_EQ(OK
, result
);
571 EXPECT_TRUE(proxy_info
.is_direct());
573 // We called dnsResolveEx() exactly once, by passing through the "host"
574 // argument to FindProxyForURL(). The brackets should have been stripped.
575 ASSERT_EQ(1U, resolver
.mock_js_bindings()->dns_resolves_ex
.size());
576 EXPECT_EQ("abcd::efff", resolver
.mock_js_bindings()->dns_resolves_ex
[0]);
579 // Test that terminating a script within DnsResolve() leads to eventual
580 // termination of the script. Also test that repeatedly calling terminate is
581 // safe, and running the script again after termination still works.
582 TEST(ProxyResolverV8Test
, Terminate
) {
583 ProxyResolverV8WithMockBindings resolver
;
584 int result
= resolver
.SetPacScriptFromDisk("terminate.js");
585 EXPECT_EQ(OK
, result
);
587 MockJSBindings
* bindings
= resolver
.mock_js_bindings();
589 // Terminate script execution upon reaching dnsResolve(). Note that
590 // termination may not take effect right away (so the subsequent dnsResolve()
591 // and alert() may be run).
592 bindings
->should_terminate
= true;
594 ProxyInfo proxy_info
;
595 result
= resolver
.GetProxyForURL(
596 GURL("http://hang/"), &proxy_info
,
597 CompletionCallback(), NULL
, BoundNetLog());
599 // The script execution was terminated.
600 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED
, result
);
602 EXPECT_EQ(1U, resolver
.mock_js_bindings()->dns_resolves
.size());
603 EXPECT_GE(2U, resolver
.mock_js_bindings()->dns_resolves_ex
.size());
604 EXPECT_GE(1U, bindings
->alerts
.size());
606 EXPECT_EQ(1U, bindings
->errors
.size());
608 // Termination shows up as an uncaught exception without any message.
609 EXPECT_EQ("", bindings
->errors
[0]);
611 bindings
->errors
.clear();
613 // Try running the script again, this time with a different input which won't
614 // cause a termination+hang.
615 result
= resolver
.GetProxyForURL(
616 GURL("http://kittens/"), &proxy_info
,
617 CompletionCallback(), NULL
, BoundNetLog());
619 EXPECT_EQ(OK
, result
);
620 EXPECT_EQ(0u, bindings
->errors
.size());
621 EXPECT_EQ("kittens:88", proxy_info
.proxy_server().ToURI());