diff --git a/app/routers/api_v3_actions_hosted_file.py b/app/routers/api_v3_actions_hosted_file.py index 58ab9f6..8cca3f0 100644 --- a/app/routers/api_v3_actions_hosted_file.py +++ b/app/routers/api_v3_actions_hosted_file.py @@ -7,6 +7,7 @@ import pathlib from typing import Dict, List, Optional, Set, Union import asyncio import logging +from urllib.parse import quote log = logging.getLogger(__name__) @@ -286,6 +287,12 @@ async def download_file_action( end = min(end, file_size - 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( file_streamer(full_file_path, start, end + 1), media_type = media_type, @@ -294,7 +301,7 @@ async def download_file_action( 'Accept-Ranges': 'bytes', 'Content-Range': f'bytes {start}-{end}/{file_size}', 'Content-Length': str(content_length), - 'Content-Disposition': f'attachment; filename="{target_filename}"' + 'Content-Disposition': f'attachment; filename="{safe_filename}"; filename*=utf-8\'\'{encoded_filename}' } )