Coverage for src/local_deep_research/web/utils/download_headers.py: 100%
13 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
1"""Content-Disposition headers for in-memory downloads."""
3import re
4import unicodedata
5from urllib.parse import quote
8def build_content_disposition(filename: str, *, inline: bool = False) -> str:
9 """Keep Unicode names and offer a safe ASCII name to older clients.
11 The fallback is deliberately conservative: punctuation that needs quoting
12 or escaping, percent escapes and control characters become underscores.
13 The extended parameter retains the original name using RFC 5987 encoding.
14 """
15 ascii_name = (
16 unicodedata.normalize("NFKD", filename)
17 .encode("ascii", "ignore")
18 .decode("ascii")
19 )
20 ascii_name = ascii_name.replace("\\", "/").rsplit("/", 1)[-1]
21 fallback = re.sub(r"[^a-zA-Z0-9._() -]", "_", ascii_name).strip()
22 if not fallback.strip("."):
23 fallback = "download"
24 elif fallback.startswith("."):
25 # An entirely non-Latin stem can leave only the file extension.
26 fallback = "download" + fallback
28 disposition = "inline" if inline else "attachment"
29 return (
30 f'{disposition}; filename="{fallback}"; '
31 f"filename*=UTF-8''{quote(filename, safe='')}"
32 )