Recover failed conversion workers and validate Nitro downloads correctly
CI / check (push) Successful in 1m36s
CI / deploy (push) Successful in 1m15s
CI / e2e (push) Successful in 21s

This commit is contained in:
Simo committed 2026-09-05 14:18:28 +02:00
1 parent a78d8256e0
commit 7880d5d5df
5 files changed
+91 -8

No files matched your search

+17 -1
View File
@@ -1,5 +1,10 @@
import { describe, expect, it } from "vitest";
import { validatePngBytes, validateSwfBytes } from "./download";
import { createNitroBundle } from "../../swf/nitro-builder";
import {
validateNitroBytes,
validatePngBytes,
validateSwfBytes,
} from "./download";
describe("import/core/download validators", () => {
it("accepts FWS/CWS/ZWS swf magic", () => {
@@ -22,3 +27,14 @@ describe("import/core/download validators", () => {
expect(validatePngBytes(Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]))).toBe(false);
});
});
it("validates nitro bundles separately from PNG files", () => {
const png = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
const bundle = createNitroBundle({ name: "chair" }, png, "chair");
expect(validateNitroBytes(bundle)).toBe(true);
expect(validatePngBytes(bundle)).toBe(false);
expect(validateNitroBytes(png)).toBe(false);
expect(validateNitroBytes(Buffer.from("<html>Access denied</html>"))).toBe(
false,
);
});
+18 -1
View File
@@ -1,4 +1,5 @@
import { promises as fs } from "node:fs";
import { parseNitroBundle } from "../../swf/nitro-builder";
import { browserHeaders } from "./browser-headers";
@@ -18,6 +19,20 @@ export function validatePngBytes(buffer: Buffer): boolean {
);
}
export function validateNitroBytes(buffer: Buffer): boolean {
try {
const bundle = parseNitroBundle(buffer);
return (
!!bundle.json &&
typeof bundle.json === "object" &&
!Array.isArray(bundle.json) &&
validatePngBytes(bundle.png)
);
} catch {
return false;
}
}
export async function tryDownloadCandidates(
urls: string[],
destPath: string,
@@ -33,7 +48,7 @@ export async function tryDownloadCandidates(
export async function downloadFile(
url: string,
destPath: string,
options?: { maxRetries?: number; validate?: "swf" | "png" },
options?: { maxRetries?: number; validate?: "swf" | "png" | "nitro" },
): Promise<{ ok: boolean; size: number }> {
const maxRetries = options?.maxRetries ?? 3;
const baseDelay = 1000;
@@ -79,6 +94,8 @@ export async function downloadFile(
}
continue;
}
if (options?.validate === "nitro" && !validateNitroBytes(buffer))
return { ok: false, size: 0 };
await fs.writeFile(/*turbopackIgnore: true*/ destPath, buffer);
return { ok: true, size: buffer.length };
} catch (err) {