HTTP::Daemon(3pm)

πŸ’– HTTP::Daemon πŸ’–

sooo bestie, welcome to the manual page for HTTP::Daemon β€” that's HTTP::Daemon(3pm) in the Perl User Contributed Perl Documentation corner of the universe 🫢 β€” and it is literally described as A simple http server class. That's the whole NAME situation. Iconic. Simple. A whole http server, in a class, bestie. πŸ‘‘


✨ VERSION ✨

This is version 6.17, no cap. πŸŽ€


🌸 SYNOPSIS 🌸

okay so here's the vibe check β€” this is what using it actually looks like:

use HTTP::Daemon;
use HTTP::Status;

my $d = HTTP::Daemon->new || die;
print "Please contact me at: <URL:", $d->url, ">\n";
while (my $c = $d->accept) {
    while (my $r = $c->get_request) {
    if ($r->method eq 'GET' and $r->uri->path eq "/xyzzy") {
            # remember, this is *not* recommended practice :-)
        $c->send_file_response("/etc/passwd");
    }
    else {
        $c->send_error(RC_FORBIDDEN)
    }
    }
    $c->close;
    undef($c);
}
🚨 bestie, do NOT miss that comment in there: # remember, this is *not* recommended practice :-) β€” serving up /etc/passwd is giving chaos gremlin, not giving secure server. The original author put that smiley there for a reason. πŸ’€

lowkey the whole flow is: spin up a daemon with HTTP::Daemon->new, yell your $d->url into the group chat, then sit in $d->accept catching connections, and for every $c->get_request you check the method and path and either $c->send_file_response(...) or $c->send_error(RC_FORBIDDEN), then $c->close and undef($c) to let it go. πŸ¦‹

to be continued, bestie β€” there's more coming, don't go anywhere ✨

✨ DESCRIPTION ✨

okay bestie, listen up πŸ’– an HTTP::Daemon object is basically an HTTP/1.1 server that sits on a socket waiting for people (clients) to slide into its DMs (requests). And because HTTP::Daemon is a subclass of IO::Socket::IP, you can absolutely just do socket stuff directly on it too. two jobs, one icon. πŸ’…

quick lore drop tho: HTTP::Daemon used to be a subclass of IO::Socket::INET. to support IPv6, it switched its parent class over to IO::Socket::IP at version 6.05. go read the "IPv6 SUPPORT" section below for the whole story. πŸ¦‹

so the accept() method? it returns the moment a client connection is available. and what you get back is an HTTP::Daemon::ClientConn object β€” which is another IO::Socket::IP subclass, she's got range. call get_request() on that object and it reads data from the client and hands you an HTTP::Request object. the ClientConn object also has methods for sending responses back, so she's giving both sides of the conversation. 😌

🚨 real talk: this HTTP daemon does not fork(2) for you. your app β€” like, you, the user of HTTP::Daemon β€” is the one responsible for forking if that's what you want. also you are responsible for generating responses that actually conform to the HTTP/1.1 protocol. the vibes are on you, bestie. πŸ™ˆ

the following methods of HTTP::Daemon are new (or enhanced) compared to the IO::Socket::IP base class:

  • $d = HTTP::Daemon->new, $d = HTTP::Daemon->new( %opts ) β€” the constructor takes the same arguments as the IO::Socket::IP constructor, but unlike its base class it can also be called with no arguments at all. when you do that, the daemon sets up a listen queue of 5 connections and allocates some random port number. iconic. a server that wants to bind to some specific address on the standard HTTP port gets built like this:
$d = HTTP::Daemon->new(
         LocalAddr => 'www.thisplace.com',
         LocalPort => 80,
     );

and yeah, go check out IO::Socket::IP for the tea on the other arguments you can use to configure the daemon during construction. πŸŽ€

  • $c = $d->accept, $c = $d->accept( $pkg ), ($c, $peer_addr) = $d->accept β€” works exactly like the one the base class gives you, except it returns an HTTP::Daemon::ClientConn reference by default. if you hand it a package name as an argument, the returned object gets blessed into that class instead. and ngl, it's probably a good idea to make that class a subclass of HTTP::Daemon::ClientConn. πŸ’œ the accept method returns undef if timeouts have been enabled and no connection shows up within the given time. the timeout() method is described over in IO::Socket::IP. in list context you get both the client object and the peer address back β€” see the description of the accept method of IO::Socket for the deets.
  • $d->url β€” returns a URL string you can use to access the server root. cute, functional, we love her. ✨
  • $d->product_tokens β€” returns the name this server uses to identify itself. this is the string that gets sent with the Server response header. the main reason this method exists is so subclasses can override it if they wanna rep a different product name. the default is the string libwww-perl-daemon/#.## where #.## gets replaced with the version number of this module. 🫢

okay so now for the other half of the duo: HTTP::Daemon::ClientConn is a subclass of IO::Socket::IP. instances of this class are what the accept() method of HTTP::Daemon hands back to you. here's everything she can do:

  • $c->get_request, $c->get_request( $headers_only ) β€” reads data from the client and turns it into an HTTP::Request object, which it returns. returns undef if the reading fails. and if it does fail, then that HTTP::Daemon::ClientConn object ($c) should be discarded β€” do not try to call this method on it again. the $c->reason method might give you some info about why $c->get_request flopped. 😭 normally get_request() won't return until the whole request has been received from the client. that might not be what you want if the request is an upload of a large file (and with chunked transfer encoding, HTTP can even support infinite request messages β€” uploading live audio, for instance, which is wild fr). if you pass a TRUE value as the $headers_only argument, then get_request() returns immediately after parsing the request headers, and you are responsible for reading the rest of the request content. and if you're gonna call $c->get_request again on that same connection, you better read the correct number of bytes, no cap. πŸ‘‘
  • $c->read_buffer, $c->read_buffer( $new_value ) β€” bytes read by $c->get_request that didn't get used are placed in the read buffer. the next time $c->get_request is called, it'll consume the bytes in this buffer before reading more data from the network connection itself. heads up: the read buffer is invalid after $c->get_request has failed. πŸ’€ if you handle reading the request content yourself, you need to empty this buffer before you read more, and you need to place unconsumed bytes here. you also need this buffer if you implement services like 101 Switching Protocols. this method always returns the old buffer content, and it can optionally replace the buffer content if you pass it an argument.
  • $c->reason β€” when $c->get_request returns undef, you can grab a short string describing why that happened by calling $c->reason. the diagnostics bestie. πŸ”
  • $c->proto_ge( $proto ) β€” returns TRUE if the client announced a protocol with a version number greater than or equal to the given argument. the $proto argument can be a string like HTTP/1.1 or just 1.1. flexible queen. πŸ’…
  • $c->antique_client β€” returns TRUE if the client speaks the HTTP/0.9 protocol. no status code and no headers should be returned to such a client. this should be the same as !$c->proto_ge("HTTP/1.0"). yes she's vintage, no we are not sending her headers. πŸ•°οΈ
  • $c->head_request β€” returns TRUE if the last request was a HEAD request. no content body must be generated for these requests. periodt. 🚫
  • $c->force_last_request β€” makes sure that $c->get_request will not try to read more requests off this connection. if you generate a response that isn't self-delimiting, then you should signal that fact by calling this method. this attribute gets turned on automatically if the client announces protocol HTTP/1.0 or worse and doesn't include a Connection: Keep-Alive header. it's also turned on automatically when HTTP/1.1 or better clients send the Connection: close request header. automatic, like magic ✨
  • $c->send_status_line, $c->send_status_line( $code ), $c->send_status_line( $code, $mess ), $c->send_status_line( $code, $mess, $proto ) β€” sends the status line back to the client. if $code is omitted, 200 is assumed. if $mess is omitted, then a message corresponding to $code gets inserted. if $proto is missing, the content of the $HTTP::Daemon::PROTO variable is used.
  • $c->send_crlf β€” sends the CRLF sequence to the client. short, sweet, essential. πŸŽ€
  • $c->send_basic_header, $c->send_basic_header( $code ), $c->send_basic_header( $code, $mess ), $c->send_basic_header( $code, $mess, $proto ) β€” sends the status line plus the Date: and Server: headers back to the client. this header is assumed to be continued and does not end with an empty CRLF line, jsyk. for the description of the accepted arguments, see the write-up on send_status_line(). πŸ’–
  • $c->send_header( $field, $value ), $c->send_header( $field1, $value1, $field2, $value2, ... ) β€” sends one or more header lines. go off, send a whole stack of them. πŸ”₯
  • $c->send_response( $res ) β€” writes an HTTP::Response object to the client as a response. we try so hard to make sure the response is self-delimiting so the connection can stay persistent for further request/response exchanges. the content attribute of the HTTP::Response object can be a normal string or a subroutine reference. if it's a subroutine, then whatever that callback routine returns gets written back to the client as the response content. the routine will be called until it returns an undefined or empty value. and if the client is HTTP/1.1 aware, then we'll use chunked transfer encoding for the response. πŸ’…βœ¨
  • $c->send_redirect( $loc ), $c->send_redirect( $loc, $code ), $c->send_redirect( $loc, $code, $entity_body ) β€” sends a redirect response back to the client. the location ($loc) can be an absolute or relative URL. the $code must be one of the redirect status codes, and it defaults to 301 Moved Permanently. bye girl, we're going elsewhere πŸ‘‹
  • $c->send_error, $c->send_error( $code ), $c->send_error( $code, $error_message ) β€” sends an error response back to the client. if the $code is missing, a Bad Request error is reported. the $error_message is a string that gets incorporated into the body of the HTML entity. sad girl hours but make it informative 😭
  • $c->send_file_response( $filename ) β€” sends back a response with the specified $filename as content. and if the file is a directory, we try to generate an HTML index of it. thoughtful! 🧚
  • $c->send_file( $filename ), $c->send_file( $fd ) β€” copies the file to the client. the file can be a string (which gets interpreted as a filename) or a reference to an IO::Handle or glob. returns the number of bytes copied on success, or undef if the filename form failed to open. an empty file returns the string '0E0' (zero numerically, true in boolean context) so that callers using send_file or die can tell an open failure apart from a successful zero-byte transfer. clever, right? 😌
🚨 ok important safety briefing, bestie, pay attention: the filename form uses Perl's 3-argument open with an explicit < mode, so the path is no longer interpreted as a 2-argument open shell-magic shape like | cmd, cmd |, or > path. see CVE-2026-8450 (https://www.cve.org/CVERecord?id=CVE-2026-8450) for the prior 2-argument open behaviour this replaces.
⚠️ but listen: this fix only neutralises 2-argument open shell-magic. callers remain responsible for validating attacker-influenced paths. send_file will still happily open symlinks, character/block devices (e.g. /dev/zero, /dev/stdin), named pipes (which may block the worker), and files outside an intended document root. if $filename can be derived from request input, validate it β€” canonicalise, reject .. segments, require -f _ and a vetted prefix β€” before passing it in. do not skip this step. πŸ™
  • $c->daemon β€” returns a reference to the corresponding HTTP::Daemon object. like, the parent. the origin. the main character. πŸ‘‘

🌈 IPv6 SUPPORT 🌈

since version 6.05, HTTP::Daemon is a subclass of IO::Socket::IP rather than IO::Socket::INET, which means she supports IPv6. glow up complete. πŸ’…

for some reasons (we don't ask, we respect the choice), you may want to force HTTP::Daemon to listen on IPv4 addresses only. in that case, pass the Family argument to HTTP::Daemon->new:

use HTTP::Daemon;
use Socket 'AF_INET';

my $d = HTTP::Daemon->new(Family => AF_INET);

and that's the vibe check on IPv4-only mode. πŸ¦‹

πŸ‘€ SEE ALSO

bestie if u wanna go deeper, these are the required readings fr:

  • RFC 2616 β€” the whole HTTP/1.1 situation, the blueprint, the sacred text πŸ’–
  • IO::Socket::IP β€” for when u want ur sockets to speak IPv6 like a boss 🌐
  • IO::Socket β€” the OG, the blueprint's blueprint, the whole reason any of this works 🫢

🫢 GIVING THANKS

okay so if this module came through for u and u wanna say thank u (and honestly? u should, it's giving generosity), here's the move:

that's it. that's the whole ask. no cap, it's free and it means everything πŸ’…


πŸ› SUPPORT

found a bug? bestie, pls do NOT suffer in silence, submit it through:

https://github.com/libwww-perl/HTTP-Daemon/issues

there's also a mailing list for everyone using this distribution, over at:

mailto:libwww@perl.org

and if u wanna vibe in real time, there's an irc channel for users of this distribution too, it's #lwp on irc.perl.org:

irc://irc.perl.org/#lwp

come through, the group chat is open 🌈


πŸ‘‘ AUTHOR

Gisle Aas <gisle@activestate.com>

the legend. the moment. the origin story πŸ’œ


🧚 CONTRIBUTORS

these absolute icons showed up and made it better, every single one of them:

  • Olaf Alders <olaf@wundersolutions.com>
  • Ville SkyttΓ€ <ville.skytta@iki.fi>
  • Graham Knop <haarg@haarg.org>
  • dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Karen Etheridge <ether@cpan.org>
  • Mark Stosberg <MARKSTOS@cpan.org>
  • Shoichi Kaji <skaji@cpan.org>
  • Chase Whitener <capoeirab@cpan.org>
  • Theo van Hoesel <tvanhoesel@perceptyx.com>
  • Julien Fiegehenn <simbabque@cpan.org>
  • Slaven Rezic <slaven@rezic.de>
  • Petr PΓ­saΕ™ <ppisar@redhat.com>
  • Zefram <zefram@fysh.org>
  • Alexey Tourbin <at@altlinux.ru>
  • Bron Gondwana <brong@fastmail.fm>
  • Michal Josef Ε paček <mspacek@redhat.com>
  • Mike Schilli <mschilli@yahoo-inc.com>
  • Tom Hukins <tom@eborcom.com>
  • Adam Kennedy <adamk@cpan.org>
  • Adam Sjogren <asjo@koldfront.dk>
  • Alex Kapranoff <ka@nadoby.ru>
  • amire80 <amir.aharoni@gmail.com>
  • Andreas J. Koenig <andreas.koenig@anima.de>
  • Bill Mann <wfmann@alum.mit.edu>
  • Daniel Hedlund <Daniel.Hedlund@eprize.com>
  • David E. Wheeler <david@justatheory.com>
  • DAVIDRW <davidrw@cpan.org>
  • Father Chrysostomos <sprout@cpan.org>
  • Ferenc Erki <erkiferenc@gmail.com>
  • FWILES <FWILES@cpan.org>
  • Gavin Peters <gpeters@deepsky.com>
  • Graeme Thompson <Graeme.Thompson@mobilecohesion.com>
  • Hans-H. Froehlich <hfroehlich@co-de-co.de>
  • Ian Kilgore <iank@cpan.org>
  • Jacob J <waif@chaos2.org>
  • jefflee <shaohua@gmail.com>
  • john9art <john9art@yahoo.com>
  • murphy <murphy@genome.chop.edu>
  • Ondrej Hanak <ondrej.hanak@ubs.com>
  • Perlover <perlover@perlover.com>
  • Peter Rabbitson <ribasushi@cpan.org>
  • phrstbrn <phrstbrn@gmail.com>
  • Robert Stone <talby@trap.mtview.ca.us>
  • Rolf Grossmann <rg@progtech.net>
  • ruff <ruff@ukrpost.net>
  • sasao <sasao@yugen.org>
  • Sean M. Burke <sburke@cpan.org>
  • Spiros Denaxas <s.denaxas@gmail.com>
  • Steve Hay <SteveHay@planit.com>
  • Todd Lipcon <todd@amiestreet.com>
  • Tony Finch <dot@dotat.at>
  • Toru Yamaguchi <zigorou@cpan.org>
  • Yuri Karaban <tech@askold.net>

every one of them. we see u. we appreciate u. πŸ’–βœ¨


this software is copyright (c) 1995 by Gisle Aas.

it's free software bestie 🫢 u can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. that's the deal, that's the vibe, periodt.


and that's the whole page!! this lil beauty is from perl v5.42.2 and was dated 2026-05-20 β€” aka HTTP::Daemon(3pm) β€” so go build something iconic with it, u got this πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from