From 509b3d99964cbeda5b472e8c36ea3eaeca90f4c7 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 13 Nov 2021 18:31:05 +0200 Subject: [PATCH] stream: destroying stream without error is abort If an autoDestroy stream is destroyed by user without an error we automatically convert it to an AbortError in order to avoid a weird state. --- lib/internal/streams/destroy.js | 14 +++++++++++- test/parallel/test-stream-auto-abort.js | 29 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-stream-auto-abort.js diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 7d3657443e6ab5..0033a7ba46f7c8 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -1,5 +1,6 @@ 'use strict'; +const console = require('console'); const { aggregateTwoErrors, codes: { @@ -14,7 +15,10 @@ const { kDestroyed, isDestroyed, isFinished, - isServerRequest + isServerRequest, + isReadable, + isReadableFinished, + isWritableEnded } = require('internal/streams/utils'); const kDestroy = Symbol('kDestroy'); @@ -86,6 +90,14 @@ function _destroy(self, err, cb) { const r = self._readableState; const w = self._writableState; + if (!err) { + if (r?.autoDestroy && !isReadableFinished(self)) { + err = new AbortError(); + } else if (w?.autoDestroy && !isWritableEnded(self)) { + err = new AbortError(); + } + } + checkError(err, w, r); if (w) { diff --git a/test/parallel/test-stream-auto-abort.js b/test/parallel/test-stream-auto-abort.js new file mode 100644 index 00000000000000..454e78ede8d6a9 --- /dev/null +++ b/test/parallel/test-stream-auto-abort.js @@ -0,0 +1,29 @@ +'use strict'; + +const { Readable, Writable } = require('stream'); +const common = require('../common'); +const assert = require('assert'); + +{ + const w = new Writable({ + write() { + + } + }); + w.on('error', common.mustCall((err) => { + assert.strictEqual(err.name, 'AbortError'); + })); + w.destroy(); +} + +{ + const r = new Readable({ + read() { + + } + }); + r.on('error', common.mustCall((err) => { + assert.strictEqual(err.name, 'AbortError'); + })); + r.destroy(); +}