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"