時代もhtml5になって、音声とか動画であればブラウザの標準機能だけで再生できる時代になって久しいですが、認証をつけたいとかの理由でvideoタグに使うファイルの配信をPlackでやるときの注意点みたいなの。
htmlのvideoタグの動作
src属性に指定したコンテンツを一括で取りにいって再生しているのかと思いきや違って以下の動作をする。
src属性のファイルに対してRangeヘッダをつけたリクエストを発行する
↓
206(Partial Content)
が返ってくる(事を期待する)
↓
そのあと再度src属性のファイルを全部取ってくる
(206についてはここらへんを参照。)
最初のリクエストでファイルの長さとかファイルの種類を取得して、その上で再生をするという仕組みではないかと思われる。 (要出典)
Plackではrangeリクエストが対応していないようで、一回目のヘッダにrangeが含まれるリクエストを投げても200を返される事となり、その結果videoタグで再生されない。
nginxなどのフルスタックなサーバであるとここらへんはしっかり実装されており、documentrootなどの静的なファイルを置く場所に置いて配信すると普通にvideoタグは動作する。
いや、rangeに対応させる手段が無い訳ではない
どっちなんだよという話ですが。
Rangeに対応させるPlackのmidlewareはPlack::Middleware::Static::Rangeというのが存在する。
で、意気揚々とcpanm Plack::Middleware::Static::Range
と打つ訳ですがエラーが出る訳です。
cpanm (App::cpanminus) 1.7001 on perl 5.020000 built for darwin-2level
Work directory is /Users/agile/.cpanm/work/1428416540.25616
You have make /usr/bin/make
You have LWP 6.06
You have /usr/bin/tar: bsdtar 2.8.3 - libarchive 2.8.3
You have /usr/bin/unzip
Searching Plack::Middleware::Static::Range on cpanmetadb ...
--> Working on Plack::Middleware::Static::Range
Fetching http://www.cpan.org/authors/id/A/AU/AUDREYT/Plack-Middleware-Static-Range-0.01.tar.gz
-> OK
Unpacking Plack-Middleware-Static-Range-0.01.tar.gz
Entering Plack-Middleware-Static-Range-0.01
Checking configure dependencies from META.yml
Checking if you have ExtUtils::MakeMaker 6.42 ... Yes (6.98)
Configuring Plack-Middleware-Static-Range-0.01
Running Makefile.PL
Cannot determine license info from lib/Plack/Middleware/Static/Range.pm
Warning: prerequisite PerlIO::subfile 0 not found.
Checking if your kit is complete...
Looks good
Generating a Unix-style Makefile
Writing Makefile for Plack::Middleware::Static::Range
Writing MYMETA.yml and MYMETA.json
-> OK
Checking dependencies from MYMETA.json ...
Checking if you have parent 0 ... Yes (0.228)
Checking if you have ExtUtils::MakeMaker 6.42 ... Yes (6.98)
Checking if you have Plack::Middleware 0 ... Yes (undef)
Checking if you have PerlIO::subfile 0 ... No
Checking if you have HTTP::Message 0 ... Yes (6.06)
==> Found dependencies: PerlIO::subfile
Searching PerlIO::subfile on cpanmetadb ...
--> Working on PerlIO::subfile
Fetching http://www.cpan.org/authors/id/N/NW/NWCLARK/PerlIO-subfile-0.08.tar.gz
-> OK
Unpacking PerlIO-subfile-0.08.tar.gz
Entering PerlIO-subfile-0.08
Checking configure dependencies from META.yml
Configuring PerlIO-subfile-0.08
Running Makefile.PL
You need perl 5.7.1 or later, configured to use perlio (and not to use sfio)
Yes, this module is currently only suitable for the development branch of
perl
Note
1: The features required for layers have only recently been added to
development perl, so if your doesn't have the header perliol.h it's
too old
2: The perlio layers API has changed (at least once) between the initial
version and 5.7.1, and may well change again. If so, it is quite
possible that this module will fail to compile.
-> N/A
-> FAIL Configure failed for PerlIO-subfile-0.08. See /Users/agile/.cpanm/work/1428416540.25616/build.log for details.
-> FAIL Installing the dependencies failed: Module 'PerlIO::subfile' is not installed
-> FAIL Bailing out the installation for Plack-Middleware-Static-Range-0.01.
Expiring 7 work directories.
Plack::App::File::Rangeの仕組み
Plack::Middleware::Static::Range
内で使われているPlack::App::File::Range内でこういうコードがあります。
open my $fh, "<:raw:subfile(start=$start,end=".($end+1).")", $file
openの第三引数に :moge
みたいな形式で指定するのはPerlIOの機能を使うためのものです。
ある程度のPerl使いなら:encoding(sjis)
とか :utf8
とか指定した事があるかと思いますが、それを自作するための仕組みがPerlIOなわけです。
で、上記では:subfile
という標準でないPerlIOのレイヤーを使っている訳ですが、その実態はPerlIO::subfileです。
PerlIO::subfile
のSYNOPSISを見ると一目瞭然ですが
use PerlIO::subfile;
open FOO, "<:subfile(start=123,end=+43)", "bigfile" or die $!;
print while <FOO>; # Just prints the specified subsection of the file
seek (FOO, 0, SEEK_SET) # Takes you to offset 123 in bigfile.
あるファイルの取得したい範囲を:subfile
レイヤーで指定すると、その範囲のみを取得するファイルハンドルを作成してくれるというPerlIOレイヤーなわけです。ファイルハンドルを返せばファイルハンドルの内容をcontentにしてくれるPlackの仕組みと相性がいい訳ですね。
エラーの原因
PerlIOを使っていると分かったところで、先ほどのエラーログを見返してみるとこう出力されている訳です。
1: The features required for layers have only recently been added to
development perl, so if your doesn't have the header perliol.h it's
too old
PerlIOは開発版のperlじゃねぇと使えねぇよバーーーーカwwwwwww
開発版のperlを本番環境で置く事は無いと思うのでつかえないというわけです。
おしまい。
まとめ
Plackでは現在のところ、Rangeヘッダに対応していない。正し開発版のperlを使えば出来る事は出来る。
これをやりたかった背景として、取りためた動画やラジオをブラウザのみで見れるようにしたいというもくろみがあったのですが、この前ふとenclosureなRSSを書いてPodcastに読ませてみたら普通に音声を再生できたのでもういらなくなったという消極的理由もあったりはする。