Angelos github.com/dann dann
How to develop
Modern WAF
dann
techmemo@gmail.com
YAPC::Asia 2009 2009/09/10
Angelos github.com/dann dann
About Me
•Dann
•Creator of Angelos
•Yet Another WAF
•http://github.com/dann/
Angelos github.com/dann dann
Presentation Overview
•What is modern web application
framework?
•How to develop the minimal
elements of modern WAF
•How to develop the plugin
architecture of WAF
Angelos github.com/dann dann
What is modern WAF?
•Fullstack like Rails
•Pluggable like Plagger
•Server Abstraction like WSGI
•Separete WAF and App
Usability
Extendability
Testability
Angelos github.com/dann dann
How to develop
the basic elements
of WAF
Angelos github.com/dann dann
The basic elements
Component
ManagerDispatcher
Engine
recieve a request and return a
response
(Server Abstraction)
URL to Controller
resolver Load and search component
Angelos github.com/dann dann
Basic Sequence of 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,
);
} psgi handler which is passed to
the server gateay
the type of 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 );
}
pass psgi handler to server
gateway
Create Server Gateway
Angelos github.com/dann dann
Create 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;
}
Create server gateway with
Plack::Loader
Angelos github.com/dann dann
psgi handler s code
...
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;
}
... return PSGI response
recieve PSGI env
and convert it to WAF 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);
}
# return response
return $self->context->res;
}
②dispatch request to
Dispatcher
①recive a request
Angelos github.com/dann dann
Dispatching
sub DISPATCH {
my ( $self, $req ) = @_;
my $dispatch = $self->dispatcher->dispatch($req);
...
$dispatch->run;
# return response
$c->res;
}
② Dispatch a request do
dispatcher
Angelos github.com/dann dann
Angelos::Dispatcher
sub dispatch {
my ( $self, $request ) = @_;
my $match = $self->router->match($request);
my $dispatch = $self->dispatch_class->new( match =>
$match );
return $dispatch;
}
③ <URL to Controller>
search controller name
based on the request path
with HTTP::Router
④ Create dispatch
instance
Angelos github.com/dann dann
Angelos::Dispatcher::Dispatch
my $controller = $match->params->{controller};
my $controller_instance = $self-
>find_controller_instance(
{ context => $c,
controller => $controller,
}
);
...
$controller_instance->_dispatch_action( $action,
$params );
⑤ search a controller
instance from Component
Manager
⑥ execute Controller’s
action and return response.
Angelos github.com/dann dann
Routing
HTTP::Router->define(
sub {
$_->match('/')->to( { controller => 'Root', action
=> 'index' } );
$_->resources('Book');
}
);
conf/routes.pl- define routing information
Angelos github.com/dann dann
Routing Table
.----------------------------------------------+------------+------------+--------------.
| path | method | controller | action |
+---------------------------------------------+------------+------------+------------+
| / | | Root | index |
| /book.{format} | POST | Books | create |
| /book | POST | Books | create |
| /book.{format} | GET | Books | index |
| /book | GET | Books | index |
| /book/new.{format} | GET | Books | post |
| /book/new | GET | Books | post |
| /book/{book_id}.{format} | GET | Books | show |
| /book.{format} | POST | Books | create |
| /book | POST | Books | create |
| /book.{format} | GET | Books | index |
| /book.{bookk_id}.{format} | DELETE | Books | destroy |
| /book/{book_id} | DELETE | Books | destroy |
| /book/{book_id}.{format} | PUT | Books | update |
| /book/{book_id} | PUT | Books | update |
'-----------------------------------------------+------------+------------+-------------
Angelos github.com/dann dann
Finished developing basic
elements of WAF
•It’s really easy to develop basic
elements of WAF
•You can develop simple WAF
like Sinatra in 4 or 5 hours
Angelos github.com/dann dann
How to develop the plugin
architecture of WAF
Angelos github.com/dann dann
How to development the plugin
architecture of WAF
• What the plugin architecture of WAF
SHOULD be
• The type of Plugins
• How to develop plugin architecture of
WAF
• Example: the plugin of Angelos
Angelos github.com/dann dann
What the plugin architecture of WAF SHOULD
• the core elements of WAF should be as
small as possible and the all parts of WAF
should be extendable and pluggable
• The scope of plugin should be limeted
• Controller,View, Middleware, Request,
Response
• Extension point must be declaretive
Angelos github.com/dann dann
The types of Plugins
•Hook WAF’s Lifecycle
•Add methods to WAF’s class
Angelos github.com/dann dann
Plugin Implementation
• Hook WAF’s lifecycle
• Mouse’s Role + method modifier
• Class::Trigger
• MouseX::Object::Pluggable
• Add methods to WAF’s classes
• Mouse’s Role
• Exporter
• Multiple inheritance
Angelos github.com/dann dann
How to develop plugin in Angelos
• Make Plugin as Role
• User consume plugins in the WAF Component
• Hook WAF’s lifecycle with method modifier
• hook Component’s hook point
• Declare hook point method with CAPITAL
character
Angelos github.com/dann dann
Hook point example
sub _dispatch_action {
my ( $self, $action, $params ) = @_;
...
eval { $self->ACTION( $self->context, $action, $params ); };
...
}
Declare hook point with
Capital character
Angelos github.com/dann dann
the code of Plugin
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
secsn";
$self->log->info($message);
};
Angelos github.com/dann dann
What The WAF developer should do
• WAF developer should make default plugin sets
which user should use
• if there aren’t default plugins sets...
• How can I use Unicode in WAF?
• ... UseXXX,YYY...
• How can I inflate datetime? ...
Angelos github.com/dann dann
Conclusion
• The basic elements of WAF
• Engine, Dispatcher, Component Loader
• WAF’s plugin
• Hook WAF Lifecycle or add a Method to the
Component of WAF
• Plugin Scope must be limited
• the plugin and plugins default sets should be
provided by WAF developer
Angelos github.com/dann dann
Fin.
• It’s really easy to implement WAF now
• Let’s develop modern WAF with us ;)
• Repository
• http://github.com/dann/angelos/tree/master

How to develop modern web application framework

  • 1.
    Angelos github.com/dann dann Howto develop Modern WAF dann [email protected] YAPC::Asia 2009 2009/09/10
  • 2.
    Angelos github.com/dann dann AboutMe •Dann •Creator of Angelos •Yet Another WAF •http://github.com/dann/
  • 3.
    Angelos github.com/dann dann PresentationOverview •What is modern web application framework? •How to develop the minimal elements of modern WAF •How to develop the plugin architecture of WAF
  • 4.
    Angelos github.com/dann dann Whatis modern WAF? •Fullstack like Rails •Pluggable like Plagger •Server Abstraction like WSGI •Separete WAF and App Usability Extendability Testability
  • 5.
    Angelos github.com/dann dann Howto develop the basic elements of WAF
  • 6.
    Angelos github.com/dann dann Thebasic elements Component ManagerDispatcher Engine recieve a request and return a response (Server Abstraction) URL to Controller resolver Load and search component
  • 7.
    Angelos github.com/dann dann BasicSequence of WAF ② ① ③ ④ ⑤ ⑥
  • 8.
    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, ); } psgi handler which is passed to the server gateay the type of server gateway
  • 9.
    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 ); } pass psgi handler to server gateway Create Server Gateway
  • 10.
    Angelos github.com/dann dann CreateServer 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; } Create server gateway with Plack::Loader
  • 11.
    Angelos github.com/dann dann psgihandler s code ... 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; } ... return PSGI response recieve PSGI env and convert it to WAF Request
  • 12.
    Angelos github.com/dann dann RequestHandler - Angelos::Engine::Base sub handle_request { my ( $self, $req ) = @_; eval { $self->DISPATCH($req); }; if ( my $e = Exception::Class->caught() ) { $self->HANDLE_EXCEPTION($e); } # return response return $self->context->res; } ②dispatch request to Dispatcher ①recive a request
  • 13.
    Angelos github.com/dann dann Dispatching subDISPATCH { my ( $self, $req ) = @_; my $dispatch = $self->dispatcher->dispatch($req); ... $dispatch->run; # return response $c->res; } ② Dispatch a request do dispatcher
  • 14.
    Angelos github.com/dann dann Angelos::Dispatcher subdispatch { my ( $self, $request ) = @_; my $match = $self->router->match($request); my $dispatch = $self->dispatch_class->new( match => $match ); return $dispatch; } ③ <URL to Controller> search controller name based on the request path with HTTP::Router ④ Create dispatch instance
  • 15.
    Angelos github.com/dann dann Angelos::Dispatcher::Dispatch my$controller = $match->params->{controller}; my $controller_instance = $self- >find_controller_instance( { context => $c, controller => $controller, } ); ... $controller_instance->_dispatch_action( $action, $params ); ⑤ search a controller instance from Component Manager ⑥ execute Controller’s action and return response.
  • 16.
    Angelos github.com/dann dann Routing HTTP::Router->define( sub{ $_->match('/')->to( { controller => 'Root', action => 'index' } ); $_->resources('Book'); } ); conf/routes.pl- define routing information
  • 17.
    Angelos github.com/dann dann RoutingTable .----------------------------------------------+------------+------------+--------------. | path | method | controller | action | +---------------------------------------------+------------+------------+------------+ | / | | Root | index | | /book.{format} | POST | Books | create | | /book | POST | Books | create | | /book.{format} | GET | Books | index | | /book | GET | Books | index | | /book/new.{format} | GET | Books | post | | /book/new | GET | Books | post | | /book/{book_id}.{format} | GET | Books | show | | /book.{format} | POST | Books | create | | /book | POST | Books | create | | /book.{format} | GET | Books | index | | /book.{bookk_id}.{format} | DELETE | Books | destroy | | /book/{book_id} | DELETE | Books | destroy | | /book/{book_id}.{format} | PUT | Books | update | | /book/{book_id} | PUT | Books | update | '-----------------------------------------------+------------+------------+-------------
  • 18.
    Angelos github.com/dann dann Finisheddeveloping basic elements of WAF •It’s really easy to develop basic elements of WAF •You can develop simple WAF like Sinatra in 4 or 5 hours
  • 19.
    Angelos github.com/dann dann Howto develop the plugin architecture of WAF
  • 20.
    Angelos github.com/dann dann Howto development the plugin architecture of WAF • What the plugin architecture of WAF SHOULD be • The type of Plugins • How to develop plugin architecture of WAF • Example: the plugin of Angelos
  • 21.
    Angelos github.com/dann dann Whatthe plugin architecture of WAF SHOULD • the core elements of WAF should be as small as possible and the all parts of WAF should be extendable and pluggable • The scope of plugin should be limeted • Controller,View, Middleware, Request, Response • Extension point must be declaretive
  • 22.
    Angelos github.com/dann dann Thetypes of Plugins •Hook WAF’s Lifecycle •Add methods to WAF’s class
  • 23.
    Angelos github.com/dann dann PluginImplementation • Hook WAF’s lifecycle • Mouse’s Role + method modifier • Class::Trigger • MouseX::Object::Pluggable • Add methods to WAF’s classes • Mouse’s Role • Exporter • Multiple inheritance
  • 24.
    Angelos github.com/dann dann Howto develop plugin in Angelos • Make Plugin as Role • User consume plugins in the WAF Component • Hook WAF’s lifecycle with method modifier • hook Component’s hook point • Declare hook point method with CAPITAL character
  • 25.
    Angelos github.com/dann dann Hookpoint example sub _dispatch_action { my ( $self, $action, $params ) = @_; ... eval { $self->ACTION( $self->context, $action, $params ); }; ... } Declare hook point with Capital character
  • 26.
    Angelos github.com/dann dann thecode of Plugin 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 secsn"; $self->log->info($message); };
  • 27.
    Angelos github.com/dann dann WhatThe WAF developer should do • WAF developer should make default plugin sets which user should use • if there aren’t default plugins sets... • How can I use Unicode in WAF? • ... UseXXX,YYY... • How can I inflate datetime? ...
  • 28.
    Angelos github.com/dann dann Conclusion •The basic elements of WAF • Engine, Dispatcher, Component Loader • WAF’s plugin • Hook WAF Lifecycle or add a Method to the Component of WAF • Plugin Scope must be limited • the plugin and plugins default sets should be provided by WAF developer
  • 29.
    Angelos github.com/dann dann Fin. •It’s really easy to implement WAF now • Let’s develop modern WAF with us ;) • Repository • http://github.com/dann/angelos/tree/master