From 87ac81c6c94bc7d9a65a31ae9bbfd14ce70c82c1 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Fri, 13 Mar 2026 20:50:37 +0200 Subject: [PATCH] fix: encode unicode filenames in Content-Disposition headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filenames with Romanian characters (Ș, Ț, etc.) caused ByteString errors. Also pass original filename through to extreme mode response. Co-Authored-By: Claude Opus 4.6 --- src/app/api/compress-pdf/cloud/route.ts | 2 +- src/app/api/compress-pdf/extreme/route.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/app/api/compress-pdf/cloud/route.ts b/src/app/api/compress-pdf/cloud/route.ts index bb8a9ca..b489273 100644 --- a/src/app/api/compress-pdf/cloud/route.ts +++ b/src/app/api/compress-pdf/cloud/route.ts @@ -195,7 +195,7 @@ export async function POST(req: NextRequest) { status: 200, headers: { "Content-Type": "application/pdf", - "Content-Disposition": `attachment; filename="${upload.filename.replace(/\.pdf$/i, "-comprimat.pdf")}"`, + "Content-Disposition": `attachment; filename="${encodeURIComponent(upload.filename.replace(/\.pdf$/i, "-comprimat.pdf"))}"`, "X-Original-Size": String(originalSize), "X-Compressed-Size": String(compressedSize), }, diff --git a/src/app/api/compress-pdf/extreme/route.ts b/src/app/api/compress-pdf/extreme/route.ts index 267efb9..d356aba 100644 --- a/src/app/api/compress-pdf/extreme/route.ts +++ b/src/app/api/compress-pdf/extreme/route.ts @@ -42,6 +42,7 @@ function streamFileResponse( filePath: string, originalSize: number, compressedSize: number, + filename: string, ): NextResponse { const nodeStream = createReadStream(filePath); const webStream = Readable.toWeb(nodeStream) as ReadableStream; @@ -51,7 +52,7 @@ function streamFileResponse( headers: { "Content-Type": "application/pdf", "Content-Length": String(compressedSize), - "Content-Disposition": 'attachment; filename="optimized.pdf"', + "Content-Disposition": `attachment; filename="${encodeURIComponent(filename)}"`, "X-Original-Size": String(originalSize), "X-Compressed-Size": String(compressedSize), }, @@ -128,13 +129,13 @@ export async function POST(req: NextRequest) { // Stream result from disk — if bigger, stream original if (compressedSize >= originalSize) { - return streamFileResponse(inputPath, originalSize, originalSize); + return streamFileResponse(inputPath, originalSize, originalSize, upload.filename); } // NOTE: cleanup is deferred — we can't delete files while streaming. // The files will be cleaned up by the OS temp cleaner or on next request. // For immediate cleanup, we'd need to buffer, but that defeats the purpose. - return streamFileResponse(outputPath, originalSize, compressedSize); + return streamFileResponse(outputPath, originalSize, compressedSize, upload.filename); } catch (err) { const message = err instanceof Error ? err.message : "Unknown error"; console.error(`[compress-pdf] Error:`, message);