fix(v3-actions): fix UnicodeEncodeError in download filenames

Hardened StreamingResponse headers to use RFC 6266 filename* parameter with UTF-8 encoding. This prevents the latin-1 codec crash when filenames contain non-ASCII characters like smart quotes.
This commit is contained in:
Scott Idem
2026-02-06 10:44:22 -05:00
parent 1492b01dad
commit 37a43babb9

View File

@@ -7,6 +7,7 @@ import pathlib
from typing import Dict, List, Optional, Set, Union from typing import Dict, List, Optional, Set, Union
import asyncio import asyncio
import logging import logging
from urllib.parse import quote
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -286,6 +287,12 @@ async def download_file_action(
end = min(end, file_size - 1) end = min(end, file_size - 1)
content_length = end - start + 1 content_length = end - start + 1
# ID Vision: Properly encode filename for headers to avoid UnicodeEncodeError (latin-1)
# 1. Standard filename (Sanitized for legacy clients - latin-1 safe)
safe_filename = target_filename.encode('ascii', errors='ignore').decode('ascii')
# 2. filename* (UTF-8 encoded for modern clients)
encoded_filename = quote(target_filename)
return StreamingResponse( return StreamingResponse(
file_streamer(full_file_path, start, end + 1), file_streamer(full_file_path, start, end + 1),
media_type = media_type, media_type = media_type,
@@ -294,7 +301,7 @@ async def download_file_action(
'Accept-Ranges': 'bytes', 'Accept-Ranges': 'bytes',
'Content-Range': f'bytes {start}-{end}/{file_size}', 'Content-Range': f'bytes {start}-{end}/{file_size}',
'Content-Length': str(content_length), 'Content-Length': str(content_length),
'Content-Disposition': f'attachment; filename="{target_filename}"' 'Content-Disposition': f'attachment; filename="{safe_filename}"; filename*=utf-8\'\'{encoded_filename}'
} }
) )