NAME

Linux::Event::HTTP::Server - Serve HTTP requests with Linux::Event

SYNOPSIS

use v5.36;
use Linux::Event::Loop;
use Linux::Event::HTTP::Server;

my $loop = Linux::Event::Loop->new;

my $server = Linux::Event::HTTP::Server->new(
    loop => $loop,
    host => '127.0.0.1',
    port => 8080,

    on_request => sub ($tx, $req) {
        $tx->respond(
            status  => 200,
            headers => [['content-type', 'text/plain']],
            body    => "Hello from Linux::Event!\n",
        );
    },
);

say "Listening on http://127.0.0.1:8080/";
$loop->run;

Save this as server.pl and run perl server.pl. In another terminal, try:

curl http://127.0.0.1:8080/

The server keeps running until you stop it.

DESCRIPTION

Linux::Event::HTTP::Server listens for HTTP requests and calls your code to handle them. You do not need to read from sockets or parse HTTP yourself. HTTP/1.1 works by default; HTTP/2 and HTTP/3 are optional.

HANDLING REQUESTS

on_request runs when a complete request arrives. It receives:

  • $req - the request, with its method, URL target, headers, and body.

  • $tx - the transaction you use to send a response.

Read the request with:

$req->method;                  # GET, POST, ...
$req->target;                  # /items?color=blue
$req->header('content-type');  # A request header
$req->body;                    # Complete request body

target includes the query string. This module does not provide a router; you can inspect the method and target yourself.

For example, replace on_request in the first example with:

on_request => sub ($tx, $req) {
    if ($req->method eq 'GET' && $req->target eq '/') {
        $tx->respond(status => 200, body => "Welcome\n");
    }
    elsif ($req->method eq 'POST' && $req->target eq '/echo') {
        $tx->respond(status => 200, body => $req->body);
    }
    else {
        $tx->respond(status => 404, body => "Not found\n");
    }
},

Use $tx->respond to send the status, headers, and body. Headers are an array reference of name/value pairs:

$tx->respond(
    status  => 200,
    headers => [['content-type', 'text/html; charset=utf-8']],
    body    => '<h1>Hello</h1>',
);

RECEIVING LARGE REQUESTS

By default, the server collects each request body before calling on_request. The body has a 1 MiB limit by default. A larger non-streamed body fails rather than using unlimited memory.

If an upload might be large, receive it a chunk at a time. Supply on_headers alongside on_request in the server constructor:

on_headers => sub ($tx, $req) {
    $tx->on_data(sub ($tx, $bytes) {
        say "Received ", length($bytes), " bytes";
    });
},

on_request => sub ($tx, $req) {
    $tx->respond(status => 200, body => "Upload complete\n");
},

on_headers runs before body data arrives. Registering on_data there tells the server to stream the body instead of collecting it in $req->body. on_request still runs after the upload finishes successfully; it does not run if the request fails.

To change the HTTP/1 buffered body limit, pass http1 => { max_buffered_body_bytes => $bytes } to new.

SENDING LARGE RESPONSES

For a response made in pieces, start with stream_body => 1, then send data with write and finish with end:

$tx->respond(status => 200, stream_body => 1);
$tx->write("First part\n");
$tx->end("Last part\n");

If a producer sends lots of data, use on_drain to resume when the connection has room again. A false result from write means the bytes were accepted, but you must pause before writing more. Do not resend that chunk.

HTTPS AND HTTP VERSIONS

To serve HTTPS, give the server a certificate and private key:

my $server = Linux::Event::HTTP::Server->new(
    loop => $loop,
    host => '127.0.0.1',
    port => 8443,
    tls => {
        cert_file => 'cert.pem',
        key_file  => 'key.pem',
    },
    on_request => sub ($tx, $req) {
        $tx->respond(status => 200, body => "Secure\n");
    },
);

HTTP/1.1 is enabled by default. To also serve HTTP/2, install Unblock::HTTP2 0.13 or newer and set http2 => 1. HTTP/2 servers require TLS.

To also serve HTTP/3, install Unblock::HTTP3 0.14 or newer and Net::QUIC 0.06 or newer, then set http3 => 1. HTTP/3 needs TLS, a specific host address (not a wildcard), and a TCP listener alongside its UDP listener.

The same on_request callback handles all enabled HTTP versions.

ERRORS AND SERVER CONTROL

on_error reports HTTP transaction errors. on_listener_error reports problems accepting connections. Both are optional options to new:

on_error => sub ($tx, $error, @details) {
    warn "HTTP error: $error\n";
},
on_listener_error => sub ($listener, $error) {
    warn "Listener error: $error\n";
},

host and port return the listening address and port. connection_count returns the number of live connections. pause and resume control acceptance of new connections.

close stops accepting new connections but does not immediately discard work already in progress. To shut down gracefully:

$server->shutdown(
    grace => 30,
    on_complete => sub ($server) {
        $loop->stop;
    },
);

grace is in seconds. The server finishes admitted work when possible and closes remaining connections at the deadline. on_complete runs when shutdown is done; it may run immediately if the server is idle.

WEBSOCKETS AND CONNECT

WebSockets are optional. Enable them for an HTTP version, such as http1 => { websocket => 1 }, and provide on_websocket. See Unblock::HTTP::Server for the WebSocket callback options.

For custom protocol upgrades and CONNECT tunnels, see docs/CONNECT.md in the distribution. Neither feature is needed for ordinary HTTP servers.

SEE ALSO

Linux::Event::HTTP::Client, Linux::Event::Loop, Uniform::HTTP::Request.

The distribution's docs/GETTING-STARTED.md has more examples.