File Coverage

blib/lib/Plack/Middleware/RealIP.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Plack::Middleware::RealIP;
2 1     1   28125 use strict;
  1         4  
  1         49  
3 1     1   6 use warnings;
  1         2  
  1         35  
4 1     1   33 use 5.008;
  1         10  
  1         911  
5             our $VERSION = 0.03;
6 1     1   1096 use parent qw/Plack::Middleware/;
  1         363  
  1         74  
7             use Net::Netmask;
8              
9             use Plack::Util::Accessor qw( header trusted_proxy );
10              
11             sub prepare_app {
12             my $self = shift;
13              
14             if (my $trusted_proxy = $self->trusted_proxy) {
15             my @trusted_proxy = map { Net::Netmask->new($_) } ref($trusted_proxy) ? @{ $trusted_proxy } : ($trusted_proxy);
16             $self->trusted_proxy(\@trusted_proxy);
17             }
18             }
19              
20             sub call {
21             my $self = shift;
22             my $env = shift;
23              
24             my $header;
25             if ($header = $self->header) {
26             ($header = uc $header) =~ tr/-/_/;
27             $header = "HTTP_$header" unless $header =~ /^(?:HTTP|CONTENT|COOKIE)/;
28             }
29              
30             my (@remote, @trusted_proxy);
31             @remote = $env->{$header} =~ /([^,\s]+)/g if exists $env->{$header};
32             @trusted_proxy = @{ $self->trusted_proxy } if $self->trusted_proxy;
33              
34             if (@remote and @trusted_proxy) {
35             my @unconfirmed = (@remote, $env->{REMOTE_ADDR});
36              
37             while (my $addr = pop @unconfirmed) {
38             my $has_matched = 0;
39             foreach my $netmask (@trusted_proxy) {
40             $has_matched++, last if $netmask->match($addr);
41             }
42             $env->{REMOTE_ADDR} = $addr, last unless $has_matched;
43             }
44              
45             if (@unconfirmed) {
46             $env->{$header} = join(', ', @unconfirmed);
47             } else {
48             delete $env->{$header};
49             }
50             }
51              
52             return $self->app->($env);
53             }
54              
55             1;
56              
57             =head1 NAME
58              
59             Plack::Middleware::RealIP - Override client IP with header value provided by proxy/load balancer
60              
61             =head1 SYNOPSIS
62              
63             enable 'Plack::Middleware::RealIP',
64             header => 'X-Forwarded-For',
65             trusted_proxy => [qw(192.168.1.0/24 192.168.2.1)];
66              
67             =head1 DESCRIPTION
68              
69             Plack::Middleware::RealIP is loose port of the Apache module
70             mod_remoteip. It overrides C with the IP address advertised
71             in the request header configured with C
.
72              
73             When multiple, comma delimited IP addresses are listed in the header
74             value, they are processed from right to left. The first untrusted IP
75             address found, based on C, stops the processing and is
76             set to be C. The header field is updated to this remaining
77             list of unconfirmed IP addresses, or if all IP addresses were trusted,
78             this header is removed from the request altogether.
79              
80             =head1 CONFIGURATION
81              
82             =head2 header
83              
84             Sets a request header to trust as the client IP, e.g. X-Client-IP
85              
86             =head2 trusted_proxy
87              
88             A list of IP addresses or subnet blocks which are trusted to provide IP header.
89              
90             =head1 AUTHOR
91              
92             Sherwin Daganato Esherwin@daganato.comE
93              
94             Most of the logic is based on L by Graham Barr
95              
96             =head1 LICENSE
97              
98             This library is free software; you can redistribute it and/or modify
99             it under the same terms as Perl itself.
100              
101             =head1 SEE ALSO
102              
103             L
104              
105             L
106              
107             L
108              
109             L
110              
111             =cut