From 1df94a90821ba139c212db5840cee449f2b25891 Mon Sep 17 00:00:00 2001 From: Waxoussou <45203020+Waxoussou@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:31:03 +0100 Subject: [PATCH] fix: content-disposition filename regexp (#87) * Fix: Improve Content-Disposition filename matcher - handle white space + extended filename* in UTF-8 --------- Co-authored-by: maxime.abehserra --- src/metadata.ts | 2 +- test/metadata.test.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/metadata.ts b/src/metadata.ts index 7f40eb5..fc6145d 100644 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -21,7 +21,7 @@ export function normalizeMetadata(input?: File | Response | BufferLike | StreamL } if (input instanceof Response) { const contentDisposition = input.headers.get("content-disposition") - const filename = contentDisposition && contentDisposition.match(/;\s*filename\*?=["']?(.*?)["']?$/i) + const filename = contentDisposition && contentDisposition.match(/;\s*filename\*?\s*=\s*(?:UTF-\d+''|)["']?([^;"'\r\n]*)["']?(?:;|$)/i); const urlName = filename && filename[1] || input.url && new URL(input.url).pathname.split("/").findLast(Boolean) const decoded = urlName && decodeURIComponent(urlName) // @ts-ignore allow coercion from null to zero diff --git a/test/metadata.test.ts b/test/metadata.test.ts index 8508b4e..605b65c 100644 --- a/test/metadata.test.ts +++ b/test/metadata.test.ts @@ -14,11 +14,19 @@ Deno.test("normalizeMetadata needs a filename along Responses with insufficient Deno.test("normalizeMetadata guesses filename from Content-Disposition", () => { const metadata = normalizeMetadata(new Response("four", { - headers: { "content-disposition": "attachment; filename=test.txt" } + headers: { "content-disposition": "attachment; filename=test.txt; size=0" } })) assertEquals(metadata, { uncompressedSize: 0n, encodedName, nameIsBuffer: false }) }) +Deno.test("normalizeMetadata guesses filename from non latin Content-Disposition", () => { + const metadata = normalizeMetadata(new Response("four", { + headers: { "content-disposition": "attachment; filename* = UTF-8''%CF%8C%CE%BD%CE%BF%CE%BC%CE%B1%20%CE%B1%CF%81%CF%87%CE%B5%CE%AF%CE%BF%CF%85.txt" } + })) + assertEquals(metadata, { uncompressedSize: 0n,encodedName: new TextEncoder().encode("όνομα αρχείου.txt"), nameIsBuffer: false }) +}) + + Deno.test("normalizeMetadata guesses filename from a Response URL", () => { const response = Object.create(Response.prototype, { url: { get() { return "https://example.com/path/test.txt" } },