HTTP::Proxy::GreaseMonkey::Redirector - Proxy cross-site requests


HTTP-Proxy-GreaseMonkey documentation Contained in the HTTP-Proxy-GreaseMonkey distribution.

Index


Code Index:

NAME

Top

HTTP::Proxy::GreaseMonkey::Redirector - Proxy cross-site requests

VERSION

Top

This document describes HTTP::Proxy::GreaseMonkey::Redirector version 0.05

SYNOPSIS

Top

DESCRIPTION

Top

INTERFACE

Top

passthru

Set the passthru key.

filter

Filter the request headers.

state_file

Set the name of the file that will be used to store state.

CONFIGURATION AND ENVIRONMENT

Top

HTTP::Proxy::GreaseMonkey::Redirector requires no configuration files or environment variables.

DEPENDENCIES

Top

None.

INCOMPATIBILITIES

Top

None reported.

BUGS AND LIMITATIONS

Top

No bugs have been reported.

Please report any bugs or feature requests to bug-http-proxy-greasemonkey@rt.cpan.org, or through the web interface at http://rt.cpan.org.

AUTHOR

Top

Andy Armstrong <andy@hexten.net>

LICENCE AND COPYRIGHT

Top


HTTP-Proxy-GreaseMonkey documentation Contained in the HTTP-Proxy-GreaseMonkey distribution.
package HTTP::Proxy::GreaseMonkey::Redirector;

use warnings;
use strict;
use Carp;
use JSON;
use HTTP::Response;
use HTML::Tiny;
use YAML qw( DumpFile LoadFile );
use LockFile::Simple qw( lock unlock );

use base qw( HTTP::Proxy::HeaderFilter );

our $VERSION = '0.05';

sub passthru {
    my $self = shift;
    my $key  = quotemeta shift;
    $self->{passthru} = qr{ ^/ $key 
                                  / ( [-a-z0-9]+ (?: \. [-a-z0-9]+ )+ ) 
                                  (/.*) $}xi;
    $self->{internal} = qr{ ^/ $key 
                                  / \$ internal \$ $ }xi;
}

sub filter {
    my ( $self, $headers, $message ) = @_;

    my $passthru = $self->{passthru} || return;

    my $uri  = $message->uri;
    my $path = $uri->path;

    # print "$path, $self->{internal}\n";

    if ( $path =~ $self->{internal} ) {
        $self->proxy->response(
            $self->_despatch_internal(
                $headers, $message, $uri->query
            )
        );
    }
    elsif ( $path =~ $passthru ) {
        # Redirect
        my $real_uri = $uri->scheme . '://' . $1 . $2;
        if ( my $query = $uri->query ) {
            $real_uri = join '?', $real_uri, $query;
        }
        $message->uri( $real_uri );
        $headers->header( host => $1 );
    }
}

sub state_file {
    my $self = shift;
    $self->{state_file} = shift if @_;
    croak "No state_file defined" unless defined $self->{state_file};
    return $self->{state_file};
}

sub _load_state {
    my $file = shift->state_file;
    return -f $file ? LoadFile( $file ) : {};
}

sub _save_state {
    DumpFile( shift->state_file, @_ );
}

sub _locked {
    my ( $self, $func ) = @_;
    my $file = $self->state_file;
    lock( $file );
    my @res = $func->();
    unlock( $file );
    return @res;
}

sub _despatch_internal {
    my ( $self, $headers, $message, $query ) = @_;
    my $result = eval {
        # JSON == YAML, right?
        my %handler = (
            setValue => sub {
                my ( $args, $name, $val ) = @_;
                $self->_locked(
                    sub {
                        my $state = $self->_load_state;
                        $state->{ $args->{ns} }->{ $args->{n} }->{$name}
                          = $val;
                        $self->_save_state( $state );
                    }
                );
                return 1;
            },
            getValue => sub {
                my ( $args, $name, $dflt ) = @_;
                my ( $state )
                  = $self->_locked( sub { $self->_load_state } );
                my $val
                  = $state->{ $args->{ns} }->{ $args->{n} }->{$name};
                return defined $val ? $val : $dflt;
            },
            log => sub {
                my ( $args, @argv ) = @_;
                print join( ': ', $args->{n}, join( '', @argv ) ), "\n";
                return 1;
            },
        );

        my $h    = $self->{_html} ||= HTML::Tiny->new;
        my $qs   = $h->url_decode( $query );
        my $args = from_json( $qs );

        my $method = delete $args->{m}
          || die "Missing 'm' arg";
        my $code = $handler{$method}
          || die "No method $method";

        my @arguments = @{ delete $args->{a} || [] };

        my $result = $code->( $args, @arguments );

        return HTTP::Response->new(
            200, 'OK',
            [ 'content_type' => 'application/json' ],
            to_json( [$result] )
        );
    };

    if ( $@ ) {
        ( my $err = $@ ) =~ s/\s+/ /g;
        print "Error: $err\n";
        return HTTP::Response->new( 500, $err );
    }

    return $result;
}

1;

__END__