Skip to content

Commit

Permalink
stream: don't emit end after close
Browse files Browse the repository at this point in the history
Readable stream could emit 'end' after 'close'.

PR-URL: #33076
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
  • Loading branch information
ronag authored and BethGriggs committed Apr 28, 2020
1 parent 56f50ae commit ae157b8
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 4 deletions.
7 changes: 6 additions & 1 deletion lib/_stream_readable.js
Expand Up @@ -150,6 +150,10 @@ function ReadableState(options, stream, isDuplex) {
// Indicates whether the stream has finished destroying.
this.closed = false;

// True if close has been emitted or would have been emitted
// depending on emitClose.
this.closeEmitted = false;

// Crypto is kind of old and crusty. Historically, its default string
// encoding is 'binary' so we have to make this configurable.
// Everything else in the universe uses 'utf8', though.
Expand Down Expand Up @@ -1213,7 +1217,8 @@ function endReadableNT(state, stream) {
debug('endReadableNT', state.endEmitted, state.length);

// Check that we didn't get one last unshift.
if (!state.errorEmitted && !state.endEmitted && state.length === 0) {
if (!state.errorEmitted && !state.closeEmitted &&
!state.endEmitted && state.length === 0) {
state.endEmitted = true;
stream.emit('end');

Expand Down
7 changes: 6 additions & 1 deletion lib/internal/streams/destroy.js
Expand Up @@ -73,6 +73,10 @@ function emitCloseNT(self) {
const r = self._readableState;
const w = self._writableState;

if (r) {
r.closeEmitted = true;
}

if ((w && w.emitClose) || (r && r.emitClose)) {
self.emit('close');
}
Expand Down Expand Up @@ -102,12 +106,13 @@ function undestroy() {

if (r) {
r.closed = false;
r.closeEmitted = false;
r.destroyed = false;
r.errored = false;
r.errorEmitted = false;
r.reading = false;
r.ended = false;
r.endEmitted = false;
r.errorEmitted = false;
}

if (w) {
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-stream-duplex-destroy.js
Expand Up @@ -124,7 +124,7 @@ const assert = require('assert');

duplex.removeListener('end', fail);
duplex.removeListener('finish', fail);
duplex.on('end', common.mustCall());
duplex.on('end', common.mustNotCall());
duplex.on('finish', common.mustCall());
assert.strictEqual(duplex.destroyed, true);
}
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-stream-readable-destroy.js
Expand Up @@ -113,7 +113,7 @@ const assert = require('assert');
read.destroy();

read.removeListener('end', fail);
read.on('end', common.mustCall());
read.on('end', common.mustNotCall());
assert.strictEqual(read.destroyed, true);
}

Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-stream-readable-end-destroyed.js
@@ -0,0 +1,17 @@
'use strict';

const common = require('../common');
const { Readable } = require('stream');

{
// Don't emit 'end' after 'close'.

const r = new Readable();

r.on('end', common.mustNotCall());
r.resume();
r.destroy();
r.on('close', common.mustCall(() => {
r.push(null);
}));
}

0 comments on commit ae157b8

Please sign in to comment.