Perlbal::Plugin::ProxyHost

Perlbalでreverse_proxyさせる前にHostを書き換えてreverse_proxyさせるPluginを書いた。


参考)http://trac.mizzy.org/public/wiki/PerlbalPluginProxyPass


やりたいのは特定のQuery(この場合はhoge)が付いている特定のホストからのリクエストの場合
別のHostにreverse_proxyさせる。
クライアントは当然別のHostにreverse_proxyされてるのは知らないのこと。


書けそうだったからさくっと書いてみた。


package Perlbal::Plugin::ProxyHost;
use strict;
use warnings;
use URI;
use URI::QueryParam;

sub load {
    my $class = shift;

    Perlbal::register_global_hook('manage_command.proxyhost', sub {
        my $mc = shift->parse(qr/proxyhost\s+(?:(\w+)\s+)?(\S+)\s*=\s*(\S+)$/,
                              "usage: ProxyHost [<service>] <source path> = <dest path>");
        my ($selname, $source, $target) = $mc->args;
        unless ($selname ||= $mc->{ctx}{last_created}) {
            return $mc->err("omitted service name not implied from context");
        }

        my $ss = Perlbal->service($selname);
        return $mc->err("Service '$selname' is not a reverse_proxy service")
            unless $ss && $ss->{role} eq "reverse_proxy";

        $ss->{extra_config}->{_proxyhost} ||= [];
        push @{$ss->{extra_config}->{_proxyhost}}, [ $source, $target ];

        return $mc->ok;
    });

    return 1;
}

sub register {
    my ($class, $svc) = @_;
    unless ($svc && $svc->{role} eq "reverse_proxy") {
        die "You can't load the proxyhost plugin on a service not of role reverse_proxy.\n";
    }

    $svc->register_hook(
        'ProxyHost' => 'start_proxy_request', sub {
            my Perlbal::ClientProxy $client = shift;
            for my $proxyhost ( @{ $svc->{extra_config}->{_proxyhost} } ) {
                my $source = $proxyhost->[0];
                my $target = $proxyhost->[1];
                my $uri = URI->new($client->{req_headers}->request_uri);

                if ( $uri->query_param('hoge') && $client->{req_headers}->header("Host") eq $source ) {
                    $client->{req_headers}->header("Host" => $target);
                }
            }
            return 0;
        }
    );

    return 1;
}

1;


設定ファイル的には

CREATE SERVICE example
    SET role    = reverse_proxy
    SET pool    = example_pool
    SET plugins = ProxyHost
    ProxyHost hoge.intra = proxy.hoge.intra
ENABLE example


こんな感じ。
本当ならHostごとにクエリーのキーを指定できるとよりよいんでしょうが書き捨てなので。

追記:http://github.com/nekokak/Perlbal-Plugin-ProxyHost

githubにあげてみた