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. 4 5 #include "base/compiler_specific.h" 6 #include "base/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" 16 #include "url/gurl.h" 17 18 namespace net { 19 namespace { 20 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 { 25 public: 26 MockJSBindings() : my_ip_address_count(0), my_ip_address_ex_count(0), 27 should_terminate(false) {} 28 29 virtual void Alert(const base::string16& message) OVERRIDE { 30 VLOG(1) << "PAC-alert: " << message; // Helpful when debugging. 31 alerts.push_back(base::UTF16ToUTF8(message)); 32 } 33 34 virtual bool ResolveDns(const std::string& host, 35 ResolveDnsOperation op, 36 std::string* output, 37 bool* terminate) OVERRIDE { 38 *terminate = should_terminate; 39 40 if (op == MY_IP_ADDRESS) { 41 my_ip_address_count++; 42 *output = my_ip_address_result; 43 return !my_ip_address_result.empty(); 44 } 45 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(); 50 } 51 52 if (op == DNS_RESOLVE) { 53 dns_resolves.push_back(host); 54 *output = dns_resolve_result; 55 return !dns_resolve_result.empty(); 56 } 57 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(); 62 } 63 64 CHECK(false); 65 return false; 66 } 67 68 virtual void OnError(int line_number, 69 const base::string16& message) OVERRIDE { 70 // Helpful when debugging. 71 VLOG(1) << "PAC-error: [" << line_number << "] " << message; 72 73 errors.push_back(base::UTF16ToUTF8(message)); 74 errors_line_number.push_back(line_number); 75 } 76 77 // Mock values to return. 78 std::string my_ip_address_result; 79 std::string my_ip_address_ex_result; 80 std::string dns_resolve_result; 81 std::string dns_resolve_ex_result; 82 83 // Inputs we got called with. 84 std::vector<std::string> alerts; 85 std::vector<std::string> errors; 86 std::vector<int> errors_line_number; 87 std::vector<std::string> dns_resolves; 88 std::vector<std::string> dns_resolves_ex; 89 int my_ip_address_count; 90 int my_ip_address_ex_count; 91 92 // Whether ResolveDns() should terminate script execution. 93 bool should_terminate; 94 }; 95 96 // This is the same as ProxyResolverV8, but it uses mock bindings in place of 97 // the default bindings, and has a helper function to load PAC scripts from 98 // disk. 99 class ProxyResolverV8WithMockBindings : public ProxyResolverV8 { 100 public: 101 ProxyResolverV8WithMockBindings() { 102 set_js_bindings(&mock_js_bindings_); 103 } 104 105 virtual ~ProxyResolverV8WithMockBindings() { 106 } 107 108 MockJSBindings* mock_js_bindings() { 109 return &mock_js_bindings_; 110 } 111 112 // Initialize with the PAC script data at |filename|. 113 int SetPacScriptFromDisk(const char* filename) { 114 base::FilePath path; 115 PathService::Get(base::DIR_SOURCE_ROOT, &path); 116 path = path.AppendASCII("net"); 117 path = path.AppendASCII("data"); 118 path = path.AppendASCII("proxy_resolver_v8_unittest"); 119 path = path.AppendASCII(filename); 120 121 // Try to read the file from disk. 122 std::string file_contents; 123 bool ok = base::ReadFileToString(path, &file_contents); 124 125 // If we can't load the file from disk, something is misconfigured. 126 if (!ok) { 127 LOG(ERROR) << "Failed to read file: " << path.value(); 128 return ERR_UNEXPECTED; 129 } 130 131 // Load the PAC script into the ProxyResolver. 132 return SetPacScript(ProxyResolverScriptData::FromUTF8(file_contents), 133 CompletionCallback()); 134 } 135 136 private: 137 MockJSBindings mock_js_bindings_; 138 }; 139 140 // Doesn't really matter what these values are for many of the tests. 141 const GURL kQueryUrl("http://www.google.com"); 142 const GURL kPacUrl; 143 144 TEST(ProxyResolverV8Test, Direct) { 145 ProxyResolverV8WithMockBindings resolver; 146 int result = resolver.SetPacScriptFromDisk("direct.js"); 147 EXPECT_EQ(OK, result); 148 149 ProxyInfo proxy_info; 150 CapturingBoundNetLog log; 151 result = resolver.GetProxyForURL( 152 kQueryUrl, &proxy_info, CompletionCallback(), NULL, log.bound()); 153 154 EXPECT_EQ(OK, result); 155 EXPECT_TRUE(proxy_info.is_direct()); 156 157 EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size()); 158 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 159 160 net::CapturingNetLog::CapturedEntryList entries; 161 log.GetEntries(&entries); 162 // No bindings were called, so no log entries. 163 EXPECT_EQ(0u, entries.size()); 164 } 165 166 TEST(ProxyResolverV8Test, ReturnEmptyString) { 167 ProxyResolverV8WithMockBindings resolver; 168 int result = resolver.SetPacScriptFromDisk("return_empty_string.js"); 169 EXPECT_EQ(OK, result); 170 171 ProxyInfo proxy_info; 172 result = resolver.GetProxyForURL( 173 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 174 175 EXPECT_EQ(OK, result); 176 EXPECT_TRUE(proxy_info.is_direct()); 177 178 EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size()); 179 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 180 } 181 182 TEST(ProxyResolverV8Test, Basic) { 183 ProxyResolverV8WithMockBindings resolver; 184 int result = resolver.SetPacScriptFromDisk("passthrough.js"); 185 EXPECT_EQ(OK, result); 186 187 // The "FindProxyForURL" of this PAC script simply concatenates all of the 188 // arguments into a pseudo-host. The purpose of this test is to verify that 189 // the correct arguments are being passed to FindProxyForURL(). 190 { 191 ProxyInfo proxy_info; 192 result = resolver.GetProxyForURL(GURL("http://query.com/path"), &proxy_info, 193 CompletionCallback(), NULL, BoundNetLog()); 194 EXPECT_EQ(OK, result); 195 EXPECT_EQ("http.query.com.path.query.com:80", 196 proxy_info.proxy_server().ToURI()); 197 } 198 { 199 ProxyInfo proxy_info; 200 int result = resolver.GetProxyForURL( 201 GURL("ftp://query.com:90/path"), &proxy_info, CompletionCallback(), 202 NULL, BoundNetLog()); 203 EXPECT_EQ(OK, result); 204 // Note that FindProxyForURL(url, host) does not expect |host| to contain 205 // the port number. 206 EXPECT_EQ("ftp.query.com.90.path.query.com:80", 207 proxy_info.proxy_server().ToURI()); 208 209 EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size()); 210 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 211 } 212 } 213 214 TEST(ProxyResolverV8Test, BadReturnType) { 215 // These are the filenames of PAC scripts which each return a non-string 216 // types for FindProxyForURL(). They should all fail with 217 // ERR_PAC_SCRIPT_FAILED. 218 static const char* const filenames[] = { 219 "return_undefined.js", 220 "return_integer.js", 221 "return_function.js", 222 "return_object.js", 223 // TODO(eroman): Should 'null' be considered equivalent to "DIRECT" ? 224 "return_null.js" 225 }; 226 227 for (size_t i = 0; i < arraysize(filenames); ++i) { 228 ProxyResolverV8WithMockBindings resolver; 229 int result = resolver.SetPacScriptFromDisk(filenames[i]); 230 EXPECT_EQ(OK, result); 231 232 ProxyInfo proxy_info; 233 result = resolver.GetProxyForURL( 234 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 235 236 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 237 238 MockJSBindings* bindings = resolver.mock_js_bindings(); 239 EXPECT_EQ(0U, bindings->alerts.size()); 240 ASSERT_EQ(1U, bindings->errors.size()); 241 EXPECT_EQ("FindProxyForURL() did not return a string.", 242 bindings->errors[0]); 243 EXPECT_EQ(-1, bindings->errors_line_number[0]); 244 } 245 } 246 247 // Try using a PAC script which defines no "FindProxyForURL" function. 248 TEST(ProxyResolverV8Test, NoEntryPoint) { 249 ProxyResolverV8WithMockBindings resolver; 250 int result = resolver.SetPacScriptFromDisk("no_entrypoint.js"); 251 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 252 253 ProxyInfo proxy_info; 254 result = resolver.GetProxyForURL( 255 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 256 257 EXPECT_EQ(ERR_FAILED, result); 258 } 259 260 // Try loading a malformed PAC script. 261 TEST(ProxyResolverV8Test, ParseError) { 262 ProxyResolverV8WithMockBindings resolver; 263 int result = resolver.SetPacScriptFromDisk("missing_close_brace.js"); 264 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 265 266 ProxyInfo proxy_info; 267 result = resolver.GetProxyForURL( 268 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 269 270 EXPECT_EQ(ERR_FAILED, result); 271 272 MockJSBindings* bindings = resolver.mock_js_bindings(); 273 EXPECT_EQ(0U, bindings->alerts.size()); 274 275 // We get one error during compilation. 276 ASSERT_EQ(1U, bindings->errors.size()); 277 278 EXPECT_EQ("Uncaught SyntaxError: Unexpected end of input", 279 bindings->errors[0]); 280 EXPECT_EQ(0, bindings->errors_line_number[0]); 281 } 282 283 // Run a PAC script several times, which has side-effects. 284 TEST(ProxyResolverV8Test, SideEffects) { 285 ProxyResolverV8WithMockBindings resolver; 286 int result = resolver.SetPacScriptFromDisk("side_effects.js"); 287 288 // The PAC script increments a counter each time we invoke it. 289 for (int i = 0; i < 3; ++i) { 290 ProxyInfo proxy_info; 291 result = resolver.GetProxyForURL( 292 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 293 EXPECT_EQ(OK, result); 294 EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i), 295 proxy_info.proxy_server().ToURI()); 296 } 297 298 // Reload the script -- the javascript environment should be reset, hence 299 // the counter starts over. 300 result = resolver.SetPacScriptFromDisk("side_effects.js"); 301 EXPECT_EQ(OK, result); 302 303 for (int i = 0; i < 3; ++i) { 304 ProxyInfo proxy_info; 305 result = resolver.GetProxyForURL( 306 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 307 EXPECT_EQ(OK, result); 308 EXPECT_EQ(base::StringPrintf("sideffect_%d:80", i), 309 proxy_info.proxy_server().ToURI()); 310 } 311 } 312 313 // Execute a PAC script which throws an exception in FindProxyForURL. 314 TEST(ProxyResolverV8Test, UnhandledException) { 315 ProxyResolverV8WithMockBindings resolver; 316 int result = resolver.SetPacScriptFromDisk("unhandled_exception.js"); 317 EXPECT_EQ(OK, result); 318 319 ProxyInfo proxy_info; 320 result = resolver.GetProxyForURL( 321 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 322 323 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 324 325 MockJSBindings* bindings = resolver.mock_js_bindings(); 326 EXPECT_EQ(0U, bindings->alerts.size()); 327 ASSERT_EQ(1U, bindings->errors.size()); 328 EXPECT_EQ("Uncaught ReferenceError: undefined_variable is not defined", 329 bindings->errors[0]); 330 EXPECT_EQ(3, bindings->errors_line_number[0]); 331 } 332 333 TEST(ProxyResolverV8Test, ReturnUnicode) { 334 ProxyResolverV8WithMockBindings resolver; 335 int result = resolver.SetPacScriptFromDisk("return_unicode.js"); 336 EXPECT_EQ(OK, result); 337 338 ProxyInfo proxy_info; 339 result = resolver.GetProxyForURL( 340 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 341 342 // The result from this resolve was unparseable, because it 343 // wasn't ASCII. 344 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 345 } 346 347 // Test the PAC library functions that we expose in the JS environment. 348 TEST(ProxyResolverV8Test, JavascriptLibrary) { 349 ProxyResolverV8WithMockBindings resolver; 350 int result = resolver.SetPacScriptFromDisk("pac_library_unittest.js"); 351 EXPECT_EQ(OK, result); 352 353 ProxyInfo proxy_info; 354 result = resolver.GetProxyForURL( 355 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 356 357 // If the javascript side of this unit-test fails, it will throw a javascript 358 // exception. Otherwise it will return "PROXY success:80". 359 EXPECT_EQ(OK, result); 360 EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI()); 361 362 EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size()); 363 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 364 } 365 366 // Try resolving when SetPacScriptByData() has not been called. 367 TEST(ProxyResolverV8Test, NoSetPacScript) { 368 ProxyResolverV8WithMockBindings resolver; 369 370 ProxyInfo proxy_info; 371 372 // Resolve should fail, as we are not yet initialized with a script. 373 int result = resolver.GetProxyForURL( 374 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 375 EXPECT_EQ(ERR_FAILED, result); 376 377 // Initialize it. 378 result = resolver.SetPacScriptFromDisk("direct.js"); 379 EXPECT_EQ(OK, result); 380 381 // Resolve should now succeed. 382 result = resolver.GetProxyForURL( 383 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 384 EXPECT_EQ(OK, result); 385 386 // Clear it, by initializing with an empty string. 387 resolver.SetPacScript( 388 ProxyResolverScriptData::FromUTF16(base::string16()), 389 CompletionCallback()); 390 391 // Resolve should fail again now. 392 result = resolver.GetProxyForURL( 393 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 394 EXPECT_EQ(ERR_FAILED, result); 395 396 // Load a good script once more. 397 result = resolver.SetPacScriptFromDisk("direct.js"); 398 EXPECT_EQ(OK, result); 399 result = resolver.GetProxyForURL( 400 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 401 EXPECT_EQ(OK, result); 402 403 EXPECT_EQ(0U, resolver.mock_js_bindings()->alerts.size()); 404 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 405 } 406 407 // Test marshalling/un-marshalling of values between C++/V8. 408 TEST(ProxyResolverV8Test, V8Bindings) { 409 ProxyResolverV8WithMockBindings resolver; 410 MockJSBindings* bindings = resolver.mock_js_bindings(); 411 bindings->dns_resolve_result = "127.0.0.1"; 412 int result = resolver.SetPacScriptFromDisk("bindings.js"); 413 EXPECT_EQ(OK, result); 414 415 ProxyInfo proxy_info; 416 result = resolver.GetProxyForURL( 417 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 418 419 EXPECT_EQ(OK, result); 420 EXPECT_TRUE(proxy_info.is_direct()); 421 422 EXPECT_EQ(0U, resolver.mock_js_bindings()->errors.size()); 423 424 // Alert was called 5 times. 425 ASSERT_EQ(5U, bindings->alerts.size()); 426 EXPECT_EQ("undefined", bindings->alerts[0]); 427 EXPECT_EQ("null", bindings->alerts[1]); 428 EXPECT_EQ("undefined", bindings->alerts[2]); 429 EXPECT_EQ("[object Object]", bindings->alerts[3]); 430 EXPECT_EQ("exception from calling toString()", bindings->alerts[4]); 431 432 // DnsResolve was called 8 times, however only 2 of those were string 433 // parameters. (so 6 of them failed immediately). 434 ASSERT_EQ(2U, bindings->dns_resolves.size()); 435 EXPECT_EQ("", bindings->dns_resolves[0]); 436 EXPECT_EQ("arg1", bindings->dns_resolves[1]); 437 438 // MyIpAddress was called two times. 439 EXPECT_EQ(2, bindings->my_ip_address_count); 440 441 // MyIpAddressEx was called once. 442 EXPECT_EQ(1, bindings->my_ip_address_ex_count); 443 444 // DnsResolveEx was called 2 times. 445 ASSERT_EQ(2U, bindings->dns_resolves_ex.size()); 446 EXPECT_EQ("is_resolvable", bindings->dns_resolves_ex[0]); 447 EXPECT_EQ("foobar", bindings->dns_resolves_ex[1]); 448 } 449 450 // Test calling a binding (myIpAddress()) from the script's global scope. 451 // http://crbug.com/40026 452 TEST(ProxyResolverV8Test, BindingCalledDuringInitialization) { 453 ProxyResolverV8WithMockBindings resolver; 454 455 int result = resolver.SetPacScriptFromDisk("binding_from_global.js"); 456 EXPECT_EQ(OK, result); 457 458 MockJSBindings* bindings = resolver.mock_js_bindings(); 459 460 // myIpAddress() got called during initialization of the script. 461 EXPECT_EQ(1, bindings->my_ip_address_count); 462 463 ProxyInfo proxy_info; 464 result = resolver.GetProxyForURL( 465 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 466 467 EXPECT_EQ(OK, result); 468 EXPECT_FALSE(proxy_info.is_direct()); 469 EXPECT_EQ("127.0.0.1:80", proxy_info.proxy_server().ToURI()); 470 471 // Check that no other bindings were called. 472 EXPECT_EQ(0U, bindings->errors.size()); 473 ASSERT_EQ(0U, bindings->alerts.size()); 474 ASSERT_EQ(0U, bindings->dns_resolves.size()); 475 EXPECT_EQ(0, bindings->my_ip_address_ex_count); 476 ASSERT_EQ(0U, bindings->dns_resolves_ex.size()); 477 } 478 479 // Try loading a PAC script that ends with a comment and has no terminal 480 // newline. This should not cause problems with the PAC utility functions 481 // that we add to the script's environment. 482 // http://crbug.com/22864 483 TEST(ProxyResolverV8Test, EndsWithCommentNoNewline) { 484 ProxyResolverV8WithMockBindings resolver; 485 int result = resolver.SetPacScriptFromDisk("ends_with_comment.js"); 486 EXPECT_EQ(OK, result); 487 488 ProxyInfo proxy_info; 489 result = resolver.GetProxyForURL( 490 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 491 492 EXPECT_EQ(OK, result); 493 EXPECT_FALSE(proxy_info.is_direct()); 494 EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI()); 495 } 496 497 // Try loading a PAC script that ends with a statement and has no terminal 498 // newline. This should not cause problems with the PAC utility functions 499 // that we add to the script's environment. 500 // http://crbug.com/22864 501 TEST(ProxyResolverV8Test, EndsWithStatementNoNewline) { 502 ProxyResolverV8WithMockBindings resolver; 503 int result = resolver.SetPacScriptFromDisk( 504 "ends_with_statement_no_semicolon.js"); 505 EXPECT_EQ(OK, result); 506 507 ProxyInfo proxy_info; 508 result = resolver.GetProxyForURL( 509 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 510 511 EXPECT_EQ(OK, result); 512 EXPECT_FALSE(proxy_info.is_direct()); 513 EXPECT_EQ("success:3", proxy_info.proxy_server().ToURI()); 514 } 515 516 // Test the return values from myIpAddress(), myIpAddressEx(), dnsResolve(), 517 // dnsResolveEx(), isResolvable(), isResolvableEx(), when the the binding 518 // returns empty string (failure). This simulates the return values from 519 // those functions when the underlying DNS resolution fails. 520 TEST(ProxyResolverV8Test, DNSResolutionFailure) { 521 ProxyResolverV8WithMockBindings resolver; 522 int result = resolver.SetPacScriptFromDisk("dns_fail.js"); 523 EXPECT_EQ(OK, result); 524 525 ProxyInfo proxy_info; 526 result = resolver.GetProxyForURL( 527 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 528 529 EXPECT_EQ(OK, result); 530 EXPECT_FALSE(proxy_info.is_direct()); 531 EXPECT_EQ("success:80", proxy_info.proxy_server().ToURI()); 532 } 533 534 TEST(ProxyResolverV8Test, DNSResolutionOfInternationDomainName) { 535 ProxyResolverV8WithMockBindings resolver; 536 int result = resolver.SetPacScriptFromDisk("international_domain_names.js"); 537 EXPECT_EQ(OK, result); 538 539 // Execute FindProxyForURL(). 540 ProxyInfo proxy_info; 541 result = resolver.GetProxyForURL( 542 kQueryUrl, &proxy_info, CompletionCallback(), NULL, BoundNetLog()); 543 544 EXPECT_EQ(OK, result); 545 EXPECT_TRUE(proxy_info.is_direct()); 546 547 // Check that the international domain name was converted to punycode 548 // before passing it onto the bindings layer. 549 MockJSBindings* bindings = resolver.mock_js_bindings(); 550 551 ASSERT_EQ(1u, bindings->dns_resolves.size()); 552 EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves[0]); 553 554 ASSERT_EQ(1u, bindings->dns_resolves_ex.size()); 555 EXPECT_EQ("xn--bcher-kva.ch", bindings->dns_resolves_ex[0]); 556 } 557 558 // Test that when resolving a URL which contains an IPv6 string literal, the 559 // brackets are removed from the host before passing it down to the PAC script. 560 // If we don't do this, then subsequent calls to dnsResolveEx(host) will be 561 // doomed to fail since it won't correspond with a valid name. 562 TEST(ProxyResolverV8Test, IPv6HostnamesNotBracketed) { 563 ProxyResolverV8WithMockBindings resolver; 564 int result = resolver.SetPacScriptFromDisk("resolve_host.js"); 565 EXPECT_EQ(OK, result); 566 567 ProxyInfo proxy_info; 568 result = resolver.GetProxyForURL( 569 GURL("http://[abcd::efff]:99/watsupdawg"), &proxy_info, 570 CompletionCallback(), NULL, BoundNetLog()); 571 572 EXPECT_EQ(OK, result); 573 EXPECT_TRUE(proxy_info.is_direct()); 574 575 // We called dnsResolveEx() exactly once, by passing through the "host" 576 // argument to FindProxyForURL(). The brackets should have been stripped. 577 ASSERT_EQ(1U, resolver.mock_js_bindings()->dns_resolves_ex.size()); 578 EXPECT_EQ("abcd::efff", resolver.mock_js_bindings()->dns_resolves_ex[0]); 579 } 580 581 // Test that terminating a script within DnsResolve() leads to eventual 582 // termination of the script. Also test that repeatedly calling terminate is 583 // safe, and running the script again after termination still works. 584 TEST(ProxyResolverV8Test, Terminate) { 585 ProxyResolverV8WithMockBindings resolver; 586 int result = resolver.SetPacScriptFromDisk("terminate.js"); 587 EXPECT_EQ(OK, result); 588 589 MockJSBindings* bindings = resolver.mock_js_bindings(); 590 591 // Terminate script execution upon reaching dnsResolve(). Note that 592 // termination may not take effect right away (so the subsequent dnsResolve() 593 // and alert() may be run). 594 bindings->should_terminate = true; 595 596 ProxyInfo proxy_info; 597 result = resolver.GetProxyForURL( 598 GURL("http://hang/"), &proxy_info, 599 CompletionCallback(), NULL, BoundNetLog()); 600 601 // The script execution was terminated. 602 EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, result); 603 604 EXPECT_EQ(1U, resolver.mock_js_bindings()->dns_resolves.size()); 605 EXPECT_GE(2U, resolver.mock_js_bindings()->dns_resolves_ex.size()); 606 EXPECT_GE(1U, bindings->alerts.size()); 607 608 EXPECT_EQ(1U, bindings->errors.size()); 609 610 // Termination shows up as an uncaught exception without any message. 611 EXPECT_EQ("", bindings->errors[0]); 612 613 bindings->errors.clear(); 614 615 // Try running the script again, this time with a different input which won't 616 // cause a termination+hang. 617 result = resolver.GetProxyForURL( 618 GURL("http://kittens/"), &proxy_info, 619 CompletionCallback(), NULL, BoundNetLog()); 620 621 EXPECT_EQ(OK, result); 622 EXPECT_EQ(0u, bindings->errors.size()); 623 EXPECT_EQ("kittens:88", proxy_info.proxy_server().ToURI()); 624 } 625 626 } // namespace 627 } // namespace net 628