Plack
Superglue for Perl Web Frameworks
         Tatsuhiko Miyagawa
           Perl Oasis 2010
Tatsuhiko Miyagawa

• Japanese, lives in San Francisco
• Works at Six Apart
• 170+ CPAN modules (id:MIYAGAWA)
• @miyagawa
• bulknews.typepad.com
Background
40 slides of why we need Plack.
   May I fast-forward them?
      (since Stevan spoiled)
Web Frameworks
Maypole Mason Mojo Sledge Catalyst 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
Most of them run on
 mod_perl and CGI
Some run on FastCGI
Some run standalone
Very few supports
  non-blocking
Because:
No common server
environment layers
CGI.pm
Runs “fine” on:
    CGI, FastCGI, mod_perl (1 & 2)
Standalone (with HTTP::Server::Simple)
CGI.pm = LCD
   It’s also Perl core
:-(
Catalyst
The most popular framework as of today
Catalyst::Engine::*
            Server abstractions.
Well supported Apache, FCGI and Standalone
                No CGI.pm
CGI.pm
  Jifty, CGI::Application, Spoon


mod_perl centric
Mason, Sledge, PageKit, WebGUI


       Adapters
  Catalyst, Maypole, Squatting
Problems:
       Duplicated efforts
No fair performance evaluations
Question:
Can we share?
Attempt:
HTTP::Engine
HTTP::Engine
Lots of adapters (FCGI, Apache2, POE)
     Clean Request/Response API
Written by Yappo, tokuhirom and others
Problems
Mo[ou]se everywhere
 Moose is non-realistic in CGI environment
 Mouse is lovely but has its own problems :p
Monolithic
All implementations share HTTP::Engine roles
and builders, which is sometimes hard to adapt
      and has less place for optimizations.
APIs everywhere
Most frameworks have their request/response API
          Sometimes there are gaps.
    Annoying to write bridges and wrappers
Solution
Steal great stuff
from Python/Ruby
WSGI (Python)
   Rack
WSGI (PEP-333)
mod_wsgi, Paste, AppEngine
 Django, CherryPy, Pylons
Rack
Passenger, thin, Unicorn, Mongrel, Heroku
            Rails, Merb, Sinatra
WSGI/Rack
 Completely separate interface
from the actual implementation
Approach
Split HTTP::Engine
 into three parts
Interface
       Servers
Utils & Middleware
PSGI (interface)
HTTP::Server::PSGI etc. (servers)
     Plack (utils & middleware)
PSGI
Perl Web Server Gateway Interface
Interface
WARNING
You DON’T need to care about these
   interface details unless you are
framework or middleware developers
   (But i guess many of you are ...)
# WSGI
def hello(environ, start_response):
 start_response(“200 OK”, [
   (‘Content-Type’, ‘text/plain’)
 ])
 return [“Hello World”]
# Rack
class Hello
 def call(env)
   return [
     200,
     { “Content-Type” => ”text/plain” },
     [“Hello World”]
   ]
 end
end
# PSGI
my $app = sub {
   my $env = shift;
   return [
      200,
      [ ‘Content-Type’, ‘text/plain’ ],
      [ ‘Hello World’ ],
   ];
};
PSGI application
   code reference
   $app = sub {...};
my $app = sub {
   my $env = shift;
   return [ $status, $header, $body ];
};
environment hash
$env: CGI-like env variables
+ psgi.input, psgi.errors etc.
my $app = sub {
   my $env = shift;
   return [ $status, $header, $body ];
};
Response
 array ref with three elements
status code, headers (array ref)
and body (IO-like or array ref)
my $app = sub {
   my $env = shift;
   return [ $status, $header, $body ];
};
$body
  IO::Handle-like
getline() and close()
IO::Handle::Util
Easily turns perl code ref into a IO::Handle
Streaming interface
my $app = sub {
  my $env = shift;
  return sub {
    my $respond = shift;
    # You could do some event loop
    # to delay response (e.g. Comet)
    $respond->([ $status, $header, $body ]);
  };
};
my $app = sub {
  my $env = shift;
  return sub {
    my $respond = shift;
    my $w = $respond->([ $status, $header ]);
    $w->write($body);
    $w->write($body);
    ...
    $w->close;
  };
};
Streaming Interface
 Originally designed for non-blocking servers
Now available for most servers incl. CGI, Apache
Catalyst            CGI::App              Jifty        Tatsumaki


                                                    Plack::Middleware

                               PSGI

    Plack::Handler::* (CGI, FCGI, Apache)


Apache       lighttpd       HTTP::Server::PSGI      mod_psgi   Perlbal
PSGI adaptation
Maypole Mason Mojo Sledge Catalyst 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
Maypole Mason Mojo Sledge Catalyst 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
Applications
MT::App, WebGUI
Plack
“PSGI toolkit”
HTTP::Server::PSGI
 Reference PSGI web server
      bundled in Plack
Very fast
 3000 QPS on standalone
15000 QPS with prefork :)
Plack::Handler
Connects PSGI apps to Web servers
 CGI, FastCGI, Apache, Standalone
Utilities
Plackup
Run PSGI app instantly from CLI
     (inspired by rackup)
Plack::Runner
            plackup backend
Use this to make CLI for your web app
Middleware
my $app = sub {
   my $env = shift;
   return [ $status, $header, $body ];
};

my $mw = sub {
   my $env = shift;
   # do something with $env
   my $res = $app->($env);
   # do something with $res;
   return $res;
};
Middleware
    Debug, Session, Runtime, Static, AccessLog,
  ConditionalGET, ErrorDocument, StackTrace,
Auth::Basic, Auth::Digest, ReverseProxy, Refresh etc.
Plack::Middleware
  reusable and extensible
  Middleware framework
 Plack::Builder DSL in .psgi
my $app = sub {
   return [ $status, $header, $body ];
};

use Plack::Builder;

builder {
  enable “Static”, root => “/htdocs”,
    path => qr!^/static/!;
  enable “Deflater”; # gzip/deflate
  $app;
}
plackup compatible
plackup -e ‘enable “Foo”;’ app.psgi
Plack::App::URLMap
    Multiplex multiple apps
 Integrated with Builder DSL
use CatApp;
use CGIApp;

my $c1 = sub { CatApp->run };
my $c2 = sub { CGIApp->run_psgi };

use Plack::Builder;

builder {
  mount “/cat” => $c1;
  mount “/cgi-app” => builder {
    enable “StackTrace”;
    $c2;
  };
}
CGI::PSGI
Easy migration from CGI.pm
CGI::Emulate::PSGI
    CGI::Compile
Easiest migration from CGI scripts (like Registry)
Plack::Request
    like libapreq (Apache::Request)
wrapper APIs for middleware developers
Plack::Test
 Unified interface to write tests
with 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 $cb = shift;
   my $req = GET “http://localhost/foo”;
   my $res = $cb->($req);
   # test $res;
};
use Plack::Test;
use HTTP::Request::Common;
$Plack::Test::Impl = “Server”;

my $app = sub {
   my $env = shift;
   return [ $status, $header, $body ];
};

test_psgi app => $app, client => sub {
   my $cb = shift;
   my $req = GET “http://localhost/foo”;
   my $res = $cb->($req);
   # test $res;
};
Test::WWW::Mechanize::PSGI
           acme++
Other PSGI Servers
Non-blocking servers
     psgi.nonblocking = true
AnyEvent, Coro, POE, Danga::Socket
Tatsumaki
 Non-blocking Web App framework
Comet, Server push, async HTTP client
http://github.com/miyagawa/Tatsumaki
Nomo
Unixy PSGI web servers with supervisors support
       http://github.com/miyagawa/Nomo
Re’em
Unicorn in Moose + FCGI::Manager
 http://github.com/perigrin/re-em
nginx embedded perl
 http://github.com/yappo/nginx-psgi-patchs
mod_psgi
http://github.com/spiritloose/mod_psgi
evpsgi
http://github.com/sekimura/evpsgi
Perlbal plugin
http://github.com/miyagawa/Perlbal-Plugin-PSGI
Catalyst            CGI::App              Jifty        Tatsumaki


                                                    Plack::Middleware

                               PSGI

    Plack::Handler::* (CGI, FCGI, Apache)


Apache       lighttpd       HTTP::Server::PSGI      mod_psgi   Perlbal
DEMO
Recent Updates
Common Confusions
“Is Plack a (new)
  framework?”
No.
Plack is intended to be used by developers for
   framework, web servers and middleware.
“But what is this
Plack::Request then?”
Ugh.
Plack::Request can be used as a micro framework.
   But our plan is to rename the existing one.
“Is Plack a web server?”
Not anymore.
Decided to give web servers ::PSGI name such as:
    HTTP::Server::PSGI, PoCo::Server::PSGI,
         AnyEvent::HTTPD::PSGI, etc.
“Implements PSGI
  = use Plack?”
Yeah, but not
 necessarily.
Future
PSGI 1.1
psgi.streaming
  becomes SHOULD (from MAY)
Will be BufferedStreaming middleware
psgi.input
read callback (for WebSockets)
psgi.logger
Optional: Log::Dispatch-ish logger object
useful for Debug and FirePHP integration
psgix.session
Optional: Session as a hash ref
      (API is in Piglet)
Plack 1.0
HTTP::Server::PSGI
 (partial) HTTP/1.1 support
   pull prefork out of core
refactoring loaders
Restarter, Shotgun, gateway.cgi
   Plack::Handler renames
Merge Plack::Request
   Becomes a library for middleware writers
Make it work better when created multiple times
Summary

• PSGI is an interface, Plack is the code.
• We have many (pretty fast) PSGI servers.
• We have adapters and tools for most web
  frameworks.
• Use it!
http://github.com/miyagawa/Plack
        http://plackperl.org/
   http://advent.plackperl.org/
      irc://irc.perl.org/#plack
BTW
We can fix this.
1) Help me SEO
 <a href=”http://plackperl.org/”>
(put “Perl” and “Web” here)</a>
2) More insanely:
% ls -l perlwebserver-0.3/lib/PerlWebServer/Module/
total 208
-rw-r--r-- 1 miyagawa staff 6029 Dec 15 2000 mod_cgi.pm
-rw-r--r-- 1 miyagawa staff 71770 Dec 15 2000 mod_homer.pm
-rw-r--r-- 1 miyagawa staff 5337 Jan 15 15:29 mod_psgi.pm
-rw-r--r-- 1 miyagawa staff 7394 Dec 15 2000 mod_ssi.pm
httpi: I gave up.
There is tools/phproxy which does similar things.
Questions?

Plack perl superglue for web frameworks and servers