Punk

 view release on metacpan or  search on metacpan

t/1211-proxy.t  view on Meta::CPAN

    $d = body_of($call->(xff => '9.9.9.9, 1.2.3.4'));
    is $d->{remote_addr}, '1.2.3.4',
       'a client-forged leading entry does not become REMOTE_ADDR';

    $d = body_of($call->());
    is $d->{remote_addr}, '10.0.0.1', 'no header: the peer, unchanged';
    is $d->{remote_port}, 54321, 'and the port survives when nothing moved';
    is $d->{peer_addr}, '10.0.0.1', 'punk.peer_addr is set regardless';
}

# ---- scheme, host and port -------------------------------------------------

{
    package Fwd;
    use Punk;
    proxy;
    get '/env' => \&main::echo;
}
{
    my $call = caller_for(Fwd->to_app);

    my $d = body_of($call->(proto => 'https'));
    is $d->{scheme}, 'https',
       'X-Forwarded-Proto sets psgi.url_scheme behind terminated TLS';
    is $d->{https}, 'on', 'and HTTPS=on, which is the key other code reads';

    $d = body_of($call->(proto => 'HTTPS'));
    is $d->{scheme}, 'https', 'the scheme compare is case-insensitive';

    $d = body_of($call->(proto => 'https, http'));
    is $d->{scheme}, 'https',
       'a comma-joined proto list takes the client-facing (leftmost) hop';

    $d = body_of($call->(proto => 'gopher'));
    is $d->{scheme}, 'http', 'an unknown scheme changes nothing';

    $d = body_of($call->(host => 'app.example.com'));
    is $d->{host}, 'app.example.com', 'X-Forwarded-Host sets HTTP_HOST';

    $d = body_of($call->(port => '443'));
    is $d->{port}, '443', 'X-Forwarded-Port sets SERVER_PORT';

    $d = body_of($call->(port => '44a3'));
    is $d->{port}, 80, 'a non-numeric forwarded port is ignored';
}

# ---- custom header names ---------------------------------------------------

{
    package Custom;
    use Punk;
    proxy trust => 1, for_header => 'CF-Connecting-IP';
    get '/env' => \&main::echo;
}
{
    my $call = caller_for(Custom->to_app);
    my $d = body_of($call->(hdr => 'CF_CONNECTING_IP', hval => '1.2.3.4',
                            xff => '9.9.9.9'));
    is $d->{remote_addr}, '1.2.3.4', 'for_header names a different header';
    isnt $d->{remote_addr}, '9.9.9.9',
       'and the standard X-Forwarded-For is not consulted once it is renamed';
}

# ---- CIDR trust ------------------------------------------------------------

{
    package Cidr;
    use Punk;
    proxy trust => ['10.0.0.0/8'];
    get '/env' => \&main::echo;
}
{
    my $call = caller_for(Cidr->to_app);
    my $d = body_of($call->(xff => '1.2.3.4, 10.0.0.7', peer => '10.0.0.1'));
    is $d->{remote_addr}, '1.2.3.4', 'CIDR trust walks to the first outsider';

    $d = body_of($call->(xff => '1.2.3.4, 10.0.0.7', peer => '8.8.8.8'));
    is $d->{remote_addr}, '8.8.8.8',
       'an untrusted socket peer means the header is not believed';
}

# ---- what block_ip does behind a proxy -------------------------------------

# Banning the address the socket came from bans the load balancer. Boot config
# cannot catch it, and a silent no-op would leave an operator believing they
# had banned someone.
{
    package Ban;
    use Punk;
    proxy;
    get '/ban-peer'   => sub {
        my ($c) = @_;
        $c->block_ip($c->env->{'punk.peer_addr'});
        $c->text('banned');
    };
    get '/ban-client' => sub {
        my ($c) = @_;
        $c->block_ip($c->req->address);
        $c->text('banned');
    };
    get '/env' => \&main::echo;
}
{
    my $call = caller_for(Ban->to_app);

    my $res = $call->(path => '/ban-peer', xff => '1.2.3.4');
    is $res->[0], 500, 'block_ip on the proxy address is refused';
    like join('', @{ $res->[2] }), qr/reverse proxy|took the site down|would take/i,
        'and says why rather than failing silently';

    $res = $call->(path => '/ban-client', xff => '1.2.3.4');
    is $res->[0], 200, 'banning the real client is fine';
}

# ---- boot-time refusals ----------------------------------------------------

sub boot_fails {
    my ($body, $like, $what) = @_;
    my $pkg = 'Boot' . int(rand 1e9);
    eval "package $pkg; use Punk; $body; ${pkg}->to_app; 1";
    my $err = $@ || '';



( run in 0.809 second using v1.01-cache-2.11-cpan-54e63673c56 )