---
+class: center, middle
+name: perl-code
+
+```perl
+@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP rehtona tsuJ";sub p{
+@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{$P=$P[$f^ord
+($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{$p{$_}=~/^[P.]/&&
+close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep rand(2)if/\S/;print
+```
+
+Source: [Just Another Perl / Unix Hacker](http://perl.plover.com/obfuscated/) by Mark Jason Dominus
+
+???
+This is a Perl presentation, so I hope code that looks like this doesn't frighten you.
+
+---
+
## Agenda
- Answer "What is PSGI?"
---
-class: center, middle
+class: center, middle
+name: psgi-flow1
## Extremely High-level Overview
---
-class: center, middle
+class: center, middle
+name: psgi-flow2
## Pretty High-level Overview
---
-class: center, middle
+class: center, middle
+name: psgi-flow3
## Somewhat High-level Overview
---
-class: center, middle
+class: center, middle
+name: psgi-flow4
## Somewhat High-level Overview
---
-class: center, middle
+class: center, middle
+name: psgi-flow5
## High-level Overview
???
- A web framework makes it so your app doesn't need to speak HTTP or CGI or even PSGI.
- -
---
- New skills make you more marketable.
--
-- So that you it when you see PSGI exposed through your web framework.
+- So that you understand it when you see PSGI exposed through your web framework.
--
- You can do cool things with PSGI!
---
-### Hypertext Transfer Protocol
+### **H**yper**t**ext **T**ransfer **P**rotocol
--
- Invented by Tim Berners-Lee in 1989, first specified as [HTTP 0.9](https://www.w3.org/Protocols/HTTP/AsImplemented.html) in 1991.
--
- The IETF and W3C took over standards development, resulting in [RFC 1945](https://tools.ietf.org/html/rfc1945) ("HTTP 1.0") in 1996.
+???
+- IETF = Internet Engineering Task Force
+- W3C = World Wide Web Consortium
+
--
- [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.
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
*GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
*User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-*Host: foo.acme.tld
+*Host: localhost
*Accept-Language: en-us
*Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
*HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
*Date: Thu, 07 Jul 2016 11:56:23 GMT
*Server: nginx
-*Content-Length: 30
+*Content-Length: 29
*Content-Type: text/plain
*Connection: Closed
---
-.col[
+.col.marginfix[
### Request
```http
GET /ip HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
-Host: foo.acme.tld
+Host: localhost
Accept-Language: en-us
Connection: Keep-Alive
```
]
-.col[
+.col.marginfix[
### Response
```http
HTTP/1.1 200 OK
Date: Thu, 07 Jul 2016 11:56:23 GMT
Server: nginx
-Content-Length: 30
+Content-Length: 29
Content-Type: text/plain
Connection: Closed
---
-### Common Gateway Interface
+### **C**ommon **G**ateway **I**nterface
--
- Created by the NCSA in 1993.
1. Gateway sets information about the request in the environment.
-.condensed[
+.condensed.marginfix[
.col[
-- AUTH_TYPE
-- CONTENT_LENGTH
-- CONTENT_TYPE
-- GATEWAY_INTERFACE
-- PATH_INFO
-- PATH_TRANSLATED
-- QUERY_STRING
-- REMOTE_ADDR
-- REMOTE_HOST
+- `AUTH_TYPE`
+- `CONTENT_LENGTH`
+- `CONTENT_TYPE`
+- `GATEWAY_INTERFACE`
+- `PATH_INFO`
+- `PATH_TRANSLATED`
+- `QUERY_STRING`
+- `REMOTE_ADDR`
+- `REMOTE_HOST`
]
.col[
-- REMOTE_IDENT
-- REMOTE_USER
-- REQUEST_METHOD
-- SCRIPT_NAME
-- SERVER_NAME
-- SERVER_PORT
-- SERVER_PROTOCOL
-- SERVER_SOFTWARE
+- `REMOTE_IDENT`
+- `REMOTE_USER`
+- `REQUEST_METHOD`
+- `SCRIPT_NAME`
+- `SERVER_NAME`
+- `SERVER_PORT`
+- `SERVER_PROTOCOL`
+- `SERVER_SOFTWARE`
- other "protocol-specific" variables
]
]
+???
+- In Perl, you can get these using %ENV.
+- Or getenv from stdlib.
+- If you've done some web programming before, you're probably familiar with at least a few of these.
+
---
```perl
1. Gateway sets information about the request in the environment.
2. Print response headers to `STDOUT`.
-.condensed[
+.condensed.marginfix[
.col[
-- Content-Type
-- Location
-- Status
+- `Content-Type`
+- `Location`
+- `Status`
- other "protocol-specific" header fields
]
]
producing correctly-formatted headers, and even producing HTML.
- CGI.pm was deprecated in perl 5.20 and remove from core in perl 5.22.
-TODO make a slide for this
Good:
- Conceptually simple.
- Only requires the use of the most basic and primitive program constructs (stdin, stdout, env).
+- Only other primitive construct that could have been used is that of passing program arguments.
+ - Actually, the spec does specify behavior for "search-strings" as program arguments.
Bad:
- Details can get complicated.
???
- Unlike the interfaces we have examined so far, mod_perl is code.
+- About the same time as FastCGI.
--
- Became an Apache Software Foundation project at ApacheCon 1999 in Orlando.
```
???
-- There's a separate mod_perl for nginx.
+- Notice how we're not using STDOUT (or even pretending to).
+- This program actually runs on a perl interpreter inside the web server.
+- It also has access to more information through the exposed API.
Good:
- Can run CGI programs as-is.
Bad:
- Can tie you to specific web servers.
+ - There's a separate mod_perl for nginx.
- Code runs in the same process as the HTTP server -- kinda scary.
- Using Apache's API feels heavy.
};
```
+???
+- I think it's good to understand CGI et al. so that you can understand why it was designed the way
+ it was.
+- Hopefully the ideas behind PSGI are based off of the best that CGI et al. had to offer without any
+ of the drawbacks.
+
+
+- Notice how the program is a subroutine.
+- By being a subrouting rather than a script that is executed, we're already in a form that can be
+ called repeatedly without incurring fork-exec overhead. Nice!
+
---
```perl
1. Hashref of request information.
]
+???
+- Oh, look! The variable is the same as is specified by CGI.
+ - Why throw away over a decade of convention?
+
---
```perl
1. HTTP status code.
]
+???
+- Then you'll notice that instead of printing anything, we return an arrayref as the response.
+
---
```perl
---
+class: env
+layout: true
+
+## PSGI Environment
+
+---
+
+.condensed.marginfix[
+.col[
+- `HTTP_ACCEPT`
+- `HTTP_ACCEPT_ENCODING`
+- `HTTP_ACCEPT_LANGUAGE`
+- `HTTP_CACHE_CONTROL`
+- `HTTP_CONNECTION`
+- `HTTP_DNT`
+- `HTTP_HOST`
+- `HTTP_USER_AGENT`
+- `PATH_INFO`
+- `QUERY_STRING `
+- `REMOTE_ADDR`
+- `REMOTE_PORT`
+- `REQUEST_METHOD`
+- `REQUEST_URI`
+- `SCRIPT_NAME`
+]
+.col[
+- `SERVER_NAME`
+- `SERVER_PORT`
+- `SERVER_PROTOCOL`
+- `psgi.errors`
+- `psgi.input`
+- `psgi.multiprocess`
+- `psgi.multithread`
+- `psgi.nonblocking`
+- `psgi.run_once`
+- `psgi.streaming`
+- `psgi.url_scheme`
+- `psgi.version`
+- `psgix.harakiri`
+- `psgix.input.buffered`
+- `psgix.io`
+]
+]
+
+---
+
+.condensed.marginfix[
+.col[
+- .highlight[`HTTP_ACCEPT`]
+- .highlight[`HTTP_ACCEPT_ENCODING`]
+- .highlight[`HTTP_ACCEPT_LANGUAGE`]
+- .highlight[`HTTP_CACHE_CONTROL`]
+- .highlight[`HTTP_CONNECTION`]
+- .highlight[`HTTP_DNT`]
+- .highlight[`HTTP_HOST`]
+- .highlight[`HTTP_USER_AGENT`]
+- .highlight[`PATH_INFO`]
+- .highlight[`QUERY_STRING `]
+- .highlight[`REMOTE_ADDR`]
+- .highlight[`REMOTE_PORT`]
+- .highlight[`REQUEST_METHOD`]
+- .highlight[`REQUEST_URI`]
+- .highlight[`SCRIPT_NAME`]
+]
+.col[
+- .highlight[`SERVER_NAME`]
+- .highlight[`SERVER_PORT`]
+- .highlight[`SERVER_PROTOCOL`]
+- `psgi.errors`
+- `psgi.input`
+- `psgi.multiprocess`
+- `psgi.multithread`
+- `psgi.nonblocking`
+- `psgi.run_once`
+- `psgi.streaming`
+- `psgi.url_scheme`
+- `psgi.version`
+- `psgix.harakiri`
+- `psgix.input.buffered`
+- `psgix.io`
+]
+]
+
+---
+
+.condensed.marginfix[
+.col[
+- `HTTP_ACCEPT`
+- `HTTP_ACCEPT_ENCODING`
+- `HTTP_ACCEPT_LANGUAGE`
+- `HTTP_CACHE_CONTROL`
+- `HTTP_CONNECTION`
+- `HTTP_DNT`
+- `HTTP_HOST`
+- `HTTP_USER_AGENT`
+- `PATH_INFO`
+- `QUERY_STRING `
+- `REMOTE_ADDR`
+- `REMOTE_PORT`
+- `REQUEST_METHOD`
+- `REQUEST_URI`
+- `SCRIPT_NAME`
+]
+.col[
+- `SERVER_NAME`
+- `SERVER_PORT`
+- `SERVER_PROTOCOL`
+- .highlight[`psgi.errors`]
+- .highlight[`psgi.input`]
+- .highlight[`psgi.multiprocess`]
+- .highlight[`psgi.multithread`]
+- .highlight[`psgi.nonblocking`]
+- .highlight[`psgi.run_once`]
+- .highlight[`psgi.streaming`]
+- .highlight[`psgi.url_scheme`]
+- .highlight[`psgi.version`]
+- .highlight[`psgix.harakiri`]
+- .highlight[`psgix.input.buffered`]
+- .highlight[`psgix.io`]
+]
+]
+
+???
+- Harakiri is a form of Japanese ritual suicide by disembowelment.
+
+---
+
layout: false
## Benefits of PSGI
---
+class: plack
+
## Plack
- Provides tools for building, running, and testing PSGI apps.
---
-class: env
-layout: true
-
-## Plack `$env`
-
----
-
-.condensed[
-.col[
-- HTTP_ACCEPT
-- HTTP_ACCEPT_ENCODING
-- HTTP_ACCEPT_LANGUAGE
-- HTTP_CACHE_CONTROL
-- HTTP_CONNECTION
-- HTTP_DNT
-- HTTP_HOST
-- HTTP_USER_AGENT
-- PATH_INFO
-- QUERY_STRING
-- REMOTE_ADDR
-- REMOTE_PORT
-- REQUEST_METHOD
-- REQUEST_URI
-- SCRIPT_NAME
-]
-.col[
-- SERVER_NAME
-- SERVER_PORT
-- SERVER_PROTOCOL
-- psgi.errors
-- psgi.input
-- psgi.multiprocess
-- psgi.multithread
-- psgi.nonblocking
-- psgi.run_once
-- psgi.streaming
-- psgi.url_scheme
-- psgi.version
-- psgix.harakiri
-- psgix.input.buffered
-- psgix.io
-]
-]
-
----
-
-.condensed[
-.col[
-- .highlight[HTTP_ACCEPT]
-- .highlight[HTTP_ACCEPT_ENCODING]
-- .highlight[HTTP_ACCEPT_LANGUAGE]
-- .highlight[HTTP_CACHE_CONTROL]
-- .highlight[HTTP_CONNECTION]
-- .highlight[HTTP_DNT]
-- .highlight[HTTP_HOST]
-- .highlight[HTTP_USER_AGENT]
-- .highlight[PATH_INFO]
-- .highlight[QUERY_STRING ]
-- .highlight[REMOTE_ADDR]
-- .highlight[REMOTE_PORT]
-- .highlight[REQUEST_METHOD]
-- .highlight[REQUEST_URI]
-- .highlight[SCRIPT_NAME]
-]
-.col[
-- .highlight[SERVER_NAME]
-- .highlight[SERVER_PORT]
-- .highlight[SERVER_PROTOCOL]
-- psgi.errors
-- psgi.input
-- psgi.multiprocess
-- psgi.multithread
-- psgi.nonblocking
-- psgi.run_once
-- psgi.streaming
-- psgi.url_scheme
-- psgi.version
-- psgix.harakiri
-- psgix.input.buffered
-- psgix.io
-]
-]
-
----
-
-.condensed[
-.col[
-- HTTP_ACCEPT
-- HTTP_ACCEPT_ENCODING
-- HTTP_ACCEPT_LANGUAGE
-- HTTP_CACHE_CONTROL
-- HTTP_CONNECTION
-- HTTP_DNT
-- HTTP_HOST
-- HTTP_USER_AGENT
-- PATH_INFO
-- QUERY_STRING
-- REMOTE_ADDR
-- REMOTE_PORT
-- REQUEST_METHOD
-- REQUEST_URI
-- SCRIPT_NAME
-]
-.col[
-- SERVER_NAME
-- SERVER_PORT
-- SERVER_PROTOCOL
-- .highlight[psgi.errors]
-- .highlight[psgi.input]
-- .highlight[psgi.multiprocess ]
-- .highlight[psgi.multithread ]
-- .highlight[psgi.nonblocking ]
-- .highlight[psgi.run_once ]
-- .highlight[psgi.streaming]
-- .highlight[psgi.url_scheme]
-- .highlight[psgi.version]
-- .highlight[psgix.harakiri]
-- .highlight[psgix.input.buffered]
-- .highlight[psgix.io]
-]
-]
-
----
-
layout: false
## Plack Handlers
### [`XSRFBlock`](https://metacpan.org/pod/Plack::Middleware::XSRFBlock)
```perl
-enable 'XSRFBlock';
+enable 'XSRFBlock', cookie_options => { httponly => 1 };
```
- Blocking cross-site request forgery couldn't be easier.
- Redirects from http to https (or backwards, if configured).
- Can also set HSTS header with configurable `max-age`.
+???
+- HSTS = HTTP Strict Transport Security
+
---
layout: false
![CPAN](img/cpan.png)
]
-## Plack modules on the CPAN in July 2016
+## Plack modules in July 2016
**10** `Plack-Handler-*` distributions
## Parting Thoughts
-- You should write middleware!
+- PSGI also specifies a way to delay or stream responses to the server.
+
+???
+- It's kind of complicated, but you can read the spec to learn more.
+- Read the source code of various apps and middlewares to see how it works in practice.
+
+--
+- There are tons of great apps and middleware on the CPAN.
+
+--
+- Consider writing some of your app as a middleware.
???
- The concept and implementation of middleware is cool.
- Sessions
- Rate limiters
---
-- PSGI also specifies a way to delay or stream responses to the server.
-
-???
-- It's kind of complicated, but you can read the spec to learn more.
-- Read the source code of various apps and middlewares to see how it works in practice.
-
---
class: center, middle
## Thank you
Email me: Charles McGarvey
-<cmcgarvey@bluehost.com>
<chazmcgarvey@brokenzipper.com>
.talkqr.center[
]
]
-</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></body></html>
+</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>
<!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->