際際滷

際際滷Share a Scribd company logo
PSGI and Plack
   Tatsuhiko Miyagawa
PSGI
Perl Web Server Gateway Interface
Plack
PSGI ref. implementations
          Utilities
A Perl port of:
Pythons WSGI and Rubys Rack
  (will talk about them later)
WHY
Web Frameworks
Maypole Mason Mojo Sledge Catalyst Spoon PageKit
  AxKit Egg Gantry Continuity Solstice Mojolicious
    Tripletail Konstrukt Re鍖ection Jifty Cyclone3
OpenInteract Squatting Dancer CGI::Application Nanoa
              Ark Angelos Noe Schenker
Most of them run on
 mod_perl and CGI
Some run on FCGI
Some run standalone
Very few supports
  non-blocking
Because:
No common server
environment layers
CGI.pm
Runs 鍖ne on:
    CGI, FastCGI, mod_perl (1 & 2)
Standalone (with HTTP::Server::Simple)
CGI.pm = LCD
   Its also Perl core
> grep (CGI.pm|ENV) lib/MT/App.pm
         if ( my $path_info = $ENV{PATH_INFO} ) {
                # de鍖ned which interferes with CGI.pm determining the
                delete $ENV{PATH_INFO};
  # CGI.pm has this terrible 鍖aw in that if a POST is in effect,
         my $query_string = $ENV{'QUERY_STRING'}
             if de鍖ned $ENV{'QUERY_STRING'};
         $query_string ||= $ENV{'REDIRECT_QUERY_STRING'}
             if de鍖ned $ENV{'REDIRECT_QUERY_STRING'};
         my $len = $ENV{CONTENT_LENGTH} || 0;
      return $ENV{ 'HTTP_' . $key };
         $app->{request_method} = $ENV{REQUEST_METHOD} || '';
      ## Older versions of CGI.pm didn't have an 'upload' method.
  if ( my $host = $ENV{HTTP_HOST} ) {
    : $ENV{REMOTE_ADDR});
      $cwd = $ENV{DOCUMENT_ROOT} || $app->mt_dir;
Not cool.
Catalyst
The most popular framework as of today
Catalyst::Engine::*
            Server abstractions.
Well supported Apache, FCGI and Standalone
Problems:
       Duplicated efforts
No fair performance evaluations
Catalyst::Engine
for the rest of us
= HTTP::Engine
HTTP::Engine
Lots of adapters (FCGI, Apache2, POE)
     Clean Request/Response API
Written by Yappo, tokuhirom and others
Problem
Mo[ou]se everywhere
 Mouse is light but still overspec for some env.
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 good stuff
from Python/Ruby
WSGI (Python)
   Rack
WSGI (PEP-333)
mod_wsgi, Tornado, Paste, GAE
  Django, CherryPy, Pylons
Rack
Passenger, Thin, rack, Heroku
     Rails, Merb, Sinatra
Split HTTP::Engine
 into three parts
Interface
Implementations
    Utilities
PSGI (interface)
Plack::Server (implementations)
      Plack::* (utilities)
PSGI
Interface
my $app = sub {
   my $env = shift;
   # ...
   return [ $status, $header, $body ];
};
PSGI application
   code reference
   $app = sub {...};
environment hash
$env: CGI-like env variables
+ psgi.input, psgi.errors etc.
Why a big hash?
Easy to adapt if you have CGI adapter
  Also follows what WSGI/Rack do
Response
 array ref with three elements
status code, headers (array ref)
and body (IO-like or array ref)
$body
  IO::Handle-like
getline() and close()
IO::Handle-like
       We really envy Python/Ruby
          for built-in iterators
(Perls 鍖lehandle is also an object, but it really sucks)
Frameworks
Write an adapter to return
PSGI application code ref.
Servers
   Set up $env, run the app
and emits response out of $res
Middleware
   Plays both side
Application wrapper
Plack
Plack::Server
 reference server implementations
  Standalone, FCGI, Apache2, CGI
Standalone, Prefork, AnyEvent, Coro
Very fast
 5000 QPS on standalone
15000 QPS with prefork :)
Framework Adapters
  CGI::Application, Catalyst, Maypole
Mason, Squatting, Mojo, HTTP::Engine etc.
Applications
MT::App, WebGUI
Utilities
Plackup
Run PSGI app instantly from CLI
     (inspired by rackup)
DEMO
Middlewares
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;
};
Middlewares
Static, AccessLog, ConditionalGET
 ErrorDocument, StackTrace etc.
Plack::Middleware
  reusable and extensible
  Middleware framework
 Plack::Builder DSL in .psgi
CGI::PSGI
Easy migration from CGI.pm
Plack::Request
    like libapreq (Apache::Request)
wrapper APIs for framework developers
Plack::Test
 Uni鍖ed 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;
};
Streaming
event loop / long-poll
use IO::Handle::Util qw(io_from_getline);

my $app = sub {
   my $env = shift;
   my $io = io_from_getline sub {
      return $chunk; # undef when done
   };
   return [ $status, $header, $io ];
};
use IO::Writer; # TBD: API might change
use AnyEvent::Timer;

my $app = sub {
   my $env = shift;
   my $io = writer {
      my $h = shift;
      my $t; $t = AE::timer 0, 1, sub {
         $t;
         $h->push_write($stuff);
      };
   };
   return [ $status, $header, $io ];
};
Other Servers
nginx embedded perl
 http://github.com/yappo/nginx-psgi-patchs
mod_psgi
http://github.com/spiritloose/mod_psgi
Gearman Dispatcher?
Cloud
WSGI (PEP-333)
mod_wsgi, Tornado, Paste, GAE
  Django, CherryPy, Pylons
Rack
Passenger, Thin, rack, Heroku
     Rails, Merb, Sinatra
What if GAE Perl
comes with PSGI ...
Summary

 PSGI is an interface, Plack is the code.
 We have many (pretty fast) servers.
 We have adapters and tools for most web
  frameworks.
 Use it!
http://github.com/miyagawa/Plack
        http://plackperl.org/
Questions?

More Related Content

Intro to PSGI and Plack