feat: add event.senderFrame property returning the originating webFrameMain (#26764)

This commit is contained in:
Milan Burda 2020-12-10 00:34:06 +01:00 committed by GitHub
parent 9908cc363a
commit cec6378881
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 25 additions and 14 deletions

View file

@ -4,6 +4,7 @@
* `frameId` Integer - The ID of the renderer frame that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message
* `returnValue` any - Set this to the value to be returned in a synchronous message * `returnValue` any - Set this to the value to be returned in a synchronous message
* `sender` WebContents - Returns the `webContents` that sent the message * `sender` WebContents - Returns the `webContents` that sent the message
* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message
* `ports` MessagePortMain[] - A list of MessagePorts that were transferred with this message * `ports` MessagePortMain[] - A list of MessagePorts that were transferred with this message
* `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame. * `reply` Function - A function that will send an IPC message to the renderer frame that sent the original message that you are currently handling. You should use this method to "reply" to the sent message in order to guarantee the reply will go to the correct process and frame.
* `channel` String * `channel` String

View file

@ -3,3 +3,4 @@
* `processId` Integer - The internal ID of the renderer process that sent this message * `processId` Integer - The internal ID of the renderer process that sent this message
* `frameId` Integer - The ID of the renderer frame that sent this message * `frameId` Integer - The ID of the renderer frame that sent this message
* `sender` WebContents - Returns the `webContents` that sent the message * `sender` WebContents - Returns the `webContents` that sent the message
* `senderFrame` WebFrameMain _Readonly_ - The frame that sent this message

View file

@ -26,7 +26,7 @@ win.webContents.on(
) )
``` ```
You can also access frames of existing pages by using the `webFrame` property You can also access frames of existing pages by using the `mainFrame` property
of [`WebContents`](web-contents.md). of [`WebContents`](web-contents.md).
```javascript ```javascript
@ -57,8 +57,8 @@ These methods can be accessed from the `webFrameMain` module:
### `webFrameMain.fromId(processId, routingId)` ### `webFrameMain.fromId(processId, routingId)`
* `processId` Integer - An `Integer` representing the id of the process which owns the frame. * `processId` Integer - An `Integer` representing the internal ID of the process which owns the frame.
* `routingId` Integer - An `Integer` representing the unique frame id in the * `routingId` Integer - An `Integer` representing the unique frame ID in the
current renderer process. Routing IDs can be retrieved from `WebFrameMain` current renderer process. Routing IDs can be retrieved from `WebFrameMain`
instances (`frame.routingId`) and are also passed by frame instances (`frame.routingId`) and are also passed by frame
specific `WebContents` navigation events (e.g. `did-frame-navigate`). specific `WebContents` navigation events (e.g. `did-frame-navigate`).

View file

@ -1,5 +1,5 @@
import { app, ipcMain, session, deprecate, BrowserWindowConstructorOptions } from 'electron/main'; import { app, ipcMain, session, deprecate, webFrameMain } from 'electron/main';
import type { MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main'; import type { BrowserWindowConstructorOptions, MenuItem, MenuItemConstructorOptions, LoadURLOptions } from 'electron/main';
import * as url from 'url'; import * as url from 'url';
import * as path from 'path'; import * as path from 'path';
@ -462,6 +462,13 @@ const addReplyToEvent = (event: any) => {
}; };
}; };
const addSenderFrameToEvent = (event: any) => {
const { processId, frameId } = event;
Object.defineProperty(event, 'senderFrame', {
get: () => webFrameMain.fromId(processId, frameId)
});
};
const addReturnValueToEvent = (event: any) => { const addReturnValueToEvent = (event: any) => {
Object.defineProperty(event, 'returnValue', { Object.defineProperty(event, 'returnValue', {
set: (value) => event.sendReply(value), set: (value) => event.sendReply(value),
@ -505,6 +512,7 @@ WebContents.prototype._init = function () {
// Dispatch IPC messages to the ipc module. // Dispatch IPC messages to the ipc module.
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) { this.on('-ipc-message' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) {
addSenderFrameToEvent(event);
if (internal) { if (internal) {
ipcMainInternal.emit(channel, event, ...args); ipcMainInternal.emit(channel, event, ...args);
} else { } else {
@ -515,6 +523,7 @@ WebContents.prototype._init = function () {
}); });
this.on('-ipc-invoke' as any, function (event: any, internal: boolean, channel: string, args: any[]) { this.on('-ipc-invoke' as any, function (event: any, internal: boolean, channel: string, args: any[]) {
addSenderFrameToEvent(event);
event._reply = (result: any) => event.sendReply({ result }); event._reply = (result: any) => event.sendReply({ result });
event._throw = (error: Error) => { event._throw = (error: Error) => {
console.error(`Error occurred in handler for '${channel}':`, error); console.error(`Error occurred in handler for '${channel}':`, error);
@ -529,6 +538,7 @@ WebContents.prototype._init = function () {
}); });
this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) { this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: any, internal: boolean, channel: string, args: any[]) {
addSenderFrameToEvent(event);
addReturnValueToEvent(event); addReturnValueToEvent(event);
if (internal) { if (internal) {
ipcMainInternal.emit(channel, event, ...args); ipcMainInternal.emit(channel, event, ...args);

View file

@ -4,15 +4,8 @@
#include "shell/common/gin_converters/frame_converter.h" #include "shell/common/gin_converters/frame_converter.h"
#include <string>
#include <vector>
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "shell/browser/api/electron_api_web_frame_main.h" #include "shell/browser/api/electron_api_web_frame_main.h"
#include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_helper/dictionary.h"
namespace gin { namespace gin {

View file

@ -5,8 +5,6 @@
#ifndef SHELL_COMMON_GIN_CONVERTERS_FRAME_CONVERTER_H_ #ifndef SHELL_COMMON_GIN_CONVERTERS_FRAME_CONVERTER_H_
#define SHELL_COMMON_GIN_CONVERTERS_FRAME_CONVERTER_H_ #define SHELL_COMMON_GIN_CONVERTERS_FRAME_CONVERTER_H_
#include <utility>
#include "gin/converter.h" #include "gin/converter.h"
namespace content { namespace content {

View file

@ -35,6 +35,8 @@ describe('renderer nodeIntegrationInSubFrames', () => {
expect(event1[0].frameId).to.not.equal(event2[0].frameId); expect(event1[0].frameId).to.not.equal(event2[0].frameId);
expect(event1[0].frameId).to.equal(event1[2]); expect(event1[0].frameId).to.equal(event1[2]);
expect(event2[0].frameId).to.equal(event2[2]); expect(event2[0].frameId).to.equal(event2[2]);
expect(event1[0].senderFrame.routingId).to.equal(event1[2]);
expect(event2[0].senderFrame.routingId).to.equal(event2[2]);
}); });
it('should load preload scripts in nested iframes', async () => { it('should load preload scripts in nested iframes', async () => {
@ -47,6 +49,9 @@ describe('renderer nodeIntegrationInSubFrames', () => {
expect(event1[0].frameId).to.equal(event1[2]); expect(event1[0].frameId).to.equal(event1[2]);
expect(event2[0].frameId).to.equal(event2[2]); expect(event2[0].frameId).to.equal(event2[2]);
expect(event3[0].frameId).to.equal(event3[2]); expect(event3[0].frameId).to.equal(event3[2]);
expect(event1[0].senderFrame.routingId).to.equal(event1[2]);
expect(event2[0].senderFrame.routingId).to.equal(event2[2]);
expect(event3[0].senderFrame.routingId).to.equal(event3[2]);
}); });
it('should correctly reply to the main frame with using event.reply', async () => { it('should correctly reply to the main frame with using event.reply', async () => {
@ -57,6 +62,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
event1[0].reply('preload-ping'); event1[0].reply('preload-ping');
const details = await pongPromise; const details = await pongPromise;
expect(details[1]).to.equal(event1[0].frameId); expect(details[1]).to.equal(event1[0].frameId);
expect(details[1]).to.equal(event1[0].senderFrame.routingId);
}); });
it('should correctly reply to the sub-frames with using event.reply', async () => { it('should correctly reply to the sub-frames with using event.reply', async () => {
@ -67,6 +73,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
event2[0].reply('preload-ping'); event2[0].reply('preload-ping');
const details = await pongPromise; const details = await pongPromise;
expect(details[1]).to.equal(event2[0].frameId); expect(details[1]).to.equal(event2[0].frameId);
expect(details[1]).to.equal(event2[0].senderFrame.routingId);
}); });
it('should correctly reply to the nested sub-frames with using event.reply', async () => { it('should correctly reply to the nested sub-frames with using event.reply', async () => {
@ -77,6 +84,7 @@ describe('renderer nodeIntegrationInSubFrames', () => {
event3[0].reply('preload-ping'); event3[0].reply('preload-ping');
const details = await pongPromise; const details = await pongPromise;
expect(details[1]).to.equal(event3[0].frameId); expect(details[1]).to.equal(event3[0].frameId);
expect(details[1]).to.equal(event3[0].senderFrame.routingId);
}); });
it('should not expose globals in main world', async () => { it('should not expose globals in main world', async () => {