独自の認証機能付き HTTP ダウンローダを提供するために、nginx の組み込み Perl を使ってみました。
公式のドキュメントはこちら。EmbeddedPerlModule - Nginx Community
自前の handler でリクエストをみて処理を行い、許可するなら DECLINED を返して後続の処理に任せる。そうでなければ Fobidden を返しておしまい、という流れです。
package MyAuth; use strict; use warnings; use nginx; sub handler { my $r = shift; if ( $r->header_in("MyAuth") ) { # なにか独自の認証をする(ここではリクエストヘッダを見るだけ return DECLINED; # 処理を継続させるために DECLINED } $r->status( HTTP_FORBIDDEN ); # 失敗したら FORBIDDEN $r->send_http_header; $r->print("403 Forbidden"); return OK; } 1;
nginx.conf はこんな感じで。
events { use epoll; } http { sendfile on; perl_modules /home/fujiwara/lib; perl_require MyAuth.pm; server { listen 80; location /download/ { perl MyAuth::handler; alias /var/www/download/; } } }
もちろん DECLINED を返さないで、自前でファイル配信まで処理することもできます。
$r->sendfile($path); でファイル内容を返すことは簡単にできるのですが、真面目にやろうとすると条件付き GET (If-Modified-Since) とか Range ヘッダ付きのリクエストに Partial Content を返すとか、なにかと面倒なので DECLINED で通常の nginx のハンドラに全部任せました。
ab でベンチマークを取ってみたところ、例のように $r->header_in を参照するだけの処理ならばオーバーヘッドはほぼ無視できるぐらいでした。測定誤差程度です。
ただし注意点があって、組み込み Perl は worker_processes の数 (default: 1) しか同時に動けません。そのため、途中でブロックするような処理 (外部へ HTTP リクエストを飛ばしたり) をすると極端に並列性が落ちるので、そこは要注意ですね。