fix(process): honor cancellation at bounded file read completion (#8908)

This commit is contained in:
Afloat authored and GitHub committed 2026-11-06 10:11:56 +08:00
1 parent b28b1e0ae2
commit b153ba8ddd
2 files changed
+46 -1

No files matched your search

+3
View File
@@ -41,6 +41,7 @@ export const readBoundedFileBytes = async (
expectedSize > maxBytes)
)
throw new RangeError("Expected file size must fit the byte limit");
assertActive();
if (expectedSize === undefined) {
const chunks: Buffer[] = [];
const buffer = Buffer.allocUnsafe(Math.min(64 * 1_024, maxBytes + 1));
@@ -52,6 +53,7 @@ export const readBoundedFileBytes = async (
0,
Math.min(buffer.length, maxBytes - total + 1),
);
assertActive();
if (bytesRead === 0) return Buffer.concat(chunks, total);
total += bytesRead;
if (total > maxBytes) return undefined;
@@ -64,6 +66,7 @@ export const readBoundedFileBytes = async (
for (;;) {
assertActive();
const { bytesRead } = await read(buffer, total, expectedSize - total);
assertActive();
if (bytesRead === 0) return buffer.subarray(0, total);
total += bytesRead;
if (total > maxBytes) return undefined;
@@ -26,7 +26,7 @@ describe("bounded file byte reads", () => {
},
);
it.each([undefined, 5])(
it.each([undefined, 0, 5])(
"preserves raw reasons or caller-owned cancellation with expected size %s",
async (expectedSize) => {
const root = await createTestTempDirectory("rea-bounded-cancel-");
@@ -61,6 +61,48 @@ describe("bounded file byte reads", () => {
},
);
it.each([
{ contents: "", maxBytes: 0, expectedSize: undefined, outcome: "EOF" },
{ contents: "", maxBytes: 5, expectedSize: 5, outcome: "early EOF" },
{
contents: "hello",
maxBytes: 5,
expectedSize: 5,
outcome: "expected size",
},
{
contents: "hello",
maxBytes: 4,
expectedSize: undefined,
outcome: "overflow",
},
])(
"honors cancellation while the $outcome read is in flight",
async ({ contents, maxBytes, expectedSize }) => {
const root = await createTestTempDirectory("rea-bounded-cancel-read-");
const path = join(root, "input");
await writeFile(path, contents);
const handle = await open(path, "r");
const controller = new AbortController();
const reason = new Error("cancelled during read");
const typed = new Error("typed cancellation", { cause: reason });
try {
const result = readBoundedFileBytes(handle, maxBytes, {
signal: controller.signal,
expectedSize,
cancellationFailure: (observed) => {
expect(observed).toBe(reason);
return typed;
},
});
controller.abort(reason);
await expect(result).rejects.toBe(typed);
} finally {
await handle.close();
}
},
);
it("stops after one overflow byte when a file grows beyond its admitted size", async () => {
const root = await createTestTempDirectory("rea-growing-bytes-");
const path = join(root, "input");