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

1"""Content-Disposition headers for in-memory downloads.""" 

2 

3import re 

4import unicodedata 

5from urllib.parse import quote 

6 

7 

8def build_content_disposition(filename: str, *, inline: bool = False) -> str: 

9 """Keep Unicode names and offer a safe ASCII name to older clients. 

10 

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 

27 

28 disposition = "inline" if inline else "attachment" 

29 return ( 

30 f'{disposition}; filename="{fallback}"; ' 

31 f"filename*=UTF-8''{quote(filename, safe='')}" 

32 )