diff --git a/src/metadata.ts b/src/metadata.ts index 19bd3ca..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(/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 398c49c..605b65c 100644 --- a/test/metadata.test.ts +++ b/test/metadata.test.ts @@ -19,6 +19,14 @@ Deno.test("normalizeMetadata guesses filename from Content-Disposition", () => { 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" } },