Skip to content

Commit

Permalink
child_process: support options in send()
Browse files Browse the repository at this point in the history
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: #4271
PR-URL: #5283
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
cjihrig committed Feb 22, 2016
1 parent 18abb3c commit 1952844
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 17 deletions.
6 changes: 5 additions & 1 deletion doc/api/child_process.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down Expand Up @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion doc/api/process.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
49 changes: 34 additions & 15 deletions lib/internal/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const handleConversion = {
'net.Native': {
simultaneousAccepts: true,

send: function(message, handle) {
send: function(message, handle, options) {
return handle;
},

Expand All @@ -47,7 +47,7 @@ const handleConversion = {
'net.Server': {
simultaneousAccepts: true,

send: function(message, server) {
send: function(message, server, options) {
return server._handle;
},

Expand All @@ -60,7 +60,7 @@ const handleConversion = {
},

'net.Socket': {
send: function(message, socket) {
send: function(message, socket, options) {
if (!socket._handle)
return;

Expand Down Expand Up @@ -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();
Expand All @@ -117,7 +117,7 @@ const handleConversion = {
'dgram.Native': {
simultaneousAccepts: false,

send: function(message, handle) {
send: function(message, handle, options) {
return handle;
},

Expand All @@ -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;
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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') {
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -575,6 +593,7 @@ function setupChannel(target, channel) {
this._handleQueue.push({
callback: callback,
handle: null,
options: options,
message: message,
});
return this._handleQueue.length === 1;
Expand All @@ -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);
};
Expand All @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions test/parallel/test-child-process-send-type-error.js
Original file line number Diff line number Diff line change
@@ -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]);

0 comments on commit 1952844

Please sign in to comment.