stream: finish pipeline if dst closes before src

If the destination stream is closed before the source has completed
the pipeline should finnish with premature close.

Fixes: https://github.com/nodejs/node/issues/43682

PR-URL: https://github.com/nodejs/node/pull/43701
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
This commit is contained in:
Robert Nagy 2022-07-11 12:25:05 +02:00 committed by GitHub
parent b4a7d9f987
commit e4bf5dc581
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 1 deletions

View File

@ -20,6 +20,7 @@ const {
ERR_INVALID_RETURN_VALUE,
ERR_MISSING_ARGS,
ERR_STREAM_DESTROYED,
ERR_STREAM_PREMATURE_CLOSE,
},
AbortError,
} = require('internal/errors');
@ -344,13 +345,24 @@ function pipelineImpl(streams, callback, opts) {
}
function pipe(src, dst, finish, { end }) {
let ended = false;
dst.on('close', () => {
if (!ended) {
// Finish if the destination closes before the source has completed.
finish(new ERR_STREAM_PREMATURE_CLOSE());
}
});
src.pipe(dst, { end });
if (end) {
// Compat. Before node v10.12.0 stdio used to throw an error so
// pipe() did/does not end() stdio destinations.
// Now they allow it but "secretly" don't close the underlying fd.
src.once('end', () => dst.end());
src.once('end', () => {
ended = true;
dst.end();
});
} else {
finish();
}

View File

@ -0,0 +1,21 @@
'use strict';
const common = require('../common');
const { pipeline, Duplex, PassThrough } = require('stream');
const assert = require('assert');
const remote = new PassThrough();
const local = new Duplex({
read() {},
write(chunk, enc, callback) {
callback();
}
});
pipeline(remote, local, remote, common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_STREAM_PREMATURE_CLOSE');
}));
setImmediate(() => {
remote.end();
});