Mark Morgan


POE::Filter::HTTPD::Chunked - Drop-in replacement for POE::Filter::HTTPD that also support HTTP1.1 chunked transfer-encoding.



  use warnings;
  use strict;

  use POE qw(Component::Server::TCP Filter::HTTPD::Chunked);
  use HTTP::Response;

    Port         => 8088,
    ClientFilter => 'POE::Filter::HTTPD::Chunked',

    ClientInput => sub {
      my $request = $_[ARG0];

      # It's a response for the client if there was a problem.
      if ($request->isa("HTTP::Response")) {

      my $request_fields = '';
        sub {
          my ($header, $value) = @_;
          $request_fields .= (

      my $response = HTTP::Response->new(200);
      $response->push_header( 'Content-type', 'text/html' );
        "<html><head><title>Your Request</title></head>" .
        "<body>Details about your request:" .
        "<table border='1'>$request_fields</table>" .
        "<tr><td>Body</td><td>" . $request->content . "</td>" .


  print "Aim your browser at port 8088 of this host.\n";

For detail and an example of handling partial chunks, see "Handling of partial chunked data" below.


POE::Filter::HTTPD::Chunked interprets input streams as HTTP requests. It returns a HTTP::Request object upon successfully parsing a request. On failure, it returns an HTTP::Response object describing the failure. The intention is that application code will notice the HTTP::Response and send it back without further processing. This is illustrated in the SYNOPSIS.

For output, this module accepts HTTP::Response objects and returns their corresponding streams.

Please see HTTP::Request and HTTP::Response for details about how to use these objects.

The following are the major differences between this module and the core POE POE::Filter::HTTPD:

handling of incoming chunked data

POE::Filter::HTTPD has no support for handling 'chunked' requests (part of HTTP1.1 spec), and would return an error (in the form of an HTTP::Response object returned to the POE session). For many applications, this may not be a problem, as they can put an HTTP1.1 proxy in front of the application, that will de-chunk the request, and return the normal HTTP/1.0 content-length. This method, however, causes issues with applications that either a/ want to handle partial content for a request as it comes in, b/ don't want to have to artificially adjust request timeouts whilst waiting for the proxy to get the full request or c/ don't want the additional system complexity of having to use a proxy to dechunk.

support for any request type

POE::Filter::HTTPD didn't handle all request types (ie, DELETE). This restriction has been removed in this module.


POE::Filter::HTTPD::Chunked implements the basic POE::Filter interface.

Handling of partial chunked data.

In order to allow for partial handling of data, if an optional constructor argument of 'event_on_chunk' is passed in with a true value, and a partial chunked request has been received since the last time the wheel causes a 'get' call to be emitted, the partial chunked data is returned back. This is wrapped in a class of HTTP::Request::Chunked, which is just a marker sub-class of HTTP::Request, with the following detail set:


Will be set to the partial content that has been received, since the last HTTP::Request::Chunked packet was returned.

x-chunk-offset header

The offset (in bytes) as to where the current partial content starts.

x-chunk-offset-size header

The number of bytes in this partial chunk.

Note that the final chunk will never be returned as an HTTP::Request::Chunked object. Instead, the full request will be returned as an HTTP::Request object instead.

An example usage of how partial chunks is as-follows:

 my $filter = POE::Filter::HTTPD::Chunked->new( event_on_chunk => 1 );

 sub input_event {
     my ( $kernel, $heap, $request ) = @_[ KERNEL, HEAP, ARG0 ];

     if ( $request->isa( 'HTTP::Response' ) ) {
         # if we get an HTTP::Response object in, this was due to an error
         # in parsing the request.  Just return to client.

         $heap->{ wheel }->put( $request );
     } elsif ( $request->isa( 'HTTP::Request::Chunked' ) ) {
         # more data has come in for the given request.  Can just be used
         # to reset timeout, or to deal with the data within it.

         $kernel->alarm( 'reset_timer' => time() + 30 );

            "got partial data of '%s' from byte offset %i, with size of %i",
            $request->header( 'x-chunk-offset' ),
            $request->header( 'x-chunk-offset-size' ),
     } else {
         # got a completed request.  This will be an HTTP::Request object,
         # populated with all data from the original request, converted to
         # non-chunked format.  If any body was included in the request, be
         # it chunked or not, a content-length header will be set, giving
         # the number of bytes in the body.

            "got complete request of '%s', with size of '%i'",
            $request->header( 'content-length' )


Many aspects of HTTP 1.0 and higher are not supported, such as keep-alive. A simple I/O filter can't support keep-alive, for example. A number of more feature-rich POE HTTP servers are on the CPAN. See


POE::Filter::HTTPD - Original basis for this class. Note that much of the original POE::Filter::HTTPD code is redone for this class, due to different requirements. Assume that any errors that occour in POE::Filter::HTTPD::Chunked are mine, and not based on this module.

POE::Filter - Superclass, for general Filter API.

The SEE ALSO section in POE contains a table of contents covering the entire POE distribution.

HTTP::Request and HTTP::Response explain all the wonderful things you can do with these classes.


Mark Morgan <>

Tom Clark <>

This modules is bassed off of POE::Filter::HTTPD module, contributed by Arthur Bergman, with documentation provided by Rocco Caputo.

Thanks to trutap ( for paying us whilst developing this code, and allowing it to be released.

Copyright (c) 2008-2010 Mark Morgan. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.