From f537c868b942c8a77e8ef20e9217c17679fa86f6 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 28 Aug 2020 17:09:23 +0200 Subject: [PATCH] stream: allow using `.push()`/`.unshift()` during `once('data')` Previously, the `.push()` or `.unshift()` call would just have jumped straight to emitting a `'data'` event, even if there were no listeners, effectively just silently dropping the chunk. PR-URL: https://github.com/nodejs/node/pull/34957 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Denys Otrishko Reviewed-By: Robert Nagy Reviewed-By: Ricky Zhou <0x19951125@gmail.com> --- lib/_stream_readable.js | 3 ++- ...t-stream-readable-add-chunk-during-data.js | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-stream-readable-add-chunk-during-data.js diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index a466011b682beb..2e7f751241d09a 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -292,7 +292,8 @@ function readableAddChunk(stream, chunk, encoding, addToFront) { } function addChunk(stream, state, chunk, addToFront) { - if (state.flowing && state.length === 0 && !state.sync) { + if (state.flowing && state.length === 0 && !state.sync && + stream.listenerCount('data') > 0) { // Use the guard to avoid creating `Set()` repeatedly // when we have multiple pipes. if (state.multiAwaitDrain) { diff --git a/test/parallel/test-stream-readable-add-chunk-during-data.js b/test/parallel/test-stream-readable-add-chunk-during-data.js new file mode 100644 index 00000000000000..6c36359790633e --- /dev/null +++ b/test/parallel/test-stream-readable-add-chunk-during-data.js @@ -0,0 +1,21 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { Readable } = require('stream'); + +// Verify that .push() and .unshift() can be called from 'data' listeners. + +for (const method of ['push', 'unshift']) { + const r = new Readable({ read() {} }); + r.once('data', common.mustCall((chunk) => { + assert.strictEqual(r.readableLength, 0); + r[method](chunk); + assert.strictEqual(r.readableLength, chunk.length); + + r.on('data', common.mustCall((chunk) => { + assert.strictEqual(chunk.toString(), 'Hello, world'); + })); + })); + + r.push('Hello, world'); +}