Skip to content

Commit 6d4887c

Browse files
cjihrigFishrock123
authored andcommitted
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: #4271 PR-URL: #5283 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 01c331e commit 6d4887c

File tree

4 files changed

+66
-17
lines changed

4 files changed

+66
-17
lines changed

doc/api/child_process.markdown

+5-1
Original file line numberDiff line numberDiff line change
@@ -750,10 +750,11 @@ console.log(`Spawned child pid: ${grep.pid}`);
750750
grep.stdin.end();
751751
```
752752

753-
### child.send(message[, sendHandle][, callback])
753+
### child.send(message[, sendHandle[, options]][, callback])
754754

755755
* `message` {Object}
756756
* `sendHandle` {Handle}
757+
* `options` {Object}
757758
* `callback` {Function}
758759
* Return: {Boolean}
759760

@@ -801,6 +802,9 @@ passing a TCP server or socket object to the child process. The child will
801802
receive the object as the second argument passed to the callback function
802803
registered on the `process.on('message')` event.
803804

805+
The `options` argument, if present, is an object used to parameterize the
806+
sending of certain types of handles.
807+
804808
The optional `callback` is a function that is invoked after the message is
805809
sent but before the child may have received it. The function is called with a
806810
single argument: `null` on success, or an [`Error`][] object on failure.

doc/api/process.markdown

+2-1
Original file line numberDiff line numberDiff line change
@@ -825,10 +825,11 @@ In custom builds from non-release versions of the source tree, only the
825825
`name` property may be present. The additional properties should not be
826826
relied upon to exist.
827827

828-
## process.send(message[, sendHandle][, callback])
828+
## process.send(message[, sendHandle[, options]][, callback])
829829

830830
* `message` {Object}
831831
* `sendHandle` {Handle object}
832+
* `options` {Object}
832833
* `callback` {Function}
833834
* Return: {Boolean}
834835

lib/internal/child_process.js

+34-15
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const handleConversion = {
3535
'net.Native': {
3636
simultaneousAccepts: true,
3737

38-
send: function(message, handle) {
38+
send: function(message, handle, options) {
3939
return handle;
4040
},
4141

@@ -47,7 +47,7 @@ const handleConversion = {
4747
'net.Server': {
4848
simultaneousAccepts: true,
4949

50-
send: function(message, server) {
50+
send: function(message, server, options) {
5151
return server._handle;
5252
},
5353

@@ -60,7 +60,7 @@ const handleConversion = {
6060
},
6161

6262
'net.Socket': {
63-
send: function(message, socket) {
63+
send: function(message, socket, options) {
6464
if (!socket._handle)
6565
return;
6666

@@ -90,7 +90,7 @@ const handleConversion = {
9090
return handle;
9191
},
9292

93-
postSend: function(handle) {
93+
postSend: function(handle, options) {
9494
// Close the Socket handle after sending it
9595
if (handle)
9696
handle.close();
@@ -117,7 +117,7 @@ const handleConversion = {
117117
'dgram.Native': {
118118
simultaneousAccepts: false,
119119

120-
send: function(message, handle) {
120+
send: function(message, handle, options) {
121121
return handle;
122122
},
123123

@@ -129,7 +129,7 @@ const handleConversion = {
129129
'dgram.Socket': {
130130
simultaneousAccepts: false,
131131

132-
send: function(message, socket) {
132+
send: function(message, socket, options) {
133133
message.dgramType = socket.type;
134134

135135
return socket._handle;
@@ -466,7 +466,7 @@ function setupChannel(target, channel) {
466466
target._handleQueue = null;
467467

468468
queue.forEach(function(args) {
469-
target._send(args.message, args.handle, false, args.callback);
469+
target._send(args.message, args.handle, args.options, args.callback);
470470
});
471471

472472
// Process a pending disconnect (if any).
@@ -498,13 +498,23 @@ function setupChannel(target, channel) {
498498
});
499499
});
500500

501-
target.send = function(message, handle, callback) {
501+
target.send = function(message, handle, options, callback) {
502502
if (typeof handle === 'function') {
503503
callback = handle;
504504
handle = undefined;
505+
options = undefined;
506+
} else if (typeof options === 'function') {
507+
callback = options;
508+
options = undefined;
509+
} else if (options !== undefined &&
510+
(options === null || typeof options !== 'object')) {
511+
throw new TypeError('"options" argument must be an object');
505512
}
513+
514+
options = Object.assign({swallowErrors: false}, options);
515+
506516
if (this.connected) {
507-
return this._send(message, handle, false, callback);
517+
return this._send(message, handle, options, callback);
508518
}
509519
const ex = new Error('channel closed');
510520
if (typeof callback === 'function') {
@@ -515,12 +525,17 @@ function setupChannel(target, channel) {
515525
return false;
516526
};
517527

518-
target._send = function(message, handle, swallowErrors, callback) {
528+
target._send = function(message, handle, options, callback) {
519529
assert(this.connected || this._channel);
520530

521531
if (message === undefined)
522532
throw new TypeError('message cannot be undefined');
523533

534+
// Support legacy function signature
535+
if (typeof options === 'boolean') {
536+
options = {swallowErrors: options};
537+
}
538+
524539
// package messages with a handle object
525540
if (handle) {
526541
// this message will be handled by an internalMessage event handler
@@ -549,6 +564,7 @@ function setupChannel(target, channel) {
549564
this._handleQueue.push({
550565
callback: callback,
551566
handle: handle,
567+
options: options,
552568
message: message.msg,
553569
});
554570
return this._handleQueue.length === 1;
@@ -557,8 +573,10 @@ function setupChannel(target, channel) {
557573
var obj = handleConversion[message.type];
558574

559575
// convert TCP object to native handle object
560-
handle =
561-
handleConversion[message.type].send.call(target, message, handle);
576+
handle = handleConversion[message.type].send.call(target,
577+
message,
578+
handle,
579+
options);
562580

563581
// If handle was sent twice, or it is impossible to get native handle
564582
// out of it - just send a text without the handle.
@@ -575,6 +593,7 @@ function setupChannel(target, channel) {
575593
this._handleQueue.push({
576594
callback: callback,
577595
handle: null,
596+
options: options,
578597
message: message,
579598
});
580599
return this._handleQueue.length === 1;
@@ -593,7 +612,7 @@ function setupChannel(target, channel) {
593612
if (this.async === true)
594613
control.unref();
595614
if (obj && obj.postSend)
596-
obj.postSend(handle);
615+
obj.postSend(handle, options);
597616
if (typeof callback === 'function')
598617
callback(null);
599618
};
@@ -605,9 +624,9 @@ function setupChannel(target, channel) {
605624
} else {
606625
// Cleanup handle on error
607626
if (obj && obj.postSend)
608-
obj.postSend(handle);
627+
obj.postSend(handle, options);
609628

610-
if (!swallowErrors) {
629+
if (!options.swallowErrors) {
611630
const ex = errnoException(err, 'write');
612631
if (typeof callback === 'function') {
613632
process.nextTick(callback, ex);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
6+
function noop() {}
7+
8+
function fail(proc, args) {
9+
assert.throws(() => {
10+
proc.send.apply(proc, args);
11+
}, /"options" argument must be an object/);
12+
}
13+
14+
let target = process;
15+
16+
if (process.argv[2] !== 'child')
17+
target = cp.fork(__filename, ['child']);
18+
19+
fail(target, ['msg', null, null]);
20+
fail(target, ['msg', null, '']);
21+
fail(target, ['msg', null, 'foo']);
22+
fail(target, ['msg', null, 0]);
23+
fail(target, ['msg', null, NaN]);
24+
fail(target, ['msg', null, 1]);
25+
fail(target, ['msg', null, null, noop]);

0 commit comments

Comments
 (0)