# Unblock::HTTP1

[![Tests](https://github.com/haxmeister/perl-Unblock-HTTP1/actions/workflows/test.yml/badge.svg)](https://github.com/haxmeister/perl-Unblock-HTTP1/actions/workflows/test.yml)
[![CPAN](https://img.shields.io/cpan/v/Unblock-HTTP1.svg)](https://metacpan.org/release/Unblock-HTTP1)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Unblock::HTTP1 is a non-blocking HTTP/1.0 and HTTP/1.1 protocol engine for Perl.

It parses requests, serializes responses, handles HTTP message boundaries,
streaming bodies, keep-alive, trailers, Upgrade, and CONNECT.

It does not open sockets, do DNS or TLS, run an event loop, or manage
connection pools. It can be hosted by IO::Async, AnyEvent, Linux::Event,
Mojolicious, native transport code, or another event framework.

## Installation

    cpanm Unblock::HTTP1

Requires Perl 5.16 and Uniform::HTTP 0.06 or newer.
Linux::Event, IO::Async and AnyEvent are optional host frameworks.

## Start here

The three application classes are:

- Unblock::HTTP1::Client - one client-side connection
- Unblock::HTTP1::Server - one server-side connection
- Unblock::HTTP1::Transaction - one request and response exchange

A transaction uses the shared Unblock vocabulary: respond(), write(),
end(), send_informational(), state(), error(), is_complete(),
is_cancelled(), is_error(), and is_terminal().

The easiest server response:

    $tx->respond(
        status => 200,
        body   => "Hello World!\n",
    );

The easiest client request:

    $client->request(
        method    => 'GET',
        target    => '/',
        authority => 'example.test',
        on_response => sub {
            my ($tx, $response) = @_;
            print $response->status, "\n";
        },
    );

These calls still create and use canonical Uniform::HTTP::Request and
Uniform::HTTP::Response messages internally. Existing Uniform objects
continue to work directly:

    $client->request($request);
    $tx->respond($response);

## Connect to an event framework

Create one Client or Server per framework connection:

    $self->{http1} = Unblock::HTTP1::Server->new(
        transport  => $self,
        on_request => $on_request,
    );

The framework object implements only three host methods:

    unblock_send($bytes)      # accept complete output into framework queue
    unblock_finish()          # graceful close after queued output
    unblock_abort($reason)    # immediate failure close

The framework feeds incoming events to the engine:

    $http->input($bytes);
    $http->input_eof;
    $http->transport_error($reason);

The engine delivers output automatically. A delayed response from a timer
or database callback also triggers output without another framework read
event.

An integration that exposes congestion returns false from unblock_send()
AFTER accepting the whole buffer, and later calls $http->resume_output.
If the framework simply queues all output, it may return undef.

The engine holds a weak reference to the host. The framework owns its
sockets, output queue, and loop.

**Full working server and client examples:**

- examples/io-async-server.pl
- examples/io-async-client.pl
- examples/anyevent-server.pl
- examples/anyevent-client.pl
- examples/linux-event-server.pl

The examples separate adapter code from application code. The Linux::Event
server demonstrates the same host API using a Stream subclass and a
separate application subclass. Linux::Event is not a required dependency.

For complete instructions, read:

    perldoc Unblock::HTTP1::Integration

The repository also includes docs/INTEGRATION.md and docs/COOKBOOK.md.

## Receive bodies and transaction completion

By default, incoming body data is streamed through callbacks. To retain the
decoded body in the canonical Uniform::HTTP message, construct a Client or
Server with `receive_body => 'buffered'`. Buffered reception is limited by
`max_buffered_body_bytes` (64 MiB by default).

For per-transaction streaming, register `$tx->on_data(sub { ... })` in the
incoming-headers callback, or supply `on_data` to Client->request(). That
callback receives decoded body fragments without collecting the full body.
Do not combine `on_data` and `on_body` on one Transaction.

`$tx->on_finish(sub { ... })` runs exactly once after the Transaction reaches
complete, cancelled, or error state. On an attached server, successful
completion is not reported until the host has accepted the corresponding
outgoing bytes. See the Client, Server, and Transaction POD for the callback
ordering and receive modes.

## Connection and message behavior

A Client queues requests serially on one connection; it does not silently
enable HTTP/1 pipelining. A Server can receive pipelined request bytes and
process them in HTTP order.

A server's on_request runs after the request head has arrived.
on_body delivers decoded request body fragments. on_request_end runs when the
full request, including trailers, is complete.

For a streaming response:

    $tx->respond(status => 200, stream_body => 1);
    $tx->write($chunk);
    $tx->end($final_bytes);

write() and end() accept bytes even when they return false for backpressure.
Use on_drain to resume producing data.

A clean read EOF is not the same as fatal transport failure. After a
fully received request, the server can still send a delayed response, then
close gracefully.

A 101 Upgrade response or successful CONNECT switches away from HTTP.
take_remainder() returns already-received bytes belonging to the next
protocol. An attached server invokes on_switch after the full outgoing
HTTP handshake has been accepted into the framework's write queue.

## Manual and native integration

For advanced consumers, the original low-level output interface remains:

    $http->input($bytes);
    while ($http->want_write) {
        $transport->write($http->output);
    }

This is for engines built WITHOUT an attached transport. Do not mix manual
output draining and automatic output ownership.

XS-backed transports can use Unblock::HTTP1::NativeABI v1 to pass borrowed
native input. The ABI is input-side and remains transport neutral. It
supports the same HTTP callbacks and can construct canonical Uniform
messages through Uniform::HTTP 0.06's native FastPath.

The installed C header is:

    Unblock/HTTP1/NativeABI/unblock_http1_native_abi.h

ABI discovery:

    Unblock::HTTP1::NativeABI::definition()
    Unblock::HTTP1::NativeABI::native_include_dir()
    Unblock::HTTP1::NativeABI::header_path()
    Unblock::HTTP1::NativeABI::c_header()

## Limits

Defaults:

    max_head_size              65536 bytes
    max_headers                100
    max_chunk_extension_size   16384 bytes
    high_water                 65536 bytes
    low_water                  32768 bytes

See docs/PROTOCOL_STATUS.md for the protocol feature checklist.

## License

MIT License.
