2 <html><head><meta charset=
"utf-8"><title>Introduction to PSGI
</title><link rel=
"stylesheet" href=
"css/common.css"><link rel=
"stylesheet" href=
"css/slides.css"></head><body><textarea id=
"source">
16 ![Bluehost](img/bluehost.png)
18 ### https://bluehost.com/careers
26 @P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP rehtona tsuJ";sub p{
27 @p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=
2)+=$f=!fork;map{$P=$P[$f^ord
28 ($p{$_})&
6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{$p{$_}=~/^[P.]/&&
29 close$_}%p;wait until$?;map{/^r/&&<$_
>}%p;$_=$d[$q];sleep rand(
2)if/\S/;print
32 Source: [Just Another Perl / Unix Hacker](http://perl.plover.com/obfuscated/) by Mark Jason Dominus
35 This is a Perl presentation, so I hope code that looks like this doesn't frighten you.
41 - Answer "What is PSGI?"
42 - Examine some alternatives to PSGI.
50 ### **P**erl [web] **S**erver **G**ateway **I**nterface
53 - It is an interface between Perl web applications and web servers.
56 - It is a *specification*, not code.
59 - First released to the CPAN on
13 Oct
2009.
62 - Originally written by Miyagawa.
64 .center[![Tatsuhiko Miyagawa](img/avatar-miyagawa.jpg)]
67 Written by **Tatsuhiko Miyagawa**, author of:
70 - way too many Perl modules on CPAN to list
73 - Inspired by WSGI (Python) and Rack (Ruby).
76 - PEP-
333 (WSGI
1.0) was released on
07 Dec
2003.
77 - Rack
0.1 was released on
03 Mar
2007.
79 Despite Perl's long history of powering the web, we were well behind the curve on this.
86 ## Extremely High-level Overview
89 ![Basic Flow](img/basic-flow1.svg)
93 - PSGI is the language your app speaks in order to communicate with user agents.
94 - User agents are browsers.
95 - I've glossed over some important details, like the fact that users don't speak PSGI.
102 ## Pretty High-level Overview
105 ![Basic Flow](img/basic-flow2.svg)
109 - In reality, your app speaks PSGI but user agents speak HTTP.
110 - You need software in the middle that can speak both, and that's usually a web server.
114 class: center, middle
117 ## Somewhat High-level Overview
120 ![Basic Flow](img/basic-flow3.svg)
124 - In reality, most web servers don't speak PSGI. :-(
125 - There are "handlers" that speak both PSGI and another language that web servers do speak.
130 - Yes, HTTP. Many modern web servers speak HTTP not only as a server but also as a client.
131 - This allows them to *proxy* (act as middleman) between user agents and other servers.
132 - In the world of PSGI (and "Plack"), handlers are also called adapters or connectors.
133 - There are already adapters for every major web server.
140 class: center, middle
143 ## Somewhat High-level Overview
146 ![Basic Flow](img/basic-flow4.svg)
150 - Notice that as we've zoomed in, the interaction between the web app and the rest has remained the
152 - From a developer perspective, the etremely high-level overview is sufficient.
153 - This is one of the benefits of PSGI:
154 - Write your application once and leave deployment details to devops.
155 - The intrastructure details can change (swap in a different web server) and the app will still work.
156 - Maybe you're both developer and system architect, but the separation between developer and
158 - In fairness, this isn't a new concept.
159 - The way this has been achieved before is using a *web framework*.
163 class: center, middle
166 ## High-level Overview
169 ![Basic Flow](img/basic-flow5.svg)
173 - A web framework makes it so your app doesn't need to speak HTTP or CGI or even PSGI.
181 > Writing your web application directly using [PSGI/Plack] is certainly possible but not recommended.
185 > If you're writing a web application, not a framework, then you're encouraged to use one of the web
186 > application frameworks that support PSGI (http://plackperl.org/#frameworks), or see modules like
187 > HTTP::Engine to provide higher level Request and Response API on top of PSGI.
189 > -- [Plack::Request Documentation](https://search.cpan.org/~miyagawa/Plack/lib/Plack/Request.pm)
192 - When you start learning about Plack, you'll realize that it is actually pretty capable.
193 - You may start to think that everything should be developed on that level -- don't do it!
194 - For most stuff, you'll still want to use a web framework.
195 - Web frameworks often offer more convenient abstractions than raw PSGI.
202 If you're a developer writing a web app, you're probably asking why then you should care about PSGI.
206 - So that you can understand how things work.
209 - I'll never understood people who don't want to understand things.
211 - I recommend you learn and understand as much as you can about the entire request-response cycle of
212 your web app; it will help you troubleshoot when things go wrong or aren't behaving as expected.
216 - So that you can do DevOps (if you want).
219 - New skills make you more marketable.
222 - So that you understand it when you see PSGI exposed through your web framework.
225 - You can do cool things with PSGI!
228 - Even if you do most of your work using your framework, you can do some useful things with PSGI.
229 - We will get to some of those cool things, so hang tight.
240 ### **H**yper**t**ext **T**ransfer **P**rotocol
243 - Invented by Tim Berners-Lee in
1989, first specified as [HTTP
0.9](https://www.w3.org/Protocols/HTTP/AsImplemented.html) in
1991.
246 - The IETF and W3C took over standards development, resulting in [RFC
1945](https://tools.ietf.org/html/rfc1945) ("HTTP
1.0") in
1996.
249 - IETF = Internet Engineering Task Force
250 - W3C = World Wide Web Consortium
253 - [RFC
2068](https://tools.ietf.org/html/rfc2068) ("HTTP
1.1") happened in
1997, superceded by [RFC
2616](https://tools.ietf.org/html/rfc2616) in
1999.
256 RFC
2616 was then superceded in
2014 by:
257 - [RFC
7230](https://tools.ietf.org/html/rfc7230)
258 - [RFC
7231](https://tools.ietf.org/html/rfc7231)
259 - [RFC
7232](https://tools.ietf.org/html/rfc7232)
260 - [RFC
7233](https://tools.ietf.org/html/rfc7233)
261 - [RFC
7234](https://tools.ietf.org/html/rfc7234)
262 - [RFC
7235](https://tools.ietf.org/html/rfc7235)
265 - Oh yeah, and HTTP2 came out in
2015, defined in [RFC
7540](https://tools.ietf.org/html/rfc7540).
274 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
276 Accept-Language: en-us
277 Connection: Keep-Alive
286 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
289 Content-Type: text/plain
292 Your IP address is
127.0.0.1.
303 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
305 Accept-Language: en-us
306 Connection: Keep-Alive
315 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
318 Content-Type: text/plain
321 Your IP address is
127.0.0.1.
326 1. Method, path, protocol/version
330 - Methods defined in HTTP/
1.1: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT
331 - RFC
5789 defined PATCH in March
2010.
340 *User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
342 *Accept-Language: en-us
343 *Connection: Keep-Alive
352 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
355 Content-Type: text/plain
358 Your IP address is
127.0.0.1.
363 1. Method, path, protocol/version
364 2. Headers (key-value pairs)
374 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
376 Accept-Language: en-us
377 Connection: Keep-Alive
386 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
389 Content-Type: text/plain
392 Your IP address is
127.0.0.1.
397 1. Method, path, protocol/version
398 2. Headers (key-value pairs)
399 3. Optional document (or "body")
409 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
411 Accept-Language: en-us
412 Connection: Keep-Alive
421 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
424 Content-Type: text/plain
427 Your IP address is
127.0.0.1.
432 1. Method, path, protocol/version
433 2. Headers (key-value pairs)
434 3. Optional document (or "body")
438 1. Protocol/version, status code, reason phrase
448 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
450 Accept-Language: en-us
451 Connection: Keep-Alive
460 *Date: Thu,
07 Jul
2016 11:
56:
23 GMT
463 *Content-Type: text/plain
466 Your IP address is
127.0.0.1.
471 1. Method, path, protocol/version
472 2. Headers (key-value pairs)
473 3. Optional document (or "body")
477 1. Protocol/version, status code, reason phrase
478 2. Headers (key-value pairs)
488 User-Agent: Mozilla/
5.0 (X11; Linux x86_64)
490 Accept-Language: en-us
491 Connection: Keep-Alive
500 Date: Thu,
07 Jul
2016 11:
56:
23 GMT
503 Content-Type: text/plain
506 *Your IP address is
127.0.0.1.
511 1. Method, path, protocol/version
512 2. Headers (key-value pairs)
513 3. Optional document (or "body")
517 1. Protocol/version, status code, reason phrase
518 2. Headers (key-value pairs)
519 3. Optional document (or "body")
526 ## Alternatives to PSGI
540 - All of these still exist, and actually all of these are still in common use.
541 - We're going to take a closer look at three of these.
545 ## Alternatives to PSGI
548 - .highlight[mod_perl]
549 - .highlight[FastCGI]
570 ### **C**ommon **G**ateway **I**nterface
573 - Created by the NCSA in
1993.
576 - NCSA = National Center for Supercomputing Applications
579 - More formally defined in [RFC
3875](https://tools.ietf.org/html/rfc3875) ("CGI Version
1.1") in October
2004.
584 my $client_ip = $ENV{'REMOTE_ADDR'};
586 print "Content-Type: text/plain\n";
587 print "Status:
200 OK\n";
590 print "Your IP address is ${client_ip}.";
596 *my $client_ip = $ENV{'REMOTE_ADDR'};
598 print "Content-Type: text/plain\n";
599 print "Status:
200 OK\n";
602 print "Your IP address is ${client_ip}.";
605 1. Gateway sets information about the request in the environment.
607 .condensed.marginfix[
612 - `GATEWAY_INTERFACE`
628 - other "protocol-specific" variables
633 - In Perl, you can get these using %ENV.
634 - Or getenv from stdlib.
635 - If you've done some web programming before, you're probably familiar with at least a few of these.
640 my $client_ip = $ENV{'REMOTE_ADDR'};
642 *print "Content-Type: text/plain\n";
643 *print "Status:
200 OK\n";
646 print "Your IP address is ${client_ip}.";
649 1. Gateway sets information about the request in the environment.
650 2. Print response headers to `STDOUT`.
652 .condensed.marginfix[
657 - other "protocol-specific" header fields
664 my $client_ip = $ENV{'REMOTE_ADDR'};
666 print "Content-Type: text/plain\n";
667 print "Status:
200 OK\n";
670 print "Your IP address is ${client_ip}.";
673 1. Gateway sets information about the request in the environment.
674 2. Print response headers to `STDOUT`.
680 my $client_ip = $ENV{'REMOTE_ADDR'};
682 print "Content-Type: text/plain\n";
683 print "Status:
200 OK\n";
686 *print "Your IP address is ${client_ip}.";
689 1. Gateway sets information about the request in the environment.
690 2. Print response headers to `STDOUT`.
692 4. Print response document (if any).
697 my $client_ip = $ENV{'REMOTE_ADDR'};
699 print "Content-Type: text/plain\n";
700 print "Status:
200 OK\n";
703 print "Your IP address is ${client_ip}.";
706 1. Gateway sets information about the request in the environment.
707 2. Print response headers to `STDOUT`.
709 4. Print response document (if any).
710 5. Read request document from `STDIN` (if any).
713 - CGI.pm helps cut down boilerplate by helping parse things like `QUERY_STRING` and `HTTP_COOKIE`,
714 producing correctly-formatted headers, and even producing HTML.
715 - CGI.pm was deprecated in perl
5.20 and remove from core in perl
5.22.
718 - Conceptually simple.
719 - Only requires the use of the most basic and primitive program constructs (stdin, stdout, env).
720 - Only other primitive construct that could have been used is that of passing program arguments.
721 - Actually, the spec does specify behavior for "search-strings" as program arguments.
724 - Details can get complicated.
725 - Although the de facto standard for years, modern web servers are choosing to not support it
727 - There is too much overhead in forking and execing.
735 ![FastCGI](img/fastcgi.png)
742 ### a low-overhead variation on CGI
745 - Binary protocol with support for pipelining and multiplexing.
748 - Open Market wrote the [specification](http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html) on
29 Apr
1996.
751 - Open Market was an ecommerce startup based in Massachusetts.
752 - Developed one of the first HTTP servers.
759 my $request = FCGI::Request();
761 while (
0 <= $request-
>Accept()) {
762 my $client_ip = $ENV{'REMOTE_ADDR'};
764 print "Content-Type: text/html\n\n";
765 print "Your IP address is ${client_ip}.";
774 *my $request = FCGI::Request();
776 while (
0 <= $request-
>Accept()) {
777 my $client_ip = $ENV{'REMOTE_ADDR'};
779 print "Content-Type: text/html\n\n";
780 print "Your IP address is ${client_ip}.";
784 1. Use `FCGI` and instantiate an object.
791 my $request = FCGI::Request();
793 *while (
0 <= $request-
>Accept()) {
794 my $client_ip = $ENV{'REMOTE_ADDR'};
796 print "Content-Type: text/html\n\n";
797 print "Your IP address is ${client_ip}.";
801 1. Use `FCGI` and instantiate an object.
802 2. Loop on `Accept()` which blocks until the next request is received.
809 my $request = FCGI::Request();
811 while (
0 <= $request-
>Accept()) {
812 * my $client_ip = $ENV{'REMOTE_ADDR'};
814 * print "Content-Type: text/html\n\n";
815 * print "Your IP address is ${client_ip}.";
819 1. Use `FCGI` and instantiate an object.
820 2. Loop on `Accept()` which blocks until the next request is received.
821 3. Otherwise appears similar to a CGI program.
828 my $request = FCGI::Request();
830 while (
0 <= $request-
>Accept()) {
831 my $client_ip = $ENV{'REMOTE_ADDR'};
833 print "Content-Type: text/html\n\n";
834 print "Your IP address is ${client_ip}.";
838 1. Use `FCGI` and instantiate an object.
839 2. Loop on `Accept()` which blocks until the next request is received.
840 3. Otherwise appears similar to a CGI program.
842 * IPC actually happens over a socket!
845 - Can be run unmodified as a CGI script by detecting that stdin is not a socket.
846 - Can read from stdin and write to stdout via the miracle of tied filehandles.
854 ![mod_perl](img/mod_perl.gif)
862 - First released on March
25,
1996.
865 - Unlike the interfaces we have examined so far, mod_perl is code.
866 - About the same time as FastCGI.
869 - Became an Apache Software Foundation project at ApacheCon
1999 in Orlando.
876 use Apache::RequestRec ();
877 use Apache::Connection ();
878 use Apache::Const -compile =
> qw(OK);
882 my $client_ip = $r-
>connection-
>remote_addr;
884 $r-
>content_type('text/plain');
885 $r-
>print("Your IP address is ${client_ip}.");
886 return Apache::Const::OK;
893 - Notice how we're not using STDOUT (or even pretending to).
894 - This program actually runs on a perl interpreter inside the web server.
895 - It also has access to more information through the exposed API.
898 - Can run CGI programs as-is.
901 - Can tie you to specific web servers.
902 - There's a separate mod_perl for nginx.
903 - Code runs in the same process as the HTTP server -- kinda scary.
904 - Using Apache's API feels heavy.
918 my $client_id = $env-
>{'REMOTE_ADDR'};
922 [ 'Content-Type' =
> 'text/plain' ],
923 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
929 - I think it's good to understand CGI et al. so that you can understand why it was designed the way
931 - Hopefully the ideas behind PSGI are based off of the best that CGI et al. had to offer without any
935 - Notice how the program is a subroutine.
936 - By being a subrouting rather than a script that is executed, we're already in a form that can be
937 called repeatedly without incurring fork-exec overhead. Nice!
944 * my $client_id = $env-
>{'REMOTE_ADDR'};
948 [ 'Content-Type' =
> 'text/plain' ],
949 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
957 1. Hashref of request information.
961 - Oh, look! The variable is the same as is specified by CGI.
962 - Why throw away over a decade of convention?
969 my $client_id = $env-
>{'REMOTE_ADDR'};
973 [ 'Content-Type' =
> 'text/plain' ],
974 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
982 1. Hashref of request information.
992 - Then you'll notice that instead of printing anything, we return an arrayref as the response.
999 my $client_id = $env-
>{'REMOTE_ADDR'};
1003 * [ 'Content-Type' =
> 'text/plain' ],
1004 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
1012 1. Hashref of request information.
1018 1. HTTP status code.
1019 2. Arrayref of response headers.
1023 - Why not a hashref?
1024 - To support multiple headers (e.g. Set-Cookie)
1025 - It more closely resembles how the WSGI folks did it (i.e. list of tuples).
1032 my $client_id = $env-
>{'REMOTE_ADDR'};
1036 [ 'Content-Type' =
> 'text/plain' ],
1037 * [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
1045 1. Hashref of request information.
1051 1. HTTP status code.
1052 2. Arrayref of response headers.
1053 3. Response document.
1057 - Body may be a list of chunks that are concatenated together or a handle to read from.
1068 .condensed.marginfix[
1071 - `HTTP_ACCEPT_ENCODING`
1072 - `HTTP_ACCEPT_LANGUAGE`
1073 - `HTTP_CACHE_CONTROL`
1092 - `psgi.multiprocess`
1093 - `psgi.multithread`
1094 - `psgi.nonblocking`
1100 - `psgix.input.buffered`
1107 .condensed.marginfix[
1109 - .highlight[`HTTP_ACCEPT`]
1110 - .highlight[`HTTP_ACCEPT_ENCODING`]
1111 - .highlight[`HTTP_ACCEPT_LANGUAGE`]
1112 - .highlight[`HTTP_CACHE_CONTROL`]
1113 - .highlight[`HTTP_CONNECTION`]
1114 - .highlight[`HTTP_DNT`]
1115 - .highlight[`HTTP_HOST`]
1116 - .highlight[`HTTP_USER_AGENT`]
1117 - .highlight[`PATH_INFO`]
1118 - .highlight[`QUERY_STRING `]
1119 - .highlight[`REMOTE_ADDR`]
1120 - .highlight[`REMOTE_PORT`]
1121 - .highlight[`REQUEST_METHOD`]
1122 - .highlight[`REQUEST_URI`]
1123 - .highlight[`SCRIPT_NAME`]
1126 - .highlight[`SERVER_NAME`]
1127 - .highlight[`SERVER_PORT`]
1128 - .highlight[`SERVER_PROTOCOL`]
1131 - `psgi.multiprocess`
1132 - `psgi.multithread`
1133 - `psgi.nonblocking`
1139 - `psgix.input.buffered`
1146 .condensed.marginfix[
1149 - `HTTP_ACCEPT_ENCODING`
1150 - `HTTP_ACCEPT_LANGUAGE`
1151 - `HTTP_CACHE_CONTROL`
1168 - .highlight[`psgi.errors`]
1169 - .highlight[`psgi.input`]
1170 - .highlight[`psgi.multiprocess`]
1171 - .highlight[`psgi.multithread`]
1172 - .highlight[`psgi.nonblocking`]
1173 - .highlight[`psgi.run_once`]
1174 - .highlight[`psgi.streaming`]
1175 - .highlight[`psgi.url_scheme`]
1176 - .highlight[`psgi.version`]
1177 - .highlight[`psgix.harakiri`]
1178 - .highlight[`psgix.input.buffered`]
1179 - .highlight[`psgix.io`]
1184 - Harakiri is a form of Japanese ritual suicide by disembowelment.
1192 - Everything is a data structure (almost).
1195 - Makes it easier to write tests because mocking either the app or server is clear.
1196 - Don't necessarily need to parse a bytestream to check stuff.
1199 - No global data or shared IO handles.
1202 - This lets you service multiple requests asynchronously in the same process/thread.
1205 - Takes deployment details out of web frameworks.
1208 - Web frameworks only need to target PSGI.
1209 - No need to worry about the boring stuff; they can focus on the abstractions that make them unique
1213 - End-users of your app have many deployment options for free.
1219 - [Catalyst](http://www.catalystframework.org/)
1220 - [Mojolicious](http://mojolicious.org/)
1221 - [Dancer](http://perldancer.org/)
1222 - [CGI::Application](http://cgi-app.org/)
1223 - [CGI::Ex](https://github.com/chazmcgarvey/CGI-Ex/tree/psgi-
2)
1224 - [Web::Simple](https://metacpan.org/pod/Web::Simple)
1225 - [Amon2](https://metacpan.org/pod/Amon2)
1226 - [Poet](https://metacpan.org/pod/Poet)
1227 - [Kelp](https://metacpan.org/pod/Kelp)
1228 - [Raisin](https://metacpan.org/pod/Raisin)
1237 - Provides tools for building, running, and testing PSGI apps.
1240 - [Plack::Handler](https://metacpan.org/pod/Plack::Handler)
1243 - Connects PSGI apps and web servers.
1244 - Takes a request from the server,
1245 - converts it to the PSGI-specified environment,
1247 - converts the response back to a format the server understands.
1250 - [Plack::Loader](https://metacpan.org/pod/Plack::Loader)
1253 - Picks an appropriate Plack::Handler (based on ENV, loaded modules, or arguments) and loads it.
1254 - Can also do stuff like restart the loader when files change.
1257 - [Plack::Runner](https://metacpan.org/pod/Plack::Runner), [plackup](https://metacpan.org/pod/plackup)
1260 - Run PSGI apps from the command-line.
1263 - [Plack::Middleware](https://metacpan.org/pod/Plack::Middleware)
1266 - Create subroutines that run between the handler and your app.
1267 - Can alter the request your app receives and modify the response your app returns.
1270 - [Plack::Request](https://metacpan.org/pod/Plack::Request), [Plack::Response](https://metacpan.org/pod/Plack::Response)
1273 - Request and response wrappers can help simplify writing middleware.
1276 - [Plack::Builder](https://metacpan.org/pod/Plack::Builder)
1279 - Provides DSL for composing apps and middleware.
1282 - [Plack::Test](https://metacpan.org/pod/Plack::Test), [Plack::Test::Suite](https://metacpan.org/pod/Plack::Test::Suite)
1285 - Use Plack::Test for testing apps.
1286 - Plack::Test::Suite is a series of tests for testing handlers.
1289 - [Plack::Util](https://metacpan.org/pod/Plack::Util)
1292 - Provides random useful stuff for handler and middleware developers.
1293 - Stuff like determing the length of a document or getting PSGI response headers from the arrayref.
1301 - Run PSGI apps from the command-line.
1304 # read your app from app.psgi file
1307 # choose .psgi file from ARGV[
0] (or with -a option)
1310 # switch server implementation with --server (or -s)
1311 plackup --server HTTP::Server::Simple --port
9090 --host
127.0.0.1 test.psgi
1313 # use UNIX socket to run FCGI daemon
1314 plackup -s FCGI --listen /tmp/fcgi.sock myapp.psgi
1316 # launch FCGI external server on port
9090
1317 plackup -s FCGI --port
9090
1334 my $client_id = $env-
>{'REMOTE_ADDR'};
1338 [ 'Content-Type' =
> 'text/plain' ],
1339 [ "Your IP address is ${client_id}." ],
1349 *use Plack::Builder;
1353 my $client_id = $env-
>{'REMOTE_ADDR'};
1357 [ 'Content-Type' =
> 'text/plain' ],
1358 [ "Your IP address is ${client_id}." ],
1364 * mount '/' =
> $app;
1369 - The `Runtime` middleware adds an `X-Runtime` header to the response with the number of seconds it
1370 took to process the request.
1378 - Can be found on the CPAN in the `Plack::Handler::` namespace.
1379 - [Apache1](https://metacpan.org/pod/Plack::Handler::Apache1), [Apache2](https://metacpan.org/pod/Plack::Handler::Apache2)
1380 - [CGI](https://metacpan.org/pod/Plack::Handler::CGI)
1381 - [FCGI](https://metacpan.org/pod/Plack::Handler::FCGI)
1382 - [HTTP::Server::PSGI](https://metacpan.org/pod/Plack::Handler::HTTP::Server::PSGI)
1383 - [SCGI](https://metacpan.org/pod/Plack::Handler::SCGI)
1384 - [Starman](https://metacpan.org/pod/Plack::Handler::Starman)
1385 - [Twiggy](https://metacpan.org/pod/Plack::Handler::Twiggy)
1386 - [AnyEvent::HTTPD](https://metacpan.org/pod/Plack::Handler::AnyEvent::HTTPD)
1387 - [Thrall](https://metacpan.org/pod/Plack::Handler::Thrall)
1399 name: middleware-debug
1401 ### [`Debug`](https://metacpan.org/pod/Plack::Middleware::Debug)
1409 ### [`ReverseProxy`](https://metacpan.org/pod/Plack::Middleware::ReverseProxy)
1412 enable 'ReverseProxy';
1415 - Fixes `REMOTE_ADDR`, `HTTP_HOST`, `SERVER_PORT`, and `psgi.url_scheme` in the environment.
1419 ### [`LogDispatch`](https://metacpan.org/pod/Plack::Middleware::LogDispatch)
1424 my $logger = Log::Dispatch-
>new(
1428 min_level =
> 'debug',
1434 enable 'LogDispatch', logger =
> $logger;
1439 ### [`XSRFBlock`](https://metacpan.org/pod/Plack::Middleware::XSRFBlock)
1442 enable 'XSRFBlock', cookie_options =
> { httponly =
> 1 };
1445 - Blocking cross-site request forgery couldn't be easier.
1449 ### [`RedirectSSL`](https://metacpan.org/pod/Plack::Middleware::RedirectSSL)
1452 enable 'RedirectSSL';
1455 - Redirects from http to https (or backwards, if configured).
1456 - Can also set HSTS header with configurable `max-age`.
1459 - HSTS = HTTP Strict Transport Security
1466 ![CPAN](img/cpan.png)
1469 ## Plack modules in July
2016
1471 **
10** `Plack-Handler-*` distributions
1473 **
55** `Plack-App-*` distributions
1475 **
253** `Plack-Middleware-*` distributions
1481 - PSGI also specifies a way to delay or stream responses to the server.
1484 - It's kind of complicated, but you can read the spec to learn more.
1485 - Read the source code of various apps and middlewares to see how it works in practice.
1488 - There are tons of great apps and middleware on the CPAN.
1491 - Consider writing some of your app as a middleware.
1494 - The concept and implementation of middleware is cool.
1495 - You should consider writing parts of your app as middleware so that functionality is available
1496 under different web frameworks.
1497 - Stuff that makes sense as middleware:
1506 class: center, middle
1511 ### Understand PSGI & Plack, and use them!
1515 class: center, middle
1523 class: center, middle
1529 Email me: Charles McGarvey
1530 <chazmcgarvey@brokenzipper.com
>
1533 Leave me feedback, if you want:
1535 ![Page on Joind.in](img/talkqr.svg)
1537 <https://joind.in/talk/
6e4d2
>
1545 - Thank you [Tatsuhiko Miyagawa](http://weblog.bulknews.net/) and other contributors for creating PSGI and Plack.
1549 </textarea><script src=
"https://gnab.github.io/remark/downloads/remark-latest.min.js"></script><script>var slideshow = remark.create({countIncrementalSlides: true, highlightLanguage: 'perl', highlightLines: true, ratio: '
16:
9', /*slideNumberFormat: '',*/ navigation: {scroll: false, touch: false, click: false}})
</script><script src=
"js/common.js"></script><script src=
"js/slides.js"></script></body></html>
1550 <!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->