proxy_resolver_v8.cc revision 86b75a5f88eda8b47d1e34e26dfc0210aec09367
1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Use of this source code is governed by a BSD-style license that can be
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// found in the LICENSE file.
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <algorithm>
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <cstdio>
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <string>
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <utils/String16.h>
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "proxy_resolver_v8.h"
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "proxy_resolver_script.h"
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include "net_util.h"
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <include/v8.h>
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <algorithm>
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <vector>
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <iostream>
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <string.h>
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <utils/String8.h>
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson#include <utils/String16.h>
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Notes on the javascript environment:
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// For the majority of the PAC utility functions, we use the same code
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// as Firefox. See the javascript library that proxy_resolver_scipt.h
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// pulls in.
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// In addition, we implement a subset of Microsoft's extensions to PAC.
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// - myIpAddressEx()
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// - dnsResolveEx()
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// - isResolvableEx()
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// - isInNetEx()
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// - sortIpAddressList()
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// It is worth noting that the original PAC specification does not describe
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// the return values on failure. Consequently, there are compatibility
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// differences between browsers on what to return on failure, which are
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// illustrated below:
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// --------------------+-------------+-------------------+--------------
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//                     | Firefox3    | InternetExplorer8 |  --> Us <---
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// --------------------+-------------+-------------------+--------------
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// myIpAddress()       | "127.0.0.1" |  ???              |  "127.0.0.1"
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// dnsResolve()        | null        |  false            |  null
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// myIpAddressEx()     | N/A         |  ""               |  ""
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// sortIpAddressList() | N/A         |  false            |  false
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// dnsResolveEx()      | N/A         |  ""               |  ""
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// isInNetEx()         | N/A         |  false            |  false
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// --------------------+-------------+-------------------+--------------
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// TODO: The cell above reading ??? means I didn't test it.
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Another difference is in how dnsResolve() and myIpAddress() are
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// implemented -- whether they should restrict to IPv4 results, or
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// include both IPv4 and IPv6. The following table illustrates the
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// differences:
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// --------------------+-------------+-------------------+--------------
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//                     | Firefox3    | InternetExplorer8 |  --> Us <---
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// --------------------+-------------+-------------------+--------------
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// myIpAddress()       | IPv4/IPv6   |  IPv4             |  IPv4
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// dnsResolve()        | IPv4/IPv6   |  IPv4             |  IPv4
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// isResolvable()      | IPv4/IPv6   |  IPv4             |  IPv4
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// myIpAddressEx()     | N/A         |  IPv4/IPv6        |  IPv4/IPv6
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// dnsResolveEx()      | N/A         |  IPv4/IPv6        |  IPv4/IPv6
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// sortIpAddressList() | N/A         |  IPv4/IPv6        |  IPv4/IPv6
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// isResolvableEx()    | N/A         |  IPv4/IPv6        |  IPv4/IPv6
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// isInNetEx()         | N/A         |  IPv4/IPv6        |  IPv4/IPv6
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// -----------------+-------------+-------------------+--------------
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstatic bool DoIsStringASCII(const android::String16& str) {
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  for (size_t i = 0; i < str.size(); i++) {
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    unsigned short c = str.string()[i];
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (c > 0x7F)
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      return false;
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return true;
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool IsStringASCII(const android::String16& str) {
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return DoIsStringASCII(str);
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonnamespace net {
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonnamespace {
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Pseudo-name for the PAC script.
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonconst char kPacResourceName[] = "proxy-pac-script.js";
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Pseudo-name for the PAC utility script.
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonconst char kPacUtilityResourceName[] = "proxy-pac-utility-script.js";
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// External string wrapper so V8 can access the UTF16 string wrapped by
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// ProxyResolverScriptData.
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonclass V8ExternalStringFromScriptData
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    : public v8::String::ExternalStringResource {
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public:
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  explicit V8ExternalStringFromScriptData(
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      const android::String16& script_data)
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      : script_data_(script_data) {}
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  virtual const uint16_t* data() const {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return script_data_.string();
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  virtual size_t length() const {
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return script_data_.size();
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private:
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  const android::String16& script_data_;
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//  DISALLOW_COPY_AND_ASSIGN(V8ExternalStringFromScriptData);
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// External string wrapper so V8 can access a string literal.
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonclass V8ExternalASCIILiteral : public v8::String::ExternalAsciiStringResource {
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public:
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // |ascii| must be a NULL-terminated C string, and must remain valid
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // throughout this object's lifetime.
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  V8ExternalASCIILiteral(const char* ascii, size_t length)
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      : ascii_(ascii), length_(length) {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  virtual const char* data() const {
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return ascii_;
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  virtual size_t length() const {
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return length_;
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private:
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  const char* ascii_;
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  size_t length_;
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// When creating a v8::String from a C++ string we have two choices: create
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// a copy, or create a wrapper that shares the same underlying storage.
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// For small strings it is better to just make a copy, whereas for large
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// strings there are savings by sharing the storage. This number identifies
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// the cutoff length for when to start wrapping rather than creating copies.
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonconst size_t kMaxStringBytesForCopy = 256;
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsontemplate <class string_type>
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsoninline typename string_type::value_type* WriteInto(string_type* str,
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                                   size_t length_with_null) {
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  str->reserve(length_with_null);
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  str->resize(length_with_null - 1);
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return &((*str)[0]);
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Converts a V8 String to a UTF8 std::string.
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstd::string V8StringToUTF8(v8::Handle<v8::String> s) {
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::string result;
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  s->WriteUtf8(WriteInto(&result, s->Length() + 1));
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return result;
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Converts a V8 String to a UTF16 string.
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonandroid::String16 V8StringToUTF16(v8::Handle<v8::String> s) {
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  int len = s->Length();
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  char16_t* buf = new char16_t[len + 1];
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  s->Write(buf, 0, len);
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  android::String16 ret(buf, len);
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  delete buf;
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return ret;
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstd::string UTF16ToASCII(const android::String16& str) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    android::String8 rstr(str);
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return std::string(rstr.string());
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonandroid::String16 ASCIIToUTF16(const std::string str) {
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  android::String8 str8(str.c_str());
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return android::String16(str8);
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Converts an ASCII std::string to a V8 string.
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonv8::Local<v8::String> ASCIIStringToV8String(const std::string& s) {
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return v8::String::New(s.data(), s.size());
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonv8::Local<v8::String> UTF16StringToV8String(const android::String16& s) {
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return v8::String::New(s.string(), s.size());
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Converts an ASCII string literal to a V8 string.
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonv8::Local<v8::String> ASCIILiteralToV8String(const char* ascii) {
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson//  DCHECK(IsStringASCII(ascii));
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  size_t length = strlen(ascii);
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (length <= kMaxStringBytesForCopy)
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return v8::String::New(ascii, length);
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return v8::String::NewExternal(new V8ExternalASCIILiteral(ascii, length));
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Stringizes a V8 object by calling its toString() method. Returns true
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// on success. This may fail if the toString() throws an exception.
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool V8ObjectToUTF16String(v8::Handle<v8::Value> object,
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                           android::String16* utf16_result) {
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (object.IsEmpty())
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return false;
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  v8::HandleScope scope;
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  v8::Local<v8::String> str_object = object->ToString();
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (str_object.IsEmpty())
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return false;
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  *utf16_result = V8StringToUTF16(str_object);
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return true;
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Extracts an hostname argument from |args|. On success returns true
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// and fills |*hostname| with the result.
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool GetHostnameArgument(const v8::Arguments& args, std::string* hostname) {
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // The first argument should be a string.
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString())
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return false;
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  const android::String16 hostname_utf16 = V8StringToUTF16(args[0]->ToString());
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // If the hostname is already in ASCII, simply return it as is.
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (IsStringASCII(hostname_utf16)) {
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    *hostname = UTF16ToASCII(hostname_utf16);
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return true;
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return false;
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Wrapper for passing around IP address strings and IPAddressNumber objects.
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonstruct IPAddress {
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  IPAddress(const std::string& ip_string, const IPAddressNumber& ip_number)
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      : string_value(ip_string),
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ip_address_number(ip_number) {
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Used for sorting IP addresses in ascending order in SortIpAddressList().
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // IP6 addresses are placed ahead of IPv4 addresses.
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  bool operator<(const IPAddress& rhs) const {
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    const IPAddressNumber& ip1 = this->ip_address_number;
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    const IPAddressNumber& ip2 = rhs.ip_address_number;
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (ip1.size() != ip2.size())
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      return ip1.size() > ip2.size();  // IPv6 before IPv4.
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return memcmp(&ip1[0], &ip2[0], ip1.size()) < 0;  // Ascending order.
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::string string_value;
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  IPAddressNumber ip_address_number;
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson};
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsontemplate<typename STR>
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool RemoveCharsT(const STR& input,
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                  const typename STR::value_type remove_chars[],
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                  STR* output) {
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  bool removed = false;
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  size_t found;
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  *output = input;
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  found = output->find_first_of(remove_chars);
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  while (found != STR::npos) {
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    removed = true;
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    output->replace(found, 1, STR());
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    found = output->find_first_of(remove_chars, found);
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return removed;
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool RemoveChars(const std::string& input,
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 const char remove_chars[],
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 std::string* output) {
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  return RemoveCharsT(input, remove_chars, output);
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Handler for "sortIpAddressList(IpAddressList)". |ip_address_list| is a
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// semi-colon delimited string containing IP addresses.
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// |sorted_ip_address_list| is the resulting list of sorted semi-colon delimited
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// IP addresses or an empty string if unable to sort the IP address list.
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// Returns 'true' if the sorting was successful, and 'false' if the input was an
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// empty string, a string of separators (";" in this case), or if any of the IP
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson// addresses in the input list failed to parse.
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonbool SortIpAddressList(const std::string& ip_address_list,
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                       std::string* sorted_ip_address_list) {
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  sorted_ip_address_list->clear();
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Strip all whitespace (mimics IE behavior).
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::string cleaned_ip_address_list;
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  RemoveChars(ip_address_list, " \t", &cleaned_ip_address_list);
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (cleaned_ip_address_list.empty())
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return false;
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Split-up IP addresses and store them in a vector.
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  std::vector<IPAddress> ip_vector;
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  IPAddressNumber ip_num;
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  char *tok_list = strtok((char *)cleaned_ip_address_list.c_str(), ";");
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  while (tok_list != NULL) {
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (!ParseIPLiteralToNumber(tok_list, &ip_num))
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson      return false;
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    ip_vector.push_back(IPAddress(tok_list, ip_num));
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    tok_list = strtok(NULL, ";");
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  }
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (ip_vector.empty())  // Can happen if we have something like
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    return false;         // sortIpAddressList(";") or sortIpAddressList("; ;")
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Sort lists according to ascending numeric value.
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  if (ip_vector.size() > 1)
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    std::stable_sort(ip_vector.begin(), ip_vector.end());
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // Return a semi-colon delimited list of sorted addresses (IPv6 followed by
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  // IPv4).
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson  for (size_t i = 0; i < ip_vector.size(); ++i) {
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    if (i > 0)
317      *sorted_ip_address_list += ";";
318    *sorted_ip_address_list += ip_vector[i].string_value;
319  }
320  return true;
321}
322
323
324// Handler for "isInNetEx(ip_address, ip_prefix)". |ip_address| is a string
325// containing an IPv4/IPv6 address, and |ip_prefix| is a string containg a
326// slash-delimited IP prefix with the top 'n' bits specified in the bit
327// field. This returns 'true' if the address is in the same subnet, and
328// 'false' otherwise. Also returns 'false' if the prefix is in an incorrect
329// format, or if an address and prefix of different types are used (e.g. IPv6
330// address and IPv4 prefix).
331bool IsInNetEx(const std::string& ip_address, const std::string& ip_prefix) {
332  IPAddressNumber address;
333  if (!ParseIPLiteralToNumber(ip_address, &address))
334    return false;
335
336  IPAddressNumber prefix;
337  size_t prefix_length_in_bits;
338  if (!ParseCIDRBlock(ip_prefix, &prefix, &prefix_length_in_bits))
339    return false;
340
341  // Both |address| and |prefix| must be of the same type (IPv4 or IPv6).
342  if (address.size() != prefix.size())
343    return false;
344
345  return IPNumberMatchesPrefix(address, prefix, prefix_length_in_bits);
346}
347
348}  // namespace
349
350// ProxyResolverV8::Context ---------------------------------------------------
351
352class ProxyResolverV8::Context {
353 public:
354  explicit Context(ProxyResolverJSBindings* js_bindings,
355          ProxyErrorListener* error_listener)
356      : js_bindings_(js_bindings), error_listener_(error_listener) {
357  }
358
359  ~Context() {
360    v8::Locker locked;
361
362    v8_this_.Dispose();
363    v8_context_.Dispose();
364
365    // Run the V8 garbage collector. We do this to be sure the
366    // ExternalStringResource objects we allocated get properly disposed.
367    // Otherwise when running the unit-tests they may get leaked.
368    // See crbug.com/48145.
369    PurgeMemory();
370  }
371
372  int ResolveProxy(const android::String16 url, const android::String16 host, android::String16* results) {
373    v8::Locker locked;
374    v8::HandleScope scope;
375
376    v8::Context::Scope function_scope(v8_context_);
377
378    v8::Local<v8::Value> function;
379    if (!GetFindProxyForURL(&function)) {
380      *results = ASCIIToUTF16("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      *results = V8StringToUTF16(try_catch.Message()->Get());
394      return ERR_PAC_SCRIPT_FAILED;
395    }
396
397    if (!ret->IsString()) {
398      *results = ASCIIToUTF16("FindProxyForURL() did not return a string.");
399      return ERR_PAC_SCRIPT_FAILED;
400    }
401
402    *results = V8StringToUTF16(ret->ToString());
403
404    if (!IsStringASCII(*results)) {
405      // TODO:         Rather than failing when a wide string is returned, we
406      //               could extend the parsing to handle IDNA hostnames by
407      //               converting them to ASCII punycode.
408      //               crbug.com/47234
409      *results = ASCIIToUTF16("FindProxyForURL() returned a non-ASCII string");
410      return ERR_PAC_SCRIPT_FAILED;
411    }
412
413    return OK;
414  }
415
416  int InitV8(const android::String16& pac_script) {
417    v8::Locker locked;
418    v8::HandleScope scope;
419
420    v8_this_ = v8::Persistent<v8::External>::New(v8::External::New(this));
421    v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
422
423    // Attach the javascript bindings.
424    v8::Local<v8::FunctionTemplate> alert_template =
425        v8::FunctionTemplate::New(&AlertCallback, v8_this_);
426    global_template->Set(ASCIILiteralToV8String("alert"), alert_template);
427
428    v8::Local<v8::FunctionTemplate> my_ip_address_template =
429        v8::FunctionTemplate::New(&MyIpAddressCallback, v8_this_);
430    global_template->Set(ASCIILiteralToV8String("myIpAddress"),
431        my_ip_address_template);
432
433    v8::Local<v8::FunctionTemplate> dns_resolve_template =
434        v8::FunctionTemplate::New(&DnsResolveCallback, v8_this_);
435    global_template->Set(ASCIILiteralToV8String("dnsResolve"),
436        dns_resolve_template);
437
438    // Microsoft's PAC extensions:
439
440    v8::Local<v8::FunctionTemplate> dns_resolve_ex_template =
441        v8::FunctionTemplate::New(&DnsResolveExCallback, v8_this_);
442    global_template->Set(ASCIILiteralToV8String("dnsResolveEx"),
443                         dns_resolve_ex_template);
444
445    v8::Local<v8::FunctionTemplate> my_ip_address_ex_template =
446        v8::FunctionTemplate::New(&MyIpAddressExCallback, v8_this_);
447    global_template->Set(ASCIILiteralToV8String("myIpAddressEx"),
448                         my_ip_address_ex_template);
449
450    v8::Local<v8::FunctionTemplate> sort_ip_address_list_template =
451        v8::FunctionTemplate::New(&SortIpAddressListCallback, v8_this_);
452    global_template->Set(ASCIILiteralToV8String("sortIpAddressList"),
453                         sort_ip_address_list_template);
454
455    v8::Local<v8::FunctionTemplate> is_in_net_ex_template =
456        v8::FunctionTemplate::New(&IsInNetExCallback, v8_this_);
457    global_template->Set(ASCIILiteralToV8String("isInNetEx"),
458                         is_in_net_ex_template);
459
460    v8_context_ = v8::Context::New(NULL, global_template);
461
462    v8::Context::Scope ctx(v8_context_);
463
464    // Add the PAC utility functions to the environment.
465    // (This script should never fail, as it is a string literal!)
466    // Note that the two string literals are concatenated.
467    int rv = RunScript(
468        ASCIILiteralToV8String(
469            PROXY_RESOLVER_SCRIPT
470            PROXY_RESOLVER_SCRIPT_EX),
471        kPacUtilityResourceName);
472    if (rv != OK) {
473      return rv;
474    }
475
476    // Add the user's PAC code to the environment.
477    rv = RunScript(UTF16StringToV8String(pac_script), kPacResourceName);
478    if (rv != OK) {
479      return rv;
480    }
481
482    // At a minimum, the FindProxyForURL() function must be defined for this
483    // to be a legitimiate PAC script.
484    v8::Local<v8::Value> function;
485    if (!GetFindProxyForURL(&function))
486      return ERR_PAC_SCRIPT_FAILED;
487
488    return OK;
489  }
490
491  void PurgeMemory() {
492    v8::Locker locked;
493    // Repeatedly call the V8 idle notification until it returns true ("nothing
494    // more to free").  Note that it makes more sense to do this than to
495    // implement a new "delete everything" pass because object references make
496    // it difficult to free everything possible in just one pass.
497    while (!v8::V8::IdleNotification())
498      ;
499  }
500
501 private:
502  bool GetFindProxyForURL(v8::Local<v8::Value>* function) {
503    *function = v8_context_->Global()->Get(
504        ASCIILiteralToV8String("FindProxyForURL"));
505    return (*function)->IsFunction();
506  }
507
508  // Handle an exception thrown by V8.
509  void HandleError(v8::Handle<v8::Message> message) {
510    if (message.IsEmpty())
511      return;
512    error_listener_->ErrorMessage(V8StringToUTF16(message->Get()));
513  }
514
515  // Compiles and runs |script| in the current V8 context.
516  // Returns OK on success, otherwise an error code.
517  int RunScript(v8::Handle<v8::String> script, const char* script_name) {
518    v8::TryCatch try_catch;
519
520    // Compile the script.
521    v8::ScriptOrigin origin =
522        v8::ScriptOrigin(ASCIILiteralToV8String(script_name));
523    v8::Local<v8::Script> code = v8::Script::Compile(script, &origin);
524
525    // Execute.
526    if (!code.IsEmpty())
527      code->Run();
528
529    // Check for errors.
530    if (try_catch.HasCaught()) {
531      HandleError(try_catch.Message());
532      return ERR_PAC_SCRIPT_FAILED;
533    }
534
535    return OK;
536  }
537
538  // V8 callback for when "alert()" is invoked by the PAC script.
539  static v8::Handle<v8::Value> AlertCallback(const v8::Arguments& args) {
540    Context* context =
541        static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
542
543    // Like firefox we assume "undefined" if no argument was specified, and
544    // disregard any arguments beyond the first.
545    android::String16 message;
546    if (args.Length() == 0) {
547      std::string undef = "undefined";
548      android::String8 undef8(undef.c_str());
549      android::String16 wundef(undef8);
550      message = wundef;
551    } else {
552      if (!V8ObjectToUTF16String(args[0], &message))
553        return v8::Undefined();  // toString() threw an exception.
554    }
555
556    context->error_listener_->AlertMessage(message);
557    return v8::Undefined();
558  }
559
560  // V8 callback for when "myIpAddress()" is invoked by the PAC script.
561  static v8::Handle<v8::Value> MyIpAddressCallback(const v8::Arguments& args) {
562    Context* context =
563        static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
564
565    std::string result;
566    bool success;
567
568    {
569      v8::Unlocker unlocker;
570
571      // We shouldn't be called with any arguments, but will not complain if
572      // we are.
573      success = context->js_bindings_->MyIpAddress(&result);
574    }
575
576    if (!success)
577      return ASCIILiteralToV8String("127.0.0.1");
578    return ASCIIStringToV8String(result);
579  }
580
581  // V8 callback for when "myIpAddressEx()" is invoked by the PAC script.
582  static v8::Handle<v8::Value> MyIpAddressExCallback(
583      const v8::Arguments& args) {
584    Context* context =
585        static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
586
587    std::string ip_address_list;
588    bool success;
589
590    {
591      v8::Unlocker unlocker;
592
593      // We shouldn't be called with any arguments, but will not complain if
594      // we are.
595      success = context->js_bindings_->MyIpAddressEx(&ip_address_list);
596    }
597
598    if (!success)
599      ip_address_list = std::string();
600    return ASCIIStringToV8String(ip_address_list);
601  }
602
603  // V8 callback for when "dnsResolve()" is invoked by the PAC script.
604  static v8::Handle<v8::Value> DnsResolveCallback(const v8::Arguments& args) {
605    Context* context =
606        static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
607
608    // We need at least one string argument.
609    std::string hostname;
610    if (!GetHostnameArgument(args, &hostname))
611      return v8::Null();
612
613    std::string ip_address;
614    bool success;
615
616    {
617      v8::Unlocker unlocker;
618      success = context->js_bindings_->DnsResolve(hostname, &ip_address);
619    }
620
621    return success ? ASCIIStringToV8String(ip_address) : v8::Null();
622  }
623
624  // V8 callback for when "dnsResolveEx()" is invoked by the PAC script.
625  static v8::Handle<v8::Value> DnsResolveExCallback(const v8::Arguments& args) {
626    Context* context =
627        static_cast<Context*>(v8::External::Cast(*args.Data())->Value());
628
629    // We need at least one string argument.
630    std::string hostname;
631    if (!GetHostnameArgument(args, &hostname))
632      return v8::Undefined();
633
634    std::string ip_address_list;
635    bool success;
636
637    {
638      v8::Unlocker unlocker;
639      success = context->js_bindings_->DnsResolveEx(hostname, &ip_address_list);
640    }
641
642    if (!success)
643      ip_address_list = std::string();
644
645    return ASCIIStringToV8String(ip_address_list);
646  }
647
648  // V8 callback for when "sortIpAddressList()" is invoked by the PAC script.
649  static v8::Handle<v8::Value> SortIpAddressListCallback(
650      const v8::Arguments& args) {
651    // We need at least one string argument.
652    if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString())
653      return v8::Null();
654
655    std::string ip_address_list = V8StringToUTF8(args[0]->ToString());
656    std::string sorted_ip_address_list;
657    bool success = SortIpAddressList(ip_address_list, &sorted_ip_address_list);
658    if (!success)
659      return v8::False();
660    return ASCIIStringToV8String(sorted_ip_address_list);
661  }
662
663  // V8 callback for when "isInNetEx()" is invoked by the PAC script.
664  static v8::Handle<v8::Value> IsInNetExCallback(const v8::Arguments& args) {
665    // We need at least 2 string arguments.
666    if (args.Length() < 2 || args[0].IsEmpty() || !args[0]->IsString() ||
667        args[1].IsEmpty() || !args[1]->IsString())
668      return v8::Null();
669
670    std::string ip_address = V8StringToUTF8(args[0]->ToString());
671    std::string ip_prefix = V8StringToUTF8(args[1]->ToString());
672    return IsInNetEx(ip_address, ip_prefix) ? v8::True() : v8::False();
673  }
674
675  ProxyResolverJSBindings* js_bindings_;
676  ProxyErrorListener* error_listener_;
677  v8::Persistent<v8::External> v8_this_;
678  v8::Persistent<v8::Context> v8_context_;
679};
680
681// ProxyResolverV8 ------------------------------------------------------------
682
683ProxyResolverV8::ProxyResolverV8(
684    ProxyResolverJSBindings* custom_js_bindings,
685    ProxyErrorListener* error_listener)
686    : context_(NULL), js_bindings_(custom_js_bindings),
687      error_listener_(error_listener) {
688
689}
690
691ProxyResolverV8::~ProxyResolverV8() {
692  if (context_ != NULL) {
693    delete context_;
694    context_ = NULL;
695  }
696  if (js_bindings_ != NULL) {
697    delete js_bindings_;
698  }
699}
700
701int ProxyResolverV8::GetProxyForURL(const android::String16 spec, const android::String16 host,
702                                    android::String16* results) {
703  // If the V8 instance has not been initialized (either because
704  // SetPacScript() wasn't called yet, or because it failed.
705  if (context_ == NULL)
706    return ERR_FAILED;
707
708  // Otherwise call into V8.
709  int rv = context_->ResolveProxy(spec, host, results);
710
711  return rv;
712}
713
714void ProxyResolverV8::PurgeMemory() {
715  context_->PurgeMemory();
716}
717
718int ProxyResolverV8::SetPacScript(android::String16& script_data) {
719  if (context_ != NULL) {
720    delete context_;
721    context_ = NULL;
722  }
723  if (script_data.size() == 0)
724    return ERR_PAC_SCRIPT_FAILED;
725
726  // Try parsing the PAC script.
727  context_ = new Context(js_bindings_, error_listener_);
728  int rv;
729  if ((rv = context_->InitV8(script_data)) != OK) {
730    context_ = NULL;
731  }
732  if (rv != OK)
733    context_ = NULL;
734  return rv;
735}
736
737}  // namespace net
738