child_process: support options in send()
This commit adds an options object to process.send(). The same object is propagated to process._send(), the _handleQueue, and the send() and postSend() functions of the handle converter. Fixes: https://github.com/nodejs/node/issues/4271 PR-URL: https://github.com/nodejs/node/pull/5283 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
parent
18abb3ccc2
commit
1952844f45
@ -750,10 +750,11 @@ console.log(`Spawned child pid: ${grep.pid}`);
|
||||
grep.stdin.end();
|
||||
```
|
||||
|
||||
### child.send(message[, sendHandle][, callback])
|
||||
### child.send(message[, sendHandle[, options]][, callback])
|
||||
|
||||
* `message` {Object}
|
||||
* `sendHandle` {Handle}
|
||||
* `options` {Object}
|
||||
* `callback` {Function}
|
||||
* Return: {Boolean}
|
||||
|
||||
@ -801,6 +802,9 @@ passing a TCP server or socket object to the child process. The child will
|
||||
receive the object as the second argument passed to the callback function
|
||||
registered on the `process.on('message')` event.
|
||||
|
||||
The `options` argument, if present, is an object used to parameterize the
|
||||
sending of certain types of handles.
|
||||
|
||||
The optional `callback` is a function that is invoked after the message is
|
||||
sent but before the child may have received it. The function is called with a
|
||||
single argument: `null` on success, or an [`Error`][] object on failure.
|
||||
|
@ -825,10 +825,11 @@ In custom builds from non-release versions of the source tree, only the
|
||||
`name` property may be present. The additional properties should not be
|
||||
relied upon to exist.
|
||||
|
||||
## process.send(message[, sendHandle][, callback])
|
||||
## process.send(message[, sendHandle[, options]][, callback])
|
||||
|
||||
* `message` {Object}
|
||||
* `sendHandle` {Handle object}
|
||||
* `options` {Object}
|
||||
* `callback` {Function}
|
||||
* Return: {Boolean}
|
||||
|
||||
|
@ -35,7 +35,7 @@ const handleConversion = {
|
||||
'net.Native': {
|
||||
simultaneousAccepts: true,
|
||||
|
||||
send: function(message, handle) {
|
||||
send: function(message, handle, options) {
|
||||
return handle;
|
||||
},
|
||||
|
||||
@ -47,7 +47,7 @@ const handleConversion = {
|
||||
'net.Server': {
|
||||
simultaneousAccepts: true,
|
||||
|
||||
send: function(message, server) {
|
||||
send: function(message, server, options) {
|
||||
return server._handle;
|
||||
},
|
||||
|
||||
@ -60,7 +60,7 @@ const handleConversion = {
|
||||
},
|
||||
|
||||
'net.Socket': {
|
||||
send: function(message, socket) {
|
||||
send: function(message, socket, options) {
|
||||
if (!socket._handle)
|
||||
return;
|
||||
|
||||
@ -90,7 +90,7 @@ const handleConversion = {
|
||||
return handle;
|
||||
},
|
||||
|
||||
postSend: function(handle) {
|
||||
postSend: function(handle, options) {
|
||||
// Close the Socket handle after sending it
|
||||
if (handle)
|
||||
handle.close();
|
||||
@ -117,7 +117,7 @@ const handleConversion = {
|
||||
'dgram.Native': {
|
||||
simultaneousAccepts: false,
|
||||
|
||||
send: function(message, handle) {
|
||||
send: function(message, handle, options) {
|
||||
return handle;
|
||||
},
|
||||
|
||||
@ -129,7 +129,7 @@ const handleConversion = {
|
||||
'dgram.Socket': {
|
||||
simultaneousAccepts: false,
|
||||
|
||||
send: function(message, socket) {
|
||||
send: function(message, socket, options) {
|
||||
message.dgramType = socket.type;
|
||||
|
||||
return socket._handle;
|
||||
@ -466,7 +466,7 @@ function setupChannel(target, channel) {
|
||||
target._handleQueue = null;
|
||||
|
||||
queue.forEach(function(args) {
|
||||
target._send(args.message, args.handle, false, args.callback);
|
||||
target._send(args.message, args.handle, args.options, args.callback);
|
||||
});
|
||||
|
||||
// Process a pending disconnect (if any).
|
||||
@ -498,13 +498,23 @@ function setupChannel(target, channel) {
|
||||
});
|
||||
});
|
||||
|
||||
target.send = function(message, handle, callback) {
|
||||
target.send = function(message, handle, options, callback) {
|
||||
if (typeof handle === 'function') {
|
||||
callback = handle;
|
||||
handle = undefined;
|
||||
options = undefined;
|
||||
} else if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
} else if (options !== undefined &&
|
||||
(options === null || typeof options !== 'object')) {
|
||||
throw new TypeError('"options" argument must be an object');
|
||||
}
|
||||
|
||||
options = Object.assign({swallowErrors: false}, options);
|
||||
|
||||
if (this.connected) {
|
||||
return this._send(message, handle, false, callback);
|
||||
return this._send(message, handle, options, callback);
|
||||
}
|
||||
const ex = new Error('channel closed');
|
||||
if (typeof callback === 'function') {
|
||||
@ -515,12 +525,17 @@ function setupChannel(target, channel) {
|
||||
return false;
|
||||
};
|
||||
|
||||
target._send = function(message, handle, swallowErrors, callback) {
|
||||
target._send = function(message, handle, options, callback) {
|
||||
assert(this.connected || this._channel);
|
||||
|
||||
if (message === undefined)
|
||||
throw new TypeError('"message" argument cannot be undefined');
|
||||
|
||||
// Support legacy function signature
|
||||
if (typeof options === 'boolean') {
|
||||
options = {swallowErrors: options};
|
||||
}
|
||||
|
||||
// package messages with a handle object
|
||||
if (handle) {
|
||||
// this message will be handled by an internalMessage event handler
|
||||
@ -549,6 +564,7 @@ function setupChannel(target, channel) {
|
||||
this._handleQueue.push({
|
||||
callback: callback,
|
||||
handle: handle,
|
||||
options: options,
|
||||
message: message.msg,
|
||||
});
|
||||
return this._handleQueue.length === 1;
|
||||
@ -557,8 +573,10 @@ function setupChannel(target, channel) {
|
||||
var obj = handleConversion[message.type];
|
||||
|
||||
// convert TCP object to native handle object
|
||||
handle =
|
||||
handleConversion[message.type].send.call(target, message, handle);
|
||||
handle = handleConversion[message.type].send.call(target,
|
||||
message,
|
||||
handle,
|
||||
options);
|
||||
|
||||
// If handle was sent twice, or it is impossible to get native handle
|
||||
// out of it - just send a text without the handle.
|
||||
@ -575,6 +593,7 @@ function setupChannel(target, channel) {
|
||||
this._handleQueue.push({
|
||||
callback: callback,
|
||||
handle: null,
|
||||
options: options,
|
||||
message: message,
|
||||
});
|
||||
return this._handleQueue.length === 1;
|
||||
@ -593,7 +612,7 @@ function setupChannel(target, channel) {
|
||||
if (this.async === true)
|
||||
control.unref();
|
||||
if (obj && obj.postSend)
|
||||
obj.postSend(handle);
|
||||
obj.postSend(handle, options);
|
||||
if (typeof callback === 'function')
|
||||
callback(null);
|
||||
};
|
||||
@ -605,9 +624,9 @@ function setupChannel(target, channel) {
|
||||
} else {
|
||||
// Cleanup handle on error
|
||||
if (obj && obj.postSend)
|
||||
obj.postSend(handle);
|
||||
obj.postSend(handle, options);
|
||||
|
||||
if (!swallowErrors) {
|
||||
if (!options.swallowErrors) {
|
||||
const ex = errnoException(err, 'write');
|
||||
if (typeof callback === 'function') {
|
||||
process.nextTick(callback, ex);
|
||||
|
25
test/parallel/test-child-process-send-type-error.js
Normal file
25
test/parallel/test-child-process-send-type-error.js
Normal file
@ -0,0 +1,25 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const cp = require('child_process');
|
||||
|
||||
function noop() {}
|
||||
|
||||
function fail(proc, args) {
|
||||
assert.throws(() => {
|
||||
proc.send.apply(proc, args);
|
||||
}, /"options" argument must be an object/);
|
||||
}
|
||||
|
||||
let target = process;
|
||||
|
||||
if (process.argv[2] !== 'child')
|
||||
target = cp.fork(__filename, ['child']);
|
||||
|
||||
fail(target, ['msg', null, null]);
|
||||
fail(target, ['msg', null, '']);
|
||||
fail(target, ['msg', null, 'foo']);
|
||||
fail(target, ['msg', null, 0]);
|
||||
fail(target, ['msg', null, NaN]);
|
||||
fail(target, ['msg', null, 1]);
|
||||
fail(target, ['msg', null, null, noop]);
|
Loading…
x
Reference in New Issue
Block a user