Merge pull request #8357 from electron/remote-events-error-message
Don't crash when calling stale remote listeners
This commit is contained in:
commit
8e69f94df0
4 changed files with 90 additions and 1 deletions
|
@ -3,6 +3,8 @@
|
||||||
const {Buffer} = require('buffer')
|
const {Buffer} = require('buffer')
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const v8Util = process.atomBinding('v8_util')
|
const v8Util = process.atomBinding('v8_util')
|
||||||
|
const {WebContents} = process.atomBinding('web_contents')
|
||||||
|
|
||||||
const {ipcMain, isPromise, webContents} = electron
|
const {ipcMain, isPromise, webContents} = electron
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
@ -146,6 +148,27 @@ const throwRPCError = function (message) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const removeRemoteListenersAndLogWarning = (meta, args, callIntoRenderer) => {
|
||||||
|
let message = `Attempting to call a function in a renderer window that has been closed or released.` +
|
||||||
|
`\nFunction provided here: ${meta.location}`
|
||||||
|
|
||||||
|
if (args.length > 0 && (args[0].sender instanceof WebContents)) {
|
||||||
|
const {sender} = args[0]
|
||||||
|
const remoteEvents = sender.eventNames().filter((eventName) => {
|
||||||
|
return sender.listeners(eventName).includes(callIntoRenderer)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (remoteEvents.length > 0) {
|
||||||
|
message += `\nRemote event names: ${remoteEvents.join(', ')}`
|
||||||
|
remoteEvents.forEach((eventName) => {
|
||||||
|
sender.removeListener(eventName, callIntoRenderer)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(message)
|
||||||
|
}
|
||||||
|
|
||||||
// Convert array of meta data from renderer into array of real values.
|
// Convert array of meta data from renderer into array of real values.
|
||||||
const unwrapArgs = function (sender, args) {
|
const unwrapArgs = function (sender, args) {
|
||||||
const metaToValue = function (meta) {
|
const metaToValue = function (meta) {
|
||||||
|
@ -196,7 +219,7 @@ const unwrapArgs = function (sender, args) {
|
||||||
if (!sender.isDestroyed() && webContentsId === sender.getId()) {
|
if (!sender.isDestroyed() && webContentsId === sender.getId()) {
|
||||||
sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args))
|
sender.send('ELECTRON_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args))
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`)
|
removeRemoteListenersAndLogWarning(meta, args, callIntoRenderer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,6 +494,30 @@ describe('ipc module', function () {
|
||||||
w.removeListener('test', listener)
|
w.removeListener('test', listener)
|
||||||
assert.equal(w.listenerCount('test'), 0)
|
assert.equal(w.listenerCount('test'), 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('detaches listeners subscribed to destroyed renderers, and shows a warning', (done) => {
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false
|
||||||
|
})
|
||||||
|
w.webContents.once('did-finish-load', () => {
|
||||||
|
w.webContents.once('did-finish-load', () => {
|
||||||
|
const expectedMessage = [
|
||||||
|
'Attempting to call a function in a renderer window that has been closed or released.',
|
||||||
|
'Function provided here: remote-event-handler.html:11:33',
|
||||||
|
'Remote event names: remote-handler, other-remote-handler'
|
||||||
|
].join('\n')
|
||||||
|
const results = ipcRenderer.sendSync('try-emit-web-contents-event', w.webContents.id, 'remote-handler')
|
||||||
|
assert.deepEqual(results, {
|
||||||
|
warningMessage: expectedMessage,
|
||||||
|
listenerCountBefore: 2,
|
||||||
|
listenerCountAfter: 1
|
||||||
|
})
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.webContents.reload()
|
||||||
|
})
|
||||||
|
w.loadURL('file://' + path.join(fixtures, 'api', 'remote-event-handler.html'))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws an error when removing all the listeners', () => {
|
it('throws an error when removing all the listeners', () => {
|
||||||
|
|
18
spec/fixtures/api/remote-event-handler.html
vendored
Normal file
18
spec/fixtures/api/remote-event-handler.html
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title></title>
|
||||||
|
<script>
|
||||||
|
const {remote} = require('electron')
|
||||||
|
const browserWindow = remote.getCurrentWindow()
|
||||||
|
|
||||||
|
const handler = () => {}
|
||||||
|
browserWindow.webContents.on('remote-handler', handler)
|
||||||
|
browserWindow.webContents.on('other-remote-handler', handler)
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -249,3 +249,27 @@ ipcMain.on('create-window-with-options-cycle', (event) => {
|
||||||
ipcMain.on('prevent-next-new-window', (event, id) => {
|
ipcMain.on('prevent-next-new-window', (event, id) => {
|
||||||
webContents.fromId(id).once('new-window', event => event.preventDefault())
|
webContents.fromId(id).once('new-window', event => event.preventDefault())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ipcMain.on('try-emit-web-contents-event', (event, id, eventName) => {
|
||||||
|
const consoleWarn = console.warn
|
||||||
|
let warningMessage = null
|
||||||
|
const contents = webContents.fromId(id)
|
||||||
|
const listenerCountBefore = contents.listenerCount(eventName)
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.warn = (message) => {
|
||||||
|
warningMessage = message
|
||||||
|
}
|
||||||
|
contents.emit(eventName, {sender: contents})
|
||||||
|
} finally {
|
||||||
|
console.warn = consoleWarn
|
||||||
|
}
|
||||||
|
|
||||||
|
const listenerCountAfter = contents.listenerCount(eventName)
|
||||||
|
|
||||||
|
event.returnValue = {
|
||||||
|
warningMessage,
|
||||||
|
listenerCountBefore,
|
||||||
|
listenerCountAfter
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue