X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftalk-introduction-to-psgi;a=blobdiff_plain;f=slides.html;h=430a5667a47c1d0fefd5090f20b89fa258f69a4a;hp=fef0bc2a56e47c841dfd48358d97a74927100f8d;hb=HEAD;hpb=c3702aa22054180570f09c504f29b7a3b183225b diff --git a/slides.html b/slides.html index fef0bc2..430a566 100644 --- a/slides.html +++ b/slides.html @@ -19,6 +19,23 @@ name: bluehost --- +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?" @@ -63,7 +80,8 @@ Despite Perl's long history of powering the web, we were well behind the curve o --- -class: center, middle +class: center, middle +name: psgi-flow1 ## Extremely High-level Overview @@ -78,7 +96,8 @@ class: center, middle --- -class: center, middle +class: center, middle +name: psgi-flow2 ## Pretty High-level Overview @@ -92,7 +111,8 @@ class: center, middle --- -class: center, middle +class: center, middle +name: psgi-flow3 ## Somewhat High-level Overview @@ -117,7 +137,8 @@ class: center, middle --- -class: center, middle +class: center, middle +name: psgi-flow4 ## Somewhat High-level Overview @@ -139,7 +160,8 @@ class: center, middle --- -class: center, middle +class: center, middle +name: psgi-flow5 ## High-level Overview @@ -149,7 +171,6 @@ class: center, middle ??? - A web framework makes it so your app doesn't need to speak HTTP or CGI or even PSGI. - - --- @@ -198,7 +219,7 @@ If you're a developer writing a web app, you're probably asking why then you sho - 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! @@ -216,7 +237,7 @@ layout: true --- -### 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. @@ -224,6 +245,10 @@ layout: true -- - 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. @@ -241,26 +266,26 @@ RFC 2616 was then superceded in 2014 by: --- -.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 @@ -270,26 +295,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -307,26 +332,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -341,26 +366,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -376,26 +401,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -415,26 +440,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -455,26 +480,26 @@ Your IP address is 127.0.0.1. --- -.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 @@ -542,7 +567,7 @@ layout: true --- -### Common Gateway Interface +### **C**ommon **G**ateway **I**nterface -- - Created by the NCSA in 1993. @@ -579,31 +604,36 @@ print "Your IP address is ${client_ip}."; 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 @@ -619,11 +649,11 @@ print "Your IP address is ${client_ip}."; 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 ] ] @@ -684,10 +714,11 @@ print "Your IP address is ${client_ip}."; 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. @@ -832,6 +863,7 @@ layout: true ??? - 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. @@ -858,13 +890,16 @@ sub handler { ``` ??? -- 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. @@ -890,6 +925,17 @@ my $app = sub { }; ``` +??? +- 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 @@ -911,6 +957,10 @@ my $app = sub { 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 @@ -938,6 +988,9 @@ my $app = sub { 1. HTTP status code. ] +??? +- Then you'll notice that instead of printing anything, we return an arrayref as the response. + --- ```perl @@ -1005,6 +1058,133 @@ my $app = sub { --- +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 @@ -1050,6 +1230,8 @@ layout: false --- +class: plack + ## Plack - Provides tools for building, running, and testing PSGI apps. @@ -1189,130 +1371,6 @@ my $app = sub { --- -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 @@ -1381,7 +1439,7 @@ enable 'LogDispatch', logger => $logger; ### [`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. @@ -1397,6 +1455,9 @@ enable 'RedirectSSL'; - 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 @@ -1405,7 +1466,7 @@ layout: false ![CPAN](img/cpan.png) ] -## Plack modules on the CPAN in July 2016 +## Plack modules in July 2016 **10** `Plack-Handler-*` distributions @@ -1417,7 +1478,17 @@ layout: false ## 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. @@ -1430,13 +1501,6 @@ layout: false - 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 @@ -1463,7 +1527,6 @@ name: last ## Thank you Email me: Charles McGarvey - .talkqr.center[ @@ -1483,5 +1546,5 @@ Leave me feedback, if you want: ] ] - +