@nqounetです。

Perlの仕事で、Amon2を使ってサイトを作っていました。

その際に、動画ファイルをログイン中しか見れないようにするために、動画ファイルを直接送信する必要がありました。

その時に使った便利なモジュールを紹介します。

Plack::App::File::Range

range

Plack::App::File::Range - Serve static files with support for Range requests

Plack::App::File::Rangeは、レスポンスをHTTPのRange対応にしてくれるモジュールです。

あまり難しいことはわかりませんが、動画などを直接送信する場合には使っておいたほうが良いです。

簡単な使い方

本来はPSGIアプリとしてそのまま使えるのですが、認証を通してから送信したいので、Amon2のコントローラーの中でレスポンス全体を作成しています。

1
2
3
4
5
6
7
8
9
10
11
12
# Amon2のコントローラーと思ってください
# 簡素化のため色々と省いています
sub contents {
my ($class, $c, $args) = @_;
my $id = $args->{id};
my $row = $c->db->single('movies', {id => $id});
my $path = path($row->content_path);
return $c->res_404 unless $path->is_file;
my $refs = Plack::App::File::Range->new->serve_path($c->req->env,
$path->stringify);
return $c->create_response(@$refs);
}

説明的に言うと、Plack::App::File::Rangeのインスタンスからserve_pathメソッドに「PSGI環境変数」と「送信したいファイルのパス」を渡すと、HTTPのRangeに対応したPSGI仕様のレスポンスが返ってきます。

そして、Amon2のコントローラーの、create_responseメソッドを使ってそのレスポンスをそのまま返してやります。

リファレンスのまま渡す方法もあるのかもしれませんが、そのレベルには到達できませんでした。

WAFのあるべき姿の一つ

Amon2で、コントローラーから直接レスポンスを返せるのは良いと思いました。

何かをラップするようなモジュールは、いざという時のためにラップしない手段を持っておく、ということが結構大事だなと感じました。

例えば、全てがrender_*のようなものを経由する必要があった場合、Plack::App::File::Rangeみたいなモジュールは使えなかったわけで、泣きながらRangeに対応していたことでしょう。