Plack basics for Perl websites - YAPC::EU 2011
-
Upload
leo-lapworth -
Category
Technology
-
view
20.636 -
download
3
description
Transcript of Plack basics for Perl websites - YAPC::EU 2011
Plack Basics
Leo Lapworth @ YAPC::EU 2011
Much content from Tatsuhiko Miyagawa’sYAPC::NA 2010 talk
What is Plack?
What is Plack?
“Superglue for Perl 5 Web Frameworks and Web
Servers”
How will that help me?
How will that help me?‣ Flexibility
How will that help me?‣ Flexibility
‣ Middleware (plugins)
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
‣ Development
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
‣ Development
‣ Testing
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
‣ Development
‣ Testing
‣ Deployment
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
‣ Development
‣ Testing
‣ Deployment
‣ World peace
How will that help me?‣ Flexibility
‣ Middleware (plugins)
‣ Apps
‣ Development
‣ Testing
‣ Deployment
‣ World peace
History...
Hello World
#!/usr/bin/perluse strict;
print “Content-Type: text/plain\r\n\r\n”;print “Hello World”;
package HelloWorld;use strict;use Apache::RequestRec;use Apache::RequestIO;use Apache::Const -compile => qw(OK);
sub handler { my $r = shift;
$r->content_type(‘text/plain’); $r->print(“Hello World”);
return Apache::Const::OK;}
1;
use FCGI;
my $req = FCGI::Request();
while ($req->Accept >= 0) {
print “Content-Type: text/plain\r\n\r\n”; print “Hello World”;
}
package HelloWorld;use base qw(HTTP::Server::Simple::CGI);
sub handle_request { my($self, $cgi) = @_;
print “HTTP/1.0 200 OK\r\n”; print “Content-Type: text/plain\r\n\r\n”; print “Hello World”;}
1;
All similar but slightly different
Painful to supportall of them
There wasone common way to do all of this.
CGI.pm
#!/usr/bin/perluse CGI;
my $q = CGI->new;
print $q->header(‘text/plain’);print “Hello World”;
Works under...CGI
FastCGImod_perl
HTTP::Server::Simple::CGI
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
CGI.pm?
CGI.pm?meh
Frameworks to the rescue!
Catalyst Maypole Mason Mojo Sledge Spoon PageKit AxKit Egg Gantry Continuity Solstice Mojolicious Tripletail Konstrukt Reaction Jifty Cyclone3 WebGUI OpenInteract Squatting
Dancer CGI::Application Nanoa Ark Angelos Noe Schenker Tatsumaki Amon
Apache2::WebApp Web::Simple Apache2::REST SweetPea Hydrant Titanium
Let’s look how they handled web servers.
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
CGI::Application
Apache IIS lighttpd
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
Jifty
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
Jifty Catalyst
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
Jifty Catalyst
Catalyst::Engine
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
Jifty Catalyst
Catalyst::Engine
nginx
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
Jifty Catalyst
Catalyst::Engine
nginxHTTP::Server::Simple
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
JiftyMason Catalyst
Catalyst::Engine
nginxHTTP::Server::Simple
CGI::Application
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
JiftyMason Catalyst
Mason::CGIHandlerCatalyst::Engine
nginxHTTP::Server::Simple
Gross.
CGI.pmJifty, CGI::Application, Spoon
mod_perl centricMason, Sledge, PageKit, WebGUI
AdaptersCatalyst, Maypole, Squatting
That was 2008...
Gentleman thief &Double agent
Miyagawa
Acquired a great ideafrom Python/Ruby
WSGI (Python)Rack (Ruby)
WSGI (PEP-333)
WSGI Python Frameworks• Django
• Bottle
• CherryPy
• Tornado
• Pylons
• Flask
• mod_wsgi
• Paste
• gunicorn
• uWSGI
• wsgiref
• Google AppEngine
WSGI
WSGI middleware
Django Bottle Flask Tornado
Apache lighttpd nginx mod_wsgi
wsgi handlers
GAE
Rack
Rack Ruby Frameworks• Rails
• Merb
• Sinatra
• Camping
• Ramaze
• etc.
• Unicorn
• Thin
• Mongrel
• Rainbows!
• Phusion Passenger
• Heroku
Rack
Rack middleware
Rails Merb Sinatra Ramaze
Apache lighttpd Thin Unicorn
Rack handlers
Mongrel
Perl ?
Perl ?PSGIPerl Web Server Gateway Interface
Interface
Interface
InterfacePSGI != Plack
PSGI applicationcode reference$app = sub {...};
# PSGI Hello Worldmy $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ];};
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
CGI-like environment variables+ psgi.input, psgi.errors etc.
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
HTTP status code (int.): 200, 404 etc.
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
Array reference of header pairs:[ ‘Content-Type’, ‘text/html’, ... ]
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
String, array reference of content chunks,Filehandle or IO::Handle-ish object
That’s it.(There’s a callback based streaming interface as well)
# PSGImy $app = sub { my $env = shift; return [ 200, [ ‘Content-Type’, ‘text/plain’ ], [ ‘Hello World’ ], ];};
Now you’ve gota PSGI compatible
application.
Apache IIS lighttpd
CGI.pm
CGI fastcgimod_perl
JiftyMason Catalyst
Mason::CGIHandlerCatalyst::Engine
nginxHTTP::Server::Simple
CGI::App
PSGI Compatible App
Plack::Middleware
Catalyst CGI::App Jifty Mason 2
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
PSGI Compatible App
Plack::Middleware
Catalyst CGI::App Jifty Mason 2
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
other PSGI Webservers
Web Servers
Plack::HandlerConnects PSGI compatible apps
to Web servers...
FCGIPlack::Handler::FCGI
ApachePlack::Handler::Apache1Plack::Handler::Apache2
StarmanUNIX Preforking HTTP servers (like Unicorn.rb)
HTTP/1.1 chunk + keep-alives / Very Fast
HTTP::Server::Simple::PSGIZero-deps other than HTTP::Server::Simple
Best for embedding PSGI applications
StarletSimpler UNIX HTTP/1.0 Server
Best used with Server::Starter and nginx/lighttpd
TwiggyNon-blocking web server (like Thin.rb)
based on AnyEvent framework
Perlbal pluginhttp://github.com/miyagawa/Perlbal-Plugin-PSGI
nginx embedded perlhttp://github.com/yappo/nginx-psgi-patchs
mod_psgihttp://github.com/spiritloose/mod_psgi
Apache2
Gepokhttp://metacpan/module/Gepok
Pure Perl standalone HTTPSFirst released July 2011
evpsgihttp://github.com/sekimura/evpsgi
Feersumhttp://github.com/stash/Feersum
uWSGIhttp://projects.unbit.it/uwsgi/
CoronaCoroutine for each connection
based on Coro.pm
PSGI
Plack::Middleware
Frameworks Apps Your own code
Plack::Handler::* (CGI, FCGI, Apache)
PSGI
Plack::Middleware
Frameworks Apps Your own code
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
Starman Twiggy uWSGI Corona etc, etc
25+ Plack::Handlers
Adoption?
PSGI Compatible App
Plack::Middleware
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
Starman Twiggy uWSGI Corona etc
PSGI Compatible App
Plack::Middleware
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
?
Starman Twiggy uWSGI Corona etc
Catalyst Maypole Mason Mojo Sledge Spoon PageKit AxKit Egg Gantry Continuity Solstice Mojolicious
Tripletail Konstrukt Reaction Jifty Cyclone3 WebGUIOpenInteract Squatting Dancer CGI::Application
Nanoa Ark Angelos Noe Schenker Tatsumaki Amon Apache2::WebApp Web::Simple Apache2::REST
SweetPea Hydrant Titanium
Catalyst Maypole Mason Mojo Sledge Spoon PageKit AxKit Egg Gantry Continuity Solstice Mojolicious
Tripletail Konstrukt Reaction Jifty Cyclone3 WebGUIOpenInteract Squatting Dancer CGI::Application
Nanoa Ark Angelos Noe Schenker Tatsumaki Amon Apache2::WebApp Web::Simple Apache2::REST
SweetPea Hydrant Titanium
• Amon
• Angelos
• Ark
• Catalyst
• CGI::Application
• Continuity
• Dancer
• Hydrant
• Jifty
• Mason
• Maypole
• Mojo
• Mojolicious
• Noe
• Schenker
• Sledge
• Squatting
• Tatsumaki
• Titanium
• Web::Simple
PSGI Perl Frameworks
ApplicationsMovable Type 6
WebGUI 8RT4
ACT (conference toolkit)Bricolage (if someone gets time)
PSGI Compatible App
Plack::Middleware
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
Starman Twiggy uWSGI Corona evpsgi
PSGI Compatible App
Plack::Middleware
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Plack::Handler::* (CGI, FCGI, Apache)
Starman Twiggy uWSGI Corona evpsgi
Catalyst CGI::App Jifty Tatsumaki
Dancer Mojoliscious MT6 Mason 2
Web::Simple WebGui 8 Mojo etc...
PSGI from a framework
use Dancer;
get ‘/’ => sub { “Hello World”;};
dance;
use Mojolicious::Lite;
get ‘/:name’ => sub { my $self = shift; $self->render_text(‘Hello!’);};
app->start;
use My::Jifty::App;
my $app = My::Jifty::App->psgi_app;
use Web::Simple ‘MyApp’;
package MyApp;
dispatch { sub(GET) { [ 200, [...], [ ‘Hello’ ] ]; }};
my $app = MyApp->as_psgi;
use My::Catalyst::App;
My::Catalyst::App->setup_engine(‘PSGI’);
my $app = sub {
My::Catalyst::App->run(@_)
};
catalyst.pl My::Catalyst::App
Plack“PSGI implementation & toolkit”
Plack toolkit
Plack toolkitPlack::Handlers Connect PSGI apps and Web Servers
Plack toolkit
plackup Command line launcher
Plack::Handlers Connect PSGI apps and Web Servers
Plack toolkit
plackup Command line launcher
Plack::Loader (auto)load Plack Servers
Plack::Handlers Connect PSGI apps and Web Servers
Plack toolkit
plackup Command line launcher
Plack::Loader (auto)load Plack Servers
Plack::Handlers Connect PSGI apps and Web Servers
Plack::Middleware Easy-to-use PSGI Middleware
Plack toolkit
plackup Command line launcher
Plack::Loader (auto)load Plack Servers
Plack::Handlers Connect PSGI apps and Web Servers
Plack::Middleware Easy-to-use PSGI Middleware
Plack::Builder OO & DSL to enable Middleware
Plack toolkit
plackup Command line launcher
Plack::Loader (auto)load Plack Servers
Plack::Handlers Connect PSGI apps and Web Servers
Plack::Middleware Easy-to-use PSGI Middleware
Plack::Apps Apps
Plack::Builder OO & DSL to enable Middleware
Plack toolkit
plackup Command line launcher
Plack::Loader (auto)load Plack Servers
Plack::Handlers Connect PSGI apps and Web Servers
Plack::Middleware Easy-to-use PSGI Middleware
Plack::Apps Apps
Plack::Test Testing
Plack::Builder OO & DSL to enable Middleware
plackupRuns PSGI app instantly from CLI
(inspired by rackup)
> plackup app.psgi
> plackup app.psgiHTTP::Server::PSGI: Accepting connections at http://0:5000/
HTTP::Server::PSGIReference PSGI web server
bundled in Plack
Standalone, single-process HTTP servergreat for development and testing
Plack::Middleware(160+ modules - July 2011)
MiddlewareDebug, Session, Logger, Static, Lint,
AccessLog, ErrorDocument, StackTrace, Auth::Basic, Auth::Digest, ReverseProxy, Refresh, Auth::OAuth,
Throttle....
Access AccessLog AccessLog::Timed Acme::YadaYada AddDefaultCharset AllowCrossSiteAJAX AMF Assets Auth::Digest Auth::Form Auth::Htpasswd Auth::Negotiate Auth::Basic AutoRefresh BufferedStreaming Cache Cached ChromeFrame Chunked Class::Refresh Compile Conditional ConditionalGET ConsoleLogger ContentLength ContentMD5 CrossOrigin CSRFBlock Dancer::Debug DBIC::QueryLog Debug Debug::CatalystPluginCache Debug::DBIC::QueryLog Debug::DBIProfile Debug::Profiler::NYTProf Debug::W3CValidate Deflater DoCoMoGUID Doorman ErrorDocument ESI ETag Expires File::Sass Firebug::Lite FirePHP ForceEnv Head Header HTMLify HTMLMinify HTTPExceptions IEnosniff IIS6ScriptNameFix Image::Scale Inline InteractiveDebugger IPAddressFilter iPhone JavaScript::Ectype JSConcat JSONP LighttpdScriptNameFix Lint Log::Contextual Log::Minimal Log4perl LogDispatch LogWarn MethodOverride Mirror NeverExpire NoDeflate NoMultipleSlashes NullLogger Options OptionsOK Precompressed ProxyMap RearrangeHeaders Recursive RefererCheck Refresh REPL Reproxy ReverseProxy Rewrite Runtime Scope::Container Scope::Session ServerStatus::Lite Session Session::SerializedCookie SetAccept SimpleContentFilter SimpleLogger SizeLimit SocketIO SSI StackTrace Static Static::Minifier StaticShared Status Test::StashWarnings Throttle TMT UseChromeFrame Watermark
Plack MiddlewareWraps a PSGI applicationto add pre/post processing
Logging
LoggingStatus code redirect
LoggingStatus code redirectError Handler
LoggingStatus code redirectError HandlerCache Middleware
LoggingStatus code redirectError HandlerCache MiddlewareSession Middleware
LoggingStatus code redirectError HandlerCache MiddlewareSession MiddlewareRoutes Middleware
LoggingStatus code redirectError HandlerCache MiddlewareSession MiddlewareRoutes MiddlewareYour App
Plack::Middleware::A
Plack::Middleware::B
PSGI Compatible App
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
P::MW::B
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
P::MW::A
P::MW::B
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
Response out
P::MW::A
P::MW::B
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
e.g. Redirect Response out
P::MW::A
P::MW::B
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
e.g. Redirect
e.g. Static
Response out
P::MW::A
P::MW::B
PSGI App
P::MW::B
P::MW::A
Plack::Middleware::A
Request in
Plack::Middleware::B
PSGI Compatible App
Enabling Plack::Middleware
reusable and extensible Middleware framework
Plack::Builder DSL in .psgi
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; enable “B”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; enable “B”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; enable “B”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; enable “B”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; # Plack::Middleware::A enable “B”; # Order matters $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “A”; enable “B”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “Static”, root => “/htdocs”, path => qr!^/static/!; enable “Deflater”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “Static”, root => “/htdocs”, path => qr!^/static/!; enable “Deflater”; $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “Static”, root => “/htdocs”, path => qr!^/static/!; enable “Deflater”; # gzip/deflate $app;}
my $app = sub { return [ $status, $header, $body ];};
use Plack::Builder;
return builder { enable “Static”, root => “/htdocs”, path => qr!^/static/!; enable “Deflater”; $app;}
Plack::Middleware::Static
Plack::Middleware::Deflate
PSGI Compatible App
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
-
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
PSGI App
-
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
Deflate compresses
PSGI App
-
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
-
Deflate compresses
PSGI App
-
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
=~ ^/static Response out
-
Deflate compresses
PSGI App
-
Static
Plack::Middleware::Static
Request in
Plack::Middleware::Deflate
PSGI Compatible App
plackup compatibleplackup -e ‘enable “Foo”;’ app.psgi
MiddlewareWrite once, run in every framework
A few demos..
Assume...
use Plack::Builder;
my $body = ‘<html><body>Hello World</body></html>’;
my $app = sub { my $self = shift;
return [200, ['Content-Type' => 'text/html'], [ $body ]];};
Assume...
use Plack::Builder;
my $body = ‘<html><body>Hello World</body></html>’;
my $app = sub { my $self = shift;
return [200, ['Content-Type' => 'text/html'], [ $body ]];};
Assume...
use Plack::Builder;
my $body = ‘<html><body>Hello World</body></html>’;
my $app = sub { my $self = shift;
return [200, ['Content-Type' => 'text/html'], [ $body ]];};
Debugger
return builder { # Precious debug info. Right on your page! enable 'Debug';
$app;}
InteractiveDebugger
my $app = sub { my $foo = 'bar'; die "oops" if $foo eq 'bar';
[200, ['Content-Type' => 'text/html'], [ $body ]];};
return builder { # Enable Interactive debugging enable "InteractiveDebugger";
$app;}
my $app = sub { my $foo = 'bar'; die "oops" if $foo eq 'bar';
[200, ['Content-Type' => 'text/html'], [ $body ]];};
return builder { # Enable Interactive debugging enable "InteractiveDebugger";
$app;}
my $app = sub { my $foo = 'bar'; die "oops" if $foo eq 'bar';
[200, ['Content-Type' => 'text/html'], [ $body ]];};
return builder { # Enable Interactive debugging enable "InteractiveDebugger";
$app;}
NYTProf - profiler
First rule of Program Optimisation
Don’t do it!
Second rule of Program Optimisation
(for experts only)
Don’t do it - yet!
return builder { enable 'Debug', panels => [ [ 'Profiler::NYTProf' ] ]; $app;};
ServerStatus::Lite
use Plack::Builder;
return builder { enable "ServerStatus::Lite", path => '/server-status', allow => [ '127.0.0.1'], scoreboard => '/tmp/score'; $app;}
SizeLimit
use Plack::Builder;
return builder { enable "SizeLimit", max_unshared_size_in_kb => 3000, check_every_n_requests => 5; $app;}
Plack::App::*ready-to-use applications
Apache::ActionWrapper CGIBin Cascade CocProxy DAV Directory Directory::Xslate FCGIDispatcher File ImageMagick JSP PSGIBin Path::Router Proxy Proxy::Backend::AnyEvent::HTTP Proxy::Backend::LWP Proxy::Selective Proxy::Test URLMap WrapApacheReq WrapApacheReq::FakeRequest WrapCGI
Plack::App::CGIBinmount /cgi-bin as PSGI applications
CGI::PSGIEasy migration from CGI.pm
Plack::App::DirectoryStatic content file server
Plack::App::Proxy(non-blocking) proxy server
Can be used as reverse proxy as well
Plack::App::JSPRuns JavaScript PSGI apps :)
# app.psgi - Javascript! Plack::App::JSP->new( js => q{ function respond(body) { return [ 200, [ 'Content-type', 'text/html' ], [ body ] ] } respond("Five factorial is " + (function(x) { if ( x<2 ) return x; return x * arguments.callee(x - 1); })(5) ); });
# app.psgi - Javascript! Plack::App::JSP->new( js => q{ function respond(body) { return [ 200, [ 'Content-type', 'text/html' ], [ body ] ] } respond("Five factorial is " + (function(x) { if ( x<2 ) return x; return x * arguments.callee(x - 1); })(5) ); });
Plack::App::URLMapMultiplex multiple apps
Integrated with Builder DSL
use CatApp;use CGIApp;
my $c1 = sub { CatApp->run };my $c2 = sub { CGIApp->run_psgi };
use Plack::Builder;
return builder { mount “/cat” => $c1; mount “/cgi-app” => builder { enable “StackTrace”; $c2; };}
use CatApp;use CGIApp;
my $c1 = sub { CatApp->run };my $c2 = sub { CGIApp->run_psgi };
use Plack::Builder;
return builder { mount “/cat” => $c1; mount “/cgi-app” => builder { enable “StackTrace”; $c2; };}
use CatApp;use CGIApp;
my $c1 = sub { CatApp->run };my $c2 = sub { CGIApp->run_psgi };
use Plack::Builder;
return builder { mount “/cat” => $c1; mount “/cgi-app” => builder { enable “StackTrace”; $c2; };}
Some more demos...
Basic website
TemplateToolkit + Static
my $root = '/path/to/html_doc_root';
my $app = Plack::Middleware::TemplateToolkit->new( INCLUDE_PATH => root,)->to_app;
return builder {
enable 'Static', path =>
qr{\.[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$}, root => $root;
$app; }
my $root = '/path/to/html_doc_root';
my $app = Plack::Middleware::TemplateToolkit->new( INCLUDE_PATH => root,)->to_app;
return builder {
enable 'Static', path =>
qr{\.[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$}, root => $root;
$app; }
my $root = '/path/to/html_doc_root';
my $app = Plack::Middleware::TemplateToolkit->new( INCLUDE_PATH => root,)->to_app;
return builder {
enable 'Static', path =>
qr{\.[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$}, root => $root;
$app; }
my $root = '/path/to/html_doc_root';
my $app = Plack::Middleware::TemplateToolkit->new( INCLUDE_PATH => root,)->to_app;
return builder {
enable 'Static', path =>
qr{\.[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$}, root => $root;
$app; }
my $root = '/path/to/html_doc_root';
my $app = Plack::Middleware::TemplateToolkit->new( INCLUDE_PATH => root,)->to_app;
return builder {
enable 'Static', path =>
qr{\.[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$}, root => $root;
$app; }
Creating utilities
Caching Proxy
Website
Website
Developing code
Website
Developing code
Website
Developing code
Slow website
Slow website
Developing code
Slow website
Developing code
Caching Proxy
use Plack::Middleware::Cache;use Plack::App::Proxy;
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
return builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache'; $app;};
use Plack::Middleware::Cache;use Plack::App::Proxy;
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
return builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache'; $app;};
use Plack::Middleware::Cache;use Plack::App::Proxy;
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
return builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache'; $app;};
use LWP::Simple;
my $content = get(‘http://localhost:5000/’);
Caching Proxy + Domain hijack
use LWP::Simple;
my $content = get(‘http://localhost:5000/’);
use LWP::Simple;
my $content = get(‘http://london.pm.org/’);
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
return builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache2'; $app;};
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
return builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache2'; $app;};
my $app = Plack::App::Proxy->new(
remote => "http://london.pm.org/" )->to_app;
$app = builder { enable "Cache", match_url => '^/.*', # everything cache_dir => '/tmp/plack-cache2'; $app;};
# Hijack Any LWP::Useragent requestsLWP::Protocol::PSGI->register($app);
use LWP::Simple;
my $content = get("http://london.pm.org/");
say '\o/' if $content =~ /London Perl Mongers/;
# Hijack Any LWP::Useragent requestsLWP::Protocol::PSGI->register($app);
use LWP::Simple;
my $content = get("http://london.pm.org/");
say '\o/' if $content =~ /London Perl Mongers/;
# Hijack Any LWP::Useragent requestsLWP::Protocol::PSGI->register($app);
use LWP::Simple;
my $content = get("http://london.pm.org/");
say '\o/' if $content =~ /London Perl Mongers/;
# Hijack Any LWP::Useragent requestsLWP::Protocol::PSGI->register($app);
use LWP::Simple;
my $content = get("http://london.pm.org/");
say '\o/' if $content =~ /London Perl Mongers/;
Plack::TestUnified interface to write TAP testswith Mock HTTP and Live HTTP
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req); ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req);
ok $res->[0] == ‘200’, ‘Success’; };
use Plack::Test;use HTTP::Request::Common;
my $app = sub { my $env = shift; return [ $status, $header, $body ];};
test_psgi app => $app,client => sub { my $callback = shift;
my $req = GET “http://localhost/foo”; my $res = $callback->($req);
ok $res->[0] == ‘200’, ‘Success’; };
Test::WWW::Mechanize::PSGI
use Test::WWW::Mechanize::PSGI; my $mech = Test::WWW::Mechanize::PSGI->new( app => $app, );
$mech->get_ok('/');
use Test::WWW::Mechanize::PSGI; my $mech = Test::WWW::Mechanize::PSGI->new( app => $app, );
$mech->get_ok('/');
Testing your full configuration!
Network setup tip
Use a reverse proxy
• Sits in front of servers, not clients - “reverse”
Use a reverse proxy
• Sits in front of servers, not clients - “reverse”
•Makes servers more efficient
Use a reverse proxy
• Sits in front of servers, not clients - “reverse”
•Makes servers more efficient
• Add HTTPS easily
Use a reverse proxy
• Sits in front of servers, not clients - “reverse”
•Makes servers more efficient
• Add HTTPS easily
•Makes scaling easier
Use a reverse proxy
Webserver App
Internet / Users
Webserver App
Internet / Users
Webserver App
Internet / Users
Webserver App
Internet / Users
Webserver App
Internet / Users
Reverse ProxyNGINX Perlbal Pound
Webserver App
Internet / Users
Reverse ProxyNGINX Perlbal Pound
Webserver App
Internet / Users
Reverse ProxyNGINX Perlbal Pound
Webserver App
Internet / Users
Reverse ProxyNGINX Perlbal Pound
Webserver App
Internet / Users
Reverse ProxyNGINX Perlbal Pound
Server
Reverse ProxyNGINX Perlbal Pound
Server 1
Reverse ProxyNGINX Perlbal Pound
Server 2
Server 1
Reverse ProxyNGINX Perlbal Pound
Server 2
Server 3
Server 1
Reverse ProxyNGINX Perlbal Pound
Server 2
Server 3
Plack::Middleware::ReverseProxy
Updates $env->{REMOTE_ADDRESS}
Why use Plack?
Why use Plack?
‣ Flexibility
‣ Middleware
‣ Apps
‣ Development
‣ Testing
‣ Deployment
Flexibility
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Starman Twiggy uWSGI Corona etc
Plack::Handler::* (CGI, FCGI, Apache)
Flexibility• Easy to change webserver (25+!)
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Starman Twiggy uWSGI Corona etc
Plack::Handler::* (CGI, FCGI, Apache)
Flexibility• Easy to change webserver (25+!)
Apache lighttpd HTTP::Server::PSGI Perlbalmod_psgi
Starman Twiggy uWSGI Corona etc
• Starman seems to be used most
Plack::Handler::* (CGI, FCGI, Apache)
Middleware
Middleware
• Easy to reuse with any PSGI app
Middleware
• Easy to reuse with any PSGI app
• Many tools to make your life easy
Middleware
• Easy to reuse with any PSGI app
• Many tools to make your life easy
• 160+ on CPAN now
App
App
• URLMapping / Routing
App
• URLMapping / Routing
• Static files
App
• URLMapping / Routing
• Static files
• Proxying
Development
Development
• plackup
Development
• plackup
• Restarter (monitor changes on disk)
Development
• plackup
• Restarter (monitor changes on disk)
• HTTP::Server::PSGI
Development
• plackup
• Restarter (monitor changes on disk)
• HTTP::Server::PSGI
• Debugging middleware
Development
• plackup
• Restarter (monitor changes on disk)
• HTTP::Server::PSGI
• Debugging middleware
• Profiler
Testing
Testing
• Testing your full configuration
Testing
• Testing your full configuration
• Test::WWW::Mechanize::PSGI
Testing
• Testing your full configuration
• Test::WWW::Mechanize::PSGI
• Plack::Test
Deployment
Deployment
• No separate configuration files
Deployment
• No separate configuration files
• Easy to choose/change webserver
Deployment
• No separate configuration files
• Easy to choose/change webserver
• DotCloud etc - cloud deployment
Summary
Summary
✦ PSGI is an interface, Plack is the code.
Summary
✦ PSGI is an interface, Plack is the code.
✦ Many fast PSGI servers.
Summary
✦ PSGI is an interface, Plack is the code.
✦ Many fast PSGI servers.
✦ Adapters and tools for frameworks and webservers.
Summary
✦ PSGI is an interface, Plack is the code.
✦ Many fast PSGI servers.
✦ Adapters and tools for frameworks and webservers.
✦ An amazing amount of middleware
Summary
✦ PSGI is an interface, Plack is the code.
✦ Many fast PSGI servers.
✦ Adapters and tools for frameworks and webservers.
✦ An amazing amount of middleware
✦ Used in many production systems
Use Plack
Thank you!Slides: http://slideshare.net/ranguard
http://plackperl.org/
irc://irc.perl.org/#plack