From 15e4046c19b29592dedfb713e30e53702848681d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A1=8C=E5=AD=90=E6=BD=94?= Date: Tue, 4 Aug 2026 03:21:08 +0800 Subject: [PATCH] fix(results): encode download filenames (#587) --- src/helpers/buildDownloadUrl.ts | 3 +++ src/pages/results.tsx | 5 +++-- tests/pages/results.test.ts | 12 ++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/helpers/buildDownloadUrl.ts create mode 100644 tests/pages/results.test.ts diff --git a/src/helpers/buildDownloadUrl.ts b/src/helpers/buildDownloadUrl.ts new file mode 100644 index 0000000..2de45e0 --- /dev/null +++ b/src/helpers/buildDownloadUrl.ts @@ -0,0 +1,3 @@ +export function buildDownloadUrl(webroot: string, outputPath: string, fileName: string): string { + return `${webroot}/download/${outputPath}${encodeURIComponent(fileName)}`; +} diff --git a/src/pages/results.tsx b/src/pages/results.tsx index e439959..64dd221 100644 --- a/src/pages/results.tsx +++ b/src/pages/results.tsx @@ -3,6 +3,7 @@ import { BaseHtml } from "../components/base"; import { Header } from "../components/header"; import db from "../db/db"; import { Filename, Jobs } from "../db/types"; +import { buildDownloadUrl } from "../helpers/buildDownloadUrl"; import { ALLOW_UNAUTHENTICATED, WEBROOT } from "../helpers/env"; import { DownloadIcon } from "../icons/download"; import { DeleteIcon } from "../icons/delete"; @@ -107,7 +108,7 @@ function ResultsArticle({ text-accent-500 underline hover:text-accent-400 `} - href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`} + href={buildDownloadUrl(WEBROOT, outputPath, file.output_file_name)} > @@ -116,7 +117,7 @@ function ResultsArticle({ text-accent-500 underline hover:text-accent-400 `} - href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`} + href={buildDownloadUrl(WEBROOT, outputPath, file.output_file_name)} download={file.output_file_name} > diff --git a/tests/pages/results.test.ts b/tests/pages/results.test.ts new file mode 100644 index 0000000..7673ad9 --- /dev/null +++ b/tests/pages/results.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from "bun:test"; +import { buildDownloadUrl } from "../../src/helpers/buildDownloadUrl"; + +test("encodes reserved characters in download filenames", () => { + expect(buildDownloadUrl("", "1/2/", "clip #1?.gif")).toBe("/download/1/2/clip%20%231%3F.gif"); +}); + +test("preserves output path segments while encoding the filename", () => { + expect(buildDownloadUrl("/convertx", "user/job/", "報告 100%.pdf")).toBe( + "/convertx/download/user/job/%E5%A0%B1%E5%91%8A%20100%25.pdf", + ); +});