Index: net/proxy/proxy_resolver_v8.cc |
=================================================================== |
--- net/proxy/proxy_resolver_v8.cc (revision 51195) |
+++ net/proxy/proxy_resolver_v8.cc (working copy) |
@@ -4,6 +4,7 @@ |
#include "net/proxy/proxy_resolver_v8.h" |
+#include "base/basictypes.h" |
#include "base/logging.h" |
#include "base/string_util.h" |
#include "base/utf_string_conversions.h" |
@@ -72,6 +73,76 @@ |
// Pseudo-name for the PAC utility script. |
const char kPacUtilityResourceName[] = "proxy-pac-utility-script.js"; |
+// External string wrapper so V8 can access a string16. |
+class V8ExternalString16 : public v8::String::ExternalStringResource { |
+ public: |
+ explicit V8ExternalString16(const string16& string) : string_(string) {} |
+ |
+ virtual const uint16_t* data() const { |
+ return reinterpret_cast<const uint16*>(string_.data()); |
+ } |
+ |
+ virtual size_t length() const { |
+ return string_.size(); |
+ } |
+ |
+ private: |
+ const string16 string_; |
+ DISALLOW_COPY_AND_ASSIGN(V8ExternalString16); |
+}; |
+ |
+// External string wrapper so V8 can access a string literal. |
+class V8ExternalASCIILiteral : public v8::String::ExternalAsciiStringResource { |
+ public: |
+ // |ascii| must be a NULL-terminated C string, and must remain valid |
+ // throughout this object's lifetime. |
+ V8ExternalASCIILiteral(const char* ascii, size_t length) |
+ : ascii_(ascii), length_(length) { |
+ DCHECK(IsStringASCII(ascii)); |
+ } |
+ |
+ virtual const char* data() const { |
+ return ascii_; |
+ } |
+ |
+ virtual size_t length() const { |
+ return length_; |
+ } |
+ |
+ private: |
+ const char* ascii_; |
+ size_t length_; |
+ DISALLOW_COPY_AND_ASSIGN(V8ExternalASCIILiteral); |
+}; |
+ |
+// External string wrapper so V8 can access a std::string. |
+class V8ExternalASCIIString : public v8::String::ExternalAsciiStringResource { |
+ public: |
+ explicit V8ExternalASCIIString(const std::string& ascii) |
+ : ascii_(ascii) { |
+ DCHECK(IsStringASCII(ascii)); |
+ } |
+ |
+ virtual const char* data() const { |
+ return ascii_.data(); |
+ } |
+ |
+ virtual size_t length() const { |
+ return ascii_.size(); |
+ } |
+ |
+ private: |
+ const std::string ascii_; |
+ DISALLOW_COPY_AND_ASSIGN(V8ExternalASCIIString); |
+}; |
+ |
+// When creating a v8::String from a C++ string we have two choices: create |
+// a copy, or create a wrapper that shares the same underlying storage. |
+// For small strings it is better to just make a copy, whereas for large |
+// strings there are savings by sharing the storage. This number identifies |
+// the cutoff length for when to start wrapping rather than creating copies. |
+const size_t kMaxStringBytesForCopy = 256; |
+ |
// Converts a V8 String to a UTF16 string16. |
string16 V8StringToUTF16(v8::Handle<v8::String> s) { |
int len = s->Length(); |
@@ -82,11 +153,32 @@ |
return result; |
} |
-// Converts a std::string (UTF8) to a V8 string. |
-v8::Local<v8::String> UTF8StdStringToV8String(const std::string& s) { |
- return v8::String::New(s.data(), s.size()); |
+// Converts an ASCII std::string to a V8 string. |
+v8::Local<v8::String> ASCIIStringToV8String(const std::string& s) { |
+ DCHECK(IsStringASCII(s)); |
+ if (s.size() <= kMaxStringBytesForCopy) |
+ return v8::String::New(s.data(), s.size()); |
+ return v8::String::NewExternal(new V8ExternalASCIIString(s)); |
} |
+// Converts a UTF16 string16 to a V8 string. |
+v8::Local<v8::String> UTF16StringToV8String(const string16& s) { |
+ if (s.size() * 2 <= kMaxStringBytesForCopy) { |
+ return v8::String::New( |
+ reinterpret_cast<const uint16_t*>(s.data()), s.size()); |
+ } |
+ return v8::String::NewExternal(new V8ExternalString16(s)); |
+} |
+ |
+// Converts an ASCII string literal to a V8 string. |
+v8::Local<v8::String> ASCIILiteralToV8String(const char* ascii) { |
+ DCHECK(IsStringASCII(ascii)); |
+ size_t length = strlen(ascii); |
+ if (length <= kMaxStringBytesForCopy) |
+ return v8::String::New(ascii, length); |
+ return v8::String::NewExternal(new V8ExternalASCIILiteral(ascii, length)); |
+} |
+ |
// Stringizes a V8 object by calling its toString() method. Returns true |
// on success. This may fail if the toString() throws an exception. |
bool V8ObjectToUTF16String(v8::Handle<v8::Value> object, |
@@ -169,8 +261,8 @@ |
} |
v8::Handle<v8::Value> argv[] = { |
- UTF8StdStringToV8String(query_url.spec()), |
- UTF8StdStringToV8String(query_url.host()), |
+ ASCIIStringToV8String(query_url.spec()), |
+ ASCIIStringToV8String(query_url.host()), |
}; |
v8::TryCatch try_catch; |
@@ -206,7 +298,7 @@ |
return OK; |
} |
- int InitV8(const std::string& pac_data_utf8) { |
+ int InitV8(const string16& pac_script) { |
v8::Locker locked; |
v8::HandleScope scope; |
@@ -216,28 +308,28 @@ |
// Attach the javascript bindings. |
v8::Local<v8::FunctionTemplate> alert_template = |
v8::FunctionTemplate::New(&AlertCallback, v8_this_); |
- global_template->Set(v8::String::New("alert"), alert_template); |
+ global_template->Set(ASCIILiteralToV8String("alert"), alert_template); |
v8::Local<v8::FunctionTemplate> my_ip_address_template = |
v8::FunctionTemplate::New(&MyIpAddressCallback, v8_this_); |
- global_template->Set(v8::String::New("myIpAddress"), |
+ global_template->Set(ASCIILiteralToV8String("myIpAddress"), |
my_ip_address_template); |
v8::Local<v8::FunctionTemplate> dns_resolve_template = |
v8::FunctionTemplate::New(&DnsResolveCallback, v8_this_); |
- global_template->Set(v8::String::New("dnsResolve"), |
+ global_template->Set(ASCIILiteralToV8String("dnsResolve"), |
dns_resolve_template); |
// Microsoft's PAC extensions (incomplete): |
v8::Local<v8::FunctionTemplate> dns_resolve_ex_template = |
v8::FunctionTemplate::New(&DnsResolveExCallback, v8_this_); |
- global_template->Set(v8::String::New("dnsResolveEx"), |
+ global_template->Set(ASCIILiteralToV8String("dnsResolveEx"), |
dns_resolve_ex_template); |
v8::Local<v8::FunctionTemplate> my_ip_address_ex_template = |
v8::FunctionTemplate::New(&MyIpAddressExCallback, v8_this_); |
- global_template->Set(v8::String::New("myIpAddressEx"), |
+ global_template->Set(ASCIILiteralToV8String("myIpAddressEx"), |
my_ip_address_ex_template); |
v8_context_ = v8::Context::New(NULL, global_template); |
@@ -247,16 +339,18 @@ |
// Add the PAC utility functions to the environment. |
// (This script should never fail, as it is a string literal!) |
// Note that the two string literals are concatenated. |
- int rv = RunScript(PROXY_RESOLVER_SCRIPT |
- PROXY_RESOLVER_SCRIPT_EX, |
- kPacUtilityResourceName); |
+ int rv = RunScript( |
+ ASCIILiteralToV8String( |
+ PROXY_RESOLVER_SCRIPT |
+ PROXY_RESOLVER_SCRIPT_EX), |
+ kPacUtilityResourceName); |
if (rv != OK) { |
NOTREACHED(); |
return rv; |
} |
// Add the user's PAC code to the environment. |
- rv = RunScript(pac_data_utf8, kPacResourceName); |
+ rv = RunScript(UTF16StringToV8String(pac_script), kPacResourceName); |
if (rv != OK) |
return rv; |
@@ -285,7 +379,8 @@ |
private: |
bool GetFindProxyForURL(v8::Local<v8::Value>* function) { |
- *function = v8_context_->Global()->Get(v8::String::New("FindProxyForURL")); |
+ *function = v8_context_->Global()->Get( |
+ ASCIILiteralToV8String("FindProxyForURL")); |
return (*function)->IsFunction(); |
} |
@@ -301,15 +396,15 @@ |
js_bindings_->OnError(line_number, error_message); |
} |
- // Compiles and runs |script_utf8| in the current V8 context. |
+ // Compiles and runs |script| in the current V8 context. |
// Returns OK on success, otherwise an error code. |
- int RunScript(const std::string& script_utf8, const char* script_name) { |
+ int RunScript(v8::Handle<v8::String> script, const char* script_name) { |
v8::TryCatch try_catch; |
// Compile the script. |
- v8::Local<v8::String> text = UTF8StdStringToV8String(script_utf8); |
- v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New(script_name)); |
- v8::Local<v8::Script> code = v8::Script::Compile(text, &origin); |
+ v8::ScriptOrigin origin = |
+ v8::ScriptOrigin(ASCIILiteralToV8String(script_name)); |
+ v8::Local<v8::Script> code = v8::Script::Compile(script, &origin); |
// Execute. |
if (!code.IsEmpty()) |
@@ -370,8 +465,8 @@ |
} |
if (!success) |
- result = "127.0.0.1"; |
- return UTF8StdStringToV8String(result); |
+ return ASCIILiteralToV8String("127.0.0.1"); |
+ return ASCIIStringToV8String(result); |
} |
// V8 callback for when "myIpAddressEx()" is invoked by the PAC script. |
@@ -403,7 +498,7 @@ |
if (!success) |
ip_address_list = std::string(); |
- return UTF8StdStringToV8String(ip_address_list); |
+ return ASCIIStringToV8String(ip_address_list); |
} |
// V8 callback for when "dnsResolve()" is invoked by the PAC script. |
@@ -435,7 +530,7 @@ |
NULL); |
} |
- return success ? UTF8StdStringToV8String(ip_address) : v8::Null(); |
+ return success ? ASCIIStringToV8String(ip_address) : v8::Null(); |
} |
// V8 callback for when "dnsResolveEx()" is invoked by the PAC script. |
@@ -471,7 +566,7 @@ |
if (!success) |
ip_address_list = std::string(); |
- return UTF8StdStringToV8String(ip_address_list); |
+ return ASCIIStringToV8String(ip_address_list); |
} |
static void LogEventToCurrentRequest(Context* context, |
@@ -540,15 +635,15 @@ |
} |
int ProxyResolverV8::SetPacScript(const GURL& /*url*/, |
- const std::string& bytes_utf8, |
+ const string16& pac_script, |
CompletionCallback* /*callback*/) { |
context_.reset(); |
- if (bytes_utf8.empty()) |
+ if (pac_script.empty()) |
return ERR_PAC_SCRIPT_FAILED; |
// Try parsing the PAC script. |
scoped_ptr<Context> context(new Context(js_bindings_.get())); |
- int rv = context->InitV8(bytes_utf8); |
+ int rv = context->InitV8(pac_script); |
if (rv == OK) |
context_.reset(context.release()); |
return rv; |