NAME
PAGI::App::File - Serve static files
SYNOPSIS
use PAGI::App::File;
my $app = PAGI::App::File->new(
root => '/var/www/static',
)->to_app;
DESCRIPTION
PAGI::App::File serves static files from a configured root directory.
Features
Efficient streaming (no memory bloat for large files)
ETag caching with If-None-Match support (304 Not Modified)
Range requests (HTTP 206 Partial Content)
Automatic MIME type detection for common file types
Index file resolution (index.html, index.htm)
Security
This module implements multiple layers of path traversal protection:
Null byte injection blocking
Double-dot and triple-dot component blocking
Backslash normalization (Windows path separator)
Hidden file blocking (dotfiles like .htaccess, .env)
Symlink escape detection via realpath verification
CONFIGURATION
root - Root directory for files
default_type - Default MIME type (default: application/octet-stream)
index - Index file names (default: [index.html, index.htm])
handle_ranges - Process Range headers (default: 1)
When enabled (default), the app processes Range request headers and returns 206 Partial Content responses. Set to 0 to ignore Range headers and always return the full file.
When to disable Range handling:
When using PAGI::Middleware::XSendfile with a reverse proxy (Nginx, Apache), you should disable range handling. The proxy will handle Range requests more efficiently using its native sendfile implementation:
my $app = PAGI::App::File->new( root => '/var/www/files', handle_ranges => 0, # Let proxy handle Range requests )->to_app; my $wrapped = builder { enable 'XSendfile', type => 'X-Accel-Redirect', mapping => { '/var/www/files/' => '/protected/' }; $app; };With this setup, your app always sends the full file path via X-Sendfile header, and Nginx handles Range requests natively (which is faster than doing it in Perl).