Unblock::HTTP1
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.