Plack-Middleware-ReverseProxyPath
view release on metacpan or search on metacpan
lib/Plack/Middleware/ReverseProxyPath.pm view on Meta::CPAN
enable "ReverseProxy";
# 2) https://somehost/bepath/to/x
# ReverseProxyPath uses new headers
# fixes SCRIPT_NAME and PATH_INFO
enable "ReverseProxyPath";
# 3) https://somehost/fepath/from/x
# $req->base + $req->path now is the client-facing url
# so URLs, Set-Cookie, Location can work naively
mount "/base" => \&echo_base;
mount "/env" => \&echo_env;
};
mount "/env" => \&echo_env;
# proxy to myself to keep the synopsis short (needs >1 worker)
proxy_builder();
};
# synopsis plumbing:
sub echo_base { require Plack::Request;
[200, [ qw(Content-type text/plain) ],
[ Plack::Request->new(shift)->base . "\n" ] ]
}
sub echo_env {
my ($env) = @_;
[200, [ qw(Content-type text/plain) ],
[ map { "$_: $env->{$_}\n" } keys %$env ] ]
}
sub mw(&) { my $code = shift;
sub { my $app = shift; sub { $code->($app, @_); } } };
Plack::Runner->new->run($app);
__END__
# with ReverseProxyPath and ReverseProxy applied
GET http://localhost:5000/fepath/from/base
https://somehost/fepath/from/base
# talking directly to the back-end
GET http://localhost:5000/bepath/to/base
http://localhost:5000/bepath/to/base
=head1 DESCRIPTION
Use case: reverse proxying /sub/path/ to http://0:5000/other/path/ .
This middleware sits on the back-end and uses headers sent by the proxy
to hide the proxy plumbing from the back-end app.
Plack::Middleware::B<ReverseProxy> does the host, port and scheme.
Plack::Middleware::B<ReverseProxyPath> adds handling of paths.
The goal is to allow proxied back-end apps to reconstruct and use
the client-facing url. ReverseProxy does most of the work
and ReverseProxyPath does the paths. The inner app can simply
use $req->base to redirect, set cookies and the like.
I find the term B<reverse proxy> leads to confusion, so I'll
use B<front-end> to refer to the reverse proxy (eg. squid) which
the client hits first, and B<back-end> to refer to the server
that runs your PSGI application (eg. starman).
Plack::Middleware::ReverseProxyPath adjusts SCRIPT_NAME and PATH_INFO
based on headers from a front-end so that it's inner app can pretend
there is no proxy there. This is useful when you aren't proxying and
entire server, but only a deeper path. In Apache terms:
ProxyPass /mirror/foo/ http://localhost:5000/bar/
It should be used with Plack::Middleware::ReverseProxy which does equivalent
adjustments to the scheme, host and port environment attributes.
=head2 Required Headers
In order for this middleware to perform the path adjustments
you will need to configure your reverse proxy to send the following
headers (as applicable):
=over 4
=item X-Forwarded-Script-Name
The front-end prefix being forwarded FROM. This is the replacement.
The value of SCRIPT_NAME on the front-end.
=item X-Traversal-Path
The back-end prefix being forwarded TO. This is to be replaced.
This is the part of the back-end URI that is just plumbing which
should be hidden from the app.
If you aren't forwarding to the root of a server, but to some
deeper path, this contains the deeper path portion. So if you
forward to http://localhost:8080/myapp, and there is a request for
/article/1, then the full path forwarded to will be
/myapp/article/1. X-Traversal-Path will contain /myapp.
=back
=head2 Path Adjustment Logic
If there is either X-Traversal-Path or X-Forwarded-Script-Name, roughly:
SCRIPT_NAME . PATH_INFO =~ s/^${X-Traversal-Path}/${X-Forwarded-Script-Name}/
The X-Traversal-Path prefix will be stripped from SCRIPT_NAME
(borrowing from PATH_INFO if needed) and
SCRIPT_NAME will be prefixed with X-Forwarded-Script-Name.
In the absence of reverse proxy headers, leave SCRIPT_NAME and PATH_INFO alone.
This allows direct connections to the back-end to function.
Also, leave REQUEST_URI alone with the old/original value.
Front-ends should clear client-sent X-Traversal-Path,
and X-Forwarded-Script-Name
(for security).
Note that while it is intended that this module operates on one
directory segment at a time, that is not enforced at present.
( run in 0.557 second using v1.01-cache-2.11-cpan-e93a5daba3e )