Skip to content

Commit 269103a

Browse files
committed
stream: fix regression introduced in #26059
In #26059, we introduced a bug that caused 'readable' to be nextTicked on EOF of a ReadableStream. This breaks the dicer module on CITGM. That change was partially reverted to still fix the bug in #25810 and not break dicer. See: #26059 Fixes: #25810 PR-URL: #26643 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent c5e619b commit 269103a

7 files changed

+28
-33
lines changed

lib/_stream_readable.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -512,12 +512,24 @@ function onEofChunk(stream, state) {
512512
}
513513
}
514514
state.ended = true;
515-
state.needReadable = false;
516515

517-
// We are not protecting if emittedReadable = true,
518-
// so 'readable' gets scheduled anyway.
519-
state.emittedReadable = true;
520-
process.nextTick(emitReadable_, stream);
516+
if (state.sync) {
517+
// If we are sync, wait until next tick to emit the data.
518+
// Otherwise we risk emitting data in the flow()
519+
// the readable code triggers during a read() call
520+
emitReadable(stream);
521+
} else {
522+
// Emit 'readable' now to make sure it gets picked up.
523+
state.needReadable = false;
524+
state.emittedReadable = true;
525+
// We have to emit readable now that we are EOF. Modules
526+
// in the ecosystem (e.g. dicer) rely on this event being sync.
527+
if (state.ended) {
528+
emitReadable_(stream);
529+
} else {
530+
process.nextTick(emitReadable_, stream);
531+
}
532+
}
521533
}
522534

523535
// Don't emit readable right away in sync mode, because this can trigger

test/parallel/test-stream-readable-emit-readable-short-stream.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const assert = require('assert');
5454
break;
5555
assert.strictEqual(chunk.toString(), 'content');
5656
}
57-
}, 2));
57+
}));
5858
}
5959

6060
{
@@ -78,7 +78,7 @@ const assert = require('assert');
7878
break;
7979
assert.strictEqual(chunk.toString(), 'content');
8080
}
81-
}, 2));
81+
}));
8282
}
8383

8484
{
@@ -94,7 +94,7 @@ const assert = require('assert');
9494
break;
9595
assert.strictEqual(chunk.toString(), 'content');
9696
}
97-
}, 2));
97+
}));
9898

9999
t.push('content');
100100
t.push(null);

test/parallel/test-stream-readable-emittedReadable.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,12 @@ const noRead = new Readable({
4343
read: () => {}
4444
});
4545

46-
noRead.once('readable', common.mustCall(() => {
46+
noRead.on('readable', common.mustCall(() => {
4747
// emittedReadable should be true when the readable event is emitted
4848
assert.strictEqual(noRead._readableState.emittedReadable, true);
4949
noRead.read(0);
5050
// emittedReadable is not reset during read(0)
5151
assert.strictEqual(noRead._readableState.emittedReadable, true);
52-
53-
noRead.on('readable', common.mustCall(() => {
54-
// The second 'readable' is emitted because we are ending
55-
56-
// emittedReadable should be true when the readable event is emitted
57-
assert.strictEqual(noRead._readableState.emittedReadable, false);
58-
noRead.read(0);
59-
// emittedReadable is not reset during read(0)
60-
assert.strictEqual(noRead._readableState.emittedReadable, false);
61-
62-
}));
6352
}));
6453

6554
noRead.push('foo');

test/parallel/test-stream-readable-needReadable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ readable.on('readable', common.mustCall(() => {
1414
// When the readable event fires, needReadable is reset.
1515
assert.strictEqual(readable._readableState.needReadable, false);
1616
readable.read();
17-
}, 2));
17+
}));
1818

1919
// If a readable listener is attached, then a readable event is needed.
2020
assert.strictEqual(readable._readableState.needReadable, true);

test/parallel/test-stream-readable-reading-readingMore.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ const Readable = require('stream').Readable;
3131
assert.strictEqual(state.reading, false);
3232
}
3333

34-
const expectedReadingMore = [true, false, false];
34+
const expectedReadingMore = [true, true, false];
3535
readable.on('readable', common.mustCall(() => {
3636
// There is only one readingMore scheduled from on('data'),
3737
// after which everything is governed by the .read() call

test/parallel/test-stream2-httpclient-response-end.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const server = http.createServer(function(req, res) {
1515
while ((chunk = res.read()) !== null) {
1616
data += chunk;
1717
}
18-
}, 2));
18+
}));
1919
res.on('end', common.mustCall(function() {
2020
console.log('end event');
2121
assert.strictEqual(msg, data);

test/parallel/test-stream2-transform.js

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,10 @@ const Transform = require('_stream_transform');
321321

322322
pt.end();
323323

324-
// The next readable is emitted on the next tick.
325-
assert.strictEqual(emits, 0);
326-
327-
process.on('nextTick', function() {
328-
assert.strictEqual(emits, 1);
329-
assert.strictEqual(pt.read(5).toString(), 'l');
330-
assert.strictEqual(pt.read(5), null);
331-
332-
assert.strictEqual(emits, 1);
333-
});
324+
assert.strictEqual(emits, 1);
325+
assert.strictEqual(pt.read(5).toString(), 'l');
326+
assert.strictEqual(pt.read(5), null);
327+
assert.strictEqual(emits, 1);
334328
}
335329

336330
{

0 commit comments

Comments
 (0)