authorgravatar for zacharyjwebb@gmail.comZach Webb <zacharyjwebb@gmail.com> 2026-08-21 03:10:14+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-20 22:10:14-04:00
log820e5639c30be83a9433f696613760f8ee42075a
tree9d346b86a160cbfe7a9e818d662e749beeda786c
parent6d3bf01b4f021eb3fbd2feaf07fcacaa4f55881d
signature Signed by PGP key B5690EEEBB952194

fix(server): serve html assets with utf-8 charset (#6409)


2 files changed, 16 insertions(+), 1 deletions(-)

apps/server/src/http.test.ts+11
......@@ -44,4 +44,15 @@ describe("assetResponseHeaders", () => {
4444 "X-Content-Type-Options": "nosniff",
4545 });
4646 });
47
48 it("declares utf-8 for HTML assets so non-ASCII content renders correctly", () => {
49 expect(assetResponseHeaders("/workspace/page.html")).toHaveProperty(
50 "Content-Type",
51 "text/html; charset=utf-8",
52 );
53 expect(assetResponseHeaders("/workspace/PAGE.HTM")).toHaveProperty(
54 "Content-Type",
55 "text/html; charset=utf-8",
56 );
57 });
4758});
apps/server/src/http.ts+5-1
......@@ -46,10 +46,14 @@ const DESKTOP_RENDERER_ORIGINS = ["t3code://app", "t3code-dev://app"];
4646const SVG_CONTENT_SECURITY_POLICY = "default-src 'none'; style-src 'unsafe-inline'; sandbox";
4747
4848export function assetResponseHeaders(filePath: string): Record<string, string> {
49 const lowerPath = filePath.toLowerCase();
4950 return {
5051 "Cache-Control": "private, max-age=3600",
5152 "X-Content-Type-Options": "nosniff",
52 ...(filePath.toLowerCase().endsWith(".svg")
53 ...(lowerPath.endsWith(".html") || lowerPath.endsWith(".htm")
54 ? { "Content-Type": "text/html; charset=utf-8" }
55 : {}),
56 ...(lowerPath.endsWith(".svg")
5357 ? { "Content-Security-Policy": SVG_CONTENT_SECURITY_POLICY }
5458 : {}),
5559 };