Plackで使うmiddlewareを書いてみた
補足)2011-06-13
下で書いているmiddlewareはレスポンスにファイルハンドルが渡ってくる事を考慮していない問題があります。 参考にしてる人はいないと思いますが念の為。 又このレイヤーでencodeとかするべきではないと思います。
最初に
PSGI(Perl Server Gateway Interface)というのは、RubyのRackやPythonのWSGIにあたる、WebサーバーとWebアプリケーションフレームワーク(WAF)とを仲立ちするプロトコルです。
Webサーバー側のインターフェース実装とWebアプリケーションやWAFの結節点となるFacadeのようなものであり、これによってWAF毎にインターフェース実装を行わなくて済むようになり、壮大なDRY(Don't Repeat Yourself)が達成されるという具合です。
Plackというのは、そのPSGI仕様のリファレンス実装なのです。
Plackを使うと何が嬉しいかと言うとPlackに乗っておけば楽できるよ!!って事だと思います。
で最近になりPlackを使って簡単なWAFを書いてたりするんですが日本語を扱う上で避けて通れないencode処理です。 middlewareにあるよなと思い探しても無いっぽい?
ならばと試しにmiddleware書いてみました。
WAF内部では全て Flagged UTF8 で処理してmiddleware側でよきに計らってくれるモジュールを目指しました。
もう少し説明するとレスポンスヘッダーにエンコードの指定をしておけばmiddlewareがヘッダを見てencodeしてくれます。
なのでWAF側ではencode処理は一切気にせず済むと言う訳です。
最初はWAF側で全部encodeまでやってたのですがPlack側でも出来るだろと思いこの方法に落ち着きました。
これを使うことでWAF側がちょっとだけコンパクトになり見やすくなりましたよ。
需要はほとんど無いと思いますがせっかくなので晒しておきます。
使い方
my $app = MyApp->new();
builder {
enable "Plack::Middleware::XEncode",
default_encode => "utf8",
module => 'Encode';
$app->psgi_handler;
};
コード
package Plack::Middleware::XEncode;
use strict;
use warnings;
use parent qw(Plack::Middleware);
use Plack::Util ();
use Scalar::Util ();
use Encode qw(encode);
use Plack::Util::Accessor qw( module default_encode );
our $VERSION = '0.01';
my $module;
sub call {
my ( $self, $env ) = @_;
my $res = $self->app->($env);
$module or do {
$module = $self->module || "Encode";
Plack::Util::load_class($module) if $module ne "Encode";
};
$self->response_cb(
$res,
sub {
my $res = shift;
return unless defined $res->[2];
if ( !Scalar::Util::blessed( $res->[2] ) && defined $res->[2]->[0] )
{
my $h = Plack::Util::headers( $res->[1] );
my $encoding =
$h->get('X-Encode')
|| $self->default_encode
|| "utf-8";
my $encode_txt = Encode::encode( $encoding, $res->[2]->[0] );
$res->[2] = [$encode_txt];
$h->set( 'Content-Length', length $encode_txt );
}
}
);
}
1;
__END__
=head1 NAME
Plack::Middleware::XEncode -
=head1 SYNOPSIS
enable "Plack::Middleware::XEncode",
# given used Encode module name. default is 'Encode'
module => 'Encode::JP::Mobile',
# given encoding name. default is 'utf8'
default_encode => "x-utf8-kddi",
ex1)
builder {
enable "Plack::Middleware::XEncode",
default_encode => "shift_jis";
$app->psgi_handler;
};
ex2)
builder {
enable "Plack::Middleware::XEncode",
default_encode => "x-utf8-kddi",
module => 'Encode::JP::Mobile';
$app->psgi_handler;
};
=head1 DESCRIPTION
Plack::Middleware::XEncode is fainal response body Encoding.
response body Shift_JIS encode when response header add ('X-Encode' => 'shift_jis')
default encode is utf-8.
=head1 AUTHOR
Tooru Midorikawa Etooru@omakase.orgE
=head1 SEE ALSO
=head1 LICENSE
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
Plack::Util::Accessor に対応させました。2009-12-22