Skip to content

Commit

Permalink
stream: ensure finish is emitted in next tick
Browse files Browse the repository at this point in the history
When using end() it was possible for 'finish' to
be emitted synchronously.
  • Loading branch information
ronag committed Nov 30, 2019
1 parent 52a3e35 commit cdc12a6
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 17 deletions.
34 changes: 22 additions & 12 deletions lib/_stream_writable.js
Original file line number Diff line number Diff line change
Expand Up @@ -671,30 +671,40 @@ function prefinish(stream, state) {
}
}

function finishMaybe(stream, state) {
function finishMaybe(stream, state, sync) {
const need = needFinish(state);
if (need) {
prefinish(stream, state);
if (state.pendingcb === 0) {
state.finished = true;
stream.emit('finish');

if (state.autoDestroy) {
// In case of duplex streams we need a way to detect
// if the readable side is ready for autoDestroy as well
const rState = stream._readableState;
if (!rState || (rState.autoDestroy && rState.endEmitted)) {
stream.destroy();
}
state.pendingcb++;
if (sync) {
process.nextTick(finish, stream, state);
} else {
finish(stream, state);
}
}
}
return need;
}

function finish(stream, state) {
state.pendingcb--;
state.finished = true;
stream.emit('finish');

if (state.autoDestroy) {
// In case of duplex streams we need a way to detect
// if the readable side is ready for autoDestroy as well
const rState = stream._readableState;
if (!rState || (rState.autoDestroy && rState.endEmitted)) {
stream.destroy();
}
}
}

function endWritable(stream, state, cb) {
state.ending = true;
finishMaybe(stream, state);
finishMaybe(stream, state, true);
if (cb) {
if (state.finished)
process.nextTick(cb);
Expand Down
4 changes: 3 additions & 1 deletion test/parallel/test-internal-fs-syncwritestream.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,7 @@ const filename = path.join(tmpdir.path, 'sync-write-stream.txt');
assert.strictEqual(stream.fd, fd);

stream.end();
assert.strictEqual(stream.fd, null);
stream.on('close', common.mustCall(() => {
assert.strictEqual(stream.fd, null);
}));
}
10 changes: 6 additions & 4 deletions test/parallel/test-stream-writable-destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,15 @@ const assert = require('assert');
// called again.
const write = new Writable({
write: common.mustNotCall(),
final: common.mustCall((cb) => cb(), 2)
final: common.mustCall((cb) => cb(), 2),
autoDestroy: true
});

write.end();
write.destroy();
write._undestroy();
write.end();
write.once('close', common.mustCall(() => {
write._undestroy();
write.end();
}));
}

{
Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-stream-writable-finished.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ const assert = require('assert');
assert.strictEqual(writable.writableFinished, true);
}));
}

{
// Emit finish asynchronously

const w = new Writable({
write(chunk, encoding, cb) {
cb();
}
});

w.end();
w.on('finish', common.mustCall());
}

0 comments on commit cdc12a6

Please sign in to comment.