feat: preloads and nodeIntegration in iframes (#16425)

* feat: add support for node / preloads in subframes

This feature has delibrately been built / implemented in such a way
that it has minimum impact on existing apps / code-paths.
Without enabling the new "nodeSupportInSubFrames" option basically none of this
new code will be hit.

The things that I believe need extra scrutiny are:

* Introduction of `event.reply` for IPC events and usage of `event.reply` instead of `event.sender.send()`
* Usage of `node::FreeEnvironment(env)` when the new option is enabled in order to avoid memory leaks.  I have tested this quite a bit and haven't managed to cause a crash but it is still feature flagged behind the "nodeSupportInSubFrames" flag to avoid potential impact.

Closes #10569
Closes #10401
Closes #11868
Closes #12505
Closes #14035

* feat: add support preloads in subframes for sandboxed renderers

* spec: add tests for new nodeSupportInSubFrames option

* spec: fix specs for .reply and ._replyInternal for internal messages

* chore: revert change to use flag instead of environment set size

* chore: clean up subframe impl

* chore: apply suggestions from code review

Co-Authored-By: MarshallOfSound <samuel.r.attard@gmail.com>

* chore: clean up reply usage

* chore: fix TS docs generation

* chore: cleanup after rebase

* chore: rename wrap to add in event fns
This commit is contained in:
Samuel Attard 2019-01-22 11:24:46 -08:00 committed by GitHub
parent 92b9525cfd
commit 58a6fe13d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 332 additions and 49 deletions

View file

@ -255,6 +255,10 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
* `nodeIntegrationInWorker` Boolean (optional) - Whether node integration is
enabled in web workers. Default is `false`. More about this can be found
in [Multithreading](../tutorial/multithreading.md).
* `nodeIntegrationInSubFrames` Boolean (optional) - Experimental option for
enabling NodeJS support in sub-frames such as iframes. All your preloads will load for
every iframe, you can use `process.isMainFrame` to determine if you are
in the main frame or not.
* `preload` String (optional) - Specifies a script that will be loaded before other
scripts run in the page. This script will always have access to node APIs
no matter whether node integration is turned on or off. The value should

View file

@ -18,7 +18,9 @@ process, see [webContents.send][web-contents-send] for more information.
* When sending a message, the event name is the `channel`.
* To reply to a synchronous message, you need to set `event.returnValue`.
* To send an asynchronous message back to the sender, you can use
`event.sender.send(...)`.
`event.reply(...)`. This helper method will automatically handle messages
coming from frames that aren't the main frame (e.g. iframes) whereas
`event.sender.send(...)` will always send to the main frame.
An example of sending and handling messages between the render and main
processes:
@ -28,7 +30,7 @@ processes:
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.sender.send('asynchronous-reply', 'pong')
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
@ -86,6 +88,10 @@ Removes listeners of the specified `channel`.
The `event` object passed to the `callback` has the following methods:
### `event.frameId`
An `Integer` representing the ID of the renderer frame that sent this message.
### `event.returnValue`
Set this to the value to be returned in a synchronous message.
@ -97,3 +103,10 @@ Returns the `webContents` that sent the message, you can call
[webContents.send][web-contents-send] for more information.
[web-contents-send]: web-contents.md#contentssendchannel-arg1-arg2-
### `event.reply`
A function that will send an IPC message to the renderer frane that sent
the original message that you are currently handling. You should use this
method to "reply" to the sent message in order to guaruntee the reply will go
to the correct process and frame.

View file

@ -59,6 +59,11 @@ process.once('loaded', () => {
A `Boolean`. When app is started by being passed as parameter to the default app, this
property is `true` in the main process, otherwise it is `undefined`.
### `process.isMainFrame`
A `Boolean`, `true` when the current renderer context is the "main" renderer
frame. If you want the ID of the current frame you should use `webFrame.routingId`.
### `process.mas`
A `Boolean`. For Mac App Store build, this property is `true`, for other builds it is

View file

@ -1420,6 +1420,36 @@ app.on('ready', () => {
</html>
```
#### `contents.sendToFrame(frameId, channel[, arg1][, arg2][, ...])`
* `frameId` Integer
* `channel` String
* `...args` any[]
Send an asynchronous message to a specific frame in a renderer process via
`channel`. Arguments will be serialized
as JSON internally and as such no functions or prototype chains will be included.
The renderer process can handle the message by listening to `channel` with the
[`ipcRenderer`](ipc-renderer.md) module.
If you want to get the `frameId` of a given renderer context you should use
the `webFrame.routingId` value. E.g.
```js
// In a renderer process
console.log('My frameId is:', require('electron').webFrame.routingId)
```
You can also read `frameId` from all incoming IPC messages in the main process.
```js
// In the main process
ipcMain.on('ping', (event) => {
console.info('Message came from frameId:', event.frameId)
})
```
#### `contents.enableDeviceEmulation(parameters)`
* `parameters` Object