|
@@ -21,6 +21,7 @@
|
|
|
#include "shell/common/gin_helper/error_thrower.h"
|
|
|
#include "shell/common/gin_helper/promise.h"
|
|
|
#include "shell/common/node_includes.h"
|
|
|
+#include "shell/common/options_switches.h"
|
|
|
#include "shell/renderer/api/electron_api_spell_check_client.h"
|
|
|
#include "third_party/blink/public/common/page/page_zoom.h"
|
|
|
#include "third_party/blink/public/common/web_cache/web_cache_resource_type_stats.h"
|
|
@@ -120,25 +121,83 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
|
|
|
|
|
explicit ScriptExecutionCallback(
|
|
|
gin_helper::Promise<v8::Local<v8::Value>> promise,
|
|
|
+ bool world_safe_result,
|
|
|
CompletionCallback callback)
|
|
|
- : promise_(std::move(promise)), callback_(std::move(callback)) {}
|
|
|
+ : promise_(std::move(promise)),
|
|
|
+ world_safe_result_(world_safe_result),
|
|
|
+ callback_(std::move(callback)) {}
|
|
|
|
|
|
~ScriptExecutionCallback() override = default;
|
|
|
|
|
|
+ void CopyResultToCallingContextAndFinalize(
|
|
|
+ v8::Isolate* isolate,
|
|
|
+ const v8::Local<v8::Value>& result) {
|
|
|
+ blink::CloneableMessage ret;
|
|
|
+ bool success;
|
|
|
+ std::string error_message;
|
|
|
+ {
|
|
|
+ v8::TryCatch try_catch(isolate);
|
|
|
+ success = gin::ConvertFromV8(isolate, result, &ret);
|
|
|
+ if (try_catch.HasCaught()) {
|
|
|
+ auto message = try_catch.Message();
|
|
|
+
|
|
|
+ if (message.IsEmpty() ||
|
|
|
+ !gin::ConvertFromV8(isolate, message->Get(), &error_message)) {
|
|
|
+ error_message =
|
|
|
+ "An unknown exception occurred while getting the result of "
|
|
|
+ "the script";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!success) {
|
|
|
+ // Failed convert so we send undefined everywhere
|
|
|
+ if (callback_)
|
|
|
+ std::move(callback_).Run(
|
|
|
+ v8::Undefined(isolate),
|
|
|
+ v8::Exception::Error(
|
|
|
+ v8::String::NewFromUtf8(isolate, error_message.c_str())
|
|
|
+ .ToLocalChecked()));
|
|
|
+ promise_.RejectWithErrorMessage(error_message);
|
|
|
+ } else {
|
|
|
+ v8::Local<v8::Context> context = promise_.GetContext();
|
|
|
+ v8::Context::Scope context_scope(context);
|
|
|
+ v8::Local<v8::Value> cloned_value = gin::ConvertToV8(isolate, ret);
|
|
|
+ if (callback_)
|
|
|
+ std::move(callback_).Run(cloned_value, v8::Undefined(isolate));
|
|
|
+ promise_.Resolve(cloned_value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
void Completed(
|
|
|
const blink::WebVector<v8::Local<v8::Value>>& result) override {
|
|
|
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
|
if (!result.empty()) {
|
|
|
if (!result[0].IsEmpty()) {
|
|
|
- // Right now only single results per frame is supported.
|
|
|
- if (!callback_.is_null())
|
|
|
- std::move(callback_).Run(result[0], v8::Undefined(isolate));
|
|
|
- promise_.Resolve(result[0]);
|
|
|
+ v8::Local<v8::Value> value = result[0];
|
|
|
+ // Either world safe results are disabled or the result was created in
|
|
|
+ // the same world as the caller or the result is not an object and
|
|
|
+ // therefore does not have a prototype chain to protect
|
|
|
+ bool should_clone_value =
|
|
|
+ world_safe_result_ &&
|
|
|
+ !(value->IsObject() &&
|
|
|
+ promise_.GetContext() ==
|
|
|
+ value.As<v8::Object>()->CreationContext()) &&
|
|
|
+ value->IsObject();
|
|
|
+ if (should_clone_value) {
|
|
|
+ CopyResultToCallingContextAndFinalize(isolate, value);
|
|
|
+ } else {
|
|
|
+ // Right now only single results per frame is supported.
|
|
|
+ if (callback_)
|
|
|
+ std::move(callback_).Run(value, v8::Undefined(isolate));
|
|
|
+ promise_.Resolve(value);
|
|
|
+ }
|
|
|
} else {
|
|
|
const char* error_message =
|
|
|
"Script failed to execute, this normally means an error "
|
|
|
"was thrown. Check the renderer console for the error.";
|
|
|
if (!callback_.is_null()) {
|
|
|
+ v8::Local<v8::Context> context = promise_.GetContext();
|
|
|
+ v8::Context::Scope context_scope(context);
|
|
|
std::move(callback_).Run(
|
|
|
v8::Undefined(isolate),
|
|
|
v8::Exception::Error(
|
|
@@ -152,6 +211,8 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
|
|
"WebFrame was removed before script could run. This normally means "
|
|
|
"the underlying frame was destroyed";
|
|
|
if (!callback_.is_null()) {
|
|
|
+ v8::Local<v8::Context> context = promise_.GetContext();
|
|
|
+ v8::Context::Scope context_scope(context);
|
|
|
std::move(callback_).Run(
|
|
|
v8::Undefined(isolate),
|
|
|
v8::Exception::Error(v8::String::NewFromUtf8(isolate, error_message)
|
|
@@ -164,6 +225,7 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
|
|
|
|
|
private:
|
|
|
gin_helper::Promise<v8::Local<v8::Value>> promise_;
|
|
|
+ bool world_safe_result_;
|
|
|
CompletionCallback callback_;
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
|
|
@@ -491,10 +553,13 @@ v8::Local<v8::Promise> ExecuteJavaScript(gin_helper::Arguments* args,
|
|
|
ScriptExecutionCallback::CompletionCallback completion_callback;
|
|
|
args->GetNext(&completion_callback);
|
|
|
|
|
|
+ bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
+ switches::kWorldSafeExecuteJavaScript);
|
|
|
+
|
|
|
render_frame->GetWebFrame()->RequestExecuteScriptAndReturnValue(
|
|
|
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
|
|
|
has_user_gesture,
|
|
|
- new ScriptExecutionCallback(std::move(promise),
|
|
|
+ new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
|
|
|
std::move(completion_callback)));
|
|
|
|
|
|
return handle;
|
|
@@ -554,13 +619,16 @@ v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
|
|
blink::WebURL(GURL(url)), start_line));
|
|
|
}
|
|
|
|
|
|
+ bool world_safe_exec_js = base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
|
+ switches::kWorldSafeExecuteJavaScript);
|
|
|
+
|
|
|
// Debugging tip: if you see a crash stack trace beginning from this call,
|
|
|
// then it is very likely that some exception happened when executing the
|
|
|
// "content_script/init.js" script.
|
|
|
render_frame->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
|
|
|
world_id, &sources.front(), sources.size(), has_user_gesture,
|
|
|
scriptExecutionType,
|
|
|
- new ScriptExecutionCallback(std::move(promise),
|
|
|
+ new ScriptExecutionCallback(std::move(promise), world_safe_exec_js,
|
|
|
std::move(completion_callback)));
|
|
|
|
|
|
return handle;
|