DevKits
Concept

Content-Disposition Header — How to Force Downloads and Control Filenames

The Content-Disposition HTTP header controls whether a file downloads or opens inline, and specifies the filename to save. Learn how attachment, inline, and filename* (RFC 5987) work, and why non-ASCII filenames break in older browsers.

Last updated:

Core Concepts

attachment vs inline — the two modes
Content-Disposition: inline means 'the browser should render this in-page if it can' (default for images, HTML, PDFs in modern browsers). Content-Disposition: attachment means 'always download this as a file.' The filename parameter specifies the suggested download name.
The filename vs filename* distinction (RFC 5987)
filename='report.pdf' uses ASCII only — non-ASCII characters in the filename will be mojibake (garbled) in older browsers. filename*=UTF-8''%E6%8A%A5%E5%91%8A.pdf encodes the filename in percent-encoded UTF-8, which handles any Unicode name (Japanese, Chinese, emoji). Modern browsers support both; always include filename* for non-ASCII filenames and filename as a fallback.
Security: never trust user-supplied filenames
A user-uploaded filename like '../../etc/passwd' or '..\..\windows\system32\config\sam' can cause path traversal if the server blindly uses it. Always sanitize: strip directory separators, prefix with a safe path, and optionally force a safe extension. Also, filenames with embedded ';' or '%00' (null byte) can truncate filenames in vulnerable implementations.

Frequently Asked Questions

How do I force a PDF to download instead of open in the browser?

Set Content-Disposition: attachment; filename='document.pdf' on the HTTP response. Without this header, modern browsers preview PDFs inline. With attachment, the browser shows a 'Save As' dialog.

Why is my Japanese filename showing as ??? in the download dialog?

The server is using filename='...' with unescaped non-ASCII characters. Switch to filename*=UTF-8'' plus a percent-encoded UTF-8 name. Also verify the charset of the HTTP response itself — it should declare UTF-8.

Try these related tools