From db2fda1b6f31f33431d20a51ebc42375f03df774 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 10 Dec 2018 09:37:42 +0900 Subject: [PATCH] chore: make rpc-server reply to sender frame instead of the main frame (#15973) * chore: make rpc-server reply to frame * fix: check IsRenderFrameLive --- atom/browser/api/atom_api_web_contents.cc | 20 +++++++++++++++++++- atom/browser/api/atom_api_web_contents.h | 6 ++++++ atom/browser/api/event_emitter.cc | 3 +++ lib/browser/api/web-contents.js | 12 ++++++++++++ lib/browser/rpc-server.js | 20 +++++++++++--------- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 1ea6d243db4d..41024affd84f 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -1674,6 +1674,23 @@ bool WebContents::SendIPCMessageWithSender(bool internal, return false; } +bool WebContents::SendIPCMessageToFrame(bool internal, + bool send_to_all, + int32_t frame_id, + const std::string& channel, + const base::ListValue& args) { + auto frames = web_contents()->GetAllFrames(); + auto iter = std::find_if(frames.begin(), frames.end(), [frame_id](auto* f) { + return f->GetRoutingID() == frame_id; + }); + if (iter == frames.end()) + return false; + if (!(*iter)->IsRenderFrameLive()) + return false; + return (*iter)->Send(new AtomFrameMsg_Message( + frame_id, internal, send_to_all, channel, args, 0 /* sender_id */)); +} + void WebContents::SendInputEvent(v8::Isolate* isolate, v8::Local input_event) { content::RenderWidgetHostView* view = @@ -2119,6 +2136,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .SetMethod("isFocused", &WebContents::IsFocused) .SetMethod("tabTraverse", &WebContents::TabTraverse) .SetMethod("_send", &WebContents::SendIPCMessage) + .SetMethod("_sendToFrame", &WebContents::SendIPCMessageToFrame) .SetMethod("sendInputEvent", &WebContents::SendInputEvent) .SetMethod("beginFrameSubscription", &WebContents::BeginFrameSubscription) .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription) @@ -2183,7 +2201,7 @@ void WebContents::OnRendererMessage(content::RenderFrameHost* frame_host, const std::string& channel, const base::ListValue& args) { // webContents.emit(channel, new Event(), args...); - Emit(channel, args); + EmitWithSender(channel, frame_host, nullptr, args); } void WebContents::OnRendererMessageSync(content::RenderFrameHost* frame_host, diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 4f37e621bd4e..9a1ed0f571fa 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -218,6 +218,12 @@ class WebContents : public mate::TrackableObject, const base::ListValue& args, int32_t sender_id = 0); + bool SendIPCMessageToFrame(bool internal, + bool send_to_all, + int32_t frame_id, + const std::string& channel, + const base::ListValue& args); + // Send WebInputEvent to the page. void SendInputEvent(v8::Isolate* isolate, v8::Local input_event); diff --git a/atom/browser/api/event_emitter.cc b/atom/browser/api/event_emitter.cc index c6e810b51225..4b4c0caa7261 100644 --- a/atom/browser/api/event_emitter.cc +++ b/atom/browser/api/event_emitter.cc @@ -5,6 +5,7 @@ #include "atom/browser/api/event_emitter.h" #include "atom/browser/api/event.h" +#include "content/public/browser/render_frame_host.h" #include "native_mate/arguments.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" @@ -56,6 +57,8 @@ v8::Local CreateJSEvent(v8::Isolate* isolate, event = CreateEventObject(isolate); } mate::Dictionary(isolate, event).Set("sender", object); + if (sender) + mate::Dictionary(isolate, event).Set("frameId", sender->GetRoutingID()); return event; } diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 2d05b390cf17..dd9f9eefdc3d 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -142,6 +142,18 @@ WebContents.prototype._sendInternalToAll = function (channel, ...args) { return this._send(internal, sendToAll, channel, args) } +WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) { + if (typeof channel !== 'string') { + throw new Error('Missing required channel argument') + } else if (typeof frameId !== 'number') { + throw new Error('Missing required frameId argument') + } + + const internal = true + const sendToAll = false + + return this._sendToFrame(internal, sendToAll, frameId, channel, args) +} // Following methods are mapped to webFrame. const webFrameMethods = [ diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index a75a78b01c63..db2afa42273a 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -174,7 +174,7 @@ const removeRemoteListenersAndLogWarning = (sender, callIntoRenderer) => { } // Convert array of meta data from renderer into array of real values. -const unwrapArgs = function (sender, contextId, args) { +const unwrapArgs = function (sender, frameId, contextId, args) { const metaToValue = function (meta) { switch (meta.type) { case 'value': @@ -182,7 +182,7 @@ const unwrapArgs = function (sender, contextId, args) { case 'remote-object': return objectsRegistry.get(meta.id) case 'array': - return unwrapArgs(sender, contextId, meta.value) + return unwrapArgs(sender, frameId, contextId, meta.value) case 'buffer': return bufferUtils.metaToBuffer(meta.value) case 'date': @@ -216,9 +216,11 @@ const unwrapArgs = function (sender, contextId, args) { } const callIntoRenderer = function (...args) { + let succeed = false if (!sender.isDestroyed()) { - sender._sendInternal('ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args)) - } else { + succeed = sender._sendToFrameInternal(frameId, 'ELECTRON_RENDERER_CALLBACK', contextId, meta.id, valueToMeta(sender, contextId, args)) + } + if (!succeed) { removeRemoteListenersAndLogWarning(this, callIntoRenderer) } } @@ -334,7 +336,7 @@ handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, co }) handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, id, args) { - args = unwrapArgs(event.sender, contextId, args) + args = unwrapArgs(event.sender, event.frameId, contextId, args) const constructor = objectsRegistry.get(id) if (constructor == null) { @@ -345,7 +347,7 @@ handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, }) handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId, id, args) { - args = unwrapArgs(event.sender, contextId, args) + args = unwrapArgs(event.sender, event.frameId, contextId, args) const func = objectsRegistry.get(id) if (func == null) { @@ -356,7 +358,7 @@ handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId }) handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, contextId, id, method, args) { - args = unwrapArgs(event.sender, contextId, args) + args = unwrapArgs(event.sender, event.frameId, contextId, args) const object = objectsRegistry.get(id) if (object == null) { @@ -367,7 +369,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, cont }) handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId, id, method, args) { - args = unwrapArgs(event.sender, contextId, args) + args = unwrapArgs(event.sender, event.frameId, contextId, args) const obj = objectsRegistry.get(id) if (obj == null) { @@ -378,7 +380,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId, }) handleRemoteCommand('ELECTRON_BROWSER_MEMBER_SET', function (event, contextId, id, name, args) { - args = unwrapArgs(event.sender, contextId, args) + args = unwrapArgs(event.sender, event.frameId, contextId, args) const obj = objectsRegistry.get(id) if (obj == null) {