Plack::Middleware::Proxy::RewriteLocation - Rewrites redirect headers


Plack-App-Proxy documentation Contained in the Plack-App-Proxy distribution.

Index


Code Index:

NAME

Top

Plack::Middleware::Proxy::RewriteLocation - Rewrites redirect headers

SYNOPSIS

Top

  use Plack::Builder;
  use Plack::App::Proxy;

  builder {
      enable "Proxy::RewriteLocation";
      Plack::App::Proxy->new(remote => "http://10.0.1.2:8080/")->to_app;
  };

  ### or, if mounting (i.e. URLMap) the proxied site at /foo

  builder {
      enable "Proxy::RewriteLocation", url_map => [ '/foo' => http://10.0.1.2:8080' ];
      mount '/foo' => Plack::App::Proxy->new(remote => "http://10.0.1.2:8080/")->to_app;
  };

DESCRIPTION

Top

Plack::Middleware::Proxy::RewriteLocation rewrites the Location header in the response when the remote host redirects using its own headers, like mod_proxy's ProxyPassReverse option.

OPTIONS

Top

url_map (arrayref)

If given, will account for mounted (URLMapped) Proxy apps when rewriting Location headers. Will be applied in order, stopping at the first successful match with the remote Location.

AUTHOR

Top

Tatsuhiko Miyagawa Robert Buels

SEE ALSO

Top

Plack::App::Proxy


Plack-App-Proxy documentation Contained in the Plack-App-Proxy distribution.

package Plack::Middleware::Proxy::RewriteLocation;
use strict;
use parent 'Plack::Middleware';

use Plack::Util;
use Plack::Util::Accessor 'url_map';
use URI;

sub _different_part($$) {
    my ($from, $to) = @_;

    while ($from =~ m{[^/]+(?:\://$|/$|$)}g) {
        my $last_part = $&;
        last unless $to =~ /\Q$last_part\E$/;

        $from =~ s!\Q$last_part\E$!!;
        $to   =~ s!\Q$last_part\E$!!;
    }

    $from => $to;
}

sub new {
    my $self = shift->SUPER::new( @_ );

    # regularize the remote URLs in the URL map
    if( my $m = $self->url_map ) {
        for( my $i = 1; $i < @$m; $i += 2 ) {
            $m->[$i] = $self->_regularize_url( $m->[$i] );
        }
    }

    return $self;
}

sub call {
    my($self, $env) = @_;

    return sub {
        my $respond = shift;

        my $cb = $self->app->($env);
        return $respond->( $cb ) unless ref $cb eq 'CODE';

        $cb->(sub {
            my $res = shift;

            if ( $env->{HTTP_HOST} and my $location = Plack::Util::header_get($res->[1], 'Location') ) {

                my @map;
                if ($self->url_map) {
                    # regularize the format of the location so we can
                    # compare it correctly (some apps print this
                    # non-canonically)
                    $location = $self->_regularize_url( $location );

                    my $proxy = "$env->{'psgi.url_scheme'}://$env->{HTTP_HOST}";
                    my @url_map = @{$self->url_map};

                    while(my ($proxy_path, $remote) = splice @url_map, 0, 2) {
                        push @map, "$proxy$proxy_path" => $remote;
                    }
                } else {
                    # Auto-guessing url_map
                    my $original_url = "$env->{'psgi.url_scheme'}://" . 
                                       "$env->{HTTP_HOST}$env->{REQUEST_URI}";
                    $original_url .= '?' . $env->{QUERY_STRING}
                        if defined $env->{QUERY_STRING} && $env->{QUERY_STRING};
                    @map = _different_part(
                        $original_url => $env->{'plack.proxy.last_url'}
                    );
                }

                while(my ($proxy_url, $remote) = splice @map, 0, 2) {
                    last if $location =~ s!^$remote!$proxy_url!;
                }

                $location =~ s!//$!/!; #< avoid double slashes

                Plack::Util::header_set( $res->[1], 'Location' => $location );
            }

            return $respond->( $res );
        });
    };
}

sub _regularize_url {
    '' . URI->new( $_[1] )->canonical
}

1;

__END__