child_process: truncate output when maxBuffer is exceeded
Preserves truncated output for `child_process.exec()` when `maxBuffer` is exceeded. This is particularly useful for commands which have indistinguishable error codes for what output they produce. PR-URL: https://github.com/nodejs/node/pull/24951 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
5f866821ad
commit
e47f972d68
@ -147,8 +147,9 @@ changes:
|
|||||||
`'/bin/sh'` on UNIX, `process.env.ComSpec` on Windows.
|
`'/bin/sh'` on UNIX, `process.env.ComSpec` on Windows.
|
||||||
* `timeout` {number} **Default:** `0`
|
* `timeout` {number} **Default:** `0`
|
||||||
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
||||||
stderr. If exceeded, the child process is terminated. See caveat at
|
stderr. If exceeded, the child process is terminated and any output is
|
||||||
[`maxBuffer` and Unicode][]. **Default:** `200 * 1024`.
|
truncated. See caveat at [`maxBuffer` and Unicode][].
|
||||||
|
**Default:** `200 * 1024`.
|
||||||
* `killSignal` {string|integer} **Default:** `'SIGTERM'`
|
* `killSignal` {string|integer} **Default:** `'SIGTERM'`
|
||||||
* `uid` {number} Sets the user identity of the process (see setuid(2)).
|
* `uid` {number} Sets the user identity of the process (see setuid(2)).
|
||||||
* `gid` {number} Sets the group identity of the process (see setgid(2)).
|
* `gid` {number} Sets the group identity of the process (see setgid(2)).
|
||||||
@ -245,8 +246,9 @@ changes:
|
|||||||
* `encoding` {string} **Default:** `'utf8'`
|
* `encoding` {string} **Default:** `'utf8'`
|
||||||
* `timeout` {number} **Default:** `0`
|
* `timeout` {number} **Default:** `0`
|
||||||
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
||||||
stderr. If exceeded, the child process is terminated. See caveat at
|
stderr. If exceeded, the child process is terminated and any output is
|
||||||
[`maxBuffer` and Unicode][]. **Default:** `200 * 1024`.
|
truncated. See caveat at [`maxBuffer` and Unicode][].
|
||||||
|
**Default:** `200 * 1024`.
|
||||||
* `killSignal` {string|integer} **Default:** `'SIGTERM'`
|
* `killSignal` {string|integer} **Default:** `'SIGTERM'`
|
||||||
* `uid` {number} Sets the user identity of the process (see setuid(2)).
|
* `uid` {number} Sets the user identity of the process (see setuid(2)).
|
||||||
* `gid` {number} Sets the group identity of the process (see setgid(2)).
|
* `gid` {number} Sets the group identity of the process (see setgid(2)).
|
||||||
@ -779,8 +781,9 @@ changes:
|
|||||||
* `killSignal` {string|integer} The signal value to be used when the spawned
|
* `killSignal` {string|integer} The signal value to be used when the spawned
|
||||||
process will be killed. **Default:** `'SIGTERM'`.
|
process will be killed. **Default:** `'SIGTERM'`.
|
||||||
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
||||||
stderr. If exceeded, the child process is terminated. See caveat at
|
stderr. If exceeded, the child process is terminated and any output is
|
||||||
[`maxBuffer` and Unicode][]. **Default:** `200 * 1024`.
|
truncated. See caveat at [`maxBuffer` and Unicode][].
|
||||||
|
**Default:** `200 * 1024`.
|
||||||
* `encoding` {string} The encoding used for all stdio inputs and outputs.
|
* `encoding` {string} The encoding used for all stdio inputs and outputs.
|
||||||
**Default:** `'buffer'`.
|
**Default:** `'buffer'`.
|
||||||
* `windowsHide` {boolean} Hide the subprocess console window that would
|
* `windowsHide` {boolean} Hide the subprocess console window that would
|
||||||
@ -842,8 +845,9 @@ changes:
|
|||||||
* `killSignal` {string|integer} The signal value to be used when the spawned
|
* `killSignal` {string|integer} The signal value to be used when the spawned
|
||||||
process will be killed. **Default:** `'SIGTERM'`.
|
process will be killed. **Default:** `'SIGTERM'`.
|
||||||
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
* `maxBuffer` {number} Largest amount of data in bytes allowed on stdout or
|
||||||
stderr. If exceeded, the child process is terminated. See caveat at
|
stderr. If exceeded, the child process is terminated and any output is
|
||||||
[`maxBuffer` and Unicode][]. **Default:** `200 * 1024`.
|
truncated. See caveat at [`maxBuffer` and Unicode][].
|
||||||
|
**Default:** `200 * 1024`.
|
||||||
* `encoding` {string} The encoding used for all stdio inputs and outputs.
|
* `encoding` {string} The encoding used for all stdio inputs and outputs.
|
||||||
**Default:** `'buffer'`.
|
**Default:** `'buffer'`.
|
||||||
* `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses
|
* `shell` {boolean|string} If `true`, runs `command` inside of a shell. Uses
|
||||||
|
@ -343,9 +343,15 @@ exports.execFile = function execFile(file /* , args, options, callback */) {
|
|||||||
|
|
||||||
child.stdout.on('data', function onChildStdout(chunk) {
|
child.stdout.on('data', function onChildStdout(chunk) {
|
||||||
var encoding = child.stdout._readableState.encoding;
|
var encoding = child.stdout._readableState.encoding;
|
||||||
stdoutLen += encoding ? Buffer.byteLength(chunk, encoding) : chunk.length;
|
const length = encoding ?
|
||||||
|
Buffer.byteLength(chunk, encoding) :
|
||||||
|
chunk.length;
|
||||||
|
stdoutLen += length;
|
||||||
|
|
||||||
if (stdoutLen > options.maxBuffer) {
|
if (stdoutLen > options.maxBuffer) {
|
||||||
|
const truncatedLen = options.maxBuffer - (stdoutLen - length);
|
||||||
|
_stdout.push(chunk.slice(0, truncatedLen));
|
||||||
|
|
||||||
ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stdout');
|
ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stdout');
|
||||||
kill();
|
kill();
|
||||||
} else {
|
} else {
|
||||||
@ -360,9 +366,15 @@ exports.execFile = function execFile(file /* , args, options, callback */) {
|
|||||||
|
|
||||||
child.stderr.on('data', function onChildStderr(chunk) {
|
child.stderr.on('data', function onChildStderr(chunk) {
|
||||||
var encoding = child.stderr._readableState.encoding;
|
var encoding = child.stderr._readableState.encoding;
|
||||||
stderrLen += encoding ? Buffer.byteLength(chunk, encoding) : chunk.length;
|
const length = encoding ?
|
||||||
|
Buffer.byteLength(chunk, encoding) :
|
||||||
|
chunk.length;
|
||||||
|
stderrLen += length;
|
||||||
|
|
||||||
if (stderrLen > options.maxBuffer) {
|
if (stderrLen > options.maxBuffer) {
|
||||||
|
const truncatedLen = options.maxBuffer - (stderrLen - length);
|
||||||
|
_stderr.push(chunk.slice(0, truncatedLen));
|
||||||
|
|
||||||
ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stderr');
|
ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stderr');
|
||||||
kill();
|
kill();
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,13 +22,13 @@ function runChecks(err, stdio, streamName, expected) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const cmd = 'echo "hello world"';
|
const cmd = 'echo hello world';
|
||||||
|
|
||||||
cp.exec(
|
cp.exec(
|
||||||
cmd,
|
cmd,
|
||||||
{ maxBuffer: 5 },
|
{ maxBuffer: 5 },
|
||||||
common.mustCall((err, stdout, stderr) => {
|
common.mustCall((err, stdout, stderr) => {
|
||||||
runChecks(err, { stdout, stderr }, 'stdout', '');
|
runChecks(err, { stdout, stderr }, 'stdout', 'hello');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ const unicode = '中文测试'; // length = 4, byte length = 12
|
|||||||
cmd,
|
cmd,
|
||||||
{ maxBuffer: 10 },
|
{ maxBuffer: 10 },
|
||||||
common.mustCall((err, stdout, stderr) => {
|
common.mustCall((err, stdout, stderr) => {
|
||||||
runChecks(err, { stdout, stderr }, 'stdout', '');
|
runChecks(err, { stdout, stderr }, 'stdout', '中文测试\n');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ const unicode = '中文测试'; // length = 4, byte length = 12
|
|||||||
cmd,
|
cmd,
|
||||||
{ maxBuffer: 3 },
|
{ maxBuffer: 3 },
|
||||||
common.mustCall((err, stdout, stderr) => {
|
common.mustCall((err, stdout, stderr) => {
|
||||||
runChecks(err, { stdout, stderr }, 'stderr', '');
|
runChecks(err, { stdout, stderr }, 'stderr', '中文测');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -66,7 +66,7 @@ const unicode = '中文测试'; // length = 4, byte length = 12
|
|||||||
cmd,
|
cmd,
|
||||||
{ encoding: null, maxBuffer: 10 },
|
{ encoding: null, maxBuffer: 10 },
|
||||||
common.mustCall((err, stdout, stderr) => {
|
common.mustCall((err, stdout, stderr) => {
|
||||||
runChecks(err, { stdout, stderr }, 'stdout', '');
|
runChecks(err, { stdout, stderr }, 'stdout', '中文测试\n');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -80,9 +80,22 @@ const unicode = '中文测试'; // length = 4, byte length = 12
|
|||||||
cmd,
|
cmd,
|
||||||
{ encoding: null, maxBuffer: 3 },
|
{ encoding: null, maxBuffer: 3 },
|
||||||
common.mustCall((err, stdout, stderr) => {
|
common.mustCall((err, stdout, stderr) => {
|
||||||
runChecks(err, { stdout, stderr }, 'stderr', '');
|
runChecks(err, { stdout, stderr }, 'stderr', '中文测');
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
child.stderr.setEncoding('utf-8');
|
child.stderr.setEncoding('utf-8');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const cmd = `"${process.execPath}" -e "console.error('${unicode}');"`;
|
||||||
|
|
||||||
|
cp.exec(
|
||||||
|
cmd,
|
||||||
|
{ encoding: null, maxBuffer: 5 },
|
||||||
|
common.mustCall((err, stdout, stderr) => {
|
||||||
|
const buf = Buffer.from(unicode).slice(0, 5);
|
||||||
|
runChecks(err, { stdout, stderr }, 'stderr', buf);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user