From a0f3d2b71880f0cb91aba3b0e1965219f2067598 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Wed, 11 Mar 2020 13:56:24 +0100 Subject: [PATCH] stream: avoid destroying writable source User might still want to be able to use the writable side of src. This is in the case where e.g. the Duplex input is not directly connected to its output. Such a case could happen when the Duplex is reading from a socket and then echos the data back on the same socket. Fixes: https://github.com/nodejs/node/commit/4d93e105bfad79ff6c6f01e4b7c2fdd70caeb43b#commitcomment-37751035 Backport-PR-URL: https://github.com/nodejs/node/pull/32211 --- lib/internal/streams/pipeline.js | 5 +++++ test/parallel/test-stream-pipeline.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/internal/streams/pipeline.js b/lib/internal/streams/pipeline.js index edbfed3e516c05..7b7cb94b3b0af8 100644 --- a/lib/internal/streams/pipeline.js +++ b/lib/internal/streams/pipeline.js @@ -37,6 +37,11 @@ function destroyer(stream, reading, writing, final, callback) { eos(stream, { readable: reading, writable: writing }, (err) => { if (destroyed) return; destroyed = true; + + if (!err && reading && !writing && stream.writable) { + return callback(); + } + const readable = stream.readable || isRequest(stream); if (err || !final || !readable) { destroyImpl.destroyer(stream, err); diff --git a/test/parallel/test-stream-pipeline.js b/test/parallel/test-stream-pipeline.js index 9939a16494499c..354d6d9a55cdd8 100644 --- a/test/parallel/test-stream-pipeline.js +++ b/test/parallel/test-stream-pipeline.js @@ -995,3 +995,19 @@ const { promisify } = require('util'); assert.strictEqual(res, ''); })); } + +{ + // Might still want to be able to use the writable side + // of src. This is in the case where e.g. the Duplex input + // is not directly connected to its output. Such a case could + // happen when the Duplex is reading from a socket and then echos + // the data back on the same socket. + const src = new PassThrough(); + assert.strictEqual(src.writable, true); + const dst = new PassThrough(); + pipeline(src, dst, common.mustCall((err) => { + assert.strictEqual(src.writable, true); + assert.strictEqual(src.destroyed, false); + })); + src.push(null); +}