{
    "mode": "perldoc",
    "parameter": "POE::Filter::HTTPD",
    "section": "",
    "url": "https://www.chedong.com/phpMan.php/perldoc/POE%3A%3AFilter%3A%3AHTTPD/json",
    "generated": "2026-07-05T10:17:48Z",
    "synopsis": "#!perl\nuse warnings;\nuse strict;\nuse POE qw(Component::Server::TCP Filter::HTTPD);\nuse HTTP::Response;\nPOE::Component::Server::TCP->new(\nPort         => 8088,\nClientFilter => 'POE::Filter::HTTPD',  ### <-- HERE WE ARE!\nClientInput => sub {\nmy $request = $[ARG0];\n# It's a response for the client if there was a problem.\nif ($request->isa(\"HTTP::Response\")) {\nmy $response = $request;\n$request = $response->request;\nwarn \"ERROR: \", $request->message if $request;\n$[HEAP]{client}->put($response);\n$[KERNEL]->yield(\"shutdown\");\nreturn;\n}\nmy $requestfields = '';\n$request->headers()->scan(\nsub {\nmy ($header, $value) = @;\n$requestfields .= (\n\"<tr><td>$header</td><td>$value</td></tr>\"\n);\n}\n);\nmy $response = HTTP::Response->new(200);\n$response->pushheader( 'Content-type', 'text/html' );\n$response->content(\n\"<html><head><title>Your Request</title></head>\" .\n\"<body>Details about your request:\" .\n\"<table border='1'>$requestfields</table>\" .\n\"</body></html>\"\n);\n$[HEAP]{client}->put($response);\n$[KERNEL]->yield(\"shutdown\");\n}\n);\nprint \"Aim your browser at port 8088 of this host.\\n\";\nPOE::Kernel->run();\nexit;",
    "sections": {
        "NAME": {
            "content": "POE::Filter::HTTPD - parse simple HTTP requests, and serialize HTTP::Response\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "#!perl\n\nuse warnings;\nuse strict;\n\nuse POE qw(Component::Server::TCP Filter::HTTPD);\nuse HTTP::Response;\n\nPOE::Component::Server::TCP->new(\nPort         => 8088,\nClientFilter => 'POE::Filter::HTTPD',  ### <-- HERE WE ARE!\n\nClientInput => sub {\nmy $request = $[ARG0];\n\n# It's a response for the client if there was a problem.\nif ($request->isa(\"HTTP::Response\")) {\nmy $response = $request;\n\n$request = $response->request;\nwarn \"ERROR: \", $request->message if $request;\n\n$[HEAP]{client}->put($response);\n$[KERNEL]->yield(\"shutdown\");\nreturn;\n}\n\nmy $requestfields = '';\n$request->headers()->scan(\nsub {\nmy ($header, $value) = @;\n$requestfields .= (\n\"<tr><td>$header</td><td>$value</td></tr>\"\n);\n}\n);\n\nmy $response = HTTP::Response->new(200);\n$response->pushheader( 'Content-type', 'text/html' );\n$response->content(\n\"<html><head><title>Your Request</title></head>\" .\n\"<body>Details about your request:\" .\n\"<table border='1'>$requestfields</table>\" .\n\"</body></html>\"\n);\n\n$[HEAP]{client}->put($response);\n$[KERNEL]->yield(\"shutdown\");\n}\n);\n\nprint \"Aim your browser at port 8088 of this host.\\n\";\nPOE::Kernel->run();\nexit;\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "POE::Filter::HTTPD interprets input streams as HTTP 0.9, 1.0 or 1.1 requests. It returns a\nHTTP::Request objects upon successfully parsing a request.\n\nOn failure, it returns an HTTP::Response object describing the failure. The intention is that\napplication code will notice the HTTP::Response and send it back without further processing. The\nerroneous request object is sometimes available via the \"$r->request\" in HTTP::Response method.\nThis is illustrated in the \"SYNOPSIS\".\n\nFor output, POE::Filter::HTTPD accepts HTTP::Response objects and returns their corresponding\nstreams.\n\nPlease see HTTP::Request and HTTP::Response for details about how to use these objects.\n\nHTTP headers are not allowed to have UTF-8 characters; they must be ISO-8859-1.\nPOE::Filter::HTTPD will convert all UTF-8 into the MIME encoded equivalent. It uses\n\"utf8::isutf8\" for detection-8 and Email::MIME::RFC2047::Encoder for convertion. If utf8 is not\ninstalled, no conversion happens. If Email::MIME::RFC2047::Encoder is not installed,\n\"utf8::downgrade\" is used instead. In this last case, you will see a warning if you try to send\nUTF-8 headers.\n",
            "subsections": []
        },
        "PUBLIC FILTER METHODS": {
            "content": "POE::Filter::HTTPD implements the basic POE::Filter interface.\n\nnew",
            "subsections": [
                {
                    "name": "new",
                    "content": "\"MaxBuffer\" sets the maximum amount of data the filter will hold in memory. Defaults to 512 MB\n(536870912 octets). Because POE::Filter::HTTPD copies all data into memory, setting this number\nto high would allow a malicious HTTPD client to fill all server memory and swap.\n\n\"MaxContent\" sets the maximum size of the content of an HTTP request. Defaults to 1 MB (1038336\noctets). Because POE::Filter::HTTPD copies all data into memory, setting this number to high\nwould allow a malicious HTTPD client to fill all server memory and swap. Ignored if \"Streaming\"\nis set.\n\n\"Streaming\" turns on request streaming mode. Defaults to off. In streaming mode this filter will\nreturn either an HTTP::Request object or a block of content. The HTTP::Request object's content\nwill return empty. The blocks of content will be parts of the request's body, up to\nContent-Length in size. You distinguish between request objects and content blocks using\n\"Scalar::Util/bless\" (See \"Streaming Request\" below). This option supersedes \"MaxContent\".\n"
                }
            ]
        },
        "CAVEATS": {
            "content": "Some versions of libwww are known to generate invalid HTTP. For example, this code (adapted from\nthe HTTP::Request::Common documentation) will cause an error in a POE::Filter::HTTPD daemon:\n\nNOTE: Using this test with libwww-perl/5.834 showed that it added the proper HTTP/1.1 data!\nWe're not sure which version of LWP fixed this. This example is valid for older LWP\ninstallations, beware!\n\nuse HTTP::Request::Common;\nuse LWP::UserAgent;\n\nmy $ua = LWP::UserAgent->new();\n$ua->request(POST 'http://example.com', [ foo => 'bar' ]);\n\nBy default, HTTP::Request is HTTP version agnostic. It makes no attempt to add an HTTP version\nheader unless you specifically declare a protocol using \"$request->protocol('HTTP/1.0')\".\n\nAccording to the HTTP 1.0 RFC (1945), when faced with no HTTP version header, the parser is to\ndefault to HTTP/0.9. POE::Filter::HTTPD follows this convention. In the transaction detailed\nabove, the Filter::HTTPD based daemon will return a 400 error since POST is not a valid HTTP/0.9\nrequest type.\n\nUpon handling a request error, it is most expedient and reliable to respond with the error and\nshut down the connection. Invalid HTTP requests may corrupt the request stream. For example, the\nabsence of a Content-Length header signals that a request has no content. Requests with content\nbut without that header will be broken into a content-less request and invalid data. The invalid\ndata may also appear to be a request! Hilarity will ensue, possibly repeatedly, until the filter\ncan find the next valid request. By shutting down the connection on the first sign of error, the\nclient can retry its request with a clean connection and filter.\n",
            "subsections": []
        },
        "Streaming Request": {
            "content": "Normally POE::Filter::HTTPD reads the entire request content into memory before returning the\nHTTP::Request to your code. In streaming mode, it will return the content separately, as\nunblessed scalars. The content may be split up into blocks of varying sizes, depending on OS and\ntransport constraints. Your code can distinguish the request object from the content blocks\nusing \"blessed\" in Scalar::Util.\n\nuse Scalar::Util;\nuse POE::Wheel::ReadWrite;\nuse POE::Filter:HTTPD;\n\n$heap->{wheel} = POE::Wheel::ReadWrite->new(\nInputEvent => 'httpinput',\nFilter => POE::Filter::HTTPD->new( Streaming => 1 ),\n# ....\n);\n\nsub httpinputhandler\n{\nmy( $heap, $reqordata ) = @[ HEAP, ARG0 ];\nif( blessed $reqordata ) {\nmy $request = $reqordata;\nif( $request->isa( 'HTTP::Response') ) {\n# HTTP error\n$heap->{wheel}->put( $request );\n}\nelse {\n# HTTP request\n# ....\n}\n}\nelse {\nmy $data = $reqordata;\n# ....\n}\n}\n\nYou may trivally create a DoS bug if you hold all content in memory but do not impose a maximum\nContent-Length. An attacker could send \"Content-Length: 1099511627776\" (aka 1 TB) and keep\nsending data until all your system's memory and swap is filled.\n\nContent-Length has been sanitized by POE::Filter::HTTPD so checking it is trivial :\n\nif( $request->headers( 'Content-Length' ) > 1024*1024 ) {\nmy $resp = HTTP::Response->new( RCREQUESTENTITYTOOLARGE ),\n\"So much content!\" )\n$heap->{wheel}->put( $resp );\nreturn;\n}\n\nIf you want to handle large amounts of data, you should save the content to a file before\nprocessing it. You still need to check Content-Length or an attacker might fill up the\npartition.\n\nuse File::Temp qw(tempfile);\n\nif( blessed $[ARG0] ) {\n$heap->{request} = $[ARG0];\nif( $heap->{request}->method eq 'GET' ) {\nhandleget( $heap );\ndelete $heap->{request};\nreturn;\n}\nmy( $fh, $file ) = tempfile( \"httpd-XXXXXXXX\", TMPDIR=>1 );\n$heap->{contentfile} = $file;\n$heap->{contentfh} = $fh;\n$heap->{contentsize} = 0;\n}\nelse {\nreturn unless $heap->{request};\n\n$heap->{contentsize} += length( $[ARG0] );\n$heap->{contentfh}->print( $[ARG0] );\nif( $heap->{contentsize} >= $heap->{request}->headers( 'content-length' ) ) {\ndelete $heap->{contentfh};\ndelete $heap->{contentsize};\n\n# Now we can parse $heap->{contentfile}\nif( $heap->{request}->method eq 'POST' ) {\nhandlepost( $heap );\n}\nelse {\n# error ...\n}\n}\n}\n\nsub handlepost\n{\nmy( $heap ) = @;\n# Now we have to load and parse $heap->{contentfile}\n\n# Next 6 lines make the data available to CGI->init\nlocal $ENV{REQUESTMETHOD} = 'POST';\nlocal $CGI::PERLEX = $CGI::PERLEX = \"CGI-PerlEx/Fake\";\nlocal $ENV{CONTENTTYPE} = $heap->{req}->header( 'content-type' );\nlocal $ENV{CONTENTLENGTH} = $heap->{req}->header( 'content-length' );\nmy $keep = IO::File->new( \"<&STDIN\" ) or die \"Unable to reopen STDIN: $!\";\nopen STDIN, \"<$heap->{contentfile}\" or die \"Reopening STDIN failed: $!\";\n\nmy $qcgi = CGI->new();\n\n# cleanup\nopen STDIN, \"<&\".$keep->fileno or die \"Unable to reopen $keep: $!\";\nundef $keep;\nunlink delete $heap->{contentfile};\n\n# now use $q as you would normaly\nmy $file = $q->upload( 'fieldname' );\n\n# ....\n}\n\nsub handleget\n{\nmy( $heap ) = @;\n\n# 4 lines to get data into CGI->init\nlocal $ENV{REQUESTMETHOD} = 'GET';\nlocal $CGI::PERLEX = $CGI::PERLEX = \"CGI-PerlEx/Fake\";\nlocal $ENV{CONTENTTYPE} = $heap->{req}->header( 'content-type' );\nlocal $ENV{'QUERYSTRING'} = $heap->{req}->uri->query;\n\nmy $q = CGI->new();\n\n# now use $q as you would normaly\n# ....\n}\n",
            "subsections": []
        },
        "Streaming Response": {
            "content": "It is possible to use POE::Filter::HTTPD for streaming content, but an application can use it to\nsend headers and then switch to POE::Filter::Stream.\n\nFrom the input handler (the InputEvent handler if you're using wheels, or the ClientInput\nhandler for POE::Component::Server::TCP):\n\nmy $response = HTTP::Response->new(200);\n$response->pushheader('Content-type', 'audio/x-mpeg');\n$[HEAP]{client}->put($response);\n$[HEAP]{client}->setoutputfilter(POE::Filter::Stream->new());\n\nThen the output-flushed handler (FlushEvent for POE::Wheel::ReadWrite, or ClientFlushed for\nPOE::Component::Server::TCP) can put() chunks of the stream as needed.\n\nmy $bytesread = sysread(\n$[HEAP]{filetostream}, my $buffer = '', 4096\n);\n\nif ($bytesread) {\n$[HEAP]{client}->put($buffer);\n}\nelse {\ndelete $[HEAP]{filetostream};\n$[KERNEL]->yield(\"shutdown\");\n}\n",
            "subsections": []
        },
        "SEE ALSO": {
            "content": "Please see POE::Filter for documentation regarding the base interface.\n\nThe SEE ALSO section in POE contains a table of contents covering the entire POE distribution.\n\nHTTP::Request and HTTP::Response explain all the wonderful things you can do with these classes.\n",
            "subsections": []
        },
        "BUGS": {
            "content": "Many aspects of HTTP 1.0 and higher are not supported, such as keep-alive. A simple I/O filter\ncan't support keep-alive, for example. A number of more feature-rich POE HTTP servers are on the\nCPAN. See <http://search.cpan.org/search?query=POE+http+server&mode=dist>\n\nAUTHORS & COPYRIGHTS\nPOE::Filter::HTTPD was contributed by Artur Bergman. Documentation is provided by Rocco Caputo.\n\nPlease see POE for more information about authors and contributors.\n",
            "subsections": []
        }
    },
    "summary": "POE::Filter::HTTPD - parse simple HTTP requests, and serialize HTTP::Response",
    "flags": [],
    "examples": [],
    "see_also": []
}