From 99624cd2eb55e4fab45e10f9342c789ad4177fa6 Mon Sep 17 00:00:00 2001 From: RUiNtheExtinct Date: Sun, 28 Dec 2025 14:33:54 +0530 Subject: [PATCH] fix(server): escape quotes in Content-Disposition ASCII filename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quotes in filenames would cause malformed Content-Disposition headers: filename="file"name.png" ← Invalid header with unbalanced quotes Now quotes are replaced with single quotes in the ASCII fallback while the UTF-8 filename* uses proper percent-encoding (%22). --- server.py | 2 ++ tests-unit/server_test/test_content_disposition.py | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/server.py b/server.py index 6a918db04..ca71e13b3 100644 --- a/server.py +++ b/server.py @@ -200,6 +200,8 @@ def create_content_disposition_header(filename: str) -> str: """ # ASCII-safe filename for legacy clients (replace non-ASCII with ?) ascii_filename = filename.encode('ascii', 'replace').decode('ascii') + # Escape quotes to prevent malformed header (e.g., filename="file"name.png") + ascii_filename = ascii_filename.replace('"', "'") # RFC 5987 percent-encoded filename for UTF-8 support encoded_filename = quote(filename, safe='') return f"attachment; filename=\"{ascii_filename}\"; filename*=UTF-8''{encoded_filename}" diff --git a/tests-unit/server_test/test_content_disposition.py b/tests-unit/server_test/test_content_disposition.py index 07ccb5214..36f87410e 100644 --- a/tests-unit/server_test/test_content_disposition.py +++ b/tests-unit/server_test/test_content_disposition.py @@ -15,6 +15,8 @@ def create_content_disposition_header(filename: str) -> str: """ # ASCII-safe filename for legacy clients (replace non-ASCII with ?) ascii_filename = filename.encode('ascii', 'replace').decode('ascii') + # Escape quotes to prevent malformed header (e.g., filename="file"name.png") + ascii_filename = ascii_filename.replace('"', "'") # RFC 5987 percent-encoded filename for UTF-8 support encoded_filename = quote(filename, safe='') return f"attachment; filename=\"{ascii_filename}\"; filename*=UTF-8''{encoded_filename}" @@ -80,12 +82,14 @@ class TestContentDispositionHeader: def test_filename_with_quotes(self): """Test that quotes in filename don't break the header.""" - # Note: Quotes in filenames are edge cases but should not crash + # Quotes in filenames must be escaped to prevent malformed headers result = create_content_disposition_header('file"name.png') assert result.startswith("attachment;") - # The function should still produce valid output - assert "filename*=UTF-8''" in result + # Quotes should be replaced with single quotes in ASCII fallback + assert "filename=\"file'name.png\"" in result + # UTF-8 version should have percent-encoded quote + assert "filename*=UTF-8''file%22name.png" in result def test_mixed_ascii_unicode(self): """Test filenames with both ASCII and Unicode characters."""