handle remote exception (#12694)
* add cause property to exception in callFunction * update exceptionToMeta function * add sender argument * and cause property to return value * update exception convert in metaToValue function * add from and cause properties to the exception error * unit test for remote exception
This commit is contained in:
parent
2579071b98
commit
9c65abd746
4 changed files with 54 additions and 17 deletions
|
@ -131,11 +131,12 @@ const plainObjectToMeta = function (obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Error into meta data.
|
// Convert Error into meta data.
|
||||||
const exceptionToMeta = function (error) {
|
const exceptionToMeta = function (sender, error) {
|
||||||
return {
|
return {
|
||||||
type: 'exception',
|
type: 'exception',
|
||||||
message: error.message,
|
message: error.message,
|
||||||
stack: error.stack || error
|
stack: error.stack || error,
|
||||||
|
cause: valueToMeta(sender, error.cause)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ const unwrapArgs = function (sender, args) {
|
||||||
// Call a function and send reply asynchronously if it's a an asynchronous
|
// Call a function and send reply asynchronously if it's a an asynchronous
|
||||||
// style function and the caller didn't pass a callback.
|
// style function and the caller didn't pass a callback.
|
||||||
const callFunction = function (event, func, caller, args) {
|
const callFunction = function (event, func, caller, args) {
|
||||||
let funcMarkedAsync, funcName, funcPassedCallback, ref, ret
|
let err, funcMarkedAsync, funcName, funcPassedCallback, ref, ret
|
||||||
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
funcMarkedAsync = v8Util.getHiddenValue(func, 'asynchronous')
|
||||||
funcPassedCallback = typeof args[args.length - 1] === 'function'
|
funcPassedCallback = typeof args[args.length - 1] === 'function'
|
||||||
try {
|
try {
|
||||||
|
@ -254,7 +255,9 @@ const callFunction = function (event, func, caller, args) {
|
||||||
// them with the function name so it's easier to trace things like
|
// them with the function name so it's easier to trace things like
|
||||||
// `Error processing argument -1.`
|
// `Error processing argument -1.`
|
||||||
funcName = ((ref = func.name) != null) ? ref : 'anonymous'
|
funcName = ((ref = func.name) != null) ? ref : 'anonymous'
|
||||||
throw new Error(`Could not call remote function '${funcName}'. Check that the function signature is correct. Underlying error: ${error.message}`)
|
err = new Error(`Could not call remote function '${funcName}'. Check that the function signature is correct. Underlying error: ${error.message}`)
|
||||||
|
err.cause = error
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +265,7 @@ ipcMain.on('ELECTRON_BROWSER_REQUIRE', function (event, module) {
|
||||||
try {
|
try {
|
||||||
event.returnValue = valueToMeta(event.sender, process.mainModule.require(module))
|
event.returnValue = valueToMeta(event.sender, process.mainModule.require(module))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -270,7 +273,7 @@ ipcMain.on('ELECTRON_BROWSER_GET_BUILTIN', function (event, module) {
|
||||||
try {
|
try {
|
||||||
event.returnValue = valueToMeta(event.sender, electron[module])
|
event.returnValue = valueToMeta(event.sender, electron[module])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -278,7 +281,7 @@ ipcMain.on('ELECTRON_BROWSER_GLOBAL', function (event, name) {
|
||||||
try {
|
try {
|
||||||
event.returnValue = valueToMeta(event.sender, global[name])
|
event.returnValue = valueToMeta(event.sender, global[name])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -286,7 +289,7 @@ ipcMain.on('ELECTRON_BROWSER_CURRENT_WINDOW', function (event) {
|
||||||
try {
|
try {
|
||||||
event.returnValue = valueToMeta(event.sender, event.sender.getOwnerBrowserWindow())
|
event.returnValue = valueToMeta(event.sender, event.sender.getOwnerBrowserWindow())
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -308,7 +311,7 @@ ipcMain.on('ELECTRON_BROWSER_CONSTRUCTOR', function (event, id, args) {
|
||||||
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
||||||
event.returnValue = valueToMeta(event.sender, obj)
|
event.returnValue = valueToMeta(event.sender, obj)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -323,7 +326,7 @@ ipcMain.on('ELECTRON_BROWSER_FUNCTION_CALL', function (event, id, args) {
|
||||||
|
|
||||||
callFunction(event, func, global, args)
|
callFunction(event, func, global, args)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -341,7 +344,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, id, method, a
|
||||||
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args)))()
|
||||||
event.returnValue = valueToMeta(event.sender, obj)
|
event.returnValue = valueToMeta(event.sender, obj)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -356,7 +359,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) {
|
||||||
|
|
||||||
callFunction(event, obj[method], obj, args)
|
callFunction(event, obj[method], obj, args)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -372,7 +375,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_SET', function (event, id, name, args) {
|
||||||
obj[name] = args[0]
|
obj[name] = args[0]
|
||||||
event.returnValue = null
|
event.returnValue = null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -386,7 +389,7 @@ ipcMain.on('ELECTRON_BROWSER_MEMBER_GET', function (event, id, name) {
|
||||||
|
|
||||||
event.returnValue = valueToMeta(event.sender, obj[name])
|
event.returnValue = valueToMeta(event.sender, obj[name])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -404,7 +407,7 @@ ipcMain.on('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', function (event, guestInstance
|
||||||
let guestViewManager = require('./guest-view-manager')
|
let guestViewManager = require('./guest-view-manager')
|
||||||
event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId))
|
event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -420,7 +423,7 @@ ipcMain.on('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function (event, request
|
||||||
}
|
}
|
||||||
guest[method].apply(guest, args)
|
guest[method].apply(guest, args)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
event.returnValue = exceptionToMeta(error)
|
event.returnValue = exceptionToMeta(event.sender, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ function metaToValue (meta) {
|
||||||
promise: () => resolvePromise({then: metaToValue(meta.then)}),
|
promise: () => resolvePromise({then: metaToValue(meta.then)}),
|
||||||
error: () => metaToPlainObject(meta),
|
error: () => metaToPlainObject(meta),
|
||||||
date: () => new Date(meta.value),
|
date: () => new Date(meta.value),
|
||||||
exception: () => { throw new Error(`${meta.message}\n${meta.stack}`) }
|
exception: () => { throw metaToException(meta) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta.type in types) {
|
if (meta.type in types) {
|
||||||
|
@ -256,6 +256,15 @@ function metaToPlainObject (meta) {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct an exception error from the meta.
|
||||||
|
function metaToException (meta) {
|
||||||
|
const error = new Error(`${meta.message}\n${meta.stack}`)
|
||||||
|
const remoteProcess = exports.process
|
||||||
|
error.from = remoteProcess ? remoteProcess.type : null
|
||||||
|
error.cause = metaToValue(meta.cause)
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
|
||||||
// Browser calls a callback in renderer.
|
// Browser calls a callback in renderer.
|
||||||
ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', (event, id, args) => {
|
ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', (event, id, args) => {
|
||||||
callbacksRegistry.apply(id, metaToValue(args))
|
callbacksRegistry.apply(id, metaToValue(args))
|
||||||
|
|
|
@ -370,4 +370,26 @@ describe('remote module', () => {
|
||||||
assert.equal(method(), 'method')
|
assert.equal(method(), 'method')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('remote exception', () => {
|
||||||
|
const throwFunction = remote.require(path.join(fixtures, 'module', 'exception.js'))
|
||||||
|
|
||||||
|
it('throws errors from the main process', () => {
|
||||||
|
assert.throws(() => {
|
||||||
|
throwFunction()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws custom errors from the main process', () => {
|
||||||
|
let err = new Error('error')
|
||||||
|
err.cause = new Error('cause')
|
||||||
|
err.prop = 'error prop'
|
||||||
|
try {
|
||||||
|
throwFunction(err)
|
||||||
|
} catch (error) {
|
||||||
|
assert.ok(error.from)
|
||||||
|
assert.deepEqual(error.cause, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
3
spec/fixtures/module/exception.js
vendored
Normal file
3
spec/fixtures/module/exception.js
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function (error) {
|
||||||
|
throw error
|
||||||
|
}
|
Loading…
Reference in a new issue