NAME

Unblock::HTTP1::Client - One non-blocking HTTP/1 client connection

SYNOPSIS

use Unblock::HTTP1::Client;

my $client = Unblock::HTTP1::Client->new(
    transport => $transport,
);

my $tx = $client->request(
    method    => 'GET',
    target    => '/',
    authority => 'example.com',

    on_response => sub {
        my ($tx, $response) = @_;
        print $response->status, "\n";
    },

    on_body => sub {
        my ($tx, $response, $bytes) = @_;
        consume($bytes);
    },

    on_complete => sub {
        my ($tx) = @_;
        print "done\n";
    },
);

DESCRIPTION

Unblock::HTTP1::Client owns the HTTP/1 protocol state for one client connection.

It does not open a socket, perform DNS, negotiate TLS, or run an event loop. Those jobs belong to the host framework.

Supply transport => $host to new() to deliver outgoing wire bytes automatically through the host. The host owns its socket and implements unblock_send(), unblock_finish(), and unblock_abort(). See Unblock::HTTP1::Integration for a complete example and the contract.

The lower-level form is:

my $client = Unblock::HTTP1::Client->new;

In that mode the caller feeds input with input() and drains output with output().

One Client object represents one HTTP/1 connection. Requests may be queued, but this implementation sends them serially. It does not enable HTTP/1 pipelining.

RECEIVE BODY OPTIONS

receive_body accepts buffered or stream. Streaming remains the default. max_buffered_body_bytes is a positive byte limit, defaulting to 64 MiB. Zero does not mean unlimited. Buffered reception installs the body on the same Uniform message before freezing it and invoking the body-completion callback. Empty completed bodies have an empty string representation. The engine releases retained chunks on failure or cancellation.

Select streaming per transaction with $tx->on_data(...) during the header callback. Do not combine buffered mode with legacy on_body. Do not combine on_data and on_body. See "RECEIVE AND FINISH CALLBACKS" in Unblock::HTTP1::Transaction.

A buffer limit failure closes the HTTP/1 connection. It does not call successful body completion.

CONSTRUCTOR

new

my $client = Unblock::HTTP1::Client->new(%options);

Creates one client protocol engine.

Common options are:

transport

Optional framework-owned object implementing unblock_send($bytes), unblock_finish(), and unblock_abort($reason). The engine holds a weak reference to it. See Unblock::HTTP1::Integration.

max_head_size

Maximum response head size in bytes. Default: 65536.

max_headers

Maximum number of header or trailer fields. Default: 100.

max_chunk_extension_size

Maximum total chunk-extension bytes allowed for one chunked message. Default: 16384.

high_water

High-water mark for the HTTP output queue. Default: 65536.

low_water

Low-water mark used to resume a blocked streaming producer. Default: 32768.

REQUESTS

request

my $tx = $client->request(
    method    => 'GET',
    target    => '/',
    authority => 'example.com',
    on_response => sub { ... },
);

Queues one HTTP request and returns an Unblock::HTTP1::Transaction.

The normal form accepts request fields directly. request() constructs the canonical Uniform::HTTP::Request internally.

If the caller already has a Uniform request object it can be passed directly:

my $tx = $client->request(
    $request,
    on_response => sub { ... },
);

Request fields and transaction options are intentionally separate. In the concise form these names are consumed by the HTTP transaction rather than passed to Uniform::HTTP::Request->new():

stream_body
on_informational
on_response
on_body
on_complete
on_error
on_switch
on_drain

All other fields are request-construction fields.

Requests are queued in call order. The next request starts only after the current transaction completes and the connection is reusable.

transaction

my $tx = $client->transaction;

Returns the currently active transaction, or undef when no request is active.

Queued transactions are not returned by this method.

REQUEST CALLBACKS

Callbacks belong to the transaction returned by request().

on_informational

on_informational => sub {
    my ($tx, $response) = @_;
}

Called for each informational response from 100 through 199, except 101.

The $response is a canonical Uniform::HTTP::Response. A 101 response is handled as a protocol switch and goes to on_switch instead.

on_response

on_response => sub {
    my ($tx, $response) = @_;
}

Called once when the final response head has been parsed.

The response body may not have arrived yet. Body bytes are delivered later through on_body.

on_body

on_body => sub {
    my ($tx, $response, $bytes) = @_;
}

Called zero or more times with response body bytes.

HTTP transfer framing such as chunk boundaries has already been removed. Unblock does not automatically decode content codings such as gzip.

on_complete

on_complete => sub {
    my ($tx) = @_;
}

Called when the complete request/response exchange is finished.

For a streaming request body, completion requires the local request body to be finished as well as the final response to be complete.

on_error

on_error => sub {
    my ($tx, $error) = @_;
}

Called when the transaction fails.

Protocol errors, unexpected EOF, callback failures, transport failure, or a non-reusable connection that invalidates queued work can lead here.

The transaction state is error when this callback is invoked.

on_switch

on_switch => sub {
    my ($tx, $response) = @_;
}

Called when a 101 response or successful CONNECT transfers ownership of the connection away from HTTP.

After this callback, is_switched() is true. Any bytes already read beyond the HTTP boundary can be obtained with take_remainder().

Queued HTTP requests cannot continue after a switch.

on_drain

on_drain => sub {
    my ($tx) = @_;
}

Used only with stream_body => 1.

If $tx->write() returns false, the supplied bytes were accepted but the producer should pause. on_drain runs when the HTTP output path becomes writable again.

STREAMING REQUEST BODIES

Use stream_body when the request body is produced incrementally:

my $tx = $client->request(
    method      => 'POST',
    target      => '/upload',
    authority   => 'example.com',
    stream_body => 1,
    on_drain    => sub { produce_more() },
);

$tx->write($chunk);
$tx->end($last_chunk);

write() and end() are methods on the Transaction.

For HTTP/1.1, chunked transfer framing is used when required. An explicit Content-Length is honored and enforced.

A false return from write() means the bytes were accepted but the producer should wait for on_drain before producing more.

CONNECTION INPUT

input

my $accepted = $client->input($bytes);

Feeds received response bytes into the engine.

The portable input path copies the supplied bytes into engine-owned storage as needed. The return value is the number of supplied bytes accepted by the engine.

Do not call input() recursively from an HTTP callback.

input_eof

$client->input_eof;

Reports a clean read-side EOF. It completes a close-delimited response body when allowed by HTTP framing; premature EOF fails an incomplete exchange. Do not use input('') as EOF or report ordinary EOF as transport failure.

transport_error

$client->transport_error($reason);

Reports a broken socket, TLS failure, or other unusable transport. Unsent HTTP output is discarded; outstanding work fails and unblock_abort() is called. Do not call this on ordinary read-side EOF.

CONNECTION OUTPUT

want_write

if ($client->want_write) {
    ...
}

True when the engine has bytes buffered for output.

Normally unnecessary when a transport is attached because output is forwarded automatically.

output

my $bytes = $client->output;
my $bytes = $client->output($maximum);

Removes and returns queued wire bytes in manual integration mode. output() throws when a transport is attached to prevent mixed ownership.

$maximum, when supplied, must be a positive integer.

Draining the queue below the low-water mark may trigger transaction on_drain.

Do not call output() recursively from an HTTP callback.

resume_output

$client->resume_output;

Called by an attached host after unblock_send() returned a defined false value (meaning complete acceptance followed by congestion). The host must call this again when it can accept more output. It can trigger a streaming Transaction's on_drain callback.

An output-queueing host that always returns undef does not need it.

CONNECTION STATE

want_read

$client->want_read;

True while the engine is still accepting HTTP input.

It becomes false after read EOF, close, or protocol switch.

is_closed

$client->is_closed;

True when the HTTP connection is closed.

is_switched

$client->is_switched;

True after HTTP ownership ended because of 101 or successful CONNECT.

take_remainder

my $bytes = $client->take_remainder;

Returns bytes already received after the HTTP protocol boundary.

This method is valid only after is_switched() becomes true.

close

$client->close;
$client->close($reason);

Closes the HTTP engine and fails unfinished transactions.

With an attached transport, already queued HTTP output is handed to the transport before graceful close when possible.

Use transport_error() instead when the transport itself has failed.

TRANSACTION OBJECTS

request() returns Unblock::HTTP1::Transaction.

Use that object for:

request
response
write
end
cancel
state
error
is_complete
is_cancelled
is_error
is_terminal

NATIVE INPUT

XS-backed transports can use Unblock::HTTP1::NativeABI to feed borrowed native buffers without changing the Client object or application API.

The normal input() method remains the portable correctness path.

SEE ALSO

Unblock::HTTP1::Integration, Unblock::HTTP1, Unblock::HTTP1::Transaction, Unblock::HTTP1::NativeABI, Uniform::HTTP::Request, Uniform::HTTP::Response