mirror of
https://github.com/morluto/rea.git
synced 2026-11-06 23:06:18 +00:00
fix(process): honor cancellation at bounded file read completion (#8908)
This commit is contained in:
1 parent
b28b1e0ae2
commit
b153ba8ddd
2 files changed
+46
-1
No files matched your search
@@ -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");
|
||||
|
||||
Reference in new issue
Block a user