The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Examples for POE::Component::Server::HTTPServer

EXAMPLES

This document contains some examples of using HTTPServer in various ways. HTTPServer uses the POE framework, but you don't need to know much (if anything) about POE in order to use HTTPServer in most cases. But if you're curious about what $poe_kernel->run() really does, or what the value returned by create_server() might be used for, POE is where to look.

Basic Server

Setting up a basic server which uses all the defaults, is easy:

    use POE;
    use POE::Component::Server::HTTPServer;
    
    my $server = POE::Component::Server::HTTPServer->new();
    $server->create_server();
    $poe_kernel->run();
    exit 0;

Running this program should start a new HTTPServer listening on port 8080 (the default port). It will return a 404 Not Found response for any request (via the default backstop handler).

The two use lines, as well as the final three lines (create_server, run, exit), are basic boilerplate. They import the necessary modules and set the server in motion.

Serving Static Files

Serving a set of files from the file system is also easy:

    my $server = POE::Component::Server::HTTPServer->new(
      handlers => [ '/' => new_handler("StaticHandler", "./html") ]
    );

Any requests the server recieves will be mapped to files underneath the html directory, and their contents will be served. Any requests for non-existant files will fall through to the backstop handler, which will reply with a 404.

A Simple Generated Response

The easiest way to generate a response is something like this:

    use POE::Component::Server::HTTPServer::Handler;

    my $server = POE::Component::Server::HTTPServer->new();
    $server->handlers( [ 
      '/' => sub {
               my $context = shift;
               $context->{response}->code(200);
               $context->{response}->content(
                 "<HTML><BODY><H1>Hi There</H1></BODY></HTML>\n"
               );
               return H_FINAL;
             }
    ] );

Notice that handlers() takes as an argument a list reference. The => notation is used to highlight the pairs in the list.

In this example, the URI prefix '/' is associated with a handler sub, which returns a simple HTML page. It sets the response code, the content of the response, and returns a value (H_FINAL, exported by HTTPServer::Handler) indicating that processing is finished. Because every request to this server will match the handler prefix ('/'), and because the handler finalizes itself, every request will now get this sample response page.

Passing on Requests

You can choose to not handle certain requests:

    $server->handlers( [
      '/a/?' => sub {
                  my $context = shift;
                  if ( $context->{contextpath} eq '/chuck' ) {
                    return H_CONT; # don't handle chuck!
                  }
                  $context->{response}->code(200);
                  $context->{response}->content(
                    "<HTML><BODY><H1>Hi There, A.</H1></BODY></HTML>\n"
                  );
                  return H_FINAL;
                },
      '/a/?' => sub {
                  my $context = shift;
                  $context->{error_message} = "No chucks allowed!";
                  return H_CONT;
                },
    ] );

There are now two handlers defined, both of which are associated with the prefix '/a/?'. These handlers will be invoked only for requests whose URIs begin with that prefix. Order of handlers is important, so the first handler will be invoked and then, if it does not return H_FINAL, the second.

The first handler passes on the request if the request URI is '/a/chuck'. In that case, the second handler is invoked, which sets an attribute ("error_message") in the context and passes itself. Because the second handler also passes, the request falls through to the backstop, which will return a 404.

In this example, any request not beginning with '/a/' will result in a 404 response.

A Simple Handler Object

Another alternative for writing handlers is to package them seperately. Aside from being a little more pretty (though taste varies), it allows you to write reusable, configurable handlers.

This example does the same as the "Simple Generated Response" example:

    my $server = POE::Component::Server::HTTPServer->new(
      [ '/' => MyHandler->new() ]
    );
    $server->create_server();
    $poe_kernel->run();
    exit 0;
    
    package MyHandler;
    use POE::Component::Server::HTTPServer::Handler;
    our @ISA = qw(POE::Component::Server::HTTPServer::Handler);

    sub handle {
        my $self = shift;
        my $context = shift;
        $context->{response}->code(200);
        $context->{response}->content(
            "<HTML><BODY><H1>Hi There</H1></BODY></HTML>\n"
        );
        return H_FINAL;
    }
    
    1;

Accessing Parameters

The ParameterParseHandler can be used to access CGI parameters:

    my $server->handlers( [
      '/' => new_handler( 'ParameterParseHandler' ),
      '/' => sub {
               my $context = shift;
               my $name = $context->{param}->{name} || "(undefined)";
               $context->code(200);
               $context->content( qq{
                   <HTML><BODY>
                   Name was $name.<BR>
                   <FORM method="GET" action="/">
                   Enter name: <input type="text" name="name">
                               <input type="submit">
                   </FORM>
                   </HTML></BODY>
               } );
               return H_FINAL;
             }
    ] );

This will print a simple form with a text field, and should print the value entered on submission.

Filtering Requests

Though handlers are chosen by matching against the request URI, the URI matching is done against a path stored in the context. This allows handlers to modify the request path seen by later handlers.

You can use this to perform request filtering:

    my $server->handlers( [
      '/' => sub {
               my $context = shift;
               $context->{fullpath} =~ s{^/oldsite/}{/newsite/};
               $context->{fullpath} =~ s{\.htm$}{\.html}i;
               return H_CONT;
             },
      '/' => new_handler('StaticHandler', './html'),
    ] );

The first handler performs two url filtering operations: it changes any path beginning with "/oldsite", to one beginning with "/newsite", and it changes urls ending in ".htm" or ".HTM" to ".html". Since this handler returns H_CONT, all requests fall through to the StaticHandler after being (possibly) modified.

Redispatching Requests

Sometimes, after a handler has done some work and modified the context, it may wish to restart the dispatch process from the top. HTTPServer's dispatch() method restarts processing at the start at the handler list, but keeps the current context unchanged. This can be used to perform an "internal redirect":

    my $server->handlers( [
      # our input forms are in here:
      '/html/' => new_handler('StaticHandler', './html'),
      # this handles a form submission:
      '/sub/' => new_handler('ParameterParseHandler'),
      '/sub/newEntry' => sub {
        my $context = shift;
        my($name, $value) =
          ($context->{param}->{name},$context->{param}->{info});
        # save the submitted data:
        open(my $out, "> $DataDir/$name.txt") || die $!;
        print $out $info;
        $context->{status_message} = "Data for $name saved!";
        return $context->{dispatcher}->dispatch($context,"/html/success.html");
      },
    ] );

The handler for /sub/newEntry accepts a form submission (presumably, from a form in /html), writes the data to a file, and tells HTTPServer to start again, as though the request had been for /html/success.html. The context now has the status_message attribute, however.

SEE ALSO

POE::Component::Server::HTTPServer, POE::Component::Server::HTTPServer::Handler, POE.

AUTHOR

Greg Fast <gdf@speakeasy.net>

COPYRIGHT

Copyright 2003 Greg Fast.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.