mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-08-11 00:30:12 -04:00
Reported by @1000Delta. The printer file download (and three sibling endpoints) raised UnicodeEncodeError: 'latin-1' codec can't encode characters... on any filename outside U+0000..U+00FF (Chinese, Japanese, Arabic, accented Latin), because the route pushed `filename` straight into Content-Disposition: attachment; filename="...". Starlette/uvicorn encodes response headers as latin-1, so the assignment crashed at write-time. New backend/app/utils/http.py::build_content_disposition emits both an ASCII-stripped legacy filename="..." fallback and an RFC 5987 filename*=UTF-8''<percent-encoded> parameter. Every modern browser prefers the *= form, so the original Unicode filename round-trips through Save-As intact. Same shape was latent in three siblings and fixed in the same PR (no deferred follow-ups): archive QR endpoint (archive.print_name from 3MF metadata), project ZIP export (project.name — the existing isalnum() sanitiser passes non-ASCII through), and the PDF label streamer (latent today, callers ASCII-only but the helper hardens it).
17 lines
859 B
Python
17 lines
859 B
Python
"""HTTP response helpers."""
|
|
|
|
from urllib.parse import quote
|
|
|
|
|
|
def build_content_disposition(filename: str, disposition: str = "attachment") -> str:
|
|
"""Build an RFC 6266-compliant Content-Disposition header value.
|
|
|
|
Starlette/uvicorn encodes response headers as latin-1, so any non-ASCII
|
|
character in a raw `filename="..."` parameter raises UnicodeEncodeError.
|
|
The fix is RFC 5987's `filename*=UTF-8''<percent-encoded>` form alongside
|
|
a stripped ASCII fallback in the legacy `filename="..."` parameter — every
|
|
modern browser prefers the `*` form when present.
|
|
"""
|
|
ascii_fallback = filename.encode("ascii", "ignore").decode("ascii").strip(" ._-") or "download"
|
|
ascii_fallback = ascii_fallback.replace('"', "").replace("\\", "")
|
|
return f"{disposition}; filename=\"{ascii_fallback}\"; filename*=UTF-8''{quote(filename)}"
|