]> Dogcows Code - chaz/talk-introduction-to-psgi/blob - slides.html
fix font size and typos
[chaz/talk-introduction-to-psgi] / slides.html
1 <!DOCTYPE html>
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">
3
4 class: center, middle
5 name: title
6
7 # Introduction to PSGI
8
9 Charles McGarvey
10
11 ---
12
13 class: center, middle
14 name: bluehost
15
16 ![Bluehost](img/bluehost.png)
17
18 ### https://bluehost.com/careers
19
20 ---
21
22 ## Agenda
23
24 - Answer "What is PSGI?"
25 - Examine some alternatives to PSGI.
26 - Examine PSGI.
27 - Examine Plack.
28
29 ---
30
31 ## What is PSGI?
32
33 ### **P**erl [web] **S**erver **G**ateway **I**nterface
34
35 --
36 - It is an interface between Perl web applications and web servers.
37
38 --
39 - It is a *specification*, not code.
40
41 --
42 - First released to the CPAN on 13 Oct 2009.
43
44 --
45 - Originally written by Miyagawa.
46
47 .center[![Tatsuhiko Miyagawa](img/avatar-miyagawa.jpg)]
48
49 ???
50 Written by **Tatsuhiko Miyagawa**, author of:
51 - cpanm
52 - carton
53 - way too many Perl modules on CPAN to list
54
55 --
56 - Inspired by WSGI (Python) and Rack (Ruby).
57
58 ???
59 - PEP-333 (WSGI 1.0) was released on 07 Dec 2003.
60 - Rack 0.1 was released on 03 Mar 2007.
61
62 Despite Perl's long history of powering the web, we were well behind the curve on this.
63
64 ---
65
66 class: center, middle
67
68 ## Extremely High-level Overview
69
70 .basic-flow[
71 ![Basic Flow](img/basic-flow1.svg)
72 ]
73
74 ???
75 - PSGI is the language your app speaks in order to communicate with user agents.
76 - User agents are browsers.
77 - I've glossed over some important details, like the fact that users don't speak PSGI.
78
79 ---
80
81 class: center, middle
82
83 ## Pretty High-level Overview
84
85 .basic-flow[
86 ![Basic Flow](img/basic-flow2.svg)
87 ]
88
89 ???
90 - In reality, your app speaks PSGI but user agents speak HTTP.
91 - You need software in the middle that can speak both, and that's usually a web server.
92
93 ---
94
95 class: center, middle
96
97 ## Somewhat High-level Overview
98
99 .basic-flow[
100 ![Basic Flow](img/basic-flow3.svg)
101 ]
102
103 ???
104 - In reality, most web servers don't speak PSGI. :-(
105 - There are "handlers" that speak both PSGI and another language that web servers do speak.
106 - CGI
107 - mod_perl
108 - FastCGI
109 - **HTTP**
110 - Yes, HTTP. Many modern web servers speak HTTP not only as a server but also as a client.
111 - This allows them to *proxy* (act as middleman) between user agents and other servers.
112 - In the world of PSGI (and "Plack"), handlers are also called adapters or connectors.
113 - There are already adapters for every major web server.
114 - Apache
115 - nginx
116 - IIS
117
118 ---
119
120 class: center, middle
121
122 ## Somewhat High-level Overview
123
124 .basic-flow[
125 ![Basic Flow](img/basic-flow4.svg)
126 ]
127
128 ???
129 - Notice that as we've zoomed in, the interaction between the web app and the rest has remained the
130 same: PSGI.
131 - From a developer perspective, the etremely high-level overview is sufficient.
132 - This is one of the benefits of PSGI:
133 - Write your application once and leave deployment details to devops.
134 - The intrastructure details can change (swap in a different web server) and the app will still work.
135 - Maybe you're both developer and system architect, but the separation between developer and
136 devops is valuable.
137 - In fairness, this isn't a new concept.
138 - The way this has been achieved before is using a *web framework*.
139
140 ---
141
142 class: center, middle
143
144 ## High-level Overview
145
146 .basic-flow[
147 ![Basic Flow](img/basic-flow5.svg)
148 ]
149
150 ???
151 - A web framework makes it so your app doesn't need to speak HTTP or CGI or even PSGI.
152 -
153
154 ---
155
156 class: middle
157
158 ## Word of Caution
159
160 > Writing your web application directly using [PSGI/Plack] is certainly possible but not recommended.
161 >
162 > […]
163 >
164 > If you're writing a web application, not a framework, then you're encouraged to use one of the web
165 > application frameworks that support PSGI (http://plackperl.org/#frameworks), or see modules like
166 > HTTP::Engine to provide higher level Request and Response API on top of PSGI.
167 >
168 > -- [Plack::Request Documentation](https://search.cpan.org/~miyagawa/Plack/lib/Plack/Request.pm)
169
170 ???
171 - When you start learning about Plack, you'll realize that it is actually pretty capable.
172 - You may start to think that everything should be developed on that level -- don't do it!
173 - For most stuff, you'll still want to use a web framework.
174 - Web frameworks often offer more convenient abstractions than raw PSGI.
175
176 ---
177
178 ## Why care?
179
180 ???
181 If you're a developer writing a web app, you're probably asking why then you should care about PSGI.
182
183 --
184
185 - So that you can understand how things work.
186
187 ???
188 - I'll never understood people who don't want to understand things.
189 - Knowledge is cool!
190 - I recommend you learn and understand as much as you can about the entire request-response cycle of
191 your web app; it will help you troubleshoot when things go wrong or aren't behaving as expected.
192 - Be an expert!
193
194 --
195 - So that you can do DevOps (if you want).
196
197 ???
198 - New skills make you more marketable.
199
200 --
201 - So that you understand it when you see PSGI exposed through your web framework.
202
203 --
204 - You can do cool things with PSGI!
205
206 ???
207 - Even if you do most of your work using your framework, you can do some useful things with PSGI.
208 - We will get to some of those cool things, so hang tight.
209
210 ---
211
212 class: http
213 layout: true
214
215 ## HTTP
216
217 ---
218
219 ### **H**yper**t**ext **T**ransfer **P**rotocol
220
221 --
222 - Invented by Tim Berners-Lee in 1989, first specified as [HTTP 0.9](https://www.w3.org/Protocols/HTTP/AsImplemented.html) in 1991.
223
224 --
225 - The IETF and W3C took over standards development, resulting in [RFC 1945](https://tools.ietf.org/html/rfc1945) ("HTTP 1.0") in 1996.
226
227 --
228 - [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.
229
230 ???
231 RFC 2616 was then superceded in 2014 by:
232 - [RFC 7230](https://tools.ietf.org/html/rfc7230)
233 - [RFC 7231](https://tools.ietf.org/html/rfc7231)
234 - [RFC 7232](https://tools.ietf.org/html/rfc7232)
235 - [RFC 7233](https://tools.ietf.org/html/rfc7233)
236 - [RFC 7234](https://tools.ietf.org/html/rfc7234)
237 - [RFC 7235](https://tools.ietf.org/html/rfc7235)
238
239 --
240 - Oh yeah, and HTTP2 came out in 2015, defined in [RFC 7540](https://tools.ietf.org/html/rfc7540).
241
242 ---
243
244 .col.marginfix[
245 ### Request
246
247 ```http
248 GET /ip HTTP/1.1
249 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
250 Host: foo.acme.tld
251 Accept-Language: en-us
252 Connection: Keep-Alive
253 ```
254 ]
255
256 .col.marginfix[
257 ### Response
258
259 ```http
260 HTTP/1.1 200 OK
261 Date: Thu, 07 Jul 2016 11:56:23 GMT
262 Server: nginx
263 Content-Length: 30
264 Content-Type: text/plain
265 Connection: Closed
266
267 Your IP address is 127.0.0.1.
268 ```
269 ]
270
271 ---
272
273 .col.marginfix[
274 ### Request
275
276 ```http
277 *GET /ip HTTP/1.1
278 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
279 Host: foo.acme.tld
280 Accept-Language: en-us
281 Connection: Keep-Alive
282 ```
283 ]
284
285 .col.marginfix[
286 ### Response
287
288 ```http
289 HTTP/1.1 200 OK
290 Date: Thu, 07 Jul 2016 11:56:23 GMT
291 Server: nginx
292 Content-Length: 30
293 Content-Type: text/plain
294 Connection: Closed
295
296 Your IP address is 127.0.0.1.
297 ```
298 ]
299
300 .col[
301 1. Method, path, protocol/version
302 ]
303
304 ???
305 - Methods defined in HTTP/1.1: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT
306 - RFC 5789 defined PATCH in March 2010.
307
308 ---
309
310 .col.marginfix[
311 ### Request
312
313 ```http
314 GET /ip HTTP/1.1
315 *User-Agent: Mozilla/5.0 (X11; Linux x86_64)
316 *Host: foo.acme.tld
317 *Accept-Language: en-us
318 *Connection: Keep-Alive
319 ```
320 ]
321
322 .col.marginfix[
323 ### Response
324
325 ```http
326 HTTP/1.1 200 OK
327 Date: Thu, 07 Jul 2016 11:56:23 GMT
328 Server: nginx
329 Content-Length: 30
330 Content-Type: text/plain
331 Connection: Closed
332
333 Your IP address is 127.0.0.1.
334 ```
335 ]
336
337 .col[
338 1. Method, path, protocol/version
339 2. Headers (key-value pairs)
340 ]
341
342 ---
343
344 .col.marginfix[
345 ### Request
346
347 ```http
348 GET /ip HTTP/1.1
349 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
350 Host: foo.acme.tld
351 Accept-Language: en-us
352 Connection: Keep-Alive
353 ```
354 ]
355
356 .col.marginfix[
357 ### Response
358
359 ```http
360 HTTP/1.1 200 OK
361 Date: Thu, 07 Jul 2016 11:56:23 GMT
362 Server: nginx
363 Content-Length: 30
364 Content-Type: text/plain
365 Connection: Closed
366
367 Your IP address is 127.0.0.1.
368 ```
369 ]
370
371 .col[
372 1. Method, path, protocol/version
373 2. Headers (key-value pairs)
374 3. Optional document (or "body")
375 ]
376
377 ---
378
379 .col.marginfix[
380 ### Request
381
382 ```http
383 GET /ip HTTP/1.1
384 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
385 Host: foo.acme.tld
386 Accept-Language: en-us
387 Connection: Keep-Alive
388 ```
389 ]
390
391 .col.marginfix[
392 ### Response
393
394 ```http
395 *HTTP/1.1 200 OK
396 Date: Thu, 07 Jul 2016 11:56:23 GMT
397 Server: nginx
398 Content-Length: 30
399 Content-Type: text/plain
400 Connection: Closed
401
402 Your IP address is 127.0.0.1.
403 ```
404 ]
405
406 .col[
407 1. Method, path, protocol/version
408 2. Headers (key-value pairs)
409 3. Optional document (or "body")
410 ]
411
412 .col[
413 1. Protocol/version, status code, reason phrase
414 ]
415
416 ---
417
418 .col.marginfix[
419 ### Request
420
421 ```http
422 GET /ip HTTP/1.1
423 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
424 Host: foo.acme.tld
425 Accept-Language: en-us
426 Connection: Keep-Alive
427 ```
428 ]
429
430 .col.marginfix[
431 ### Response
432
433 ```http
434 HTTP/1.1 200 OK
435 *Date: Thu, 07 Jul 2016 11:56:23 GMT
436 *Server: nginx
437 *Content-Length: 30
438 *Content-Type: text/plain
439 *Connection: Closed
440
441 Your IP address is 127.0.0.1.
442 ```
443 ]
444
445 .col[
446 1. Method, path, protocol/version
447 2. Headers (key-value pairs)
448 3. Optional document (or "body")
449 ]
450
451 .col[
452 1. Protocol/version, status code, reason phrase
453 2. Headers (key-value pairs)
454 ]
455
456 ---
457
458 .col.marginfix[
459 ### Request
460
461 ```http
462 GET /ip HTTP/1.1
463 User-Agent: Mozilla/5.0 (X11; Linux x86_64)
464 Host: foo.acme.tld
465 Accept-Language: en-us
466 Connection: Keep-Alive
467 ```
468 ]
469
470 .col.marginfix[
471 ### Response
472
473 ```http
474 HTTP/1.1 200 OK
475 Date: Thu, 07 Jul 2016 11:56:23 GMT
476 Server: nginx
477 Content-Length: 30
478 Content-Type: text/plain
479 Connection: Closed
480
481 *Your IP address is 127.0.0.1.
482 ```
483 ]
484
485 .col[
486 1. Method, path, protocol/version
487 2. Headers (key-value pairs)
488 3. Optional document (or "body")
489 ]
490
491 .col[
492 1. Protocol/version, status code, reason phrase
493 2. Headers (key-value pairs)
494 3. Optional document (or "body")
495 ]
496
497 ---
498
499 layout: false
500
501 ## Alternatives to PSGI
502
503 - CGI
504 - mod_perl
505 - FastCGI
506 - SCGI
507 - WSGI
508 - JSGI
509 - Rack
510 - ISAPI
511 - many more...
512
513
514 ???
515 - All of these still exist, and actually all of these are still in common use.
516 - We're going to take a closer look at three of these.
517
518 ---
519
520 ## Alternatives to PSGI
521
522 - .highlight[CGI]
523 - .highlight[mod_perl]
524 - .highlight[FastCGI]
525 - SCGI
526 - WSGI
527 - JSGI
528 - Rack
529 - ISAPI
530 - many more...
531
532 ---
533
534 class: cgi
535 layout: true
536
537 .top-right[
538 ![CGI](img/cgi.gif)
539 ]
540
541 ## CGI
542
543 ---
544
545 ### **C**ommon **G**ateway **I**nterface
546
547 --
548 - Created by the NCSA in 1993.
549
550 ???
551 - NCSA = National Center for Supercomputing Applications
552
553 --
554 - More formally defined in [RFC 3875](https://tools.ietf.org/html/rfc3875) ("CGI Version 1.1") in October 2004.
555
556 ---
557
558 ```perl
559 my $client_ip = $ENV{'REMOTE_ADDR'};
560
561 print "Content-Type: text/plain\n";
562 print "Status: 200 OK\n";
563
564 print "\n";
565 print "Your IP address is ${client_ip}.";
566 ```
567
568 ---
569
570 ```perl
571 *my $client_ip = $ENV{'REMOTE_ADDR'};
572
573 print "Content-Type: text/plain\n";
574 print "Status: 200 OK\n";
575
576 print "\n";
577 print "Your IP address is ${client_ip}.";
578 ```
579
580 1. Gateway sets information about the request in the environment.
581
582 .condensed.marginfix[
583 .col[
584 - `AUTH_TYPE`
585 - `CONTENT_LENGTH`
586 - `CONTENT_TYPE`
587 - `GATEWAY_INTERFACE`
588 - `PATH_INFO`
589 - `PATH_TRANSLATED`
590 - `QUERY_STRING`
591 - `REMOTE_ADDR`
592 - `REMOTE_HOST`
593 ]
594 .col[
595 - `REMOTE_IDENT`
596 - `REMOTE_USER`
597 - `REQUEST_METHOD`
598 - `SCRIPT_NAME`
599 - `SERVER_NAME`
600 - `SERVER_PORT`
601 - `SERVER_PROTOCOL`
602 - `SERVER_SOFTWARE`
603 - other "protocol-specific" variables
604 ]
605 ]
606
607 ???
608 - If you've done some web programming before, you're probably familiar with at least a few of these.
609
610 ---
611
612 ```perl
613 my $client_ip = $ENV{'REMOTE_ADDR'};
614
615 *print "Content-Type: text/plain\n";
616 *print "Status: 200 OK\n";
617
618 print "\n";
619 print "Your IP address is ${client_ip}.";
620 ```
621
622 1. Gateway sets information about the request in the environment.
623 2. Print response headers to `STDOUT`.
624
625 .condensed.marginfix[
626 .col[
627 - `Content-Type`
628 - `Location`
629 - `Status`
630 - other "protocol-specific" header fields
631 ]
632 ]
633
634 ---
635
636 ```perl
637 my $client_ip = $ENV{'REMOTE_ADDR'};
638
639 print "Content-Type: text/plain\n";
640 print "Status: 200 OK\n";
641
642 *print "\n";
643 print "Your IP address is ${client_ip}.";
644 ```
645
646 1. Gateway sets information about the request in the environment.
647 2. Print response headers to `STDOUT`.
648 3. Print newline.
649
650 ---
651
652 ```perl
653 my $client_ip = $ENV{'REMOTE_ADDR'};
654
655 print "Content-Type: text/plain\n";
656 print "Status: 200 OK\n";
657
658 print "\n";
659 *print "Your IP address is ${client_ip}.";
660 ```
661
662 1. Gateway sets information about the request in the environment.
663 2. Print response headers to `STDOUT`.
664 3. Print newline.
665 4. Print response document (if any).
666
667 ---
668
669 ```perl
670 my $client_ip = $ENV{'REMOTE_ADDR'};
671
672 print "Content-Type: text/plain\n";
673 print "Status: 200 OK\n";
674
675 print "\n";
676 print "Your IP address is ${client_ip}.";
677 ```
678
679 1. Gateway sets information about the request in the environment.
680 2. Print response headers to `STDOUT`.
681 3. Print newline.
682 4. Print response document (if any).
683 5. Read request document from `STDIN` (if any).
684
685 ???
686 - CGI.pm helps cut down boilerplate by helping parse things like `QUERY_STRING` and `HTTP_COOKIE`,
687 producing correctly-formatted headers, and even producing HTML.
688 - CGI.pm was deprecated in perl 5.20 and remove from core in perl 5.22.
689
690 TODO make a slide for this
691 Good:
692 - Conceptually simple.
693 - Only requires the use of the most basic and primitive program constructs (stdin, stdout, env).
694
695 Bad:
696 - Details can get complicated.
697 - Although the de facto standard for years, modern web servers are choosing to not support it
698 directly any longer.
699 - There is too much overhead in forking and execing.
700
701 ---
702
703 class: fastcgi
704 layout: true
705
706 .top-right[
707 ![FastCGI](img/fastcgi.png)
708 ]
709
710 ## FastCGI
711
712 ---
713
714 ### a low-overhead variation on CGI
715
716 --
717 - Binary protocol with support for pipelining and multiplexing.
718
719 --
720 - Open Market wrote the [specification](http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html) on 29 Apr 1996.
721
722 ???
723 - Open Market was an ecommerce startup based in Massachusetts.
724 - Developed one of the first HTTP servers.
725
726 ---
727
728 ```perl
729 use FCGI;
730
731 my $request = FCGI::Request();
732
733 while (0 <= $request->Accept()) {
734 my $client_ip = $ENV{'REMOTE_ADDR'};
735
736 print "Content-Type: text/html\n\n";
737 print "Your IP address is ${client_ip}.";
738 }
739 ```
740
741 ---
742
743 ```perl
744 *use FCGI;
745 *
746 *my $request = FCGI::Request();
747
748 while (0 <= $request->Accept()) {
749 my $client_ip = $ENV{'REMOTE_ADDR'};
750
751 print "Content-Type: text/html\n\n";
752 print "Your IP address is ${client_ip}.";
753 }
754 ```
755
756 1. Use `FCGI` and instantiate an object.
757
758 ---
759
760 ```perl
761 use FCGI;
762
763 my $request = FCGI::Request();
764
765 *while (0 <= $request->Accept()) {
766 my $client_ip = $ENV{'REMOTE_ADDR'};
767
768 print "Content-Type: text/html\n\n";
769 print "Your IP address is ${client_ip}.";
770 }
771 ```
772
773 1. Use `FCGI` and instantiate an object.
774 2. Loop on `Accept()` which blocks until the next request is received.
775
776 ---
777
778 ```perl
779 use FCGI;
780
781 my $request = FCGI::Request();
782
783 while (0 <= $request->Accept()) {
784 * my $client_ip = $ENV{'REMOTE_ADDR'};
785 *
786 * print "Content-Type: text/html\n\n";
787 * print "Your IP address is ${client_ip}.";
788 }
789 ```
790
791 1. Use `FCGI` and instantiate an object.
792 2. Loop on `Accept()` which blocks until the next request is received.
793 3. Otherwise appears similar to a CGI program.
794
795 ---
796
797 ```perl
798 use FCGI;
799
800 my $request = FCGI::Request();
801
802 while (0 <= $request->Accept()) {
803 my $client_ip = $ENV{'REMOTE_ADDR'};
804
805 print "Content-Type: text/html\n\n";
806 print "Your IP address is ${client_ip}.";
807 }
808 ```
809
810 1. Use `FCGI` and instantiate an object.
811 2. Loop on `Accept()` which blocks until the next request is received.
812 3. Otherwise appears similar to a CGI program.
813
814 * IPC actually happens over a socket!
815
816 ???
817 - Can be run unmodified as a CGI script by detecting that stdin is not a socket.
818 - Can read from stdin and write to stdout via the miracle of tied filehandles.
819
820 ---
821
822 class: mod_perl
823 layout: true
824
825 .top-right[
826 ![mod_perl](img/mod_perl.gif)
827 ]
828
829 ## mod_perl
830
831 ---
832
833 --
834 - First released on March 25, 1996.
835
836 ???
837 - Unlike the interfaces we have examined so far, mod_perl is code.
838
839 --
840 - Became an Apache Software Foundation project at ApacheCon 1999 in Orlando.
841
842 --
843
844 ```perl
845 package GetIP;
846
847 use Apache::RequestRec ();
848 use Apache::Connection ();
849 use Apache::Const -compile => qw(OK);
850
851 sub handler {
852 my $r = shift;
853 my $client_ip = $r->connection->remote_addr;
854
855 $r->content_type('text/plain');
856 $r->print("Your IP address is ${client_ip}.");
857 return Apache::Const::OK;
858 }
859
860 1;
861 ```
862
863 ???
864 - There's a separate mod_perl for nginx.
865
866 Good:
867 - Can run CGI programs as-is.
868
869 Bad:
870 - Can tie you to specific web servers.
871 - Code runs in the same process as the HTTP server -- kinda scary.
872 - Using Apache's API feels heavy.
873
874 ---
875
876 class: psgi
877 layout: true
878
879 ## PSGI
880
881 ---
882
883 ```perl
884 my $app = sub {
885 my $env = shift;
886 my $client_id = $env->{'REMOTE_ADDR'};
887
888 return [
889 '200',
890 [ 'Content-Type' => 'text/plain' ],
891 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
892 ];
893 };
894 ```
895
896 ---
897
898 ```perl
899 my $app = sub {
900 * my $env = shift;
901 * my $client_id = $env->{'REMOTE_ADDR'};
902
903 return [
904 '200',
905 [ 'Content-Type' => 'text/plain' ],
906 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
907 ];
908 };
909 ```
910
911 .col[
912 ### Request
913
914 1. Hashref of request information.
915 ]
916
917 ---
918
919 ```perl
920 my $app = sub {
921 my $env = shift;
922 my $client_id = $env->{'REMOTE_ADDR'};
923
924 return [
925 * '200',
926 [ 'Content-Type' => 'text/plain' ],
927 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
928 ];
929 };
930 ```
931
932 .col[
933 ### Request
934
935 1. Hashref of request information.
936 ]
937
938 .col[
939 ### Response
940
941 1. HTTP status code.
942 ]
943
944 ---
945
946 ```perl
947 my $app = sub {
948 my $env = shift;
949 my $client_id = $env->{'REMOTE_ADDR'};
950
951 return [
952 '200',
953 * [ 'Content-Type' => 'text/plain' ],
954 [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
955 ];
956 };
957 ```
958
959 .col[
960 ### Request
961
962 1. Hashref of request information.
963 ]
964
965 .col[
966 ### Response
967
968 1. HTTP status code.
969 2. Arrayref of response headers.
970 ]
971
972 ???
973 - Why not a hashref?
974 - To support multiple headers (e.g. Set-Cookie)
975 - It more closely resembles how the WSGI folks did it (i.e. list of tuples).
976
977 ---
978
979 ```perl
980 my $app = sub {
981 my $env = shift;
982 my $client_id = $env->{'REMOTE_ADDR'};
983
984 return [
985 '200',
986 [ 'Content-Type' => 'text/plain' ],
987 * [ "Your IP address is ${client_id}." ], # or IO::Handle-like object
988 ];
989 };
990 ```
991
992 .col[
993 ### Request
994
995 1. Hashref of request information.
996 ]
997
998 .col[
999 ### Response
1000
1001 1. HTTP status code.
1002 2. Arrayref of response headers.
1003 3. Response document.
1004 ]
1005
1006 ???
1007 - Body may be a list of chunks that are concatenated together or a handle to read from.
1008
1009 ---
1010
1011 layout: false
1012
1013 ## Benefits of PSGI
1014
1015 - Everything is a data structure (almost).
1016
1017 ???
1018 - Makes it easier to write tests because mocking either the app or server is clear.
1019 - Don't necessarily need to parse a bytestream to check stuff.
1020
1021 --
1022 - No global data or shared IO handles.
1023
1024 ???
1025 - This lets you service multiple requests asynchronously in the same process/thread.
1026
1027 --
1028 - Takes deployment details out of web frameworks.
1029
1030 ???
1031 - Web frameworks only need to target PSGI.
1032 - No need to worry about the boring stuff; they can focus on the abstractions that make them unique
1033 and useful.
1034
1035 --
1036 - End-users of your app have many deployment options for free.
1037
1038 ---
1039
1040 ## Web Frameworks
1041
1042 - [Catalyst](http://www.catalystframework.org/)
1043 - [Mojolicious](http://mojolicious.org/)
1044 - [Dancer](http://perldancer.org/)
1045 - [CGI::Application](http://cgi-app.org/)
1046 - [CGI::Ex](https://github.com/chazmcgarvey/CGI-Ex/tree/psgi-2)
1047 - [Web::Simple](https://metacpan.org/pod/Web::Simple)
1048 - [Amon2](https://metacpan.org/pod/Amon2)
1049 - [Poet](https://metacpan.org/pod/Poet)
1050 - [Kelp](https://metacpan.org/pod/Kelp)
1051 - [Raisin](https://metacpan.org/pod/Raisin)
1052 - many more...
1053
1054 ---
1055
1056 class: plack
1057
1058 ## Plack
1059
1060 - Provides tools for building, running, and testing PSGI apps.
1061
1062 --
1063 - [Plack::Handler](https://metacpan.org/pod/Plack::Handler)
1064
1065 ???
1066 - Connects PSGI apps and web servers.
1067 - Takes a request from the server,
1068 - converts it to the PSGI-specified environment,
1069 - runs your app,
1070 - converts the response back to a format the server understands.
1071
1072 --
1073 - [Plack::Loader](https://metacpan.org/pod/Plack::Loader)
1074
1075 ???
1076 - Picks an appropriate Plack::Handler (based on ENV, loaded modules, or arguments) and loads it.
1077 - Can also do stuff like restart the loader when files change.
1078
1079 --
1080 - [Plack::Runner](https://metacpan.org/pod/Plack::Runner), [plackup](https://metacpan.org/pod/plackup)
1081
1082 ???
1083 - Run PSGI apps from the command-line.
1084
1085 --
1086 - [Plack::Middleware](https://metacpan.org/pod/Plack::Middleware)
1087
1088 ???
1089 - Create subroutines that run between the handler and your app.
1090 - Can alter the request your app receives and modify the response your app returns.
1091
1092 --
1093 - [Plack::Request](https://metacpan.org/pod/Plack::Request), [Plack::Response](https://metacpan.org/pod/Plack::Response)
1094
1095 ???
1096 - Request and response wrappers can help simplify writing middleware.
1097
1098 --
1099 - [Plack::Builder](https://metacpan.org/pod/Plack::Builder)
1100
1101 ???
1102 - Provides DSL for composing apps and middleware.
1103
1104 --
1105 - [Plack::Test](https://metacpan.org/pod/Plack::Test), [Plack::Test::Suite](https://metacpan.org/pod/Plack::Test::Suite)
1106
1107 ???
1108 - Use Plack::Test for testing apps.
1109 - Plack::Test::Suite is a series of tests for testing handlers.
1110
1111 --
1112 - [Plack::Util](https://metacpan.org/pod/Plack::Util)
1113
1114 ???
1115 - Provides random useful stuff for handler and middleware developers.
1116 - Stuff like determing the length of a document or getting PSGI response headers from the arrayref.
1117
1118 ---
1119
1120 class: plackup
1121
1122 ## plackup
1123
1124 - Run PSGI apps from the command-line.
1125
1126 ```sh
1127 # read your app from app.psgi file
1128 plackup
1129
1130 # choose .psgi file from ARGV[0] (or with -a option)
1131 plackup hello.psgi
1132
1133 # switch server implementation with --server (or -s)
1134 plackup --server HTTP::Server::Simple --port 9090 --host 127.0.0.1 test.psgi
1135
1136 # use UNIX socket to run FCGI daemon
1137 plackup -s FCGI --listen /tmp/fcgi.sock myapp.psgi
1138
1139 # launch FCGI external server on port 9090
1140 plackup -s FCGI --port 9090
1141 ```
1142
1143 ---
1144
1145 class: app-psgi
1146 layout: true
1147
1148 ## app.psgi
1149
1150 ---
1151
1152 ```perl
1153 #!/usr/bin/env perl
1154
1155 my $app = sub {
1156 my $env = shift;
1157 my $client_id = $env->{'REMOTE_ADDR'};
1158
1159 return [
1160 '200',
1161 [ 'Content-Type' => 'text/plain' ],
1162 [ "Your IP address is ${client_id}." ],
1163 ];
1164 };
1165 ```
1166
1167 ---
1168
1169 ```perl
1170 #!/usr/bin/env perl
1171
1172 *use Plack::Builder;
1173
1174 my $app = sub {
1175 my $env = shift;
1176 my $client_id = $env->{'REMOTE_ADDR'};
1177
1178 return [
1179 '200',
1180 [ 'Content-Type' => 'text/plain' ],
1181 [ "Your IP address is ${client_id}." ],
1182 ];
1183 };
1184
1185 *builder {
1186 * enable 'Runtime';
1187 * mount '/' => $app;
1188 *};
1189 ```
1190
1191 ???
1192 - The `Runtime` middleware adds an `X-Runtime` header to the response with the number of seconds it
1193 took to process the request.
1194
1195 ---
1196
1197 class: env
1198 layout: true
1199
1200 ## Plack `$env`
1201
1202 ---
1203
1204 .condensed.marginfix[
1205 .col[
1206 - `HTTP_ACCEPT`
1207 - `HTTP_ACCEPT_ENCODING`
1208 - `HTTP_ACCEPT_LANGUAGE`
1209 - `HTTP_CACHE_CONTROL`
1210 - `HTTP_CONNECTION`
1211 - `HTTP_DNT`
1212 - `HTTP_HOST`
1213 - `HTTP_USER_AGENT`
1214 - `PATH_INFO`
1215 - `QUERY_STRING `
1216 - `REMOTE_ADDR`
1217 - `REMOTE_PORT`
1218 - `REQUEST_METHOD`
1219 - `REQUEST_URI`
1220 - `SCRIPT_NAME`
1221 ]
1222 .col[
1223 - `SERVER_NAME`
1224 - `SERVER_PORT`
1225 - `SERVER_PROTOCOL`
1226 - `psgi.errors`
1227 - `psgi.input`
1228 - `psgi.multiprocess`
1229 - `psgi.multithread`
1230 - `psgi.nonblocking`
1231 - `psgi.run_once`
1232 - `psgi.streaming`
1233 - `psgi.url_scheme`
1234 - `psgi.version`
1235 - `psgix.harakiri`
1236 - `psgix.input.buffered`
1237 - `psgix.io`
1238 ]
1239 ]
1240
1241 ---
1242
1243 .condensed.marginfix[
1244 .col[
1245 - .highlight[`HTTP_ACCEPT`]
1246 - .highlight[`HTTP_ACCEPT_ENCODING`]
1247 - .highlight[`HTTP_ACCEPT_LANGUAGE`]
1248 - .highlight[`HTTP_CACHE_CONTROL`]
1249 - .highlight[`HTTP_CONNECTION`]
1250 - .highlight[`HTTP_DNT`]
1251 - .highlight[`HTTP_HOST`]
1252 - .highlight[`HTTP_USER_AGENT`]
1253 - .highlight[`PATH_INFO`]
1254 - .highlight[`QUERY_STRING `]
1255 - .highlight[`REMOTE_ADDR`]
1256 - .highlight[`REMOTE_PORT`]
1257 - .highlight[`REQUEST_METHOD`]
1258 - .highlight[`REQUEST_URI`]
1259 - .highlight[`SCRIPT_NAME`]
1260 ]
1261 .col[
1262 - .highlight[`SERVER_NAME`]
1263 - .highlight[`SERVER_PORT`]
1264 - .highlight[`SERVER_PROTOCOL`]
1265 - `psgi.errors`
1266 - `psgi.input`
1267 - `psgi.multiprocess`
1268 - `psgi.multithread`
1269 - `psgi.nonblocking`
1270 - `psgi.run_once`
1271 - `psgi.streaming`
1272 - `psgi.url_scheme`
1273 - `psgi.version`
1274 - `psgix.harakiri`
1275 - `psgix.input.buffered`
1276 - `psgix.io`
1277 ]
1278 ]
1279
1280 ---
1281
1282 .condensed.marginfix[
1283 .col[
1284 - `HTTP_ACCEPT`
1285 - `HTTP_ACCEPT_ENCODING`
1286 - `HTTP_ACCEPT_LANGUAGE`
1287 - `HTTP_CACHE_CONTROL`
1288 - `HTTP_CONNECTION`
1289 - `HTTP_DNT`
1290 - `HTTP_HOST`
1291 - `HTTP_USER_AGENT`
1292 - `PATH_INFO`
1293 - `QUERY_STRING `
1294 - `REMOTE_ADDR`
1295 - `REMOTE_PORT`
1296 - `REQUEST_METHOD`
1297 - `REQUEST_URI`
1298 - `SCRIPT_NAME`
1299 ]
1300 .col[
1301 - `SERVER_NAME`
1302 - `SERVER_PORT`
1303 - `SERVER_PROTOCOL`
1304 - .highlight[`psgi.errors`]
1305 - .highlight[`psgi.input`]
1306 - .highlight[`psgi.multiprocess`]
1307 - .highlight[`psgi.multithread`]
1308 - .highlight[`psgi.nonblocking`]
1309 - .highlight[`psgi.run_once`]
1310 - .highlight[`psgi.streaming`]
1311 - .highlight[`psgi.url_scheme`]
1312 - .highlight[`psgi.version`]
1313 - .highlight[`psgix.harakiri`]
1314 - .highlight[`psgix.input.buffered`]
1315 - .highlight[`psgix.io`]
1316 ]
1317 ]
1318
1319 ---
1320
1321 layout: false
1322
1323 ## Plack Handlers
1324
1325 - Can be found on the CPAN in the `Plack::Handler::` namespace.
1326 - [Apache1](https://metacpan.org/pod/Plack::Handler::Apache1), [Apache2](https://metacpan.org/pod/Plack::Handler::Apache2)
1327 - [CGI](https://metacpan.org/pod/Plack::Handler::CGI)
1328 - [FCGI](https://metacpan.org/pod/Plack::Handler::FCGI)
1329 - [HTTP::Server::PSGI](https://metacpan.org/pod/Plack::Handler::HTTP::Server::PSGI)
1330 - [SCGI](https://metacpan.org/pod/Plack::Handler::SCGI)
1331 - [Starman](https://metacpan.org/pod/Plack::Handler::Starman)
1332 - [Twiggy](https://metacpan.org/pod/Plack::Handler::Twiggy)
1333 - [AnyEvent::HTTPD](https://metacpan.org/pod/Plack::Handler::AnyEvent::HTTPD)
1334 - [Thrall](https://metacpan.org/pod/Plack::Handler::Thrall)
1335 - many more...
1336
1337 ---
1338
1339 class: middleware
1340 layout: true
1341
1342 ## Plack Middleware
1343
1344 ---
1345
1346 name: middleware-debug
1347
1348 ### [`Debug`](https://metacpan.org/pod/Plack::Middleware::Debug)
1349
1350 ```perl
1351 enable 'Debug';
1352 ```
1353
1354 ---
1355
1356 ### [`ReverseProxy`](https://metacpan.org/pod/Plack::Middleware::ReverseProxy)
1357
1358 ```perl
1359 enable 'ReverseProxy';
1360 ```
1361
1362 - Fixes `REMOTE_ADDR`, `HTTP_HOST`, `SERVER_PORT`, and `psgi.url_scheme` in the environment.
1363
1364 ---
1365
1366 ### [`LogDispatch`](https://metacpan.org/pod/Plack::Middleware::LogDispatch)
1367
1368 ```perl
1369 use Log::Dispatch;
1370
1371 my $logger = Log::Dispatch->new(
1372 outputs => [
1373 [
1374 'Syslog',
1375 min_level => 'debug',
1376 ident => 'myapp',
1377 ],
1378 ],
1379 );
1380
1381 enable 'LogDispatch', logger => $logger;
1382 ```
1383
1384 ---
1385
1386 ### [`XSRFBlock`](https://metacpan.org/pod/Plack::Middleware::XSRFBlock)
1387
1388 ```perl
1389 enable 'XSRFBlock', cookie_options => { httponly => 1 };
1390 ```
1391
1392 - Blocking cross-site request forgery couldn't be easier.
1393
1394 ---
1395
1396 ### [`RedirectSSL`](https://metacpan.org/pod/Plack::Middleware::RedirectSSL)
1397
1398 ```perl
1399 enable 'RedirectSSL';
1400 ```
1401
1402 - Redirects from http to https (or backwards, if configured).
1403 - Can also set HSTS header with configurable `max-age`.
1404
1405 ---
1406
1407 layout: false
1408
1409 .top-right[
1410 ![CPAN](img/cpan.png)
1411 ]
1412
1413 ## Plack modules in July 2016
1414
1415 **10** `Plack-Handler-*` distributions
1416
1417 **55** `Plack-App-*` distributions
1418
1419 **253** `Plack-Middleware-*` distributions
1420
1421 ---
1422
1423 ## Parting Thoughts
1424
1425 - PSGI also specifies a way to delay or stream responses to the server.
1426
1427 ???
1428 - It's kind of complicated, but you can read the spec to learn more.
1429 - Read the source code of various apps and middlewares to see how it works in practice.
1430
1431 --
1432 - There are tons of great apps and middleware on the CPAN.
1433
1434 --
1435 - Consider writing some of your app as a middleware.
1436
1437 ???
1438 - The concept and implementation of middleware is cool.
1439 - You should consider writing parts of your app as middleware so that functionality is available
1440 under different web frameworks.
1441 - Stuff that makes sense as middleware:
1442 - Auth mechanisms
1443 - Logging
1444 - Error handling
1445 - Sessions
1446 - Rate limiters
1447
1448 ---
1449
1450 class: center, middle
1451 name: conclusion
1452
1453 ## Conclusion:
1454
1455 ### Understand PSGI & Plack, and use them!
1456
1457 ---
1458
1459 class: center, middle
1460 layout: false
1461 name: questions
1462
1463 ## Questions?
1464
1465 ---
1466
1467 class: center, middle
1468 name: last
1469
1470 .col.sep[
1471 ## Thank you
1472
1473 Email me: Charles McGarvey
1474 <chazmcgarvey@brokenzipper.com>
1475
1476 .talkqr.center[
1477 Leave me feedback, if you want:
1478
1479 ![Page on Joind.in](img/talkqr.svg)
1480
1481 <https://joind.in/talk/6e4d2>
1482 ]
1483 ]
1484
1485 .col[
1486 ## Credits
1487
1488 .left[
1489 - Thank you [Tatsuhiko Miyagawa](http://weblog.bulknews.net/) and other contributors for creating PSGI and Plack.
1490 ]
1491 ]
1492
1493 </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>
1494 <!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->
This page took 0.09808 seconds and 4 git commands to generate.