Mojolicious-Plugin-ForwardedFor

 view release on metacpan or  search on metacpan

Build.PL  view on Meta::CPAN

    use strict;
    use warnings;

    require Module::Build; Module::Build->VERSION(0.28);


    my %module_build_args = (
      "configure_requires" => {
        "Module::Build::Tiny" => "0.034"
      },
      "dist_abstract" => "Retrieve the remote address from X-Forwarded-For",
      "dist_author" => [
        "Dan Book <dbook\@cpan.org>"
      ],
      "dist_name" => "Mojolicious-Plugin-ForwardedFor",
      "dist_version" => "0.002",
      "license" => "artistic_2",
      "module_name" => "Mojolicious::Plugin::ForwardedFor",
      "recursive_test_files" => 1,
      "requires" => {
        "Mojolicious" => "7.0",

META.json  view on Meta::CPAN

{
   "abstract" : "Retrieve the remote address from X-Forwarded-For",
   "author" : [
      "Dan Book <dbook@cpan.org>"
   ],
   "dynamic_config" : 0,
   "generated_by" : "Dist::Zilla version 6.017, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "artistic_2"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",

META.yml  view on Meta::CPAN

---
abstract: 'Retrieve the remote address from X-Forwarded-For'
author:
  - 'Dan Book <dbook@cpan.org>'
build_requires:
  File::Spec: '0'
  Module::Metadata: '0'
  Test::More: '0.88'
configure_requires:
  Module::Build::Tiny: '0.034'
dynamic_config: 0
generated_by: 'Dist::Zilla version 6.017, CPAN::Meta::Converter version 2.150010'

README  view on Meta::CPAN

NAME

    Mojolicious::Plugin::ForwardedFor - Retrieve the remote address from
    X-Forwarded-For

SYNOPSIS

      use Mojolicious::Lite;
      plugin ForwardedFor => {levels => 2}; # number of reverse proxies you control
      any '/' => sub {
        my $c = shift;
        $c->render(json => {remote_addr => $c->forwarded_for});
      };
      app->start;

DESCRIPTION

    Mojolicious supports deployment via a reverse proxy setup by specifying
    the proxy configuration option for Hypnotoad, or the MOJO_REVERSE_PROXY
    environment variable. However, "remote_address" in Mojo::Transaction
    will in this case only return the most recent address from the
    X-Forwarded-For header, as it cannot automatically determine how many
    remote addresses correspond to proxies.

    Mojolicious::Plugin::ForwardedFor can be configured with the number of
    reverse proxy "levels" that you control, and provides a "forwarded_for"
    helper method that will return the remote address at that level. It is
    important to set "levels" no higher than the number of proxies that
    will have appended addresses to the X-Forwarded-For header, as the
    original requests can pass anything as the initial value of the header,
    and thus spoof additional proxy levels.

    Since Mojolicious 8.72, you can configure "trusted_proxies" in
    Mojo::Server::Hypnotoad as a more reliable alternative to the baseline
    reverse proxy configuration, affecting "remote_address" in
    Mojo::Transaction directly without need of this plugin.

HELPERS

    Mojolicious::Plugin::ForwardedFor implements the following helpers.

 forwarded_for

      my $remote_addr = $c->forwarded_for;

    Returns the least recently appended remote address from the
    X-Forwarded-For header, while skipping no more than the configured
    number of reverse proxy "levels". Returns the originating address of
    the current request if configured for 0 reverse proxy levels, or if no
    addresses have been appended to the header.

METHODS

    Mojolicious::Plugin::ForwardedFor inherits all methods from
    Mojolicious::Plugin and implements the following new ones.

 register

      $plugin->register(Mojolicious->new);
      $plugin->register(Mojolicious->new, {levels => 1});

    Register helper in Mojolicious application. Takes the following
    options:

    levels

      Number of remote proxy levels to allow for when parsing
      X-Forwarded-For. Defaults to the value of the MOJO_REVERSE_PROXY
      environment variable, or 1.

BUGS

    Report any issues on the public bugtracker.

AUTHOR

    Dan Book <dbook@cpan.org>

lib/Mojolicious/Plugin/ForwardedFor.pm  view on Meta::CPAN

    unless (eval { $levels = int($options->{levels} // $ENV{MOJO_REVERSE_PROXY} // 1); 1 }) {
      $err = $@;
    }
  }

  die "Invalid reverse proxy 'levels' for ForwardedFor: $err" if defined $err;

  $app->helper(forwarded_for => sub {
    my $c = shift;
    return $c->tx->original_remote_address unless $levels > 0;
    my @addresses = split /\s*,\s*/, trim($c->tx->req->headers->header('X-Forwarded-For') // '');
    return $addresses[-$levels] // $addresses[0] // $c->tx->original_remote_address;
  });
}

1;

=head1 NAME

Mojolicious::Plugin::ForwardedFor - Retrieve the remote address from X-Forwarded-For

=head1 SYNOPSIS

  use Mojolicious::Lite;
  plugin ForwardedFor => {levels => 2}; # number of reverse proxies you control
  any '/' => sub {
    my $c = shift;
    $c->render(json => {remote_addr => $c->forwarded_for});
  };
  app->start;

=head1 DESCRIPTION

L<Mojolicious> supports deployment via a
L<reverse proxy|Mojolicious::Guides::Cookbook/"Reverse proxy"> setup by
specifying the L<proxy|Mojo::Server::Hypnotoad/"proxy"> configuration option
for Hypnotoad, or the C<MOJO_REVERSE_PROXY> environment variable. However,
L<Mojo::Transaction/"remote_address"> will in this case only return the most
recent address from the C<X-Forwarded-For> header, as it cannot automatically
determine how many remote addresses correspond to proxies.

L<Mojolicious::Plugin::ForwardedFor> can be configured with the number of
reverse proxy L</"levels"> that you control, and provides a L</"forwarded_for">
helper method that will return the remote address at that level. It is
important to set L</"levels"> no higher than the number of proxies that will
have appended addresses to the C<X-Forwarded-For> header, as the original
requests can pass anything as the initial value of the header, and thus spoof
additional proxy levels.

Since Mojolicious 8.72, you can configure
L<Mojo::Server::Hypnotoad/"trusted_proxies"> as a more reliable alternative to
the baseline reverse proxy configuration, affecting
L<Mojo::Transaction/"remote_address"> directly without need of this plugin.

=head1 HELPERS

L<Mojolicious::Plugin::ForwardedFor> implements the following helpers.

=head2 forwarded_for

  my $remote_addr = $c->forwarded_for;

Returns the least recently appended remote address from the C<X-Forwarded-For>
header, while skipping no more than the configured number of reverse proxy
L</"levels">. Returns the originating address of the current request if
configured for 0 reverse proxy levels, or if no addresses have been appended to
the header.

=head1 METHODS

L<Mojolicious::Plugin::ForwardedFor> inherits all methods from
L<Mojolicious::Plugin> and implements the following new ones.

lib/Mojolicious/Plugin/ForwardedFor.pm  view on Meta::CPAN


  $plugin->register(Mojolicious->new);
  $plugin->register(Mojolicious->new, {levels => 1});

Register helper in L<Mojolicious> application. Takes the following options:

=over 4

=item levels

Number of remote proxy levels to allow for when parsing C<X-Forwarded-For>.
Defaults to the value of the C<MOJO_REVERSE_PROXY> environment variable, or 1.

=back

=head1 BUGS

Report any issues on the public bugtracker.

=head1 AUTHOR

t/forwarded_for.t  view on Meta::CPAN

  my $c = shift;
  $c->render(text => $c->forwarded_for);
};

my $t = Test::Mojo->new;

# default 1 level
plugin 'ForwardedFor';

$t->get_ok('/')->content_is($t->tx->local_address);
$t->get_ok('/', {'X-Forwarded-For' => '1.2.3.4'})->content_is('1.2.3.4');
$t->get_ok('/', {'X-Forwarded-For' => '4.3.2.1, 1.2.3.4'})->content_is('1.2.3.4');
$t->get_ok('/', {'X-Forwarded-For' => '8.8.8.8, 4.3.2.1, 1.2.3.4'})->content_is('1.2.3.4');

# no proxy handling
plugin ForwardedFor => {levels => 0};

$t->get_ok('/')->content_is($t->tx->local_address);
$t->get_ok('/', {'X-Forwarded-For' => '1.2.3.4'})->content_is($t->tx->local_address);
$t->get_ok('/', {'X-Forwarded-For' => '4.3.2.1, 1.2.3.4'})->content_is($t->tx->local_address);
$t->get_ok('/', {'X-Forwarded-For' => '8.8.8.8, 4.3.2.1, 1.2.3.4'})->content_is($t->tx->local_address);

# 2 levels
plugin ForwardedFor => {levels => 2};

$t->get_ok('/')->content_is($t->tx->local_address);
$t->get_ok('/', {'X-Forwarded-For' => '1.2.3.4'})->content_is('1.2.3.4');
$t->get_ok('/', {'X-Forwarded-For' => '4.3.2.1, 1.2.3.4'})->content_is('4.3.2.1');
$t->get_ok('/', {'X-Forwarded-For' => '8.8.8.8, 4.3.2.1, 1.2.3.4'})->content_is('4.3.2.1');

# non-numeric levels
ok !defined eval { plugin ForwardedFor => {levels => 'foo'} }, 'non-numeric levels';
like $@, qr/isn't numeric/, 'right error';
ok !defined eval { plugin ForwardedFor => {levels => '0foo'} }, 'non-numeric levels';
like $@, qr/isn't numeric/, 'right error';
ok !defined eval { plugin ForwardedFor => {levels => ''} }, 'non-numeric levels';
like $@, qr/isn't numeric/, 'right error';

done_testing;



( run in 0.311 second using v1.01-cache-2.11-cpan-26ccb49234f )