stream: ensure writable.destroy() emits error once
Prevent the `'error'` event from being emitted multiple times if `writable.destroy()` is called with an error before the `_destroy()` callback is called. Emit the first error, discard all others. PR-URL: https://github.com/nodejs/node/pull/26057 Fixes: https://github.com/nodejs/node/issues/26015 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
60aaf2c214
commit
49f1bb9b93
@ -10,10 +10,15 @@ function destroy(err, cb) {
|
|||||||
if (readableDestroyed || writableDestroyed) {
|
if (readableDestroyed || writableDestroyed) {
|
||||||
if (cb) {
|
if (cb) {
|
||||||
cb(err);
|
cb(err);
|
||||||
} else if (err &&
|
} else if (err) {
|
||||||
(!this._writableState || !this._writableState.errorEmitted)) {
|
if (!this._writableState) {
|
||||||
process.nextTick(emitErrorNT, this, err);
|
process.nextTick(emitErrorNT, this, err);
|
||||||
|
} else if (!this._writableState.errorEmitted) {
|
||||||
|
this._writableState.errorEmitted = true;
|
||||||
|
process.nextTick(emitErrorNT, this, err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,9 +36,13 @@ function destroy(err, cb) {
|
|||||||
|
|
||||||
this._destroy(err || null, (err) => {
|
this._destroy(err || null, (err) => {
|
||||||
if (!cb && err) {
|
if (!cb && err) {
|
||||||
process.nextTick(emitErrorAndCloseNT, this, err);
|
if (!this._writableState) {
|
||||||
if (this._writableState) {
|
process.nextTick(emitErrorAndCloseNT, this, err);
|
||||||
|
} else if (!this._writableState.errorEmitted) {
|
||||||
this._writableState.errorEmitted = true;
|
this._writableState.errorEmitted = true;
|
||||||
|
process.nextTick(emitErrorAndCloseNT, this, err);
|
||||||
|
} else {
|
||||||
|
process.nextTick(emitCloseNT, this);
|
||||||
}
|
}
|
||||||
} else if (cb) {
|
} else if (cb) {
|
||||||
process.nextTick(emitCloseNT, this);
|
process.nextTick(emitCloseNT, this);
|
||||||
|
@ -152,6 +152,32 @@ const assert = require('assert');
|
|||||||
assert.strictEqual(write.destroyed, true);
|
assert.strictEqual(write.destroyed, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const writable = new Writable({
|
||||||
|
destroy: common.mustCall(function(err, cb) {
|
||||||
|
process.nextTick(cb, new Error('kaboom 1'));
|
||||||
|
}),
|
||||||
|
write(chunk, enc, cb) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
writable.on('close', common.mustCall());
|
||||||
|
writable.on('error', common.expectsError({
|
||||||
|
type: Error,
|
||||||
|
message: 'kaboom 2'
|
||||||
|
}));
|
||||||
|
|
||||||
|
writable.destroy();
|
||||||
|
assert.strictEqual(writable.destroyed, true);
|
||||||
|
assert.strictEqual(writable._writableState.errorEmitted, false);
|
||||||
|
|
||||||
|
// Test case where `writable.destroy()` is called again with an error before
|
||||||
|
// the `_destroy()` callback is called.
|
||||||
|
writable.destroy(new Error('kaboom 2'));
|
||||||
|
assert.strictEqual(writable._writableState.errorEmitted, true);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const write = new Writable({
|
const write = new Writable({
|
||||||
write(chunk, enc, cb) { cb(); }
|
write(chunk, enc, cb) { cb(); }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user