mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
feat: MessagePorts in the main process (#22404)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -44,12 +45,17 @@
|
||||
#include "content/public/common/context_menu_params.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "electron/shell/common/api/api.mojom.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "mojo/public/cpp/system/platform_handle.h"
|
||||
#include "ppapi/buildflags/buildflags.h"
|
||||
#include "shell/browser/api/electron_api_browser_window.h"
|
||||
#include "shell/browser/api/electron_api_debugger.h"
|
||||
#include "shell/browser/api/electron_api_session.h"
|
||||
#include "shell/browser/api/message_port.h"
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/browser/child_web_contents_tracker.h"
|
||||
#include "shell/browser/electron_autofill_driver_factory.h"
|
||||
@@ -84,11 +90,14 @@
|
||||
#include "shell/common/mouse_util.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
|
||||
#include "third_party/blink/public/common/input/web_input_event.h"
|
||||
#include "third_party/blink/public/common/messaging/transferable_message_mojom_traits.h"
|
||||
#include "third_party/blink/public/common/page/page_zoom.h"
|
||||
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
|
||||
#include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
|
||||
#include "third_party/blink/public/mojom/messaging/transferable_message.mojom.h"
|
||||
#include "ui/base/cursor/cursor.h"
|
||||
#include "ui/base/mojom/cursor_type.mojom-shared.h"
|
||||
#include "ui/display/screen.h"
|
||||
@@ -1088,6 +1097,49 @@ void WebContents::Invoke(bool internal,
|
||||
std::move(callback), internal, channel, std::move(arguments));
|
||||
}
|
||||
|
||||
void WebContents::ReceivePostMessage(const std::string& channel,
|
||||
blink::TransferableMessage message) {
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
auto wrapped_ports =
|
||||
MessagePort::EntanglePorts(isolate(), std::move(message.ports));
|
||||
v8::Local<v8::Value> message_value =
|
||||
electron::DeserializeV8Value(isolate(), message);
|
||||
EmitWithSender("-ipc-ports", bindings_.dispatch_context(), InvokeCallback(),
|
||||
false, channel, message_value, std::move(wrapped_ports));
|
||||
}
|
||||
|
||||
void WebContents::PostMessage(const std::string& channel,
|
||||
v8::Local<v8::Value> message_value,
|
||||
base::Optional<v8::Local<v8::Value>> transfer) {
|
||||
blink::TransferableMessage transferable_message;
|
||||
if (!electron::SerializeV8Value(isolate(), message_value,
|
||||
&transferable_message)) {
|
||||
// SerializeV8Value sets an exception.
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<gin::Handle<MessagePort>> wrapped_ports;
|
||||
if (transfer) {
|
||||
if (!gin::ConvertFromV8(isolate(), *transfer, &wrapped_ports)) {
|
||||
isolate()->ThrowException(v8::Exception::Error(
|
||||
gin::StringToV8(isolate(), "Invalid value for transfer")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool threw_exception = false;
|
||||
transferable_message.ports =
|
||||
MessagePort::DisentanglePorts(isolate(), wrapped_ports, &threw_exception);
|
||||
if (threw_exception)
|
||||
return;
|
||||
|
||||
content::RenderFrameHost* frame_host = web_contents()->GetMainFrame();
|
||||
mojo::AssociatedRemote<mojom::ElectronRenderer> electron_renderer;
|
||||
frame_host->GetRemoteAssociatedInterfaces()->GetInterface(&electron_renderer);
|
||||
electron_renderer->ReceivePostMessage(channel,
|
||||
std::move(transferable_message));
|
||||
}
|
||||
|
||||
void WebContents::MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
@@ -2663,6 +2715,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
||||
.SetMethod("isFocused", &WebContents::IsFocused)
|
||||
.SetMethod("tabTraverse", &WebContents::TabTraverse)
|
||||
.SetMethod("_send", &WebContents::SendIPCMessage)
|
||||
.SetMethod("_postMessage", &WebContents::PostMessage)
|
||||
.SetMethod("_sendToFrame", &WebContents::SendIPCMessageToFrame)
|
||||
.SetMethod("sendInputEvent", &WebContents::SendInputEvent)
|
||||
.SetMethod("beginFrameSubscription", &WebContents::BeginFrameSubscription)
|
||||
|
||||
@@ -256,6 +256,10 @@ class WebContents : public gin_helper::TrackableObject<WebContents>,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> args);
|
||||
|
||||
void PostMessage(const std::string& channel,
|
||||
v8::Local<v8::Value> message,
|
||||
base::Optional<v8::Local<v8::Value>> transfer);
|
||||
|
||||
// Send WebInputEvent to the page.
|
||||
void SendInputEvent(v8::Isolate* isolate, v8::Local<v8::Value> input_event);
|
||||
|
||||
@@ -525,6 +529,8 @@ class WebContents : public gin_helper::TrackableObject<WebContents>,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
InvokeCallback callback) override;
|
||||
void ReceivePostMessage(const std::string& channel,
|
||||
blink::TransferableMessage message) override;
|
||||
void MessageSync(bool internal,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
|
||||
276
shell/browser/api/message_port.cc
Normal file
276
shell/browser/api/message_port.cc
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2020 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/message_port.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "gin/handle.h"
|
||||
#include "gin/object_template_builder.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
#include "shell/common/gin_helper/event_emitter_caller.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
#include "third_party/blink/public/common/messaging/transferable_message.h"
|
||||
#include "third_party/blink/public/common/messaging/transferable_message_mojom_traits.h"
|
||||
#include "third_party/blink/public/mojom/messaging/transferable_message.mojom.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
gin::WrapperInfo MessagePort::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
MessagePort::MessagePort() = default;
|
||||
MessagePort::~MessagePort() = default;
|
||||
|
||||
// static
|
||||
gin::Handle<MessagePort> MessagePort::Create(v8::Isolate* isolate) {
|
||||
return gin::CreateHandle(isolate, new MessagePort());
|
||||
}
|
||||
|
||||
void MessagePort::PostMessage(gin::Arguments* args) {
|
||||
if (!IsEntangled())
|
||||
return;
|
||||
DCHECK(!IsNeutered());
|
||||
|
||||
blink::TransferableMessage transferable_message;
|
||||
|
||||
v8::Local<v8::Value> message_value;
|
||||
if (!args->GetNext(&message_value)) {
|
||||
args->ThrowTypeError("Expected at least one argument to postMessage");
|
||||
return;
|
||||
}
|
||||
|
||||
electron::SerializeV8Value(args->isolate(), message_value,
|
||||
&transferable_message);
|
||||
|
||||
v8::Local<v8::Value> transferables;
|
||||
std::vector<gin::Handle<MessagePort>> wrapped_ports;
|
||||
if (args->GetNext(&transferables)) {
|
||||
if (!gin::ConvertFromV8(args->isolate(), transferables, &wrapped_ports)) {
|
||||
args->ThrowError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we aren't connected to any of the passed-in ports.
|
||||
for (unsigned i = 0; i < wrapped_ports.size(); ++i) {
|
||||
if (wrapped_ports[i].get() == this) {
|
||||
gin_helper::ErrorThrower(args->isolate())
|
||||
.ThrowError("Port at index " + base::NumberToString(i) +
|
||||
" contains the source port.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool threw_exception = false;
|
||||
transferable_message.ports = MessagePort::DisentanglePorts(
|
||||
args->isolate(), wrapped_ports, &threw_exception);
|
||||
if (threw_exception)
|
||||
return;
|
||||
|
||||
mojo::Message mojo_message = blink::mojom::TransferableMessage::WrapAsMessage(
|
||||
std::move(transferable_message));
|
||||
connector_->Accept(&mojo_message);
|
||||
}
|
||||
|
||||
void MessagePort::Start() {
|
||||
if (!IsEntangled())
|
||||
return;
|
||||
|
||||
if (started_)
|
||||
return;
|
||||
|
||||
started_ = true;
|
||||
if (HasPendingActivity())
|
||||
Pin();
|
||||
connector_->ResumeIncomingMethodCallProcessing();
|
||||
}
|
||||
|
||||
void MessagePort::Close() {
|
||||
if (closed_)
|
||||
return;
|
||||
if (!IsNeutered()) {
|
||||
connector_ = nullptr;
|
||||
Entangle(mojo::MessagePipe().handle0);
|
||||
}
|
||||
closed_ = true;
|
||||
if (!HasPendingActivity())
|
||||
Unpin();
|
||||
}
|
||||
|
||||
void MessagePort::Entangle(mojo::ScopedMessagePipeHandle handle) {
|
||||
DCHECK(handle.is_valid());
|
||||
DCHECK(!connector_);
|
||||
connector_ = std::make_unique<mojo::Connector>(
|
||||
std::move(handle), mojo::Connector::SINGLE_THREADED_SEND,
|
||||
base::ThreadTaskRunnerHandle::Get());
|
||||
connector_->PauseIncomingMethodCallProcessing();
|
||||
connector_->set_incoming_receiver(this);
|
||||
connector_->set_connection_error_handler(
|
||||
base::Bind(&MessagePort::Close, weak_factory_.GetWeakPtr()));
|
||||
if (HasPendingActivity())
|
||||
Pin();
|
||||
}
|
||||
|
||||
void MessagePort::Entangle(blink::MessagePortChannel channel) {
|
||||
Entangle(channel.ReleaseHandle());
|
||||
}
|
||||
|
||||
blink::MessagePortChannel MessagePort::Disentangle() {
|
||||
DCHECK(!IsNeutered());
|
||||
auto result = blink::MessagePortChannel(connector_->PassMessagePipe());
|
||||
connector_ = nullptr;
|
||||
if (!HasPendingActivity())
|
||||
Unpin();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool MessagePort::HasPendingActivity() const {
|
||||
// The spec says that entangled message ports should always be treated as if
|
||||
// they have a strong reference.
|
||||
// We'll also stipulate that the queue needs to be open (if the app drops its
|
||||
// reference to the port before start()-ing it, then it's not really entangled
|
||||
// as it's unreachable).
|
||||
return started_ && IsEntangled();
|
||||
}
|
||||
|
||||
// static
|
||||
std::vector<gin::Handle<MessagePort>> MessagePort::EntanglePorts(
|
||||
v8::Isolate* isolate,
|
||||
std::vector<blink::MessagePortChannel> channels) {
|
||||
std::vector<gin::Handle<MessagePort>> wrapped_ports;
|
||||
for (auto& port : channels) {
|
||||
auto wrapped_port = MessagePort::Create(isolate);
|
||||
wrapped_port->Entangle(std::move(port));
|
||||
wrapped_ports.emplace_back(wrapped_port);
|
||||
}
|
||||
return wrapped_ports;
|
||||
}
|
||||
|
||||
// static
|
||||
std::vector<blink::MessagePortChannel> MessagePort::DisentanglePorts(
|
||||
v8::Isolate* isolate,
|
||||
const std::vector<gin::Handle<MessagePort>>& ports,
|
||||
bool* threw_exception) {
|
||||
if (!ports.size())
|
||||
return std::vector<blink::MessagePortChannel>();
|
||||
|
||||
std::unordered_set<MessagePort*> visited;
|
||||
|
||||
// Walk the incoming array - if there are any duplicate ports, or null ports
|
||||
// or cloned ports, throw an error (per section 8.3.3 of the HTML5 spec).
|
||||
for (unsigned i = 0; i < ports.size(); ++i) {
|
||||
auto* port = ports[i].get();
|
||||
if (!port || port->IsNeutered() || visited.find(port) != visited.end()) {
|
||||
std::string type;
|
||||
if (!port)
|
||||
type = "null";
|
||||
else if (port->IsNeutered())
|
||||
type = "already neutered";
|
||||
else
|
||||
type = "a duplicate";
|
||||
gin_helper::ErrorThrower(isolate).ThrowError(
|
||||
"Port at index " + base::NumberToString(i) + " is " + type + ".");
|
||||
*threw_exception = true;
|
||||
return std::vector<blink::MessagePortChannel>();
|
||||
}
|
||||
visited.insert(port);
|
||||
}
|
||||
|
||||
// Passed-in ports passed validity checks, so we can disentangle them.
|
||||
std::vector<blink::MessagePortChannel> channels;
|
||||
channels.reserve(ports.size());
|
||||
for (unsigned i = 0; i < ports.size(); ++i)
|
||||
channels.push_back(ports[i]->Disentangle());
|
||||
return channels;
|
||||
}
|
||||
|
||||
void MessagePort::Pin() {
|
||||
if (!pinned_.IsEmpty())
|
||||
return;
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::Local<v8::Value> self;
|
||||
if (GetWrapper(isolate).ToLocal(&self)) {
|
||||
pinned_.Reset(isolate, self);
|
||||
}
|
||||
}
|
||||
|
||||
void MessagePort::Unpin() {
|
||||
pinned_.Reset();
|
||||
}
|
||||
|
||||
bool MessagePort::Accept(mojo::Message* mojo_message) {
|
||||
blink::TransferableMessage message;
|
||||
if (!blink::mojom::TransferableMessage::DeserializeFromMessage(
|
||||
std::move(*mojo_message), &message)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto ports = EntanglePorts(isolate, std::move(message.ports));
|
||||
|
||||
v8::Local<v8::Value> message_value = DeserializeV8Value(isolate, message);
|
||||
|
||||
v8::Local<v8::Object> self;
|
||||
if (!GetWrapper(isolate).ToLocal(&self))
|
||||
return false;
|
||||
|
||||
auto event = gin::DataObjectBuilder(isolate)
|
||||
.Set("data", message_value)
|
||||
.Set("ports", ports)
|
||||
.Build();
|
||||
gin_helper::EmitEvent(isolate, self, "message", event);
|
||||
return true;
|
||||
}
|
||||
|
||||
gin::ObjectTemplateBuilder MessagePort::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin::Wrappable<MessagePort>::GetObjectTemplateBuilder(isolate)
|
||||
.SetMethod("postMessage", &MessagePort::PostMessage)
|
||||
.SetMethod("start", &MessagePort::Start)
|
||||
.SetMethod("close", &MessagePort::Close);
|
||||
}
|
||||
|
||||
const char* MessagePort::GetTypeName() {
|
||||
return "MessagePort";
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
using electron::MessagePort;
|
||||
|
||||
v8::Local<v8::Value> CreatePair(v8::Isolate* isolate) {
|
||||
auto port1 = MessagePort::Create(isolate);
|
||||
auto port2 = MessagePort::Create(isolate);
|
||||
mojo::MessagePipe pipe;
|
||||
port1->Entangle(std::move(pipe.handle0));
|
||||
port2->Entangle(std::move(pipe.handle1));
|
||||
return gin::DataObjectBuilder(isolate)
|
||||
.Set("port1", port1)
|
||||
.Set("port2", port2)
|
||||
.Build();
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("createPair", &CreatePair);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_message_port, Initialize)
|
||||
86
shell/browser/api/message_port.h
Normal file
86
shell/browser/api/message_port.h
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2020 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_BROWSER_API_MESSAGE_PORT_H_
|
||||
#define SHELL_BROWSER_API_MESSAGE_PORT_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "gin/wrappable.h"
|
||||
#include "mojo/public/cpp/bindings/connector.h"
|
||||
#include "mojo/public/cpp/bindings/message.h"
|
||||
#include "third_party/blink/public/common/messaging/message_port_channel.h"
|
||||
|
||||
namespace gin {
|
||||
class Arguments;
|
||||
template <typename T>
|
||||
class Handle;
|
||||
} // namespace gin
|
||||
|
||||
namespace electron {
|
||||
|
||||
// A non-blink version of blink::MessagePort.
|
||||
class MessagePort : public gin::Wrappable<MessagePort>, mojo::MessageReceiver {
|
||||
public:
|
||||
~MessagePort() override;
|
||||
static gin::Handle<MessagePort> Create(v8::Isolate* isolate);
|
||||
|
||||
void PostMessage(gin::Arguments* args);
|
||||
void Start();
|
||||
void Close();
|
||||
|
||||
void Entangle(mojo::ScopedMessagePipeHandle handle);
|
||||
void Entangle(blink::MessagePortChannel channel);
|
||||
|
||||
blink::MessagePortChannel Disentangle();
|
||||
|
||||
bool IsEntangled() const { return !closed_ && !IsNeutered(); }
|
||||
bool IsNeutered() const { return !connector_ || !connector_->is_valid(); }
|
||||
|
||||
static std::vector<gin::Handle<MessagePort>> EntanglePorts(
|
||||
v8::Isolate* isolate,
|
||||
std::vector<blink::MessagePortChannel> channels);
|
||||
|
||||
static std::vector<blink::MessagePortChannel> DisentanglePorts(
|
||||
v8::Isolate* isolate,
|
||||
const std::vector<gin::Handle<MessagePort>>& ports,
|
||||
bool* threw_exception);
|
||||
|
||||
// gin::Wrappable
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
const char* GetTypeName() override;
|
||||
|
||||
private:
|
||||
MessagePort();
|
||||
|
||||
// The blink version of MessagePort uses the very nice "ActiveScriptWrapper"
|
||||
// class, which keeps the object alive through the V8 embedder hooks into the
|
||||
// GC lifecycle: see
|
||||
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/heap/thread_state.cc;l=258;drc=b892cf58e162a8f66cd76d7472f129fe0fb6a7d1
|
||||
// We do not have that luxury, so we brutishly use v8::Global to accomplish
|
||||
// something similar. Critically, whenever the value of
|
||||
// "HasPendingActivity()" changes, we must call Pin() or Unpin() as
|
||||
// appropriate.
|
||||
bool HasPendingActivity() const;
|
||||
void Pin();
|
||||
void Unpin();
|
||||
|
||||
// mojo::MessageReceiver
|
||||
bool Accept(mojo::Message* mojo_message) override;
|
||||
|
||||
std::unique_ptr<mojo::Connector> connector_;
|
||||
bool started_ = false;
|
||||
bool closed_ = false;
|
||||
|
||||
v8::Global<v8::Value> pinned_;
|
||||
|
||||
base::WeakPtrFactory<MessagePort> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_API_MESSAGE_PORT_H_
|
||||
@@ -3,6 +3,7 @@ module electron.mojom;
|
||||
import "mojo/public/mojom/base/string16.mojom";
|
||||
import "ui/gfx/geometry/mojom/geometry.mojom";
|
||||
import "third_party/blink/public/mojom/messaging/cloneable_message.mojom";
|
||||
import "third_party/blink/public/mojom/messaging/transferable_message.mojom";
|
||||
|
||||
interface ElectronRenderer {
|
||||
Message(
|
||||
@@ -12,6 +13,8 @@ interface ElectronRenderer {
|
||||
blink.mojom.CloneableMessage arguments,
|
||||
int32 sender_id);
|
||||
|
||||
ReceivePostMessage(string channel, blink.mojom.TransferableMessage message);
|
||||
|
||||
UpdateCrashpadPipeName(string pipe_name);
|
||||
|
||||
// This is an API specific to the "remote" module, and will ultimately be
|
||||
@@ -53,6 +56,8 @@ interface ElectronBrowser {
|
||||
string channel,
|
||||
blink.mojom.CloneableMessage arguments) => (blink.mojom.CloneableMessage result);
|
||||
|
||||
ReceivePostMessage(string channel, blink.mojom.TransferableMessage message);
|
||||
|
||||
// Emits an event on |channel| from the ipcMain JavaScript object in the main
|
||||
// process, and waits synchronously for a response.
|
||||
[Sync]
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/keyboard_util.h"
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
#include "third_party/blink/public/common/context_menu_data/edit_flags.h"
|
||||
#include "third_party/blink/public/common/input/web_input_event.h"
|
||||
#include "third_party/blink/public/common/input/web_keyboard_event.h"
|
||||
@@ -481,98 +482,16 @@ bool Converter<network::mojom::ReferrerPolicy>::FromV8(
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class V8Serializer : public v8::ValueSerializer::Delegate {
|
||||
public:
|
||||
explicit V8Serializer(v8::Isolate* isolate)
|
||||
: isolate_(isolate), serializer_(isolate, this) {}
|
||||
~V8Serializer() override = default;
|
||||
|
||||
bool Serialize(v8::Local<v8::Value> value, blink::CloneableMessage* out) {
|
||||
serializer_.WriteHeader();
|
||||
bool wrote_value;
|
||||
if (!serializer_.WriteValue(isolate_->GetCurrentContext(), value)
|
||||
.To(&wrote_value)) {
|
||||
isolate_->ThrowException(v8::Exception::Error(
|
||||
StringToV8(isolate_, "An object could not be cloned.")));
|
||||
return false;
|
||||
}
|
||||
DCHECK(wrote_value);
|
||||
|
||||
std::pair<uint8_t*, size_t> buffer = serializer_.Release();
|
||||
DCHECK_EQ(buffer.first, data_.data());
|
||||
out->encoded_message = base::make_span(buffer.first, buffer.second);
|
||||
out->owned_encoded_message = std::move(data_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// v8::ValueSerializer::Delegate
|
||||
void* ReallocateBufferMemory(void* old_buffer,
|
||||
size_t size,
|
||||
size_t* actual_size) override {
|
||||
DCHECK_EQ(old_buffer, data_.data());
|
||||
data_.resize(size);
|
||||
*actual_size = data_.capacity();
|
||||
return data_.data();
|
||||
}
|
||||
|
||||
void FreeBufferMemory(void* buffer) override {
|
||||
DCHECK_EQ(buffer, data_.data());
|
||||
data_ = {};
|
||||
}
|
||||
|
||||
void ThrowDataCloneError(v8::Local<v8::String> message) override {
|
||||
isolate_->ThrowException(v8::Exception::Error(message));
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
std::vector<uint8_t> data_;
|
||||
v8::ValueSerializer serializer_;
|
||||
};
|
||||
|
||||
class V8Deserializer : public v8::ValueDeserializer::Delegate {
|
||||
public:
|
||||
V8Deserializer(v8::Isolate* isolate, const blink::CloneableMessage& message)
|
||||
: isolate_(isolate),
|
||||
deserializer_(isolate,
|
||||
message.encoded_message.data(),
|
||||
message.encoded_message.size(),
|
||||
this) {}
|
||||
|
||||
v8::Local<v8::Value> Deserialize() {
|
||||
v8::EscapableHandleScope scope(isolate_);
|
||||
auto context = isolate_->GetCurrentContext();
|
||||
bool read_header;
|
||||
if (!deserializer_.ReadHeader(context).To(&read_header))
|
||||
return v8::Null(isolate_);
|
||||
DCHECK(read_header);
|
||||
v8::Local<v8::Value> value;
|
||||
if (!deserializer_.ReadValue(context).ToLocal(&value)) {
|
||||
return v8::Null(isolate_);
|
||||
}
|
||||
return scope.Escape(value);
|
||||
}
|
||||
|
||||
private:
|
||||
v8::Isolate* isolate_;
|
||||
v8::ValueDeserializer deserializer_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
v8::Local<v8::Value> Converter<blink::CloneableMessage>::ToV8(
|
||||
v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& in) {
|
||||
return V8Deserializer(isolate, in).Deserialize();
|
||||
return electron::DeserializeV8Value(isolate, in);
|
||||
}
|
||||
|
||||
bool Converter<blink::CloneableMessage>::FromV8(v8::Isolate* isolate,
|
||||
v8::Handle<v8::Value> val,
|
||||
blink::CloneableMessage* out) {
|
||||
return V8Serializer(isolate).Serialize(val, out);
|
||||
return electron::SerializeV8Value(isolate, val, out);
|
||||
}
|
||||
|
||||
} // namespace gin
|
||||
|
||||
@@ -37,7 +37,7 @@ v8::Persistent<v8::FunctionTemplate> g_call_translater;
|
||||
void CallTranslater(v8::Local<v8::External> external,
|
||||
v8::Local<v8::Object> state,
|
||||
gin::Arguments* args) {
|
||||
// Whether the callback should only be called for once.
|
||||
// Whether the callback should only be called once.
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
auto context = isolate->GetCurrentContext();
|
||||
bool one_time =
|
||||
@@ -47,7 +47,7 @@ void CallTranslater(v8::Local<v8::External> external,
|
||||
if (one_time) {
|
||||
auto called_symbol = gin::StringToSymbol(isolate, "called");
|
||||
if (state->Has(context, called_symbol).ToChecked()) {
|
||||
args->ThrowTypeError("callback can only be called for once");
|
||||
args->ThrowTypeError("One-time callback was called more than once");
|
||||
return;
|
||||
} else {
|
||||
state->Set(context, called_symbol, v8::Boolean::New(isolate, true))
|
||||
|
||||
42
shell/common/gin_helper/function_template_extensions.h
Normal file
42
shell/common/gin_helper/function_template_extensions.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2020 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE.chromium file.
|
||||
|
||||
#ifndef SHELL_COMMON_GIN_HELPER_FUNCTION_TEMPLATE_EXTENSIONS_H_
|
||||
#define SHELL_COMMON_GIN_HELPER_FUNCTION_TEMPLATE_EXTENSIONS_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "gin/function_template.h"
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
|
||||
// This extends the functionality in //gin/function_template.h for "special"
|
||||
// arguments to gin-bound methods.
|
||||
// It's the counterpart to function_template.h, which includes these methods
|
||||
// in the gin_helper namespace.
|
||||
namespace gin {
|
||||
|
||||
// Support base::Optional as an argument.
|
||||
template <typename T>
|
||||
bool GetNextArgument(Arguments* args,
|
||||
const InvokerOptions& invoker_options,
|
||||
bool is_first,
|
||||
base::Optional<T>* result) {
|
||||
T converted;
|
||||
// Use gin::Arguments::GetNext which always advances |next| counter.
|
||||
if (args->GetNext(&converted))
|
||||
result->emplace(std::move(converted));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GetNextArgument(Arguments* args,
|
||||
const InvokerOptions& invoker_options,
|
||||
bool is_first,
|
||||
gin_helper::ErrorThrower* result) {
|
||||
*result = gin_helper::ErrorThrower(args->isolate());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gin
|
||||
|
||||
#endif // SHELL_COMMON_GIN_HELPER_FUNCTION_TEMPLATE_EXTENSIONS_H_
|
||||
@@ -44,6 +44,7 @@
|
||||
V(electron_browser_global_shortcut) \
|
||||
V(electron_browser_in_app_purchase) \
|
||||
V(electron_browser_menu) \
|
||||
V(electron_browser_message_port) \
|
||||
V(electron_browser_net) \
|
||||
V(electron_browser_power_monitor) \
|
||||
V(electron_browser_power_save_blocker) \
|
||||
|
||||
147
shell/common/v8_value_serializer.cc
Normal file
147
shell/common/v8_value_serializer.cc
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2020 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gin/converter.h"
|
||||
#include "third_party/blink/public/common/messaging/cloneable_message.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace {
|
||||
const uint8_t kVersionTag = 0xFF;
|
||||
} // namespace
|
||||
|
||||
class V8Serializer : public v8::ValueSerializer::Delegate {
|
||||
public:
|
||||
explicit V8Serializer(v8::Isolate* isolate)
|
||||
: isolate_(isolate), serializer_(isolate, this) {}
|
||||
~V8Serializer() override = default;
|
||||
|
||||
bool Serialize(v8::Local<v8::Value> value, blink::CloneableMessage* out) {
|
||||
WriteBlinkEnvelope(19);
|
||||
|
||||
serializer_.WriteHeader();
|
||||
bool wrote_value;
|
||||
if (!serializer_.WriteValue(isolate_->GetCurrentContext(), value)
|
||||
.To(&wrote_value)) {
|
||||
isolate_->ThrowException(v8::Exception::Error(
|
||||
gin::StringToV8(isolate_, "An object could not be cloned.")));
|
||||
return false;
|
||||
}
|
||||
DCHECK(wrote_value);
|
||||
|
||||
std::pair<uint8_t*, size_t> buffer = serializer_.Release();
|
||||
DCHECK_EQ(buffer.first, data_.data());
|
||||
out->encoded_message = base::make_span(buffer.first, buffer.second);
|
||||
out->owned_encoded_message = std::move(data_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// v8::ValueSerializer::Delegate
|
||||
void* ReallocateBufferMemory(void* old_buffer,
|
||||
size_t size,
|
||||
size_t* actual_size) override {
|
||||
DCHECK_EQ(old_buffer, data_.data());
|
||||
data_.resize(size);
|
||||
*actual_size = data_.capacity();
|
||||
return data_.data();
|
||||
}
|
||||
|
||||
void FreeBufferMemory(void* buffer) override {
|
||||
DCHECK_EQ(buffer, data_.data());
|
||||
data_ = {};
|
||||
}
|
||||
|
||||
void ThrowDataCloneError(v8::Local<v8::String> message) override {
|
||||
isolate_->ThrowException(v8::Exception::Error(message));
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteTag(uint8_t tag) { serializer_.WriteRawBytes(&tag, 1); }
|
||||
|
||||
void WriteBlinkEnvelope(uint32_t blink_version) {
|
||||
// Write a dummy blink version envelope for compatibility with
|
||||
// blink::V8ScriptValueSerializer
|
||||
WriteTag(kVersionTag);
|
||||
serializer_.WriteUint32(blink_version);
|
||||
}
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
std::vector<uint8_t> data_;
|
||||
v8::ValueSerializer serializer_;
|
||||
};
|
||||
|
||||
class V8Deserializer : public v8::ValueDeserializer::Delegate {
|
||||
public:
|
||||
V8Deserializer(v8::Isolate* isolate, base::span<const uint8_t> data)
|
||||
: isolate_(isolate),
|
||||
deserializer_(isolate, data.data(), data.size(), this) {}
|
||||
V8Deserializer(v8::Isolate* isolate, const blink::CloneableMessage& message)
|
||||
: V8Deserializer(isolate, message.encoded_message) {}
|
||||
|
||||
v8::Local<v8::Value> Deserialize() {
|
||||
v8::EscapableHandleScope scope(isolate_);
|
||||
auto context = isolate_->GetCurrentContext();
|
||||
|
||||
uint32_t blink_version;
|
||||
if (!ReadBlinkEnvelope(&blink_version))
|
||||
return v8::Null(isolate_);
|
||||
|
||||
bool read_header;
|
||||
if (!deserializer_.ReadHeader(context).To(&read_header))
|
||||
return v8::Null(isolate_);
|
||||
DCHECK(read_header);
|
||||
v8::Local<v8::Value> value;
|
||||
if (!deserializer_.ReadValue(context).ToLocal(&value))
|
||||
return v8::Null(isolate_);
|
||||
return scope.Escape(value);
|
||||
}
|
||||
|
||||
private:
|
||||
bool ReadTag(uint8_t* tag) {
|
||||
const void* tag_bytes = nullptr;
|
||||
if (!deserializer_.ReadRawBytes(1, &tag_bytes))
|
||||
return false;
|
||||
*tag = *reinterpret_cast<const uint8_t*>(tag_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadBlinkEnvelope(uint32_t* blink_version) {
|
||||
// Read a dummy blink version envelope for compatibility with
|
||||
// blink::V8ScriptValueDeserializer
|
||||
uint8_t tag = 0;
|
||||
if (!ReadTag(&tag) || tag != kVersionTag)
|
||||
return false;
|
||||
if (!deserializer_.ReadUint32(blink_version))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
v8::Isolate* isolate_;
|
||||
v8::ValueDeserializer deserializer_;
|
||||
};
|
||||
|
||||
bool SerializeV8Value(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> value,
|
||||
blink::CloneableMessage* out) {
|
||||
return V8Serializer(isolate).Serialize(value, out);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> DeserializeV8Value(v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& in) {
|
||||
return V8Deserializer(isolate, in).Deserialize();
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> DeserializeV8Value(v8::Isolate* isolate,
|
||||
base::span<const uint8_t> data) {
|
||||
return V8Deserializer(isolate, data).Deserialize();
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
33
shell/common/v8_value_serializer.h
Normal file
33
shell/common/v8_value_serializer.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2020 Slack Technologies, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SHELL_COMMON_V8_VALUE_SERIALIZER_H_
|
||||
#define SHELL_COMMON_V8_VALUE_SERIALIZER_H_
|
||||
|
||||
#include "base/containers/span.h"
|
||||
|
||||
namespace v8 {
|
||||
class Isolate;
|
||||
template <class T>
|
||||
class Local;
|
||||
class Value;
|
||||
} // namespace v8
|
||||
|
||||
namespace blink {
|
||||
struct CloneableMessage;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
bool SerializeV8Value(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> value,
|
||||
blink::CloneableMessage* out);
|
||||
v8::Local<v8::Value> DeserializeV8Value(v8::Isolate* isolate,
|
||||
const blink::CloneableMessage& in);
|
||||
v8::Local<v8::Value> DeserializeV8Value(v8::Isolate* isolate,
|
||||
base::span<const uint8_t> data);
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_COMMON_V8_VALUE_SERIALIZER_H_
|
||||
@@ -15,10 +15,13 @@
|
||||
#include "shell/common/api/api.mojom.h"
|
||||
#include "shell/common/gin_converters/blink_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/function_template_extensions.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
#include "shell/common/node_bindings.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
#include "third_party/blink/public/web/web_message_port_converter.h"
|
||||
|
||||
using blink::WebLocalFrame;
|
||||
using content::RenderFrame;
|
||||
@@ -57,7 +60,8 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
.SetMethod("sendSync", &IPCRenderer::SendSync)
|
||||
.SetMethod("sendTo", &IPCRenderer::SendTo)
|
||||
.SetMethod("sendToHost", &IPCRenderer::SendToHost)
|
||||
.SetMethod("invoke", &IPCRenderer::Invoke);
|
||||
.SetMethod("invoke", &IPCRenderer::Invoke)
|
||||
.SetMethod("postMessage", &IPCRenderer::PostMessage);
|
||||
}
|
||||
|
||||
const char* GetTypeName() override { return "IPCRenderer"; }
|
||||
@@ -68,7 +72,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!gin::ConvertFromV8(isolate, arguments, &message)) {
|
||||
if (!electron::SerializeV8Value(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->Message(internal, channel, std::move(message));
|
||||
@@ -79,7 +83,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!gin::ConvertFromV8(isolate, arguments, &message)) {
|
||||
if (!electron::SerializeV8Value(isolate, arguments, &message)) {
|
||||
return v8::Local<v8::Promise>();
|
||||
}
|
||||
gin_helper::Promise<blink::CloneableMessage> p(isolate);
|
||||
@@ -95,6 +99,43 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
return handle;
|
||||
}
|
||||
|
||||
void PostMessage(v8::Isolate* isolate,
|
||||
gin_helper::ErrorThrower thrower,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> message_value,
|
||||
base::Optional<v8::Local<v8::Value>> transfer) {
|
||||
blink::TransferableMessage transferable_message;
|
||||
if (!electron::SerializeV8Value(isolate, message_value,
|
||||
&transferable_message)) {
|
||||
// SerializeV8Value sets an exception.
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<v8::Local<v8::Object>> transferables;
|
||||
if (transfer) {
|
||||
if (!gin::ConvertFromV8(isolate, *transfer, &transferables)) {
|
||||
thrower.ThrowTypeError("Invalid value for transfer");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<blink::MessagePortChannel> ports;
|
||||
for (auto& transferable : transferables) {
|
||||
base::Optional<blink::MessagePortChannel> port =
|
||||
blink::WebMessagePortConverter::
|
||||
DisentangleAndExtractMessagePortChannel(isolate, transferable);
|
||||
if (!port.has_value()) {
|
||||
thrower.ThrowTypeError("Invalid value for transfer");
|
||||
return;
|
||||
}
|
||||
ports.emplace_back(port.value());
|
||||
}
|
||||
|
||||
transferable_message.ports = std::move(ports);
|
||||
electron_browser_ptr_->ReceivePostMessage(channel,
|
||||
std::move(transferable_message));
|
||||
}
|
||||
|
||||
void SendTo(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
bool send_to_all,
|
||||
@@ -102,7 +143,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!gin::ConvertFromV8(isolate, arguments, &message)) {
|
||||
if (!electron::SerializeV8Value(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->MessageTo(internal, send_to_all, web_contents_id,
|
||||
@@ -113,25 +154,25 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer> {
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!gin::ConvertFromV8(isolate, arguments, &message)) {
|
||||
if (!electron::SerializeV8Value(isolate, arguments, &message)) {
|
||||
return;
|
||||
}
|
||||
electron_browser_ptr_->MessageHost(channel, std::move(message));
|
||||
}
|
||||
|
||||
blink::CloneableMessage SendSync(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
v8::Local<v8::Value> SendSync(v8::Isolate* isolate,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
v8::Local<v8::Value> arguments) {
|
||||
blink::CloneableMessage message;
|
||||
if (!gin::ConvertFromV8(isolate, arguments, &message)) {
|
||||
return blink::CloneableMessage();
|
||||
if (!electron::SerializeV8Value(isolate, arguments, &message)) {
|
||||
return v8::Local<v8::Value>();
|
||||
}
|
||||
|
||||
blink::CloneableMessage result;
|
||||
electron_browser_ptr_->MessageSync(internal, channel, std::move(message),
|
||||
&result);
|
||||
return result;
|
||||
return electron::DeserializeV8Value(isolate, result);
|
||||
}
|
||||
|
||||
electron::mojom::ElectronBrowserPtr electron_browser_ptr_;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "base/environment.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "gin/data_object_builder.h"
|
||||
#include "mojo/public/cpp/system/platform_handle.h"
|
||||
#include "shell/common/electron_constants.h"
|
||||
#include "shell/common/gin_converters/blink_converter.h"
|
||||
@@ -18,10 +19,12 @@
|
||||
#include "shell/common/heap_snapshot.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/v8_value_serializer.h"
|
||||
#include "shell/renderer/electron_render_frame_observer.h"
|
||||
#include "shell/renderer/renderer_client_base.h"
|
||||
#include "third_party/blink/public/web/blink.h"
|
||||
#include "third_party/blink/public/web/web_local_frame.h"
|
||||
#include "third_party/blink/public/web/web_message_port_converter.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
@@ -74,6 +77,7 @@ void InvokeIpcCallback(v8::Local<v8::Context> context,
|
||||
void EmitIPCEvent(v8::Local<v8::Context> context,
|
||||
bool internal,
|
||||
const std::string& channel,
|
||||
std::vector<v8::Local<v8::Value>> ports,
|
||||
v8::Local<v8::Value> args,
|
||||
int32_t sender_id) {
|
||||
auto* isolate = context->GetIsolate();
|
||||
@@ -85,7 +89,8 @@ void EmitIPCEvent(v8::Local<v8::Context> context,
|
||||
|
||||
std::vector<v8::Local<v8::Value>> argv = {
|
||||
gin::ConvertToV8(isolate, internal), gin::ConvertToV8(isolate, channel),
|
||||
args, gin::ConvertToV8(isolate, sender_id)};
|
||||
gin::ConvertToV8(isolate, ports), args,
|
||||
gin::ConvertToV8(isolate, sender_id)};
|
||||
|
||||
InvokeIpcCallback(context, "onMessage", argv);
|
||||
}
|
||||
@@ -161,7 +166,7 @@ void ElectronApiServiceImpl::Message(bool internal,
|
||||
|
||||
v8::Local<v8::Value> args = gin::ConvertToV8(isolate, arguments);
|
||||
|
||||
EmitIPCEvent(context, internal, channel, args, sender_id);
|
||||
EmitIPCEvent(context, internal, channel, {}, args, sender_id);
|
||||
|
||||
// Also send the message to all sub-frames.
|
||||
// TODO(MarshallOfSound): Completely move this logic to the main process
|
||||
@@ -171,11 +176,39 @@ void ElectronApiServiceImpl::Message(bool internal,
|
||||
if (child->IsWebLocalFrame()) {
|
||||
v8::Local<v8::Context> child_context =
|
||||
renderer_client_->GetContext(child->ToWebLocalFrame(), isolate);
|
||||
EmitIPCEvent(child_context, internal, channel, args, sender_id);
|
||||
EmitIPCEvent(child_context, internal, channel, {}, args, sender_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElectronApiServiceImpl::ReceivePostMessage(
|
||||
const std::string& channel,
|
||||
blink::TransferableMessage message) {
|
||||
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
|
||||
if (!frame)
|
||||
return;
|
||||
|
||||
v8::Isolate* isolate = blink::MainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
v8::Local<v8::Context> context = renderer_client_->GetContext(frame, isolate);
|
||||
v8::Context::Scope context_scope(context);
|
||||
|
||||
v8::Local<v8::Value> message_value = DeserializeV8Value(isolate, message);
|
||||
|
||||
std::vector<v8::Local<v8::Value>> ports;
|
||||
for (auto& port : message.ports) {
|
||||
ports.emplace_back(
|
||||
blink::WebMessagePortConverter::EntangleAndInjectMessagePortChannel(
|
||||
context, std::move(port)));
|
||||
}
|
||||
|
||||
std::vector<v8::Local<v8::Value>> args = {message_value};
|
||||
|
||||
EmitIPCEvent(context, false, channel, ports, gin::ConvertToV8(isolate, args),
|
||||
0);
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void ElectronApiServiceImpl::DereferenceRemoteJSCallback(
|
||||
const std::string& context_id,
|
||||
@@ -198,7 +231,7 @@ void ElectronApiServiceImpl::DereferenceRemoteJSCallback(
|
||||
args.AppendInteger(object_id);
|
||||
|
||||
v8::Local<v8::Value> v8_args = gin::ConvertToV8(isolate, args);
|
||||
EmitIPCEvent(context, true /* internal */, channel, v8_args,
|
||||
EmitIPCEvent(context, true /* internal */, channel, {}, v8_args,
|
||||
0 /* sender_id */);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,8 @@ class ElectronApiServiceImpl : public mojom::ElectronRenderer,
|
||||
const std::string& channel,
|
||||
blink::CloneableMessage arguments,
|
||||
int32_t sender_id) override;
|
||||
void ReceivePostMessage(const std::string& channel,
|
||||
blink::TransferableMessage message) override;
|
||||
#if BUILDFLAG(ENABLE_REMOTE_MODULE)
|
||||
void DereferenceRemoteJSCallback(const std::string& context_id,
|
||||
int32_t object_id) override;
|
||||
|
||||
Reference in New Issue
Block a user