From 6c739f51cd0f2906cd96c82a68f169f74f97987a Mon Sep 17 00:00:00 2001 From: Neal Date: Wed, 29 Jul 2026 13:12:17 +0800 Subject: [PATCH] fix: skip writes to destroyed file streams --- src/PersistentFile.js | 2 +- test-node/files/persistent-file.test.js | 33 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test-node/files/persistent-file.test.js diff --git a/src/PersistentFile.js b/src/PersistentFile.js index 02f2a438..d101fd08 100644 --- a/src/PersistentFile.js +++ b/src/PersistentFile.js @@ -65,7 +65,7 @@ class PersistentFile extends EventEmitter { this.hash.update(buffer); } - if (this._writeStream.closed) { + if (this._writeStream.closed || this._writeStream.destroyed) { cb(); return; } diff --git a/test-node/files/persistent-file.test.js b/test-node/files/persistent-file.test.js new file mode 100644 index 00000000..6c0d424d --- /dev/null +++ b/test-node/files/persistent-file.test.js @@ -0,0 +1,33 @@ +import { strictEqual } from "node:assert"; +import { once } from "node:events"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import test from "node:test"; +import PersistentFile from "../../src/PersistentFile.js"; + +test("does not write after the file stream is destroyed", async () => { + const directory = await mkdtemp(join(tmpdir(), "formidable-destroyed-")); + + try { + const file = new PersistentFile({ + filepath: join(directory, "upload"), + newFilename: "upload", + originalFilename: "upload", + mimetype: "application/octet-stream", + }); + + file.open(); + await once(file._writeStream, "open"); + file.destroy(); + + strictEqual(file._writeStream.destroyed, true); + strictEqual(file._writeStream.closed, false); + + await new Promise((resolve) => file.write(Buffer.from("ignored"), resolve)); + + strictEqual(file.size, 0); + } finally { + await rm(directory, { recursive: true, force: true }); + } +});