1 // Copyright (c) 2010 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 <algorithm> 6 #include <cstdio> 7 #include <string> 8 9 #include <utils/String16.h> 10 11 #include "proxy_resolver_v8.h" 12 13 #include "proxy_resolver_script.h" 14 #include "net_util.h" 15 #include <include/v8.h> 16 #include <algorithm> 17 #include <vector> 18 19 #include <iostream> 20 21 #include <string.h> 22 #include <utils/String8.h> 23 #include <utils/String16.h> 24 25 // Notes on the javascript environment: 26 // 27 // For the majority of the PAC utility functions, we use the same code 28 // as Firefox. See the javascript library that proxy_resolver_scipt.h 29 // pulls in. 30 // 31 // In addition, we implement a subset of Microsoft's extensions to PAC. 32 // - myIpAddressEx() 33 // - dnsResolveEx() 34 // - isResolvableEx() 35 // - isInNetEx() 36 // - sortIpAddressList() 37 // 38 // It is worth noting that the original PAC specification does not describe 39 // the return values on failure. Consequently, there are compatibility 40 // differences between browsers on what to return on failure, which are 41 // illustrated below: 42 // 43 // --------------------+-------------+-------------------+-------------- 44 // | Firefox3 | InternetExplorer8 | --> Us <--- 45 // --------------------+-------------+-------------------+-------------- 46 // myIpAddress() | "127.0.0.1" | ??? | "127.0.0.1" 47 // dnsResolve() | null | false | null 48 // myIpAddressEx() | N/A | "" | "" 49 // sortIpAddressList() | N/A | false | false 50 // dnsResolveEx() | N/A | "" | "" 51 // isInNetEx() | N/A | false | false 52 // --------------------+-------------+-------------------+-------------- 53 // 54 // TODO: The cell above reading ??? means I didn't test it. 55 // 56 // Another difference is in how dnsResolve() and myIpAddress() are 57 // implemented -- whether they should restrict to IPv4 results, or 58 // include both IPv4 and IPv6. The following table illustrates the 59 // differences: 60 // 61 // --------------------+-------------+-------------------+-------------- 62 // | Firefox3 | InternetExplorer8 | --> Us <--- 63 // --------------------+-------------+-------------------+-------------- 64 // myIpAddress() | IPv4/IPv6 | IPv4 | IPv4 65 // dnsResolve() | IPv4/IPv6 | IPv4 | IPv4 66 // isResolvable() | IPv4/IPv6 | IPv4 | IPv4 67 // myIpAddressEx() | N/A | IPv4/IPv6 | IPv4/IPv6 68 // dnsResolveEx() | N/A | IPv4/IPv6 | IPv4/IPv6 69 // sortIpAddressList() | N/A | IPv4/IPv6 | IPv4/IPv6 70 // isResolvableEx() | N/A | IPv4/IPv6 | IPv4/IPv6 71 // isInNetEx() | N/A | IPv4/IPv6 | IPv4/IPv6 72 // -----------------+-------------+-------------------+-------------- 73 74 static bool DoIsStringASCII(const android::String16& str) { 75 for (size_t i = 0; i < str.size(); i++) { 76 unsigned short c = str.string()[i]; 77 if (c > 0x7F) 78 return false; 79 } 80 return true; 81 } 82 83 bool IsStringASCII(const android::String16& str) { 84 return DoIsStringASCII(str); 85 } 86 87 namespace net { 88 89 namespace { 90 91 // Pseudo-name for the PAC script. 92 const char kPacResourceName[] = "proxy-pac-script.js"; 93 // Pseudo-name for the PAC utility script. 94 const char kPacUtilityResourceName[] = "proxy-pac-utility-script.js"; 95 96 // External string wrapper so V8 can access the UTF16 string wrapped by 97 // ProxyResolverScriptData. 98 class V8ExternalStringFromScriptData 99 : public v8::String::ExternalStringResource { 100 public: 101 explicit V8ExternalStringFromScriptData( 102 const android::String16& script_data) 103 : script_data_(script_data) {} 104 105 virtual const uint16_t* data() const { 106 return script_data_.string(); 107 } 108 109 virtual size_t length() const { 110 return script_data_.size(); 111 } 112 113 private: 114 const android::String16& script_data_; 115 // DISALLOW_COPY_AND_ASSIGN(V8ExternalStringFromScriptData); 116 }; 117 118 // External string wrapper so V8 can access a string literal. 119 class V8ExternalASCIILiteral : public v8::String::ExternalAsciiStringResource { 120 public: 121 // |ascii| must be a NULL-terminated C string, and must remain valid 122 // throughout this object's lifetime. 123 V8ExternalASCIILiteral(const char* ascii, size_t length) 124 : ascii_(ascii), length_(length) { 125 } 126 127 virtual const char* data() const { 128 return ascii_; 129 } 130 131 virtual size_t length() const { 132 return length_; 133 } 134 135 private: 136 const char* ascii_; 137 size_t length_; 138 }; 139 140 // When creating a v8::String from a C++ string we have two choices: create 141 // a copy, or create a wrapper that shares the same underlying storage. 142 // For small strings it is better to just make a copy, whereas for large 143 // strings there are savings by sharing the storage. This number identifies 144 // the cutoff length for when to start wrapping rather than creating copies. 145 const size_t kMaxStringBytesForCopy = 256; 146 147 template <class string_type> 148 inline typename string_type::value_type* WriteInto(string_type* str, 149 size_t length_with_null) { 150 str->reserve(length_with_null); 151 str->resize(length_with_null - 1); 152 return &((*str)[0]); 153 } 154 155 // Converts a V8 String to a UTF8 std::string. 156 std::string V8StringToUTF8(v8::Handle<v8::String> s) { 157 std::string result; 158 s->WriteUtf8(WriteInto(&result, s->Length() + 1)); 159 return result; 160 } 161 162 // Converts a V8 String to a UTF16 string. 163 android::String16 V8StringToUTF16(v8::Handle<v8::String> s) { 164 int len = s->Length(); 165 char16_t* buf = new char16_t[len + 1]; 166 s->Write(buf, 0, len); 167 android::String16 ret(buf, len); 168 delete buf; 169 return ret; 170 } 171 172 std::string UTF16ToASCII(const android::String16& str) { 173 android::String8 rstr(str); 174 return std::string(rstr.string()); 175 } 176 177 // Converts an ASCII std::string to a V8 string. 178 v8::Local<v8::String> ASCIIStringToV8String(const std::string& s) { 179 return v8::String::New(s.data(), s.size()); 180 } 181 182 v8::Local<v8::String> UTF16StringToV8String(const android::String16& s) { 183 return v8::String::New(s.string(), s.size()); 184 } 185 186 // Converts an ASCII string literal to a V8 string. 187 v8::Local<v8::String> ASCIILiteralToV8String(const char* ascii) { 188 // DCHECK(IsStringASCII(ascii)); 189 size_t length = strlen(ascii); 190 if (length <= kMaxStringBytesForCopy) 191 return v8::String::New(ascii, length); 192 return v8::String::NewExternal(new V8ExternalASCIILiteral(ascii, length)); 193 } 194 195 // Stringizes a V8 object by calling its toString() method. Returns true 196 // on success. This may fail if the toString() throws an exception. 197 bool V8ObjectToUTF16String(v8::Handle<v8::Value> object, 198 android::String16* utf16_result) { 199 if (object.IsEmpty()) 200 return false; 201 202 v8::HandleScope scope; 203 v8::Local<v8::String> str_object = object->ToString(); 204 if (str_object.IsEmpty()) 205 return false; 206 *utf16_result = V8StringToUTF16(str_object); 207 return true; 208 } 209 210 // Extracts an hostname argument from |args|. On success returns true 211 // and fills |*hostname| with the result. 212 bool GetHostnameArgument(const v8::Arguments& args, std::string* hostname) { 213 // The first argument should be a string. 214 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) 215 return false; 216 217 const android::String16 hostname_utf16 = V8StringToUTF16(args[0]->ToString()); 218 219 // If the hostname is already in ASCII, simply return it as is. 220 if (IsStringASCII(hostname_utf16)) { 221 *hostname = UTF16ToASCII(hostname_utf16); 222 return true; 223 } 224 return false; 225 } 226 227 // Wrapper for passing around IP address strings and IPAddressNumber objects. 228 struct IPAddress { 229 IPAddress(const std::string& ip_string, const IPAddressNumber& ip_number) 230 : string_value(ip_string), 231 ip_address_number(ip_number) { 232 } 233 234 // Used for sorting IP addresses in ascending order in SortIpAddressList(). 235 // IP6 addresses are placed ahead of IPv4 addresses. 236 bool operator<(const IPAddress& rhs) const { 237 const IPAddressNumber& ip1 = this->ip_address_number; 238 const IPAddressNumber& ip2 = rhs.ip_address_number; 239 if (ip1.size() != ip2.size()) 240 return ip1.size() > ip2.size(); // IPv6 before IPv4. 241 return memcmp(&ip1[0], &ip2[0], ip1.size()) < 0; // Ascending order. 242 } 243 244 std::string string_value; 245 IPAddressNumber ip_address_number; 246 }; 247 248 template<typename STR> 249 bool RemoveCharsT(const STR& input, 250 const typename STR::value_type remove_chars[], 251 STR* output) { 252 bool removed = false; 253 size_t found; 254 255 *output = input; 256 257 found = output->find_first_of(remove_chars); 258 while (found != STR::npos) { 259 removed = true; 260 output->replace(found, 1, STR()); 261 found = output->find_first_of(remove_chars, found); 262 } 263 264 return removed; 265 } 266 267 bool RemoveChars(const std::string& input, 268 const char remove_chars[], 269 std::string* output) { 270 return RemoveCharsT(input, remove_chars, output); 271 } 272 273 // Handler for "sortIpAddressList(IpAddressList)". |ip_address_list| is a 274 // semi-colon delimited string containing IP addresses. 275 // |sorted_ip_address_list| is the resulting list of sorted semi-colon delimited 276 // IP addresses or an empty string if unable to sort the IP address list. 277 // Returns 'true' if the sorting was successful, and 'false' if the input was an 278 // empty string, a string of separators (";" in this case), or if any of the IP 279 // addresses in the input list failed to parse. 280 bool SortIpAddressList(const std::string& ip_address_list, 281 std::string* sorted_ip_address_list) { 282 sorted_ip_address_list->clear(); 283 284 // Strip all whitespace (mimics IE behavior). 285 std::string cleaned_ip_address_list; 286 RemoveChars(ip_address_list, " \t", &cleaned_ip_address_list); 287 if (cleaned_ip_address_list.empty()) 288 return false; 289 290 // Split-up IP addresses and store them in a vector. 291 std::vector<IPAddress> ip_vector; 292 IPAddressNumber ip_num; 293 char *tok_list = strtok((char *)cleaned_ip_address_list.c_str(), ";"); 294 while (tok_list != NULL) { 295 if (!ParseIPLiteralToNumber(tok_list, &ip_num)) 296 return false; 297 ip_vector.push_back(IPAddress(tok_list, ip_num)); 298 tok_list = strtok(NULL, ";"); 299 } 300 301 if (ip_vector.empty()) // Can happen if we have something like 302 return false; // sortIpAddressList(";") or sortIpAddressList("; ;") 303 304 // Sort lists according to ascending numeric value. 305 if (ip_vector.size() > 1) 306 std::stable_sort(ip_vector.begin(), ip_vector.end()); 307 308 // Return a semi-colon delimited list of sorted addresses (IPv6 followed by 309 // IPv4). 310 for (size_t i = 0; i < ip_vector.size(); ++i) { 311 if (i > 0) 312 *sorted_ip_address_list += ";"; 313 *sorted_ip_address_list += ip_vector[i].string_value; 314 } 315 return true; 316 } 317 318 319 // Handler for "isInNetEx(ip_address, ip_prefix)". |ip_address| is a string 320 // containing an IPv4/IPv6 address, and |ip_prefix| is a string containg a 321 // slash-delimited IP prefix with the top 'n' bits specified in the bit 322 // field. This returns 'true' if the address is in the same subnet, and 323 // 'false' otherwise. Also returns 'false' if the prefix is in an incorrect 324 // format, or if an address and prefix of different types are used (e.g. IPv6 325 // address and IPv4 prefix). 326 bool IsInNetEx(const std::string& ip_address, const std::string& ip_prefix) { 327 IPAddressNumber address; 328 std::string cleaned_ip_address; 329 if (RemoveChars(ip_address, " \t", &cleaned_ip_address)) 330 return false; 331 if (!ParseIPLiteralToNumber(ip_address, &address)) 332 return false; 333 334 IPAddressNumber prefix; 335 size_t prefix_length_in_bits; 336 if (!ParseCIDRBlock(ip_prefix, &prefix, &prefix_length_in_bits)) 337 return false; 338 339 // Both |address| and |prefix| must be of the same type (IPv4 or IPv6). 340 if (address.size() != prefix.size()) 341 return false; 342 343 return IPNumberMatchesPrefix(address, prefix, prefix_length_in_bits); 344 } 345 346 } // namespace 347 348 // ProxyResolverV8::Context --------------------------------------------------- 349 350 class ProxyResolverV8::Context { 351 public: 352 explicit Context(ProxyResolverJSBindings* js_bindings, 353 ProxyErrorListener* error_listener) 354 : js_bindings_(js_bindings), error_listener_(error_listener) { 355 } 356 357 ~Context() { 358 v8::Locker locked; 359 360 v8_this_.Dispose(); 361 v8_context_.Dispose(); 362 363 // Run the V8 garbage collector. We do this to be sure the 364 // ExternalStringResource objects we allocated get properly disposed. 365 // Otherwise when running the unit-tests they may get leaked. 366 // See crbug.com/48145. 367 PurgeMemory(); 368 } 369 370 int ResolveProxy(const android::String16 url, const android::String16 host, 371 android::String16* results) { 372 v8::Locker locked; 373 v8::HandleScope scope; 374 375 v8::Context::Scope function_scope(v8_context_); 376 377 v8::Local<v8::Value> function; 378 if (!GetFindProxyForURL(&function)) { 379 error_listener_->ErrorMessage( 380 android::String16("FindProxyForURL() is undefined")); 381 return ERR_PAC_SCRIPT_FAILED; 382 } 383 384 v8::Handle<v8::Value> argv[] = { 385 UTF16StringToV8String(url), 386 UTF16StringToV8String(host) }; 387 388 v8::TryCatch try_catch; 389 v8::Local<v8::Value> ret = v8::Function::Cast(*function)->Call( 390 v8_context_->Global(), 2, argv); 391 392 if (try_catch.HasCaught()) { 393 error_listener_->ErrorMessage( 394 V8StringToUTF16(try_catch.Message()->Get())); 395 return ERR_PAC_SCRIPT_FAILED; 396 } 397 398 if (!ret->IsString()) { 399 error_listener_->ErrorMessage( 400 android::String16("FindProxyForURL() did not return a string.")); 401 return ERR_PAC_SCRIPT_FAILED; 402 } 403 404 *results = V8StringToUTF16(ret->ToString()); 405 406 if (!IsStringASCII(*results)) { 407 // TODO: Rather than failing when a wide string is returned, we 408 // could extend the parsing to handle IDNA hostnames by 409 // converting them to ASCII punycode. 410 // crbug.com/47234 411 error_listener_->ErrorMessage( 412 android::String16("FindProxyForURL() returned a non-ASCII string")); 413 return ERR_PAC_SCRIPT_FAILED; 414 } 415 416 return OK; 417 } 418 419 int InitV8(const android::String16& pac_script) { 420 v8::Locker locked; 421 v8::HandleScope scope; 422 423 v8_this_ = v8::Persistent<v8::External>::New(v8::External::New(this)); 424 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 425 426 // Attach the javascript bindings. 427 v8::Local<v8::FunctionTemplate> alert_template = 428 v8::FunctionTemplate::New(&AlertCallback, v8_this_); 429 global_template->Set(ASCIILiteralToV8String("alert"), alert_template); 430 431 v8::Local<v8::FunctionTemplate> my_ip_address_template = 432 v8::FunctionTemplate::New(&MyIpAddressCallback, v8_this_); 433 global_template->Set(ASCIILiteralToV8String("myIpAddress"), 434 my_ip_address_template); 435 436 v8::Local<v8::FunctionTemplate> dns_resolve_template = 437 v8::FunctionTemplate::New(&DnsResolveCallback, v8_this_); 438 global_template->Set(ASCIILiteralToV8String("dnsResolve"), 439 dns_resolve_template); 440 441 // Microsoft's PAC extensions: 442 443 v8::Local<v8::FunctionTemplate> dns_resolve_ex_template = 444 v8::FunctionTemplate::New(&DnsResolveExCallback, v8_this_); 445 global_template->Set(ASCIILiteralToV8String("dnsResolveEx"), 446 dns_resolve_ex_template); 447 448 v8::Local<v8::FunctionTemplate> my_ip_address_ex_template = 449 v8::FunctionTemplate::New(&MyIpAddressExCallback, v8_this_); 450 global_template->Set(ASCIILiteralToV8String("myIpAddressEx"), 451 my_ip_address_ex_template); 452 453 v8::Local<v8::FunctionTemplate> sort_ip_address_list_template = 454 v8::FunctionTemplate::New(&SortIpAddressListCallback, v8_this_); 455 global_template->Set(ASCIILiteralToV8String("sortIpAddressList"), 456 sort_ip_address_list_template); 457 458 v8::Local<v8::FunctionTemplate> is_in_net_ex_template = 459 v8::FunctionTemplate::New(&IsInNetExCallback, v8_this_); 460 global_template->Set(ASCIILiteralToV8String("isInNetEx"), 461 is_in_net_ex_template); 462 463 v8_context_ = v8::Context::New(NULL, global_template); 464 465 v8::Context::Scope ctx(v8_context_); 466 467 // Add the PAC utility functions to the environment. 468 // (This script should never fail, as it is a string literal!) 469 // Note that the two string literals are concatenated. 470 int rv = RunScript( 471 ASCIILiteralToV8String( 472 PROXY_RESOLVER_SCRIPT 473 PROXY_RESOLVER_SCRIPT_EX), 474 kPacUtilityResourceName); 475 if (rv != OK) { 476 return rv; 477 } 478 479 // Add the user's PAC code to the environment. 480 rv = RunScript(UTF16StringToV8String(pac_script), kPacResourceName); 481 if (rv != OK) { 482 return rv; 483 } 484 485 // At a minimum, the FindProxyForURL() function must be defined for this 486 // to be a legitimiate PAC script. 487 v8::Local<v8::Value> function; 488 if (!GetFindProxyForURL(&function)) 489 return ERR_PAC_SCRIPT_FAILED; 490 491 return OK; 492 } 493 494 void PurgeMemory() { 495 v8::Locker locked; 496 // Repeatedly call the V8 idle notification until it returns true ("nothing 497 // more to free"). Note that it makes more sense to do this than to 498 // implement a new "delete everything" pass because object references make 499 // it difficult to free everything possible in just one pass. 500 while (!v8::V8::IdleNotification()) 501 ; 502 } 503 504 private: 505 bool GetFindProxyForURL(v8::Local<v8::Value>* function) { 506 *function = v8_context_->Global()->Get( 507 ASCIILiteralToV8String("FindProxyForURL")); 508 return (*function)->IsFunction(); 509 } 510 511 // Handle an exception thrown by V8. 512 void HandleError(v8::Handle<v8::Message> message) { 513 if (message.IsEmpty()) 514 return; 515 error_listener_->ErrorMessage(V8StringToUTF16(message->Get())); 516 } 517 518 // Compiles and runs |script| in the current V8 context. 519 // Returns OK on success, otherwise an error code. 520 int RunScript(v8::Handle<v8::String> script, const char* script_name) { 521 v8::TryCatch try_catch; 522 523 // Compile the script. 524 v8::ScriptOrigin origin = 525 v8::ScriptOrigin(ASCIILiteralToV8String(script_name)); 526 v8::Local<v8::Script> code = v8::Script::Compile(script, &origin); 527 528 // Execute. 529 if (!code.IsEmpty()) 530 code->Run(); 531 532 // Check for errors. 533 if (try_catch.HasCaught()) { 534 HandleError(try_catch.Message()); 535 return ERR_PAC_SCRIPT_FAILED; 536 } 537 538 return OK; 539 } 540 541 // V8 callback for when "alert()" is invoked by the PAC script. 542 static v8::Handle<v8::Value> AlertCallback(const v8::Arguments& args) { 543 Context* context = 544 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 545 546 // Like firefox we assume "undefined" if no argument was specified, and 547 // disregard any arguments beyond the first. 548 android::String16 message; 549 if (args.Length() == 0) { 550 std::string undef = "undefined"; 551 android::String8 undef8(undef.c_str()); 552 android::String16 wundef(undef8); 553 message = wundef; 554 } else { 555 if (!V8ObjectToUTF16String(args[0], &message)) 556 return v8::Undefined(); // toString() threw an exception. 557 } 558 559 context->error_listener_->AlertMessage(message); 560 return v8::Undefined(); 561 } 562 563 // V8 callback for when "myIpAddress()" is invoked by the PAC script. 564 static v8::Handle<v8::Value> MyIpAddressCallback(const v8::Arguments& args) { 565 Context* context = 566 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 567 568 std::string result; 569 bool success; 570 571 { 572 v8::Unlocker unlocker; 573 574 // We shouldn't be called with any arguments, but will not complain if 575 // we are. 576 success = context->js_bindings_->MyIpAddress(&result); 577 } 578 579 if (!success) 580 return ASCIILiteralToV8String("127.0.0.1"); 581 return ASCIIStringToV8String(result); 582 } 583 584 // V8 callback for when "myIpAddressEx()" is invoked by the PAC script. 585 static v8::Handle<v8::Value> MyIpAddressExCallback( 586 const v8::Arguments& args) { 587 Context* context = 588 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 589 590 std::string ip_address_list; 591 bool success; 592 593 { 594 v8::Unlocker unlocker; 595 596 // We shouldn't be called with any arguments, but will not complain if 597 // we are. 598 success = context->js_bindings_->MyIpAddressEx(&ip_address_list); 599 } 600 601 if (!success) 602 ip_address_list = std::string(); 603 return ASCIIStringToV8String(ip_address_list); 604 } 605 606 // V8 callback for when "dnsResolve()" is invoked by the PAC script. 607 static v8::Handle<v8::Value> DnsResolveCallback(const v8::Arguments& args) { 608 Context* context = 609 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 610 611 // We need at least one string argument. 612 std::string hostname; 613 if (!GetHostnameArgument(args, &hostname)) 614 return v8::Null(); 615 616 std::string ip_address; 617 bool success; 618 619 { 620 v8::Unlocker unlocker; 621 success = context->js_bindings_->DnsResolve(hostname, &ip_address); 622 } 623 624 return success ? ASCIIStringToV8String(ip_address) : v8::Null(); 625 } 626 627 // V8 callback for when "dnsResolveEx()" is invoked by the PAC script. 628 static v8::Handle<v8::Value> DnsResolveExCallback(const v8::Arguments& args) { 629 Context* context = 630 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 631 632 // We need at least one string argument. 633 std::string hostname; 634 if (!GetHostnameArgument(args, &hostname)) 635 return v8::Undefined(); 636 637 std::string ip_address_list; 638 bool success; 639 640 { 641 v8::Unlocker unlocker; 642 success = context->js_bindings_->DnsResolveEx(hostname, &ip_address_list); 643 } 644 645 if (!success) 646 ip_address_list = std::string(); 647 648 return ASCIIStringToV8String(ip_address_list); 649 } 650 651 // V8 callback for when "sortIpAddressList()" is invoked by the PAC script. 652 static v8::Handle<v8::Value> SortIpAddressListCallback( 653 const v8::Arguments& args) { 654 // We need at least one string argument. 655 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) 656 return v8::Null(); 657 658 std::string ip_address_list = V8StringToUTF8(args[0]->ToString()); 659 std::string sorted_ip_address_list; 660 bool success = SortIpAddressList(ip_address_list, &sorted_ip_address_list); 661 if (!success) 662 return v8::False(); 663 return ASCIIStringToV8String(sorted_ip_address_list); 664 } 665 666 // V8 callback for when "isInNetEx()" is invoked by the PAC script. 667 static v8::Handle<v8::Value> IsInNetExCallback(const v8::Arguments& args) { 668 // We need at least 2 string arguments. 669 if (args.Length() < 2 || args[0].IsEmpty() || !args[0]->IsString() || 670 args[1].IsEmpty() || !args[1]->IsString()) 671 return v8::Null(); 672 673 std::string ip_address = V8StringToUTF8(args[0]->ToString()); 674 std::string ip_prefix = V8StringToUTF8(args[1]->ToString()); 675 return IsInNetEx(ip_address, ip_prefix) ? v8::True() : v8::False(); 676 } 677 678 ProxyResolverJSBindings* js_bindings_; 679 ProxyErrorListener* error_listener_; 680 v8::Persistent<v8::External> v8_this_; 681 v8::Persistent<v8::Context> v8_context_; 682 }; 683 684 // ProxyResolverV8 ------------------------------------------------------------ 685 686 ProxyResolverV8::ProxyResolverV8( 687 ProxyResolverJSBindings* custom_js_bindings, 688 ProxyErrorListener* error_listener) 689 : context_(NULL), js_bindings_(custom_js_bindings), 690 error_listener_(error_listener) { 691 692 } 693 694 ProxyResolverV8::~ProxyResolverV8() { 695 if (context_ != NULL) { 696 delete context_; 697 context_ = NULL; 698 } 699 if (js_bindings_ != NULL) { 700 delete js_bindings_; 701 } 702 } 703 704 int ProxyResolverV8::GetProxyForURL(const android::String16 spec, const android::String16 host, 705 android::String16* results) { 706 // If the V8 instance has not been initialized (either because 707 // SetPacScript() wasn't called yet, or because it failed. 708 if (context_ == NULL) 709 return ERR_FAILED; 710 711 // Otherwise call into V8. 712 int rv = context_->ResolveProxy(spec, host, results); 713 714 return rv; 715 } 716 717 void ProxyResolverV8::PurgeMemory() { 718 context_->PurgeMemory(); 719 } 720 721 int ProxyResolverV8::SetPacScript(const android::String16& script_data) { 722 if (context_ != NULL) { 723 delete context_; 724 context_ = NULL; 725 } 726 if (script_data.size() == 0) 727 return ERR_PAC_SCRIPT_FAILED; 728 729 // Try parsing the PAC script. 730 context_ = new Context(js_bindings_, error_listener_); 731 int rv; 732 if ((rv = context_->InitV8(script_data)) != OK) { 733 context_ = NULL; 734 } 735 if (rv != OK) 736 context_ = NULL; 737 return rv; 738 } 739 740 } // namespace net 741