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 74static 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 83bool IsStringASCII(const android::String16& str) { 84 return DoIsStringASCII(str); 85} 86 87namespace net { 88 89namespace { 90 91// Pseudo-name for the PAC script. 92const char kPacResourceName[] = "proxy-pac-script.js"; 93// Pseudo-name for the PAC utility script. 94const char kPacUtilityResourceName[] = "proxy-pac-utility-script.js"; 95 96// External string wrapper so V8 can access the UTF16 string wrapped by 97// ProxyResolverScriptData. 98class 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. 119class 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. 145const size_t kMaxStringBytesForCopy = 256; 146 147template <class string_type> 148inline 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. 156std::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. 163android::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 172std::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. 178v8::Local<v8::String> ASCIIStringToV8String(v8::Isolate* isolate, const std::string& s) { 179 return v8::String::NewFromUtf8(isolate, s.data(), v8::String::kNormalString, s.size()); 180} 181 182v8::Local<v8::String> UTF16StringToV8String(v8::Isolate* isolate, const android::String16& s) { 183 return v8::String::NewFromTwoByte(isolate, s.string(), v8::String::kNormalString, s.size()); 184} 185 186// Converts an ASCII string literal to a V8 string. 187v8::Local<v8::String> ASCIILiteralToV8String(v8::Isolate* isolate, const char* ascii) { 188// DCHECK(IsStringASCII(ascii)); 189 size_t length = strlen(ascii); 190 if (length <= kMaxStringBytesForCopy) 191 return v8::String::NewFromUtf8(isolate, ascii, v8::String::kNormalString, length); 192 return v8::String::NewExternal(isolate, 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. 197bool V8ObjectToUTF16String(v8::Handle<v8::Value> object, 198 android::String16* utf16_result, 199 v8::Isolate* isolate) { 200 if (object.IsEmpty()) 201 return false; 202 203 v8::HandleScope scope(isolate); 204 v8::Local<v8::String> str_object = object->ToString(); 205 if (str_object.IsEmpty()) 206 return false; 207 *utf16_result = V8StringToUTF16(str_object); 208 return true; 209} 210 211// Extracts an hostname argument from |args|. On success returns true 212// and fills |*hostname| with the result. 213bool GetHostnameArgument(const v8::FunctionCallbackInfo<v8::Value>& args, std::string* hostname) { 214 // The first argument should be a string. 215 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) 216 return false; 217 218 const android::String16 hostname_utf16 = V8StringToUTF16(args[0]->ToString()); 219 220 // If the hostname is already in ASCII, simply return it as is. 221 if (IsStringASCII(hostname_utf16)) { 222 *hostname = UTF16ToASCII(hostname_utf16); 223 return true; 224 } 225 return false; 226} 227 228// Wrapper for passing around IP address strings and IPAddressNumber objects. 229struct IPAddress { 230 IPAddress(const std::string& ip_string, const IPAddressNumber& ip_number) 231 : string_value(ip_string), 232 ip_address_number(ip_number) { 233 } 234 235 // Used for sorting IP addresses in ascending order in SortIpAddressList(). 236 // IP6 addresses are placed ahead of IPv4 addresses. 237 bool operator<(const IPAddress& rhs) const { 238 const IPAddressNumber& ip1 = this->ip_address_number; 239 const IPAddressNumber& ip2 = rhs.ip_address_number; 240 if (ip1.size() != ip2.size()) 241 return ip1.size() > ip2.size(); // IPv6 before IPv4. 242 return memcmp(&ip1[0], &ip2[0], ip1.size()) < 0; // Ascending order. 243 } 244 245 std::string string_value; 246 IPAddressNumber ip_address_number; 247}; 248 249template<typename STR> 250bool RemoveCharsT(const STR& input, 251 const typename STR::value_type remove_chars[], 252 STR* output) { 253 bool removed = false; 254 size_t found; 255 256 *output = input; 257 258 found = output->find_first_of(remove_chars); 259 while (found != STR::npos) { 260 removed = true; 261 output->replace(found, 1, STR()); 262 found = output->find_first_of(remove_chars, found); 263 } 264 265 return removed; 266} 267 268bool RemoveChars(const std::string& input, 269 const char remove_chars[], 270 std::string* output) { 271 return RemoveCharsT(input, remove_chars, output); 272} 273 274// Handler for "sortIpAddressList(IpAddressList)". |ip_address_list| is a 275// semi-colon delimited string containing IP addresses. 276// |sorted_ip_address_list| is the resulting list of sorted semi-colon delimited 277// IP addresses or an empty string if unable to sort the IP address list. 278// Returns 'true' if the sorting was successful, and 'false' if the input was an 279// empty string, a string of separators (";" in this case), or if any of the IP 280// addresses in the input list failed to parse. 281bool SortIpAddressList(const std::string& ip_address_list, 282 std::string* sorted_ip_address_list) { 283 sorted_ip_address_list->clear(); 284 285 // Strip all whitespace (mimics IE behavior). 286 std::string cleaned_ip_address_list; 287 RemoveChars(ip_address_list, " \t", &cleaned_ip_address_list); 288 if (cleaned_ip_address_list.empty()) 289 return false; 290 291 // Split-up IP addresses and store them in a vector. 292 std::vector<IPAddress> ip_vector; 293 IPAddressNumber ip_num; 294 char *tok_list = strtok((char *)cleaned_ip_address_list.c_str(), ";"); 295 while (tok_list != NULL) { 296 if (!ParseIPLiteralToNumber(tok_list, &ip_num)) 297 return false; 298 ip_vector.push_back(IPAddress(tok_list, ip_num)); 299 tok_list = strtok(NULL, ";"); 300 } 301 302 if (ip_vector.empty()) // Can happen if we have something like 303 return false; // sortIpAddressList(";") or sortIpAddressList("; ;") 304 305 // Sort lists according to ascending numeric value. 306 if (ip_vector.size() > 1) 307 std::stable_sort(ip_vector.begin(), ip_vector.end()); 308 309 // Return a semi-colon delimited list of sorted addresses (IPv6 followed by 310 // IPv4). 311 for (size_t i = 0; i < ip_vector.size(); ++i) { 312 if (i > 0) 313 *sorted_ip_address_list += ";"; 314 *sorted_ip_address_list += ip_vector[i].string_value; 315 } 316 return true; 317} 318 319 320// Handler for "isInNetEx(ip_address, ip_prefix)". |ip_address| is a string 321// containing an IPv4/IPv6 address, and |ip_prefix| is a string containg a 322// slash-delimited IP prefix with the top 'n' bits specified in the bit 323// field. This returns 'true' if the address is in the same subnet, and 324// 'false' otherwise. Also returns 'false' if the prefix is in an incorrect 325// format, or if an address and prefix of different types are used (e.g. IPv6 326// address and IPv4 prefix). 327bool IsInNetEx(const std::string& ip_address, const std::string& ip_prefix) { 328 IPAddressNumber address; 329 std::string cleaned_ip_address; 330 if (RemoveChars(ip_address, " \t", &cleaned_ip_address)) 331 return false; 332 if (!ParseIPLiteralToNumber(ip_address, &address)) 333 return false; 334 335 IPAddressNumber prefix; 336 size_t prefix_length_in_bits; 337 if (!ParseCIDRBlock(ip_prefix, &prefix, &prefix_length_in_bits)) 338 return false; 339 340 // Both |address| and |prefix| must be of the same type (IPv4 or IPv6). 341 if (address.size() != prefix.size()) 342 return false; 343 344 return IPNumberMatchesPrefix(address, prefix, prefix_length_in_bits); 345} 346 347} // namespace 348 349// ProxyResolverV8::Context --------------------------------------------------- 350 351class ProxyResolverV8::Context { 352 public: 353 explicit Context(ProxyResolverJSBindings* js_bindings, 354 ProxyErrorListener* error_listener, v8::Isolate* isolate) 355 : js_bindings_(js_bindings), error_listener_(error_listener), isolate_(isolate) { 356 } 357 358 ~Context() { 359 v8::Locker locked(isolate_); 360 v8::Isolate::Scope isolate_scope(isolate_); 361 362 v8_this_.Reset(); 363 v8_context_.Reset(); 364 } 365 366 int ResolveProxy(const android::String16 url, const android::String16 host, 367 android::String16* results) { 368 v8::Locker locked(isolate_); 369 v8::Isolate::Scope isolate_scope(isolate_); 370 v8::HandleScope scope(isolate_); 371 372 v8::Local<v8::Context> context = 373 v8::Local<v8::Context>::New(isolate_, v8_context_); 374 v8::Context::Scope function_scope(context); 375 376 v8::Local<v8::Value> function; 377 if (!GetFindProxyForURL(&function)) { 378 error_listener_->ErrorMessage( 379 android::String16("FindProxyForURL() is undefined")); 380 return ERR_PAC_SCRIPT_FAILED; 381 } 382 383 v8::Handle<v8::Value> argv[] = { 384 UTF16StringToV8String(isolate_, url), 385 UTF16StringToV8String(isolate_, host) }; 386 387 v8::TryCatch try_catch; 388 v8::Local<v8::Value> ret = v8::Function::Cast(*function)->Call( 389 context->Global(), 2, argv); 390 391 if (try_catch.HasCaught()) { 392 error_listener_->ErrorMessage( 393 V8StringToUTF16(try_catch.Message()->Get())); 394 return ERR_PAC_SCRIPT_FAILED; 395 } 396 397 if (!ret->IsString()) { 398 error_listener_->ErrorMessage( 399 android::String16("FindProxyForURL() did not return a string.")); 400 return ERR_PAC_SCRIPT_FAILED; 401 } 402 403 *results = V8StringToUTF16(ret->ToString()); 404 405 if (!IsStringASCII(*results)) { 406 // TODO: Rather than failing when a wide string is returned, we 407 // could extend the parsing to handle IDNA hostnames by 408 // converting them to ASCII punycode. 409 // crbug.com/47234 410 error_listener_->ErrorMessage( 411 android::String16("FindProxyForURL() returned a non-ASCII string")); 412 return ERR_PAC_SCRIPT_FAILED; 413 } 414 415 return OK; 416 } 417 418 int InitV8(const android::String16& pac_script) { 419 v8::Locker locked(isolate_); 420 v8::Isolate::Scope isolate_scope(isolate_); 421 v8::HandleScope scope(isolate_); 422 423 v8_this_.Reset(isolate_, v8::External::New(isolate_, this)); 424 v8::Local<v8::External> v8_this = 425 v8::Local<v8::External>::New(isolate_, v8_this_); 426 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 427 428 // Attach the javascript bindings. 429 v8::Local<v8::FunctionTemplate> alert_template = 430 v8::FunctionTemplate::New(isolate_, &AlertCallback, v8_this); 431 global_template->Set(ASCIILiteralToV8String(isolate_, "alert"), alert_template); 432 433 v8::Local<v8::FunctionTemplate> my_ip_address_template = 434 v8::FunctionTemplate::New(isolate_, &MyIpAddressCallback, v8_this); 435 global_template->Set(ASCIILiteralToV8String(isolate_, "myIpAddress"), 436 my_ip_address_template); 437 438 v8::Local<v8::FunctionTemplate> dns_resolve_template = 439 v8::FunctionTemplate::New(isolate_, &DnsResolveCallback, v8_this); 440 global_template->Set(ASCIILiteralToV8String(isolate_, "dnsResolve"), 441 dns_resolve_template); 442 443 // Microsoft's PAC extensions: 444 445 v8::Local<v8::FunctionTemplate> dns_resolve_ex_template = 446 v8::FunctionTemplate::New(isolate_, &DnsResolveExCallback, v8_this); 447 global_template->Set(ASCIILiteralToV8String(isolate_, "dnsResolveEx"), 448 dns_resolve_ex_template); 449 450 v8::Local<v8::FunctionTemplate> my_ip_address_ex_template = 451 v8::FunctionTemplate::New(isolate_, &MyIpAddressExCallback, v8_this); 452 global_template->Set(ASCIILiteralToV8String(isolate_, "myIpAddressEx"), 453 my_ip_address_ex_template); 454 455 v8::Local<v8::FunctionTemplate> sort_ip_address_list_template = 456 v8::FunctionTemplate::New(isolate_, &SortIpAddressListCallback, v8_this); 457 global_template->Set(ASCIILiteralToV8String(isolate_, "sortIpAddressList"), 458 sort_ip_address_list_template); 459 460 v8::Local<v8::FunctionTemplate> is_in_net_ex_template = 461 v8::FunctionTemplate::New(isolate_, &IsInNetExCallback, v8_this); 462 global_template->Set(ASCIILiteralToV8String(isolate_, "isInNetEx"), 463 is_in_net_ex_template); 464 465 v8_context_.Reset( 466 isolate_, v8::Context::New(isolate_, NULL, global_template)); 467 468 v8::Local<v8::Context> context = 469 v8::Local<v8::Context>::New(isolate_, v8_context_); 470 v8::Context::Scope ctx(context); 471 472 // Add the PAC utility functions to the environment. 473 // (This script should never fail, as it is a string literal!) 474 // Note that the two string literals are concatenated. 475 int rv = RunScript( 476 ASCIILiteralToV8String(isolate_, 477 PROXY_RESOLVER_SCRIPT 478 PROXY_RESOLVER_SCRIPT_EX), 479 kPacUtilityResourceName); 480 if (rv != OK) { 481 return rv; 482 } 483 484 // Add the user's PAC code to the environment. 485 rv = RunScript(UTF16StringToV8String(isolate_, pac_script), kPacResourceName); 486 if (rv != OK) { 487 return rv; 488 } 489 490 // At a minimum, the FindProxyForURL() function must be defined for this 491 // to be a legitimiate PAC script. 492 v8::Local<v8::Value> function; 493 if (!GetFindProxyForURL(&function)) 494 return ERR_PAC_SCRIPT_FAILED; 495 496 return OK; 497 } 498 499 void PurgeMemory() { 500 v8::Locker locked(isolate_); 501 v8::Isolate::Scope isolate_scope(isolate_); 502 isolate_->LowMemoryNotification(); 503 } 504 505 private: 506 bool GetFindProxyForURL(v8::Local<v8::Value>* function) { 507 v8::Local<v8::Context> context = 508 v8::Local<v8::Context>::New(isolate_, v8_context_); 509 *function = context->Global()->Get( 510 ASCIILiteralToV8String(isolate_, "FindProxyForURL")); 511 return (*function)->IsFunction(); 512 } 513 514 // Handle an exception thrown by V8. 515 void HandleError(v8::Handle<v8::Message> message) { 516 if (message.IsEmpty()) 517 return; 518 error_listener_->ErrorMessage(V8StringToUTF16(message->Get())); 519 } 520 521 // Compiles and runs |script| in the current V8 context. 522 // Returns OK on success, otherwise an error code. 523 int RunScript(v8::Handle<v8::String> script, const char* script_name) { 524 v8::TryCatch try_catch; 525 526 // Compile the script. 527 v8::ScriptOrigin origin = 528 v8::ScriptOrigin(ASCIILiteralToV8String(isolate_, script_name)); 529 v8::Local<v8::Script> code = v8::Script::Compile(script, &origin); 530 531 // Execute. 532 if (!code.IsEmpty()) 533 code->Run(); 534 535 // Check for errors. 536 if (try_catch.HasCaught()) { 537 HandleError(try_catch.Message()); 538 return ERR_PAC_SCRIPT_FAILED; 539 } 540 541 return OK; 542 } 543 544 // V8 callback for when "alert()" is invoked by the PAC script. 545 static void AlertCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 546 Context* context = 547 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 548 549 // Like firefox we assume "undefined" if no argument was specified, and 550 // disregard any arguments beyond the first. 551 android::String16 message; 552 if (args.Length() == 0) { 553 std::string undef = "undefined"; 554 android::String8 undef8(undef.c_str()); 555 android::String16 wundef(undef8); 556 message = wundef; 557 } else { 558 if (!V8ObjectToUTF16String(args[0], &message, args.GetIsolate())) 559 return; // toString() threw an exception. 560 } 561 562 context->error_listener_->AlertMessage(message); 563 return; 564 } 565 566 // V8 callback for when "myIpAddress()" is invoked by the PAC script. 567 static void MyIpAddressCallback( 568 const v8::FunctionCallbackInfo<v8::Value>& args) { 569 Context* context = 570 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 571 572 std::string result; 573 bool success; 574 575 { 576 v8::Unlocker unlocker(args.GetIsolate()); 577 578 // We shouldn't be called with any arguments, but will not complain if 579 // we are. 580 success = context->js_bindings_->MyIpAddress(&result); 581 } 582 583 if (!success) { 584 args.GetReturnValue().Set(ASCIILiteralToV8String(args.GetIsolate(), "127.0.0.1")); 585 } else { 586 args.GetReturnValue().Set(ASCIIStringToV8String(args.GetIsolate(), result)); 587 } 588 } 589 590 // V8 callback for when "myIpAddressEx()" is invoked by the PAC script. 591 static void MyIpAddressExCallback( 592 const v8::FunctionCallbackInfo<v8::Value>& args) { 593 Context* context = 594 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 595 596 std::string ip_address_list; 597 bool success; 598 599 { 600 v8::Unlocker unlocker(args.GetIsolate()); 601 602 // We shouldn't be called with any arguments, but will not complain if 603 // we are. 604 success = context->js_bindings_->MyIpAddressEx(&ip_address_list); 605 } 606 607 if (!success) 608 ip_address_list = std::string(); 609 args.GetReturnValue().Set(ASCIIStringToV8String(args.GetIsolate(), ip_address_list)); 610 } 611 612 // V8 callback for when "dnsResolve()" is invoked by the PAC script. 613 static void DnsResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 614 Context* context = 615 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 616 617 // We need at least one string argument. 618 std::string hostname; 619 if (!GetHostnameArgument(args, &hostname)) { 620 return; 621 } 622 623 std::string ip_address; 624 bool success; 625 626 { 627 v8::Unlocker unlocker(args.GetIsolate()); 628 success = context->js_bindings_->DnsResolve(hostname, &ip_address); 629 } 630 631 if (success) { 632 args.GetReturnValue().Set(ASCIIStringToV8String(args.GetIsolate(), ip_address)); 633 } else { 634 args.GetReturnValue().SetNull(); 635 } 636 } 637 638 // V8 callback for when "dnsResolveEx()" is invoked by the PAC script. 639 static void DnsResolveExCallback( 640 const v8::FunctionCallbackInfo<v8::Value>& args) { 641 Context* context = 642 static_cast<Context*>(v8::External::Cast(*args.Data())->Value()); 643 644 // We need at least one string argument. 645 std::string hostname; 646 if (!GetHostnameArgument(args, &hostname)) { 647 args.GetReturnValue().SetNull(); 648 return; 649 } 650 651 std::string ip_address_list; 652 bool success; 653 654 { 655 v8::Unlocker unlocker(args.GetIsolate()); 656 success = context->js_bindings_->DnsResolveEx(hostname, &ip_address_list); 657 } 658 659 if (!success) 660 ip_address_list = std::string(); 661 662 args.GetReturnValue().Set(ASCIIStringToV8String(args.GetIsolate(), ip_address_list)); 663 } 664 665 // V8 callback for when "sortIpAddressList()" is invoked by the PAC script. 666 static void SortIpAddressListCallback( 667 const v8::FunctionCallbackInfo<v8::Value>& args) { 668 // We need at least one string argument. 669 if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString()) { 670 args.GetReturnValue().SetNull(); 671 return; 672 } 673 674 std::string ip_address_list = V8StringToUTF8(args[0]->ToString()); 675 std::string sorted_ip_address_list; 676 bool success = SortIpAddressList(ip_address_list, &sorted_ip_address_list); 677 if (!success) { 678 args.GetReturnValue().Set(false); 679 return; 680 } 681 args.GetReturnValue().Set(ASCIIStringToV8String(args.GetIsolate(), sorted_ip_address_list)); 682 } 683 684 // V8 callback for when "isInNetEx()" is invoked by the PAC script. 685 static void IsInNetExCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 686 // We need at least 2 string arguments. 687 if (args.Length() < 2 || args[0].IsEmpty() || !args[0]->IsString() || 688 args[1].IsEmpty() || !args[1]->IsString()) { 689 args.GetReturnValue().SetNull(); 690 return; 691 } 692 693 std::string ip_address = V8StringToUTF8(args[0]->ToString()); 694 std::string ip_prefix = V8StringToUTF8(args[1]->ToString()); 695 args.GetReturnValue().Set(IsInNetEx(ip_address, ip_prefix)); 696 } 697 698 ProxyResolverJSBindings* js_bindings_; 699 ProxyErrorListener* error_listener_; 700 v8::Isolate* isolate_; 701 v8::Persistent<v8::External> v8_this_; 702 v8::Persistent<v8::Context> v8_context_; 703}; 704 705// ProxyResolverV8 ------------------------------------------------------------ 706 707ProxyResolverV8::ProxyResolverV8( 708 ProxyResolverJSBindings* custom_js_bindings, 709 ProxyErrorListener* error_listener) 710 : context_(NULL), js_bindings_(custom_js_bindings), 711 error_listener_(error_listener) { 712 v8::V8::Initialize(); 713} 714 715ProxyResolverV8::~ProxyResolverV8() { 716 if (context_ != NULL) { 717 delete context_; 718 context_ = NULL; 719 } 720 if (js_bindings_ != NULL) { 721 delete js_bindings_; 722 } 723} 724 725int ProxyResolverV8::GetProxyForURL(const android::String16 spec, const android::String16 host, 726 android::String16* results) { 727 // If the V8 instance has not been initialized (either because 728 // SetPacScript() wasn't called yet, or because it failed. 729 if (context_ == NULL) 730 return ERR_FAILED; 731 732 // Otherwise call into V8. 733 int rv = context_->ResolveProxy(spec, host, results); 734 735 return rv; 736} 737 738void ProxyResolverV8::PurgeMemory() { 739 context_->PurgeMemory(); 740} 741 742int ProxyResolverV8::SetPacScript(const android::String16& script_data) { 743 if (context_ != NULL) { 744 delete context_; 745 context_ = NULL; 746 } 747 if (script_data.size() == 0) 748 return ERR_PAC_SCRIPT_FAILED; 749 750 // Try parsing the PAC script. 751 context_ = new Context(js_bindings_, error_listener_, v8::Isolate::New()); 752 int rv; 753 if ((rv = context_->InitV8(script_data)) != OK) { 754 context_ = NULL; 755 } 756 if (rv != OK) 757 context_ = NULL; 758 return rv; 759} 760 761} // namespace net 762