line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Plack::App::Proxy; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
208433
|
use strict; |
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
321
|
|
4
|
9
|
|
|
9
|
|
265
|
use 5.008_001; |
|
9
|
|
|
|
|
28
|
|
|
9
|
|
|
|
|
359
|
|
5
|
9
|
|
|
9
|
|
14414
|
use parent 'Plack::Component'; |
|
9
|
|
|
|
|
6017
|
|
|
9
|
|
|
|
|
51
|
|
6
|
9
|
|
|
9
|
|
232825
|
use Plack::Util::Accessor qw/remote preserve_host_header backend options/; |
|
9
|
|
|
|
|
3208
|
|
|
9
|
|
|
|
|
72
|
|
7
|
9
|
|
|
9
|
|
10530
|
use Plack::Request; |
|
9
|
|
|
|
|
700718
|
|
|
9
|
|
|
|
|
314
|
|
8
|
9
|
|
|
9
|
|
92
|
use Plack::Util; |
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
243
|
|
9
|
9
|
|
|
9
|
|
49
|
use HTTP::Headers; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
6767
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '0.29'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub prepare_app { |
14
|
4
|
|
|
4
|
1
|
418
|
my $self = shift; |
15
|
4
|
50
|
50
|
|
|
54
|
$self->backend($ENV{PLACK_PROXY_BACKEND} || 'AnyEvent::HTTP') unless defined $self->backend; |
16
|
|
|
|
|
|
|
} |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# hop-by-hop headers (see also RFC2616) |
19
|
|
|
|
|
|
|
my @hop_by_hop = qw( |
20
|
|
|
|
|
|
|
Connection Keep-Alive Proxy-Authenticate Proxy-Authorization |
21
|
|
|
|
|
|
|
TE Trailer Transfer-Encoding Upgrade |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub filter_headers { |
25
|
1
|
|
|
1
|
0
|
232
|
my $self = shift; |
26
|
1
|
|
|
|
|
2
|
my ( $headers ) = @_; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# Save from known hop-by-hop deletion. |
29
|
1
|
|
|
|
|
3
|
my @connection_tokens = $headers->header('Connection'); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Remove hop-by-hop headers. |
32
|
1
|
|
|
|
|
25
|
$headers->remove_header( $_ ) for @hop_by_hop; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Connection header's tokens are also hop-by-hop. |
35
|
1
|
|
|
|
|
72
|
for my $token ( @connection_tokens ){ |
36
|
1
|
|
|
|
|
9
|
$headers->remove_header( $_ ) for split /\s*,\s*/, $token; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub build_url_from_env { |
41
|
0
|
|
|
0
|
0
|
|
my($self, $env) = @_; |
42
|
|
|
|
|
|
|
|
43
|
0
|
0
|
|
|
|
|
return $env->{'plack.proxy.url'} |
44
|
|
|
|
|
|
|
if exists $env->{'plack.proxy.url'}; |
45
|
|
|
|
|
|
|
|
46
|
0
|
0
|
0
|
|
|
|
my $url = $env->{'plack.proxy.remote'} || $self->remote |
47
|
|
|
|
|
|
|
or return; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# avoid double slashes |
50
|
0
|
0
|
0
|
|
|
|
$url =~ s!/$!! unless $env->{SCRIPT_NAME} && $env->{SCRIPT_NAME} =~ m!/$!; |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
0
|
|
|
|
$url .= $env->{PATH_INFO} || ''; |
53
|
0
|
0
|
0
|
|
|
|
$url .= '?' . $env->{QUERY_STRING} if defined $env->{QUERY_STRING} && length $env->{QUERY_STRING} > 0; |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
|
return $url; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub build_headers_from_env { |
59
|
0
|
|
|
0
|
0
|
|
my($self, $env, $req) = @_; |
60
|
|
|
|
|
|
|
|
61
|
0
|
|
|
|
|
|
my $headers = $req->headers->clone; |
62
|
0
|
|
|
|
|
|
$headers->header("X-Forwarded-For" => $env->{REMOTE_ADDR}); |
63
|
0
|
0
|
|
|
|
|
$headers->remove_header("Host") unless $self->preserve_host_header; |
64
|
0
|
|
|
|
|
|
$self->filter_headers( $headers ); |
65
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
+{ map {$_ => scalar $headers->header($_) } $headers->header_field_names }; |
|
0
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub call { |
70
|
0
|
|
|
0
|
1
|
|
my ($self, $env) = @_; |
71
|
|
|
|
|
|
|
|
72
|
0
|
0
|
|
|
|
|
unless ($env->{'psgi.streaming'}) { |
73
|
0
|
|
|
|
|
|
die "Plack::App::Proxy only runs with the server with psgi.streaming support"; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
0
|
0
|
|
|
|
|
my $url = $self->build_url_from_env($env) |
77
|
|
|
|
|
|
|
or return [502, ["Content-Type","text/html"], ["Can't determine proxy remote URL"]]; |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
my $req = Plack::Request->new($env); |
80
|
0
|
|
|
|
|
|
my $headers = $self->build_headers_from_env($env, $req); |
81
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
my $method = $env->{REQUEST_METHOD}; |
83
|
0
|
|
|
|
|
|
my $content = $req->content; |
84
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
my $backend_class = Plack::Util::load_class( |
86
|
|
|
|
|
|
|
$self->backend, 'Plack::App::Proxy::Backend' |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
return $backend_class->new( |
90
|
|
|
|
|
|
|
url => $url, |
91
|
|
|
|
|
|
|
req => $req, |
92
|
|
|
|
|
|
|
headers => $headers, |
93
|
|
|
|
|
|
|
method => $method, |
94
|
|
|
|
|
|
|
content => $content, |
95
|
|
|
|
|
|
|
options => $self->options, |
96
|
0
|
|
|
0
|
|
|
response_headers => sub { $self->response_headers(@_) }, |
97
|
0
|
|
|
|
|
|
)->call($env); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub response_headers { |
101
|
0
|
|
|
0
|
0
|
|
my ($self, $headers) = @_; |
102
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
$self->filter_headers( $headers ); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Remove PSGI forbidden headers |
106
|
0
|
|
|
|
|
|
$headers->remove_header('Status'); |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
my @headers; |
109
|
0
|
|
|
0
|
|
|
$headers->scan( sub { push @headers, @_ } ); |
|
0
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
|
111
|
0
|
|
|
|
|
|
return @headers; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
1; |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
__END__ |