How to Mock Content-Disposition and Extract Filename in Python
Parse and mock Content-Disposition headers in Python to extract filenames, handling both plain and RFC 5987 encoded values.
Python code
50 linesimport os
from pathlib import Path
import re
from unittest.mock import patch
def get_filename_from_content_disposition(header_value):
"""
Extract filename from a Content-Disposition header value.
Supports both filename and filename* parameters (RFC 5987).
"""
if not header_value:
return None
# Match traditional filename="..."
simple_match = re.search(r'filename="?([^";]+)"?', header_value, re.IGNORECASE)
# Match encoded filename*="UTF-8''..."
encoded_match = re.search(r"filename\*\s*=\s*UTF-8''([^;]+)", header_value, re.IGNORECASE)
if encoded_match:
from urllib.parse import unquote
return unquote(encoded_match.group(1))
elif simple_match:
return simple_match.group(1)
return None
def mock_download_response(headers_dict):
"""
Simulate reading Content-Disposition from a mock HTTP response.
Returns the filename if present, else 'downloaded_file'.
"""
content_disposition = headers_dict.get('Content-Disposition', '')
filename = get_filename_from_content_disposition(content_disposition)
return filename or 'downloaded_file'
if __name__ == "__main__":
# Test cases with mock headers
test_cases = [
{'Content-Disposition': 'attachment; filename="report.pdf"'},
{'Content-Disposition': "attachment; filename*=UTF-8''%E2%82%AC%20rates.txt"},
{'Content-Disposition': ''},
{}
]
for headers in test_cases:
result = mock_download_response(headers)
print(f"Headers: {headers}")
print(f"Extracted filename: {result}\n")
Output
Headers: {'Content-Disposition': 'attachment; filename="report.pdf"'}
Extracted filename: report.pdf
Headers: {'Content-Disposition': "attachment; filename*=UTF-8''%E2%82%AC%20rates.txt"}
Extracted filename: € rates.txt
Headers: {'Content-Disposition': ''}
Extracted filename: downloaded_file
Headers: {}
Extracted filename: downloaded_file
How it works
This function uses two regex patterns to match both the simple filename parameter and the RFC 5987 filename* form. The encoded variant is URL-decoded with urllib.parse.unquote to get the original Unicode characters. The mock response simulates HTTP header dicts, and falls back to a default filename when no match is found. This pattern mirrors how real clients (like requests or urllib) parse download headers.
Common mistakes
- Using a single regex that misses the `filename*` variant when both are present
- Forgetting to URL-decode the `filename*` value before returning it
- Assuming every response has a Content-Disposition header without a fallback
- Case-matching headers without using `str.lower()` on keys or values
Variations
- Return a tuple like `(filename, disposition_type)` to capture attachment vs inline
- Use `email.message.Message` to parse the header instead of regex for full RFC compliance
Real-world use cases
- Automating file download tests in a CI pipeline by mocking response headers
- Sanitizing filenames from a third-party API before saving to disk to avoid path traversal
- Building a scraper that downloads files and names them from Content-Disposition
Sponsored
More from API design & gRPC
- Build a Bulk Array POST Mock Server in Python medium
- Build a Mock REST API with PUT and GET in Python medium
- Convert Protobuf to JSON and Dict in Python easy
- Create a Data Helper in Python for gRPC-style APIs easy
- Format data in Python using dataclasses like gRPC messages easy
- Generate an OpenAPI Spec from Mock Routes in Python easy
Keep learning
Related tutorials and quizzes for this topic.