CloudForecastや先日のNoPasteではPlack::Builderを使って、デフォルトの機能としてPlack::Middleware::ReverseProxyを有効にしている。

my @frontproxy = map { s/\s//g } split(/,/, $ENV{FRONT_PROXY} || "");
foreach my $ip ( @frontproxy ) {
    my $netip = Net::IP->new($ip) or die;
    push @frontproxies, $netip;
}
buider {
    enable_if {
        my $addr = $_[0]->{REMOTE_ADDR};
        my $netip;
        if ( defined $addr && ($netip = Net::IP->new($addr)) ) {
            for my $proxy ( @frontproxies ) {
                my $overlaps = $proxy->overlaps($netip);
                return 1 if ( $overlaps == $IP_B_IN_A_OVERLAP || $overlaps == $IP_IDENTICAL );
            }
        }
        return;
    } "Plack::Middleware::ReverseProxy";
    $app;
}

このように環境変数FRONTPROXYにReverse ProxyのIP帯域(アドレス)をいれ、Plack::Builderのenableifを使って、REMOTE_ADDRがその帯域にあれば、Middlewareを有効にするような方法をとっている。

このようなenable_ifはなんども書きそうなので、モジュールにしておいた方がいいんじゃないかと思い、書いてみた。

github: http://github.com/kazeburo/Plack-Builder-Conditionals

使い方は

use Plack::Builder;
use Plack::Builder::Conditionals;
# exports "match_if, addr, path, method, header, any, all"

builder {
    enable match_if addr(['192.168.0.0/24','127.0.0.1']),
        "Plack::Middleware::ReverseProxy";
    $app
 }

な、感じ。コードの見通しが良くなりました。

Plack::Builder::Conditionalsを利用するには、enableのあとに、matchif をおきます。matchifは内部的にPlack::Middleware::Conditionalを使っていてあとに続く条件によってMiddlewareを有効にするかの判断をします。

条件でとして、REMOTEADDRの検証を行う「addr」、PATHINFOをみる「path」、REQUEST_METHODの「method」、そして任意のヘッダを確認するための「header」のメソッドが用意されています。これに加えて複合的な条件の実現するための「all」と「any」もあります。

# REMOTE_ADDRの帯域を調べる
addr([qw!192.168.0.0/24 127.0.0.1!]);

# PATH_INFO
path('/')
path(qr!^/(\w+)/!)

#REQUEST_METHOD
method('GET')
method(qr!/^(get|head)$/!)

# 任意のヘッダ
header('User-Agent',qr/iphone/i)
header('If-Modified-Since') #ヘッダがあれば真

# REQUEST_METHODがGETかつ、PATH_INFOが/static以下
all( method('GET'), path(qr!^/static!) )

# PATH_INFOが/static以下もしくは、/favicon.ico
any( path(qr!^/static!), path('/favicon.ico') )

このように任意の条件を組み合わせても使えます。また、否定の条件の場合は

addr('!','127.0.0.1'); #localhostではない
path('!', qr!^/private($|/)!) #/private以下ではない
method('!','GET')
header('!', 'User-Agent',qr/MSIE/)

最初の引数として、「!」を渡します。

非常に簡単なメソッド名を利用しているため、アプリケーションによっては重なってしまうことも考えられます。その際はimport時に メソッド名にprefixを追加することができます。

use Plack::Builder::Conditionals -prefx => 'c'; #prefixに「c」追加
# exports "c_match_if, c_addr, c_path, c_method, c_header, c_any, c_all"

このブログ記事について

このページは、Masahiro Naganoが2010年7月16日 01:04に書いたブログ記事です。

ひとつ前のブログ記事は「バスのミニカー買った」です。

次のブログ記事は「キャッシュを制御してサイトの高速化を実現するAapcheモジュールmod_expiresのPlack版をリリースしました」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

OpenID対応しています OpenIDについて
Powered by Movable Type 4.27-ja