NAME

Linux::Event::HTTP::Client - Make HTTP requests with Linux::Event

SYNOPSIS

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

my $loop = Linux::Event::Loop->new;
my $client = Linux::Event::HTTP::Client->new(loop => $loop);

$client->get(
    'https://example.com/',
    timeout => 15,

    on_response => sub ($tx, $res) {
        say "HTTP ", $res->status;
        say $res->body;
    },

    on_error => sub ($object, $error, @details) {
        warn "Request failed: $error\n";
    },

    on_finish => sub { $loop->stop },
);

$loop->run;

DESCRIPTION

Linux::Event::HTTP::Client makes HTTP requests without blocking the event loop. Create one Client and reuse it for many requests. The Client manages connections, HTTPS, and HTTP messages for you.

HTTP/1.1 works by default. HTTP/2 and HTTP/3 are optional.

MAKING REQUESTS

Call get, post, put, head, or delete with a URL followed by options. Each call returns immediately; the request is handled while the loop runs.

To send a POST with a body and headers:

$client->post(
    'https://example.com/messages',
    headers => [['content-type', 'text/plain']],
    body => "Hello\n",
    on_response => sub ($tx, $res) {
        say $res->status;
        say $res->body;
    },
);

Headers are an array reference of name/value pairs. For other HTTP methods, use request:

$client->request(
    method => 'PATCH',
    url    => 'https://example.com/item/1',
    body   => 'updated',
    on_response => sub ($tx, $res) {
        say $res->status;
    },
);

RESPONSES AND CALLBACKS

on_response receives a transaction $tx and a response $res. The response is a Uniform::HTTP::Response object. Common methods are:

$res->status;                  # HTTP status code
$res->body;                    # Response body
$res->header('content-type');  # A header value

HTTP 404 and 500 are valid responses, not connection errors. Check $res->status to decide how to handle them.

Response bodies are not automatically decompressed. If you want to request plain content, pass headers => [['accept-encoding', 'identity']] in the request. Servers can still send compressed content, so check the Content-Encoding response header and decode the body yourself when necessary.

By default, on_response runs after the entire response body has arrived. $res->body is ready to read at that point.

  • on_response($tx, $res) - receives the response.

  • on_error($object, $error, @details) - reports failures, such as connection errors or timeouts.

  • on_finish - runs once when the operation ends, including after success, failure, or cancellation.

For a single-request program, stop the loop in on_finish, not in on_response. That way the program also stops if the request fails. An HTTP request's timeout is in seconds and includes connection waiting time.

STREAMING A RESPONSE

For a large body, add on_data to process chunks as they arrive:

$client->get(
    'https://example.com/large-file',
    on_response => sub ($tx, $res) {
        say "HTTP ", $res->status;
    },
    on_data => sub ($tx, $bytes) {
        print $bytes;
    },
    on_end => sub ($tx) {
        say "\nBody complete";
    },
    on_error => sub ($object, $error, @details) {
        warn "Request failed: $error\n";
    },
    on_finish => sub { $loop->stop },
);

Adding on_data changes the timing:

  • Without on_data, on_response runs after the full body.

  • With on_data, on_response runs as soon as headers arrive.

  • on_data receives body chunks; on_end signals successful body completion.

Without streaming, responses are buffered up to 1 MiB by default. If the body exceeds that limit, the request fails and on_error runs; on_response does not receive a partial buffered body.

You often cannot know the body size in advance. If a response might be larger than the limit, or its size is unknown, use on_data from the start. This works for small responses too. The Client does not switch from buffered mode to streaming automatically. A Content-Length header is not always available, and may not predict the amount of body data delivered.

STREAMING AN UPLOAD

Set stream_body => 1 and send pieces through the transaction provided to on_transaction:

$client->post(
    'https://example.com/upload',
    stream_body => 1,
    on_transaction => sub ($tx) {
        $tx->write("First part\n");
        $tx->end("Last part\n");
    },
    on_response => sub ($tx, $res) {
        say $res->status;
    },
);

on_transaction may run before the request call returns. Use its $tx argument, not a variable holding the returned operation. For large producers, respect backpressure and resume sending through on_drain. A false return from write means the bytes were accepted; do not send them twice.

CANCELLING AND SHUTTING DOWN

Each request returns an operation handle:

my $op = $client->get('https://example.com/',
    on_response => sub ($tx, $res) { say $res->status },
);

$op->cancel;        # Cancel when no longer needed
$op->state;         # Current state
$op->error;         # Error, if any
$op->is_terminal;   # Whether it has ended
$op->transaction;   # Available once the request starts

Call $client->shutdown to cancel queued work, let active requests finish, and retire pooled connections. pool_stats and pending_count report connection and queue information.

HTTPS AND HTTP VERSIONS

HTTPS checks certificates and hostnames by default. To trust a private certificate authority:

my $client = Linux::Event::HTTP::Client->new(
    loop => $loop,
    tls => { ca_file => 'ca.pem' },
);

HTTP/1.1 is enabled by default. To enable HTTP/2, install Unblock::HTTP2 0.13 or later and pass http2 => 1 to new. For HTTP/3, install Unblock::HTTP3 0.14 or later and Net::QUIC 0.06 or later, then pass http3 => 1. HTTP/3 uses HTTPS and supports a private CA through quic => { ca_file => 'ca.pem' }.

To require a specific HTTP version on a request, set http_version => '1.1', '2', or '3'. If the required version is unavailable, the request fails instead of falling back.

MORE OPTIONS

new requires loop => $loop. Other options include max_connections_per_origin (default 4), max_pending_requests (default 128), and idle_timeout (in seconds, disabled by default).

The Client does not automatically follow redirects or manage cookies or authentication retries.

Optional WebSocket support uses connect_websocket with a protocol option such as http1 => { websocket => 1 }. See Unblock::HTTP::Client for the full WebSocket API. For custom Upgrade and CONNECT handoff, see docs/CONNECT.md in the distribution.

SEE ALSO

Linux::Event::HTTP::Server, Linux::Event::Loop, Unblock::HTTP::Client, Uniform::HTTP::Response.

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