1POE::Component::Server:U:sSeirmpCloenHtTrTiPb(u3t)ed PerPlOED:o:cCuommepnotnaetnito:n:Server::SimpleHTTP(3)
2
3
4

NAME

6       POE::Component::Server::SimpleHTTP - Perl extension to serve HTTP
7       requests in POE.
8

VERSION

10       version 2.26
11

SYNOPSIS

13               use POE;
14               use POE::Component::Server::SimpleHTTP;
15
16               # Start the server!
17               POE::Component::Server::SimpleHTTP->new(
18                       'ALIAS'         =>      'HTTPD',
19                       'PORT'          =>      11111,
20                       'HOSTNAME'      =>      'MySite.com',
21                       'HANDLERS'      =>      [
22                               {
23                                       'DIR'           =>      '^/bar/.*',
24                                       'SESSION'       =>      'HTTP_GET',
25                                       'EVENT'         =>      'GOT_BAR',
26                               },
27                               {
28                                       'DIR'           =>      '^/$',
29                                       'SESSION'       =>      'HTTP_GET',
30                                       'EVENT'         =>      'GOT_MAIN',
31                               },
32                               {
33                                       'DIR'           =>      '^/foo/.*',
34                                       'SESSION'       =>      'HTTP_GET',
35                                       'EVENT'         =>      'GOT_NULL',
36                               },
37                               {
38                                       'DIR'           =>      '.*',
39                                       'SESSION'       =>      'HTTP_GET',
40                                       'EVENT'         =>      'GOT_ERROR',
41                               },
42                       ],
43
44                       'LOGHANDLER' => { 'SESSION' => 'HTTP_GET',
45                                         'EVENT'   => 'GOT_LOG',
46                       },
47
48                       'LOG2HANDLER' => { 'SESSION' => 'HTTP_GET',
49                                         'EVENT'   => 'POSTLOG',
50                       },
51
52                       # In the testing phase...
53                       'SSLKEYCERT'    =>      [ 'private-key.pem', 'public-cert.pem' ],
54                       'SSLINTERMEDIATECACERT' =>      'intermediate-ca-cert.pem',
55               ) or die 'Unable to create the HTTP Server';
56
57               # Create our own session to receive events from SimpleHTTP
58               POE::Session->create(
59                       inline_states => {
60                               '_start'        =>      sub {   $_[KERNEL]->alias_set( 'HTTP_GET' );
61                                                               $_[KERNEL]->post( 'HTTPD', 'GETHANDLERS', $_[SESSION], 'GOT_HANDLERS' );
62                                                       },
63
64                               'GOT_BAR'       =>      \&GOT_REQ,
65                               'GOT_MAIN'      =>      \&GOT_REQ,
66                               'GOT_ERROR'     =>      \&GOT_ERR,
67                               'GOT_NULL'      =>      \&GOT_NULL,
68                               'GOT_HANDLERS'  =>      \&GOT_HANDLERS,
69                               'GOT_LOG'       =>      \&GOT_LOG,
70                       },
71               );
72
73               # Start POE!
74               POE::Kernel->run();
75
76               sub GOT_HANDLERS {
77                       # ARG0 = HANDLERS array
78                       my $handlers = $_[ ARG0 ];
79
80                       # Move the first handler to the last one
81                       push( @$handlers, shift( @$handlers ) );
82
83                       # Send it off!
84                       $_[KERNEL]->post( 'HTTPD', 'SETHANDLERS', $handlers );
85               }
86
87               sub GOT_NULL {
88                       # ARG0 = HTTP::Request object, ARG1 = HTTP::Response object, ARG2 = the DIR that matched
89                       my( $request, $response, $dirmatch ) = @_[ ARG0 .. ARG2 ];
90
91                       # Kill this!
92                       $_[KERNEL]->post( 'HTTPD', 'CLOSE', $response );
93               }
94
95               sub GOT_REQ {
96                       # ARG0 = HTTP::Request object, ARG1 = HTTP::Response object, ARG2 = the DIR that matched
97                       my( $request, $response, $dirmatch ) = @_[ ARG0 .. ARG2 ];
98
99                       # Do our stuff to HTTP::Response
100                       $response->code( 200 );
101                       $response->content( 'Some funky HTML here' );
102
103                       # We are done!
104                       # For speed, you could use $_[KERNEL]->call( ... )
105                       $_[KERNEL]->post( 'HTTPD', 'DONE', $response );
106               }
107
108               sub GOT_ERR {
109                       # ARG0 = HTTP::Request object, ARG1 = HTTP::Response object, ARG2 = the DIR that matched
110                       my( $request, $response, $dirmatch ) = @_[ ARG0 .. ARG2 ];
111
112                       # Check for errors
113                       if ( ! defined $request ) {
114                               $_[KERNEL]->post( 'HTTPD', 'DONE', $response );
115                               return;
116                       }
117
118                       # Do our stuff to HTTP::Response
119                       $response->code( 404 );
120                       $response->content( "Hi visitor from " . $response->connection->remote_ip . ", Page not found -> '" . $request->uri->path . "'" );
121
122                       # We are done!
123                       # For speed, you could use $_[KERNEL]->call( ... )
124                       $_[KERNEL]->post( 'HTTPD', 'DONE', $response );
125               }
126
127               sub GOT_LOG {
128                       # ARG0 = HTTP::Request object, ARG1 = remote IP
129                       my ($request, $remote_ip) = @_[ARG0,ARG1];
130
131                       # Do some sort of logging activity.
132                       # If the request was malformed, $request = undef
133                       # CHECK FOR A REQUEST OBJECT BEFORE USING IT.
134               if( $request ) {
135               {
136                       warn join(' ', time(), $remote_ip, $request->uri ), "\n";
137               } else {
138                       warn join(' ', time(), $remote_ip, 'Bad request' ), "\n";
139               }
140
141                       return;
142               }
143

DESCRIPTION

145       This module makes serving up HTTP requests a breeze in POE.
146
147       The hardest thing to understand in this module is the HANDLERS. That's
148       it!
149
150       The standard way to use this module is to do this:
151
152               use POE;
153               use POE::Component::Server::SimpleHTTP;
154
155               POE::Component::Server::SimpleHTTP->new( ... );
156
157               POE::Session->create( ... );
158
159               POE::Kernel->run();
160
161   Starting SimpleHTTP
162       To start SimpleHTTP, just call it's new method:
163
164               POE::Component::Server::SimpleHTTP->new(
165                       'ALIAS'         =>      'HTTPD',
166                       'ADDRESS'       =>      '192.168.1.1',
167                       'PORT'          =>      11111,
168                       'HOSTNAME'      =>      'MySite.com',
169                       'HEADERS'       =>      {},
170                       'HANDLERS'      =>      [ ],
171               );
172
173       This method will die on error or return success.
174
175       This constructor accepts only 7 options.
176
177       "ALIAS"
178           This will set the alias SimpleHTTP uses in the POE Kernel.  This
179           will default to "SimpleHTTP"
180
181       "ADDRESS"
182           This value will be passed to POE::Wheel::SocketFactory to bind to,
183           will use INADDR_ANY if it is nothing is provided.
184
185       "PORT"
186           This value will be passed to POE::Wheel::SocketFactory to bind to.
187
188       "HOSTNAME"
189           This value is for the HTTP::Request's URI to point to.  If this is
190           not supplied, SimpleHTTP will use Sys::Hostname to find it.
191
192       "HEADERS"
193           This should be a hashref, that will become the default headers on
194           all HTTP::Response objects.  You can override this in individual
195           requests by setting it via $request->header( ... )
196
197           For more information, consult the HTTP::Headers module.
198
199       "HANDLERS"
200           This is the hardest part of SimpleHTTP :)
201
202           You supply an array, with each element being a hash. All the hashes
203           should contain those 3 keys:
204
205           DIR  ->   The regexp that will be used, more later.
206
207           SESSION   ->   The session to send the input
208
209           EVENT     ->   The event to trigger
210
211           The DIR key should be a valid regexp. This will be matched against
212           the current request path.  Pseudocode is: if ( $path =~ /$DIR/ )
213
214           NOTE: The path is UNIX style, not MSWIN style ( /blah/foo not
215           \blah\foo )
216
217           Now, if you supply 100 handlers, how will SimpleHTTP know what to
218           do? Simple! By passing in an array in the first place, you have
219           already told SimpleHTTP the order of your handlers. They will be
220           tried in order, and if a match is not found, SimpleHTTP will return
221           a 404 response.
222
223           This allows some cool things like specifying 3 handlers with DIR
224           of: '^/foo/.*', '^/$', '.*'
225
226           Now, if the request is not in /foo or not root, your 3rd handler
227           will catch it, becoming the "404 not found" handler!
228
229           NOTE: You might get weird Session/Events, make sure your handlers
230           are in order, for example: '^/', '^/foo/.*'  The 2nd handler will
231           NEVER get any requests, as the first one will match ( no $ in the
232           regex )
233
234           Now, here's what a handler receives:
235
236           ARG0 -> HTTP::Request object
237
238           ARG1 -> POE::Component::Server::SimpleHTTP::Response object
239
240           ARG2 -> The exact DIR that matched, so you can see what triggered
241           what
242
243           NOTE: If ARG0 is undef, that means POE::Filter::HTTPD encountered
244           an error parsing the client request, simply modify the
245           HTTP::Response object and send some sort of generic error.
246           SimpleHTTP will set the path used in matching the DIR regexes to an
247           empty string, so if there is a "catch-all" DIR regex like '.*', it
248           will catch the errors, and only that one.
249
250           NOTE: The only way SimpleHTTP will leak memory ( hopefully heh ) is
251           if you discard the SimpleHTTP::Response object without sending it
252           back to SimpleHTTP via the DONE/CLOSE events, so never do that!
253
254       "KEEPALIVE"
255           Set to true to enable HTTP keep-alive support.  Connections will be
256           kept alive until the client closes the connection.  All HTTP/1.1
257           connections are kept-open, unless you set the response "Connection"
258           header to "close".
259
260               $response->header( Connection => 'close' );
261
262           If you want more control, use
263           POE::Component::Server::HTTP::KeepAlive.
264
265       "LOGHANDLER"
266           Expects a hashref with the following key, values:
267
268           SESSION   ->   The session to send the input
269
270           EVENT     ->   The event to trigger
271
272           You will receive an event for each request to the server from
273           clients.  Malformed client requests will not be passed into the
274           handler.  Instead undef will be passed.  Event is called before ANY
275           content handler is called.
276
277           The event will have the following parameters:
278
279           ARG0 -> HTTP::Request object/undef if client request was malformed.
280
281           ARG1 -> the IP address of the client
282
283       "LOG2HANDLER"
284           Expect a hashref with the following key, values:
285
286           SESSION   ->   The session to send the input
287
288           EVENT     ->   The event to trigger
289
290           You will receive an event for each response that hit DONE call.
291           Malformed client requests will not be passed into the handler.
292           Event is after processing all content handlers.
293
294           The event will have the following parameters:
295
296           ARG0 -> HTTP::Request object
297
298           ARG1 -> HTTP::Response object
299
300           That makes possible following code:
301
302                   my ($login, $password) = $request->authorization_basic();
303                   printf STDERR "%s - %s [%s] \"%s %s %s\" %d %d\n",
304                           $response->connection->remote_ip, $login||'-', POSIX::strftime("%d/%b/%Y:%T %z",localtime(time())),
305                           $request->method(), $request->uri()->path(), $request->protocol(),
306                           $response->code(), length($response->content());
307
308           Emulate apache-like logs for PoCo::Server::SimpleHTTP
309
310       "SETUPHANDLER"
311           Expects a hashref with the following key, values:
312
313           SESSION   ->   The session to send the input
314
315           EVENT     ->   The event to trigger
316
317           You will receive an event when the listener wheel has been setup.
318
319           Currently there are no parameters returned.
320
321       "SSLKEYCERT"
322           This should be an arrayref of only 2 elements - the private key and
323           public certificate locations. Now, this is still in the
324           experimental stage, and testing is greatly welcome!
325
326           Again, this will automatically turn every incoming connection into
327           a SSL socket. Once enough testing has been done, this option will
328           be augmented with more SSL stuff!
329
330       "SSLINTERMEDIATECACERT"
331           This option is needed in case the SSL certificate references an
332           intermediate certification authority certificate.
333
334       "PROXYMODE"
335           Set this to a true value to enable the server to act as a proxy
336           server, ie. it won't mangle the HTTP::Request URI.
337
338   Events
339       SimpleHTTP is so simple, there are only 8 events available.
340
341       "DONE"
342                   This event accepts only one argument: the HTTP::Response object we sent to the handler.
343
344                   Calling this event implies that this particular request is done, and will proceed to close the socket.
345
346                   NOTE: This method automatically sets those 3 headers if they are not already set:
347                           Date            ->      Current date stringified via HTTP::Date->time2str
348                           Content-Type    ->      text/html
349                           Content-Length  ->      length( $response->content )
350
351                   To get greater throughput and response time, do not post() to the DONE event, call() it!
352                   However, this will force your program to block while servicing web requests...
353
354       "CLOSE"
355                   This event accepts only one argument: the HTTP::Response object we sent to the handler.
356
357                   Calling this event will close the socket, not sending any output
358
359       "GETHANDLERS"
360                   This event accepts 2 arguments: The session + event to send the response to
361
362                   This event will send back the current HANDLERS array ( deep-cloned via Storable::dclone )
363
364                   The resulting array can be played around to your tastes, then once you are done...
365
366       "SETHANDLERS"
367                   This event accepts only one argument: pointer to HANDLERS array
368
369                   BEWARE: if there is an error in the HANDLERS, SimpleHTTP will die!
370
371       "SETCLOSEHANDLER"
372               $_[KERNEL]->call( $_[SENDER], 'SETCLOSEHANDLER', $connection,
373                                 $event, @args );
374
375           Calls $event in the current session when $connection is closed.
376           You could use for persistent connection handling.
377
378           Multiple session may register close handlers.
379
380           Calling SETCLOSEHANDLER without $event to remove the current
381           session's handler:
382
383              $_[KERNEL]->call( $_[SENDER], 'SETCLOSEHANDLER', $connection );
384
385           You must make sure that @args doesn't cause a circular reference.
386           Ideally, use "$connection-"ID> or some other unique value
387           associated with this $connection.
388
389       "STARTLISTEN"
390                   Starts the listening socket, if it was shut down
391
392       "STOPLISTEN"
393                   Simply a wrapper for SHUTDOWN GRACEFUL, but will not shutdown SimpleHTTP if there is no more requests
394
395       "SHUTDOWN"
396                   Without arguments, SimpleHTTP does this:
397                           Close the listening socket
398                           Kills all pending requests by closing their sockets
399                           Removes it's alias
400
401                   With an argument of 'GRACEFUL', SimpleHTTP does this:
402                           Close the listening socket
403                           Waits for all pending requests to come in via DONE/CLOSE, then removes it's alias
404
405       "STREAM"
406                   With a $response argument it streams the content and calls back the streaming event
407                   of the user's session (or with the dont_flush option you're responsible for calling
408                   back your session's streaming event).
409
410                   To use the streaming feature see below.
411
412   Streaming with SimpleHTTP
413       It's possible to send data as a stream to clients (unbuffered and
414       integrated in the POE loop).
415
416       Just create your session to receive events from SimpleHTTP as usually
417       and add a streaming event, this event will be triggered over and over
418       each time you set the $response to a streaming state and once you
419       trigger it:
420
421          # sets the response as streamed within our session which alias is HTTP_GET
422          # with the event GOT_STREAM
423          $response->stream(
424             session     => 'HTTP_GET',
425             event       => 'GOT_STREAM',
426             dont_flush  => 1
427          );
428
429          # then you can simply yield your streaming event, once the GOT_STREAM event
430          # has reached its end it will be triggered again and again, until you
431          # send a CLOSE event to the kernel with the appropriate response as parameter
432          $kernel->yield('GOT_STREAM', $response);
433
434       The optional dont_flush option gives the user the ability to control
435       the callback to the streaming event, which means once your stream event
436       has reached its end it won't be called, you have to call it back.
437
438       You can now send data by chunks and either call yourself back (via POE)
439       or shutdown when your streaming is done (EOF for example).
440
441          sub GOT_STREAM {
442             my ( $kernel, $heap, $response ) = @_[KERNEL, HEAP, ARG0];
443
444             # sets the content of the response
445             $response->content("Hello World\n");
446
447             # send it to the client
448             POE::Kernel->post('HTTPD', 'STREAM', $response);
449
450             # if we have previously set the dont_flush option
451             # we have to trigger our event back until the end of
452             # the stream like this (that can be a yield, of course):
453             #
454             # $kernel->delay('GOT_STREAM', 1, $stream );
455
456             # otherwise the GOT_STREAM event is triggered continuously until
457             # we call the CLOSE event on the response like that :
458             #
459             if ($heap{'streaming_is_done'}) {
460                # close the socket and end the stream
461                POE::Kernel->post('HTTPD', 'CLOSE', $response );
462             }
463          }
464
465       The dont_flush option is there to be able to control the frequency of
466       flushes to the client.
467
468   SimpleHTTP Notes
469       You can enable debugging mode by doing this:
470
471               sub POE::Component::Server::SimpleHTTP::DEBUG () { 1 }
472               use POE::Component::Server::SimpleHTTP;
473
474       Also, this module will try to keep the Listening socket alive.  if it
475       dies, it will open it again for a max of 5 retries.
476
477       You can override this behavior by doing this:
478
479               sub POE::Component::Server::SimpleHTTP::MAX_RETRIES () { 10 }
480               use POE::Component::Server::SimpleHTTP;
481
482       For those who are pondering about basic-authentication, here's a tiny
483       snippet to put in the Event handler
484
485               # Contributed by Rocco Caputo
486               sub Got_Request {
487                       # ARG0 = HTTP::Request, ARG1 = HTTP::Response
488                       my( $request, $response ) = @_[ ARG0, ARG1 ];
489
490                       # Get the login
491                       my ( $login, $password ) = $request->authorization_basic();
492
493                       # Decide what to do
494                       if ( ! defined $login or ! defined $password ) {
495                               # Set the authorization
496                               $response->header( 'WWW-Authenticate' => 'Basic realm="MyRealm"' );
497                               $response->code( 401 );
498                               $response->content( 'FORBIDDEN.' );
499
500                               # Send it off!
501                               $_[KERNEL]->post( 'SimpleHTTP', 'DONE', $response );
502                       } else {
503                               # Authenticate the user and move on
504                       }
505               }
506
507   EXPORT
508       Nothing.
509

ABSTRACT

511               An easy to use HTTP daemon for POE-enabled programs
512

SEE ALSO

514               L<POE>
515
516               L<POE::Filter::HTTPD>
517
518               L<HTTP::Request>
519
520               L<HTTP::Response>
521
522               L<POE::Component::Server::SimpleHTTP::Connection>
523
524               L<POE::Component::Server::SimpleHTTP::Response>
525
526               L<POE::Component::Server::SimpleHTTP::PreFork>
527
528               L<POE::Component::SSLify>
529

AUTHOR

531       Apocalypse <APOCAL@cpan.org>
532
534       This software is copyright (c) 2017 by Apocalypse, Chris Williams,
535       Eriam Schaffter, Marlon Bailey and Philip Gwyn.
536
537       This is free software; you can redistribute it and/or modify it under
538       the same terms as the Perl 5 programming language system itself.
539
540
541
542perl v5.28.0                      2017-03-P0O9E::Component::Server::SimpleHTTP(3)
Impressum