Upload
techmemo
View
3.002
Download
2
Embed Size (px)
Citation preview
Angelos github.com/dann dann
優しいモダンなWAFの作り方
YAPC::Asia 2009 2009/09/10
Angelos github.com/dann dann
About Me•Dann•Creator of Angelos (WAF)• http://github.com/dann/angelos/tree/master
• For English Speakers• http://www.slideshare.net/techmemo/how-to-develop-modern-web-application-framework-1973871
Angelos github.com/dann dann
Presentation Overview
•モダンなWAFとは•モダンなWAFの基本構成要素の作り方•モダンなWAFの拡張の作り方•まとめ
Angelos github.com/dann dann
モダンなWAFとは
•Plaggerのようにプラガブル•WSGIのようなサーバー抽象化•Railsのようにフルスタック ユーザービリティ
拡張性
テスタビリティ
Angelos github.com/dann dann
WAFの基本構成要素の作り方
Angelos github.com/dann dann
WAFの最小構成要素
ComponentManagerDispatcher
Enginerequestを受けてresponseを返す
(サーバー抽象化 with Plack)
miyagawa++, tokuhirom++
URL to Controller名 コントローラなどのComponentのload & search
Angelos github.com/dann dann
WAFの基本処理シーケンス
②①
③
④⑤
⑥
テキスト
Angelos github.com/dann dann
Engine - Angelos::Engine
sub build_engine { my $self = shift; my $request_handler = $self->request_handler; $request_handler ||= $self->build_request_handler;
return Angelos::PSGI::Engine->new( interface => { module => $self->server, .... }, psgi_handler => $request_handler, ); }
リクエストを受けて、レスポンスを返すEngine(サーバー抽象化)
Server Gatewayに渡すpsgiのhandler
Server Gatewayの種別
Angelos github.com/dann dann
Engine - Angelos::PSGI::Engine
use Mouse;use Angelos::Types qw( ServerGateway ); has 'interface' => ( is => 'ro', isa => ServerGateway, coerce => 1,); has 'psgi_handler' => ( is => 'rw', ); sub run { my $self = shift; $self->interface->run( $self->psgi_handler );}
Server Gatewayにpsgiのhandler (coderef)
を渡して実行
Server Gateway作成
Angelos github.com/dann dann
Server Gatewayの生成
package Angelos::PSGI::ServerGatewayBuilder;use strict;use warnings;use Plack::Loader;
sub build { my ( $class, $module, $args ) = @_; my $server_gateway = Plack::Loader->load( $module, %{$args} ); $server_gateway;}
Plack::LoaderでServerGateway名渡して生成
Plack::Loaderでmodule指定してload
Angelos github.com/dann dann
psgi handlerのコード
...sub { my $env = shift; my $req = Angelos::Request->new($env); my $res = $self->handle_request($req); my $psgi_res = $self->finalize_response($res); return $psgi_res;}... PSGIのresponse形式にして返す
PSGIのenvを受け取ってWAFのRequestに
(with Plack::Request)
Angelos github.com/dann dann
Request Handler - Angelos::Engine::Base
sub handle_request { my ( $self, $req ) = @_;
eval { $self->DISPATCH($req); }; if ( my $e = Exception::Class->caught() ) { $self->HANDLE_EXCEPTION($e); }
# responseを返す return $self->context->res;}
②reqをDsipatcherでディスパッチ
①リクエスト受信
Angelos github.com/dann dann
ディスパッチ処理sub DISPATCH { my ( $self, $req ) = @_;
my $dispatch = $self->dispatcher->dispatch($req); ...
# dispatch処理を実行 $dispatch->run;
# responseを返す $c->res;}
②requestをDispatcherにdispatch
Angelos github.com/dann dann
Angelos::Dispatchersub dispatch { my ( $self, $request ) = @_;
my $match = $self->router->match($request);
my $dispatch = $self->dispatch_class->new( match => $match ); return $dispatch;}
③ <URL to Controller>HTTP::Routerでrequestにマッチするrouteを取得 (ikasam_a++)
④ dispatch生成
Angelos github.com/dann dann
Angelos::Dispatcher::Dispatch
# matching情報からcontroller名取得my $controller = $match->params->{controller};
my $controller_instance = $self->find_controller_instance( { context => $c, controller => $controller, }); ...
$controller_instance->_dispatch_action( $action, $params );
⑤Component ManagerからController検索
⑥Controllerのaction実行後レスポンスを返す
Angelos github.com/dann dann
WAFの基本部分完成
•これで基本部分は完成です•シンプルなWAFは2-3時間あれば作れちゃいます
Angelos github.com/dann dann
WAFの拡張部分の作り方(Plugin)
Angelos github.com/dann dann
優しいプラグインの作り方
•WAFの拡張性のあるべき姿•プラグインの種類•プラグインの実現方法の種類•Angelosでのプラグインの作り方
Angelos github.com/dann dann
WAFの拡張性のあるべき姿
•コアは小さく、何でも拡張/交換可能に•拡張箇所を限定し、適切な箇所を拡張可能に
•Controller, View, Middleware, Request, Response
•Hookポイントを明示的に
Angelos github.com/dann dann
プラグインの種類
•大きく分けて二つ•ライフサイクルへのHook系•メソッド生やす系
Angelos github.com/dann dann
プラグインの実現方法•ライフサイクルへのHook系•MouseのRole + method modifier•Class::Trigger•MouseX::Object::Pluggable•メソッド生やす系•MouseのRole•Exporter•多重継承
Angelos github.com/dann dann
Angelosでのプラグイン機構の作り方•Pluginを Roleに•Plugin(Role)は Component(たとえばController)にwithすることで使う
•HookポイントとしてのModifier•RoleのmodifierでComponentのHook point(メソッド)にHook
•Hook pointの明示をメソッド名の規約(大文字)で
Angelos github.com/dann dann
Hookが定義されているControllerのコード
sub _dispatch_action { my ( $self, $action, $params ) = @_; ...
eval { $self->ACTION( $self->context, $action, $params ); }; ...
}
Hookポイントを明示(大文字で)
Angelos github.com/dann dann
プラグインのコードbefore 'ACTION' => sub { my ( $self, $c, $action, $params ) = @_; $self->__action_start_time( time() );};
after 'ACTION' => sub { my ( $self, $c, $action, $params ) = @_; $self->__action_end_time( time() );
my $elapsed = $self->__action_end_time - $self->__action_start_time; my $message = "action processing time:\naction: $action \ntime : $elapsed secs\n"; $self->log->info($message);};
Angelos github.com/dann dann
拡張を提供したときにセットですべきこと
•適切なデフォルトセットの提供•WAF全体の拡張の推奨セットを用意する•デフォルトセットが無いと...•Unicode化するためのTipsが乱立...•Inflate, DeflateするためのTipsが...
Angelos github.com/dann dann
まとめ•WAFの基本構成要素•Engine, Dispatcher, Component Loader
•WAFの拡張(Plugin)•Hook系とメソッド生やす系の二つ•Scopeを限定してComponent毎に用意•Pluginとデフォルトセットはペアで
Angelos github.com/dann dann
最後に•WAF作りがかつてないほど簡単に!•次の世代のWAFに興味のある方は開発にも是非ご参加ください :)
•開発はgithubで•http://github.com/dann/angelos/tree/master