Radically simplified static file serving for WSGI applications
The WhiteNoise class provides the core static file serving functionality as WSGI middleware. It intercepts requests for static files and serves them directly, allowing your application to handle dynamic content while WhiteNoise efficiently serves static assets.
The main WSGI middleware class that serves static files with comprehensive HTTP feature support including compression, caching, range requests, and proper header handling.
class WhiteNoise:
"""
WSGI middleware for serving static files.
Wraps a WSGI application to serve static files before passing requests
to the wrapped application. Supports compression, caching, and HTTP
best practices.
"""
def __init__(
self,
application,
root=None,
prefix=None,
*,
autorefresh: bool = False,
max_age: int | None = 60,
allow_all_origins: bool = True,
charset: str = "utf-8",
mimetypes: dict[str, str] | None = None,
add_headers_function: Callable[[Headers, str, str], None] | None = None,
index_file: str | bool | None = None,
immutable_file_test: Callable | str | None = None,
):
"""
Initialize WhiteNoise middleware.
Parameters:
- application: WSGI application to wrap
- root: Path to static files directory
- prefix: URL prefix for static files (e.g., '/static/')
- autorefresh: Re-scan filesystem on each request (development only)
- max_age: Cache-Control max-age in seconds (None disables caching)
- allow_all_origins: Add Access-Control-Allow-Origin: * header
- charset: Default charset for text files
- mimetypes: Additional MIME type mappings
- add_headers_function: Custom function to add headers
- index_file: Index file name (True for 'index.html')
- immutable_file_test: Function or regex to identify immutable files
"""
def __call__(self, environ, start_response):
"""
WSGI application interface.
Parameters:
- environ: WSGI environment dictionary
- start_response: WSGI start_response callable
Returns:
- WSGI response iterator
"""
def add_files(self, root, prefix=None):
"""
Add a directory of static files to serve.
Parameters:
- root: Absolute path to static files directory
- prefix: URL prefix for files (e.g., '/static/')
"""
@staticmethod
def serve(static_file, environ, start_response):
"""
Serve a static file (static method).
Parameters:
- static_file: StaticFile instance to serve
- environ: WSGI environment dictionary
- start_response: WSGI start_response callable
Returns:
- WSGI response iterator
"""
FOREVER: int # Cache duration constant (10 years in seconds)from whitenoise import WhiteNoise
from my_app import application
# Wrap your WSGI application
application = WhiteNoise(application)
# Add static files with URL prefix
application.add_files('/var/www/static', prefix='/static/')
application.add_files('/var/www/media', prefix='/media/')# Enable autorefresh for development (performance impact)
application = WhiteNoise(
application,
autorefresh=True,
max_age=0 # Disable caching for development
)def add_security_headers(headers, path, url):
"""Add security headers to static files."""
if url.endswith('.js'):
headers['X-Content-Type-Options'] = 'nosniff'
if url.endswith('.css'):
headers['X-Content-Type-Options'] = 'nosniff'
application = WhiteNoise(
application,
max_age=31536000, # 1 year cache for production
allow_all_origins=True,
add_headers_function=add_security_headers
)import re
# Using regex pattern for versioned files
versioned_file_re = r'\.[0-9a-f]{8,32}\.'
application = WhiteNoise(
application,
immutable_file_test=versioned_file_re
)
# Using custom function
def is_immutable(path, url):
"""Check if file is immutable based on naming convention."""
return '.min.' in url or '.hash.' in url
application = WhiteNoise(
application,
immutable_file_test=is_immutable
)WhiteNoise operates in two modes for file discovery:
Static Mode (Default): Files are scanned once at startup and stored in memory for fast lookup. Suitable for production environments.
Autorefresh Mode: Files are discovered on each request by scanning the filesystem. Only use for development as it has significant performance impact.
WhiteNoise implements comprehensive HTTP best practices:
Internal classes that handle HTTP responses and file serving, used by WhiteNoise for comprehensive static file delivery.
class Response:
"""
HTTP response container for static file serving.
Represents the complete HTTP response including status, headers, and file content.
"""
def __init__(self, status, headers, file):
"""
Initialize HTTP response.
Parameters:
- status: HTTPStatus enum value
- headers: List of (name, value) header tuples
- file: File object or None for responses without body
"""
class StaticFile:
"""
Represents a static file with all its variants and metadata.
Handles compressed alternatives, conditional requests, range requests,
and proper HTTP header generation for efficient static file serving.
"""
def __init__(self, path, headers, encodings=None, stat_cache=None):
"""
Initialize static file representation.
Parameters:
- path: Absolute path to the file
- headers: List of (name, value) header tuples
- encodings: Dict mapping encodings to compressed file paths
- stat_cache: Optional stat cache for performance
"""
def get_response(self, method, request_headers):
"""
Generate HTTP response for the file.
Parameters:
- method: HTTP method (GET, HEAD, etc.)
- request_headers: Dict of request headers
Returns:
- Response: Complete HTTP response object
Handles conditional requests, range requests, content negotiation,
and proper HTTP status codes.
"""
class SlicedFile:
"""
File-like object for HTTP range requests.
Wraps a file to serve only a specific byte range, enabling
efficient partial content delivery for large files.
"""
def __init__(self, fileobj, start, end):
"""
Create sliced file for range request.
Parameters:
- fileobj: Source file object
- start: Starting byte position (inclusive)
- end: Ending byte position (inclusive)
"""
def read(self, size=-1):
"""
Read bytes respecting range limits.
Parameters:
- size: Maximum bytes to read (-1 for remaining)
Returns:
- bytes: File content within range limits
"""
class Redirect:
"""
HTTP redirect response for URL rewriting.
Used for index file handling and URL canonicalization.
"""
def __init__(self, location, headers=None):
"""
Create redirect response.
Parameters:
- location: Target URL for redirect
- headers: Optional additional headers
"""
def get_response(self, method, request_headers):
"""
Generate redirect response.
Parameters:
- method: HTTP method
- request_headers: Request headers dict
Returns:
- Response: 302 redirect response
"""
class FileEntry:
"""
File metadata container for stat caching.
Stores file path, size, and modification time for efficient
file system operations and HTTP header generation.
"""
def __init__(self, path, stat_cache=None):
"""
Create file entry with metadata.
Parameters:
- path: Absolute file path
- stat_cache: Optional stat cache for performance
"""MIME type detection system for proper Content-Type header generation.
class MediaTypes:
"""
MIME type resolver for static files.
Provides consistent media type detection across environments
using WhiteNoise's built-in type mappings with optional extensions.
"""
def __init__(self, *, extra_types: dict[str, str] | None = None):
"""
Initialize media type resolver.
Parameters:
- extra_types: Additional MIME type mappings to include
"""
def get_type(self, path: str) -> str:
"""
Determine MIME type for file path.
Parameters:
- path: File path to analyze
Returns:
- str: MIME type string (defaults to 'application/octet-stream')
Checks both filename and extension, with filename taking precedence
for special cases like 'apple-app-site-association'.
"""URL and path processing utilities for consistent handling across WhiteNoise.
def decode_path_info(path_info):
"""
Decode URL path from WSGI PATH_INFO.
Parameters:
- path_info: Raw PATH_INFO string from WSGI environ
Returns:
- str: UTF-8 decoded path string
Handles UTF-8 URLs by undoing Python's implicit ISO-8859-1 decoding.
"""
def ensure_leading_trailing_slash(path):
"""
Normalize path to have leading and trailing slashes.
Parameters:
- path: Path string to normalize
Returns:
- str: Normalized path with leading/trailing slashes
Returns '/' for empty/None input, '/{path}/' for non-empty input.
"""Specialized exceptions for static file handling and error reporting.
class NotARegularFileError(Exception):
"""
Base exception for non-regular file encounters.
Raised when attempting to serve directories, devices, or other
non-regular file system objects.
"""
class MissingFileError(NotARegularFileError):
"""
Exception for missing or inaccessible files.
Raised when a requested file cannot be found or accessed.
"""
class IsDirectoryError(MissingFileError):
"""
Exception for directory access attempts.
Raised when attempting to serve a directory as a file.
"""from typing import Callable, Any
from wsgiref.headers import Headers
from http import HTTPStatus
# WSGI application type
WSGIApplication = Callable[[dict, Callable], Any]
# Custom header function type
AddHeadersFunction = Callable[[Headers, str, str], None]
# Immutable file test types
ImmutableFileTest = Callable[[str, str], bool]
ImmutableFilePattern = str
# HTTP response components
HTTPHeaders = list[tuple[str, str]]
RequestHeaders = dict[str, str]Install with Tessl CLI
npx tessl i tessl/pypi-whitenoise