File Coverage

blib/lib/Plack/Middleware/ReverseProxyPath.pm
Criterion Covered Total %
statement 36 36 100.0
branch 12 12 100.0
condition 5 7 71.4
subroutine 10 10 100.0
pod 1 1 100.0
total 64 66 96.9


line stmt bran cond sub pod time code
1             package Plack::Middleware::ReverseProxyPath;
2              
3 3     3   149597 use 5.006;
  3         7  
4 3     3   11 use strict;
  3         3  
  3         47  
5 3     3   21 use warnings;
  3         9  
  3         68  
6 3     3   451 use parent qw(Plack::Middleware);
  3         235  
  3         14  
7             our $VERSION = '0.04';
8              
9             sub call {
10 44     44 1 125806 my $self = shift;
11 44         46 my $env = shift;
12              
13 44 100 66     132 if ( $env->{'HTTP_X_FORWARDED_SCRIPT_NAME'}
14             || $env->{'HTTP_X_TRAVERSAL_PATH'} ) {
15              
16 36   100     79 my $x_script_name = $env->{'HTTP_X_FORWARDED_SCRIPT_NAME'} || '';
17 36   50     65 my $x_traversal_path = $env->{'HTTP_X_TRAVERSAL_PATH'} || '';
18 36         35 my $script_name = $env->{SCRIPT_NAME};
19              
20             # replace $script_name . $path_info
21             # prefix of $x_traversal_path with $x_script_name
22 36 100       60 if ( length $script_name >= length $x_traversal_path ) {
23 20 100       281 $script_name =~ s/^\Q$x_traversal_path\E/$x_script_name/
24             or _throw_error(
25             "HTTP_X_TRAVERSAL_PATH: $x_traversal_path\n" .
26             "is not a prefix of \n" .
27             "SCRIPT_NAME: $script_name\n" );
28             } else {
29             # $x_traversal_path is longer, borrow from path_info
30 16 100       217 $x_traversal_path =~ s/^\Q$script_name\E//
31             or _throw_error(
32             "SCRIPT_NAME $script_name\n" .
33             "is not a prefix of \n" .
34             "HTTP_X_TRAVERSAL_PATH: $x_traversal_path\n" );
35 15         19 $script_name = $x_script_name;
36              
37 15 100       90 $env->{PATH_INFO} =~ s/^\Q$x_traversal_path\E//
38             or _throw_error(
39             "Fragment: $x_traversal_path\n" .
40             "is not a prefix of \n" .
41             "PATH_INFO: $env->{PATH_INFO}\n" .
42             " SCRIPT_NAME: $script_name\n" .
43             " HTTP_X_TRAVERSAL_PATH: $env->{HTTP_X_TRAVERSAL_PATH}\n" );
44              
45             # add PSGI required '/' (bad headers w/ trailing / could do it)
46 12         35 $env->{PATH_INFO} =~ s!^([^/])!/$1!;
47             }
48              
49 29 100       61 if ( $script_name eq '/' ) { # PSGI doesn't allow '/' only
50 6         5 $script_name = '';
51             }
52 29         49 $env->{SCRIPT_NAME} = $script_name;
53              
54             # don't touch REQUEST_URI, it will continue to refer to the original
55             }
56              
57 37         81 return $self->app->($env);
58             }
59              
60             sub _throw_error {
61 7     7   8 my ($message) = @_;
62 7         42 die Plack::Middleware::ReverseProxyPath::Exception->new($message);
63             }
64              
65             {
66             package Plack::Middleware::ReverseProxyPath::Exception;
67 3     3   21365 use overload '""' => \&message;
  3         4  
  3         20  
68             sub new {
69 7     7   9 my ($class, $message) = @_;
70 7         52 return bless { message => $message }, $class;
71             }
72 10     10   1864 sub code { return 500 }
73 17     17   312 sub message { return $_[0]->{message} }
74             }
75              
76             1;
77              
78             __END__