Skip to main content

browser-download-filename

PyPI CI Browsers License: MIT OR Apache-2.0

Name downloaded files the way Chrome does. A pure-Python port of the Content-Disposition parser and the download naming rules of Chromium, the open-source core of Chrome, Edge and other browsers.

HTTP clients hand you a response, not a file name. The usual ways to get one (the standard library's email module, RFC 6266 parsers on PyPI) disagree with browsers on headers that real servers send: an ASCII fallback before filename*, raw UTF-8, percent-encoded names, language tags, semicolons inside quotes. On those headers, this package gives the name Chrome gives.

Features

  • Chromium's answer — the header parser, the MIME type rules, the charset decoders and the file name sanitization are ports of Chromium's code at a pinned revision, and Chromium's own unit test cases are part of the tests. CI downloads more than 900 cases with a real Chromium and checks every result (How it is checked).
  • The whole response — pass all the headers of a response. As in Chrome, the first Content-Disposition value names the file, and the Content-Type lines and X-Content-Type-Options give the MIME type, which can add an extension to a name that does not come from Content-Disposition. Where Chrome sniffs the body for another type, the package, which never sees the body, keeps the declared one. blocks_download tells you when Chrome refuses the response instead, for Content-Disposition values that differ or a NUL in the headers.
  • Bytes or str — pass the headers as the bytes on the wire, folded lines included, or as the strs your HTTP library made of them, such as the Latin-1 strs of requests, urllib3 and http.client or the surrogate-escaped strs of aiohttp; name the codec as headers_encoding, and they are mapped back to the bytes exactly. Some libraries join folded lines their own way first; the documentation lists them.
  • Never raises on a malformed header — it returns what Chromium makes of it.
  • Safe names — the result is a single file name, never empty, with path separators, control characters and other characters that file systems reject replaced. platform="windows" adds Windows' rules for reserved names, trailing dots and spaces, and shortcut extensions; by default they apply when the code runs on Windows. sanitize_filename cleans a name from anywhere else, such as a page title, the same way.
  • No dependencies — pure Python, one wheel for every platform: CPython 3.11+ and PyPy.

Install

pip install browser-download-filename      # or: uv add browser-download-filename

Usage

>>> from browser_download_filename import parse_content_disposition, suggested_filename
>>> header = b"attachment; filename=report.pdf; filename*=UTF-8''%E5%A0%B1%E5%91%8A.pdf"
>>> headers = [("Content-Disposition", header)]
>>> suggested_filename(headers, url="https://example.com/download?id=42")
'報告.pdf'
>>> suggested_filename(headers)
'報告.pdf'
>>> suggested_filename(url="https://example.com/files/r%C3%A9sum%C3%A9.pdf")
'résumé.pdf'
>>> parse_content_disposition('attachment; filename="a;b;c.txt";')
ContentDisposition(type='attachment', filename='a;b;c.txt', blocks_download=False)

suggested_filename downloads nothing: it takes the headers of a response and its final URL (after redirects), and returns the name Chrome reports to DevTools and Playwright as the download's suggested file name, except in the cases listed under Limits of the port. The URL is optional: when the headers give no name, Chrome takes the last segment of its path. Leave it out if you have no URL. With httpx2:

import httpx2
from browser_download_filename import suggested_filename

with httpx2.stream("GET", url, follow_redirects=True) as response:
    name = suggested_filename(response.headers.raw, url=str(response.url))

response.headers.raw holds the header lines in bytes, each line on its own. The documentation shows the same for httpx, requests, aiohttp and urllib.request.

sanitize_filename cleans a name from anywhere else, such as a page title or user input, as Chrome cleans an <a download> value:

>>> from browser_download_filename import sanitize_filename
>>> sanitize_filename("Q3 report: draft?.pdf")
'Q3 report_ draft_.pdf'

Documentation

Full documentation (English / 正體中文), including usage with httpx2, httpx, requests, aiohttp and urllib.request, the options, how Chrome, Firefox and Safari differ, how the package is checked against Chromium, the API reference and a changelog: https://birdhackor.github.io/browser-download-filename/

License

Licensed under either of MIT or Apache-2.0 at your option.

The package contains code ported from Chromium (BSD-3-Clause) and tables generated from ICU and the WHATWG Encoding Standard (Unicode-3.0 and BSD-3-Clause), so the distributions as a whole are under (MIT OR Apache-2.0) AND BSD-3-Clause AND Unicode-3.0; see THIRD-PARTY-LICENSES.

Metadata

Release files for browser-download-filename 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for browser-download-filename 0.2.0
File Size Uploaded
browser_download_filename-0.2.0.tar.gz 112.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for browser-download-filename 0.2.0
File Interpreter ABI Platform
browser_download_filename-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 165.0 kB

Release files / browser_download_filename-0.2.0.tar.gz

Download URL browser_download_filename-0.2.0.tar.gz
Size 112.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0d0eede0296fca357dfa6addd2c04c5223f13bce46324389646810d5caf9c022
BLAKE2b-256 checksum
How to use checksums
33e767aeeb2ddb2aaaf518164200e6c0b41f1a190987809e0d9818cff8ded049
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / browser_download_filename-0.2.0-py3-none-any.whl

Download URL browser_download_filename-0.2.0-py3-none-any.whl
Size 52.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8da7e63d4dc7cff19c34884cdc83894e939b9c7efbbd571750b604fd4e35507e
BLAKE2b-256 checksum
How to use checksums
0c6d12f1dee6a3cda0f7734f73bd40a7c16258501ea010e9e9828bb62e7ade02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page