NAME
Plack::Middleware::XSendfile - Sets X-Sendfile (or a like) header for frontends
SYNOPSIS
enable "Plack::Middleware::XSendfile";
DEPRECATION NOTICE
This middleware is deprecated and will be removed in a future release, due to poor security design caused by the way configuration is passed via HTTP request headers. See "SECURITY".
The simplest replacement is to set the appropriate header directly in your application when serving a file. For example, in a Mojolicious controller:
sub download {
my $c = shift;
$c->res->headers->header('X-Accel-Redirect' => '/path/to/document.pdf');
$c->render(data => '', status => 200);
}
If you need to handle this at the middleware layer instead to make it more transparent, you can replicate the behavior inline using Plack::Builder:
use Plack::Builder;
use Plack::Util;
use Scalar::Util qw(blessed);
builder {
enable sub {
my $app = shift;
sub {
my $env = shift;
my $res = $app->($env);
Plack::Util::response_cb($res, sub {
my $res = shift;
my $body = $res->[2];
if (blessed($body) && $body->can('path')) {
my $h = Plack::Util::headers($res->[1]);
$h->set('X-Sendfile' => $body->path);
$h->set('Content-Length', 0);
$res->[2] = [];
}
});
};
};
$app;
};
DESCRIPTION
When the body is a blessed reference with a path method, then the return value of that method is used to set the X-Sendfile header.
The body is set to an empty list, and the Content-Length header is set to 0.
If the X-Sendfile header is already set, then the body and Content-Length will be untouched.
You should use IO::File::WithPath or Plack::Util's set_io_path to add path method to an IO object in the body.
See https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile for frontend configuration examples.
Plack::Middleware::XSendfile does not set the Content-Type header.
FRONTEND CONFIGURATION
Nginx
Nginx supports X-Accel-Redirect. Configure an internal location and pass the X-Accel-Mapping header to the backend so the middleware can rewrite filesystem paths into internal URLs:
location ~ /files/(.*) {
internal;
alias /var/www/$1;
}
location / {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
proxy_set_header X-Accel-Mapping /var/www/=/files/;
}
X-Accel-Mapping tells the middleware which filesystem prefix to replace and what internal URL prefix to use instead.
Apache
Enable mod_xsendfile (https://tn123.org/mod_xsendfile/) and set the request header so the middleware activates:
RequestHeader Set X-Sendfile-Type X-Sendfile
XSendFile on
lighttpd
proxy-core.allow-x-sendfile = "enable"
proxy-core.rewrite-request = (
"X-Sendfile-Type" => (".*" => "X-Sendfile")
)
SECURITY
This middleware reads X-Sendfile-Type and X-Accel-Mapping from incoming request headers to determine how to serve files. It is therefore critical that these headers are set by the frontend proxy and cannot be supplied by untrusted clients; otherwise a client could influence which files the frontend serves.
The Plack backend must not be directly reachable by untrusted clients.
For each frontend, make sure both headers are explicitly set in the proxy configuration. proxy_set_header (nginx), RequestHeader Set (Apache), and proxy-core.rewrite-request (lighttpd) all overwrite any client-supplied values, which is why the examples above use those directives.
CONFIGURATION
- variation
-
The header tag to use. If unset, the environment key
plack.xsendfile.typewill be used, then theHTTP_X_SENDFILE_TYPEheader.Supported values are:
X-Accel-RedirectX-Lighttpd-Send-FileX-Sendfile.
An unsupported value will log an error.
AUTHOR
Tatsuhiko Miyagawa