fix(pdf-compress): fix broken multipart parsing + add body size limit
Extreme mode: replace fragile manual multipart boundary parsing (which extracted only a fraction of large files, producing empty PDFs) with standard req.formData(). Add GS output validation + stderr capture. Stirling mode: parse formData first then build fresh FormData for Stirling instead of raw body passthrough (which lost data on large files). Add 5min timeout + original/compressed size headers. next.config: add 250MB body size limit for server actions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,17 +7,42 @@ const STIRLING_PDF_API_KEY =
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
// Stream body directly to Stirling — avoids FormData re-serialization
|
||||
// failure on large files ("Failed to parse body as FormData")
|
||||
// Parse incoming form data — get file + optimizeLevel
|
||||
let formData: FormData;
|
||||
try {
|
||||
formData = await req.formData();
|
||||
} catch (parseErr) {
|
||||
const msg =
|
||||
parseErr instanceof Error ? parseErr.message : "Parse error";
|
||||
return NextResponse.json(
|
||||
{ error: `Nu s-a putut citi formularul: ${msg}` },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const fileField = formData.get("fileInput");
|
||||
if (!fileField || !(fileField instanceof Blob)) {
|
||||
return NextResponse.json(
|
||||
{ error: "Lipsește fișierul PDF." },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const optimizeLevel = formData.get("optimizeLevel") ?? "3";
|
||||
const originalSize = fileField.size;
|
||||
|
||||
// Build fresh FormData for Stirling
|
||||
const stirlingForm = new FormData();
|
||||
stirlingForm.append("fileInput", fileField, "input.pdf");
|
||||
stirlingForm.append("optimizeLevel", String(optimizeLevel));
|
||||
|
||||
const res = await fetch(`${STIRLING_PDF_URL}/api/v1/misc/compress-pdf`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-KEY": STIRLING_PDF_API_KEY,
|
||||
"Content-Type": req.headers.get("content-type") || "",
|
||||
},
|
||||
body: req.body,
|
||||
// @ts-expect-error duplex required for streaming request bodies in Node
|
||||
duplex: "half",
|
||||
body: stirlingForm,
|
||||
signal: AbortSignal.timeout(300_000), // 5 min for large files
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
@@ -36,6 +61,8 @@ export async function POST(req: NextRequest) {
|
||||
headers: {
|
||||
"Content-Type": "application/pdf",
|
||||
"Content-Disposition": 'attachment; filename="compressed.pdf"',
|
||||
"X-Original-Size": String(originalSize),
|
||||
"X-Compressed-Size": String(buffer.length),
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user