Skip to content

Commit ae157b8

Browse files
ronagBethGriggs
authored andcommitted
stream: don't emit end after close
Readable stream could emit 'end' after 'close'. PR-URL: #33076 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 56f50ae commit ae157b8

File tree

5 files changed

+31
-4
lines changed

5 files changed

+31
-4
lines changed

lib/_stream_readable.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ function ReadableState(options, stream, isDuplex) {
150150
// Indicates whether the stream has finished destroying.
151151
this.closed = false;
152152

153+
// True if close has been emitted or would have been emitted
154+
// depending on emitClose.
155+
this.closeEmitted = false;
156+
153157
// Crypto is kind of old and crusty. Historically, its default string
154158
// encoding is 'binary' so we have to make this configurable.
155159
// Everything else in the universe uses 'utf8', though.
@@ -1213,7 +1217,8 @@ function endReadableNT(state, stream) {
12131217
debug('endReadableNT', state.endEmitted, state.length);
12141218

12151219
// Check that we didn't get one last unshift.
1216-
if (!state.errorEmitted && !state.endEmitted && state.length === 0) {
1220+
if (!state.errorEmitted && !state.closeEmitted &&
1221+
!state.endEmitted && state.length === 0) {
12171222
state.endEmitted = true;
12181223
stream.emit('end');
12191224

lib/internal/streams/destroy.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ function emitCloseNT(self) {
7373
const r = self._readableState;
7474
const w = self._writableState;
7575

76+
if (r) {
77+
r.closeEmitted = true;
78+
}
79+
7680
if ((w && w.emitClose) || (r && r.emitClose)) {
7781
self.emit('close');
7882
}
@@ -102,12 +106,13 @@ function undestroy() {
102106

103107
if (r) {
104108
r.closed = false;
109+
r.closeEmitted = false;
105110
r.destroyed = false;
106111
r.errored = false;
112+
r.errorEmitted = false;
107113
r.reading = false;
108114
r.ended = false;
109115
r.endEmitted = false;
110-
r.errorEmitted = false;
111116
}
112117

113118
if (w) {

test/parallel/test-stream-duplex-destroy.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ const assert = require('assert');
124124

125125
duplex.removeListener('end', fail);
126126
duplex.removeListener('finish', fail);
127-
duplex.on('end', common.mustCall());
127+
duplex.on('end', common.mustNotCall());
128128
duplex.on('finish', common.mustCall());
129129
assert.strictEqual(duplex.destroyed, true);
130130
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const assert = require('assert');
113113
read.destroy();
114114

115115
read.removeListener('end', fail);
116-
read.on('end', common.mustCall());
116+
read.on('end', common.mustNotCall());
117117
assert.strictEqual(read.destroyed, true);
118118
}
119119

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const { Readable } = require('stream');
5+
6+
{
7+
// Don't emit 'end' after 'close'.
8+
9+
const r = new Readable();
10+
11+
r.on('end', common.mustNotCall());
12+
r.resume();
13+
r.destroy();
14+
r.on('close', common.mustCall(() => {
15+
r.push(null);
16+
}));
17+
}

0 commit comments

Comments
 (0)