Skip to content

fix(storage): RFC 6266 Content-Disposition for non-ASCII attachment filenames#391

Open
gig-repo wants to merge 1 commit into
LogicLabs-OU:mainfrom
gig-repo:fix/storage-content-disposition-non-ascii
Open

fix(storage): RFC 6266 Content-Disposition for non-ASCII attachment filenames#391
gig-repo wants to merge 1 commit into
LogicLabs-OU:mainfrom
gig-repo:fix/storage-content-disposition-non-ascii

Conversation

@gig-repo

@gig-repo gig-repo commented Jun 8, 2026

Copy link
Copy Markdown

Problem

GET /api/v1/storage/download returns HTTP 500 for any archived file whose name contains non-ASCII characters (Korean / Japanese / Chinese, accented Latin, etc.). The file is located and decrypted fine — the failure is emitting the response header:

Error downloading file: TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["Content-Disposition"]
    at ServerResponse.setHeader (node:_http_outgoing)
    at downloadFile (packages/backend/.../storage.controller.js)

Node's res.setHeader only accepts Latin-1 in a header value, so:

res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`);

throws whenever fileName has non-Latin-1 bytes. Because the API and the web UI share this endpoint, such attachments can't be downloaded at all.

Fix

Follow RFC 6266: send an ASCII-only filename="..." fallback and a filename*=UTF-8''<percent-encoded> parameter carrying the real name. Modern clients use filename*; older ones fall back safely.

const asciiName = fileName.replace(/[^\x20-\x7E]/g, '_').replace(/["\\]/g, '_');
res.setHeader(
    'Content-Disposition',
    `attachment; filename="${asciiName}"; filename*=UTF-8''${encodeURIComponent(fileName)}`
);

Verification

Reproduced on a running v0.5.0 instance: a Korean-named PDF (장현준_…_원본.pdf) returned 500. After applying the equivalent change to the compiled controller and restarting, the same file now returns 200 with:

Content-Disposition: attachment; filename="b01dc-___________.pdf"; filename*=UTF-8''b01dc-%EC%9E%A5...%EC%9B%90%EB%B3%B8.pdf

Scope is limited to one header line in storage.controller.ts; no behavior change for ASCII filenames.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@gig-repo gig-repo force-pushed the fix/storage-content-disposition-non-ascii branch 2 times, most recently from 5a043ab to 37d010f Compare June 9, 2026 02:19
@hjang212

Copy link
Copy Markdown

I have read the CLA Document and I hereby sign the CLA

Downloading an archived attachment whose filename contains non-ASCII
characters (e.g. Korean/CJK) returns HTTP 500: res.setHeader throws
"TypeError [ERR_INVALID_CHAR]: Invalid character in header content
[Content-Disposition]" because a raw filename="..." value must be Latin-1.

Emit an ASCII fallback plus an RFC 6266 filename*=UTF-8''<pct-encoded>
parameter so the real (Unicode) name is delivered and the header no longer
throws. Affects both the REST API and the web UI download.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gig-repo gig-repo force-pushed the fix/storage-content-disposition-non-ascii branch from 37d010f to f600f37 Compare June 11, 2026 10:54
@gig-repo gig-repo marked this pull request as ready for review June 11, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants