Environment
@orpc/server: 1.13.8
@orpc/standard-server: 1.13.10
- Node.js: v22.17.0
- Fastify: 5.8.4
Reproduction
import { os } from '@orpc/server'
import { readFile } from 'fs/promises'
import * as z from 'zod'
const downloadTemplate = os
.route({ method: 'GET', path: '/template' })
.output(z.any())
.handler(async () => {
const buffer = await readFile('./テンプレート.xlsx')
return new File([buffer], 'テンプレート.xlsx', {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
})
})
Describe the bug
Description
generateContentDisposition in @orpc/standard-server produces an invalid Content-Disposition header when the File.name contains non-ASCII characters (e.g. Korean, Japanese, Chinese). Node.js ServerResponse.setHeader rejects the header with
ERR_INVALID_CHAR.
Current behavior
// @orpc/standard-server/dist/index.mjs
function generateContentDisposition(filename) {
const escapedFileName = filename.replace(/"/g, '\\"');
const encodedFilenameStar = encodeURIComponent(filename)...;
return `inline; filename="${escapedFileName}"; filename*=utf-8''${encodedFilenameStar}`;
}
The filename*=utf-8''... part is correctly percent-encoded, but filename="${escapedFileName}" keeps non-ASCII characters as-is. This causes:
TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["content-disposition"]
at ServerResponse.setHeader (node:_http_outgoing:703:3)
Expected behavior
Per RFC 6266, the filename= parameter should be an ASCII fallback, while filename*= carries the UTF-8 encoded name:
Content-Disposition: inline; filename="template.xlsx"; filename*=utf-8''%ED%85%9C%ED%94%8C%EB%A6%BF.xlsx
Suggested fix
Strip non-ASCII from filename= or use a generic ASCII fallback:
function generateContentDisposition(filename) {
const asciiFilename = filename.replace(/[^\x20-\x7E]/g, '_');
const encodedFilenameStar = encodeURIComponent(filename)
.replace(/['()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)
.replace(/%(7C|60|5E)/g, (str, hex) => String.fromCharCode(Number.parseInt(hex, 16)));
return `inline; filename="${asciiFilename}"; filename*=utf-8''${encodedFilenameStar}`;
}
Additional context
No response
Logs
Environment
@orpc/server: 1.13.8@orpc/standard-server: 1.13.10Reproduction
Describe the bug
Description
generateContentDispositionin@orpc/standard-serverproduces an invalidContent-Dispositionheader when theFile.namecontains non-ASCII characters (e.g. Korean, Japanese, Chinese). Node.jsServerResponse.setHeaderrejects the header withERR_INVALID_CHAR.Current behavior
The
filename*=utf-8''...part is correctly percent-encoded, butfilename="${escapedFileName}"keeps non-ASCII characters as-is. This causes:Expected behavior
Per RFC 6266, the
filename=parameter should be an ASCII fallback, whilefilename*=carries the UTF-8 encoded name:Suggested fix
Strip non-ASCII from
filename=or use a generic ASCII fallback:Additional context
No response
Logs