Skip to content

Commit 1952844

Browse files
committed
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 <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent 18abb3c commit 1952844

4 files changed

Lines changed: 66 additions & 17 deletions

File tree

‎doc/api/child_process.markdown‎

Lines changed: 5 additions & 1 deletion
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‎

Lines changed: 2 additions & 1 deletion
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‎

Lines changed: 34 additions & 15 deletions
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
returnhandle;
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
returnserver._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
returnhandle;
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
returnhandle;
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
returnsocket._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(typeofhandle==='function'){
503503
callback=handle;
504504
handle=undefined;
505+
options=undefined;
506+
}elseif(typeofoptions==='function'){
507+
callback=options;
508+
options=undefined;
509+
}elseif(options!==undefined&&
510+
(options===null||typeofoptions!=='object')){
511+
thrownewTypeError('"options" argument must be an object');
505512
}
513+
514+
options=Object.assign({swallowErrors: false},options);
515+
506516
if(this.connected){
507-
returnthis._send(message,handle,false,callback);
517+
returnthis._send(message,handle,options,callback);
508518
}
509519
constex=newError('channel closed');
510520
if(typeofcallback==='function'){
@@ -515,12 +525,17 @@ function setupChannel(target, channel) {
515525
returnfalse;
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
thrownewTypeError('"message" argument cannot be undefined');
523533

534+
// Support legacy function signature
535+
if(typeofoptions==='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
returnthis._handleQueue.length===1;
@@ -557,8 +573,10 @@ function setupChannel(target, channel) {
557573
varobj=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
returnthis._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(typeofcallback==='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
constex=errnoException(err,'write');
612631
if(typeofcallback==='function'){
613632
process.nextTick(callback,ex);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
require('../common');
3+
constassert=require('assert');
4+
constcp=require('child_process');
5+
6+
functionnoop(){}
7+
8+
functionfail(proc,args){
9+
assert.throws(()=>{
10+
proc.send.apply(proc,args);
11+
},/"options"argumentmustbeanobject/);
12+
}
13+
14+
lettarget=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)