diff --git a/src/app/api/compress-pdf/extreme/route.ts b/src/app/api/compress-pdf/extreme/route.ts index 1a9dcb3..3d4b445 100644 --- a/src/app/api/compress-pdf/extreme/route.ts +++ b/src/app/api/compress-pdf/extreme/route.ts @@ -120,18 +120,16 @@ export async function POST(req: NextRequest) { const nodeStream = Readable.fromWeb(req.body as import("stream/web").ReadableStream); await pipeline(nodeStream, createWriteStream(rawPath)); - // Extract the PDF from multipart: find the double CRLF after headers, - // then read until the boundary marker before the end + // Extract the PDF binary from the multipart body. + // Multipart format: + // --boundary\r\n + // Content-Disposition: form-data; name="fileInput"; filename="x.pdf"\r\n + // Content-Type: application/pdf\r\n + // \r\n + // + // \r\n--boundary--\r\n const rawBuf = await readFile(rawPath); - const headerEnd = rawBuf.indexOf(Buffer.from("\r\n\r\n")); - if (headerEnd === -1) { - return NextResponse.json( - { error: "Lipsește fișierul PDF." }, - { status: 400 }, - ); - } - // Extract boundary from Content-Type header const contentType = req.headers.get("content-type") || ""; const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^\s;]+))/); const boundary = boundaryMatch?.[1] ?? boundaryMatch?.[2] ?? ""; @@ -143,11 +141,50 @@ export async function POST(req: NextRequest) { ); } - // File content starts after first double CRLF, ends before closing boundary - const closingBoundary = Buffer.from(`\r\n--${boundary}`); - const fileStart = headerEnd + 4; - const fileEnd = rawBuf.indexOf(closingBoundary, fileStart); - const pdfData = fileEnd !== -1 ? rawBuf.subarray(fileStart, fileEnd) : rawBuf.subarray(fileStart); + const boundaryBuf = Buffer.from(`--${boundary}`); + + // Find the part that contains a filename (the file upload part). + // There may be multiple parts — we need the one with "filename=". + let fileStart = -1; + let searchFrom = 0; + + while (searchFrom < rawBuf.length) { + const partStart = rawBuf.indexOf(boundaryBuf, searchFrom); + if (partStart === -1) break; + + // Skip past boundary line to get to headers + const headersStart = rawBuf.indexOf(Buffer.from("\r\n"), partStart); + if (headersStart === -1) break; + + const headerEnd = rawBuf.indexOf(Buffer.from("\r\n\r\n"), headersStart); + if (headerEnd === -1) break; + + // Check if this part's headers contain a filename + const headers = rawBuf.subarray(headersStart, headerEnd).toString("utf8"); + if (headers.includes("filename=")) { + fileStart = headerEnd + 4; // skip \r\n\r\n + break; + } + + // Move past this part's headers to search for next boundary + searchFrom = headerEnd + 4; + } + + if (fileStart === -1) { + return NextResponse.json( + { error: "Lipsește fișierul PDF." }, + { status: 400 }, + ); + } + + // Find the closing boundary after the file content. + // Search from the END of the buffer backwards, since the PDF binary + // could theoretically contain the boundary string by coincidence. + const closingMarker = Buffer.from(`\r\n--${boundary}`); + const fileEnd = rawBuf.lastIndexOf(closingMarker); + const pdfData = (fileEnd > fileStart) + ? rawBuf.subarray(fileStart, fileEnd) + : rawBuf.subarray(fileStart); await writeFile(inputPath, pdfData); const originalSize = pdfData.length;