# 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) Portable, non-blocking HTTP/1 for Perl. Unblock::HTTP1 is an HTTP/1 protocol engine. It handles HTTP bytes and message boundaries, but it does not open sockets or choose an event loop. The same engine can be used with any reliable ordered byte stream. ## What it does Unblock::HTTP1 provides: - HTTP/1.0 and HTTP/1.1 client and server protocol state - request and response parsing - request and response serialization - Content-Length and chunked framing - close-delimited response bodies - streaming bodies and trailers - persistent connections - informational responses - Expect: 100-continue - Upgrade and CONNECT boundaries - configurable protocol limits - Uniform::HTTP request and response objects It does not provide sockets, DNS, TLS, connection pools, redirects, cookies, authentication, proxy policy, WebSocket framing, HTTP/2, or HTTP/3. ## Install cpan Unblock::HTTP1 ## Client use Uniform::HTTP::Request; use Unblock::HTTP1::Client; my $client = Unblock::HTTP1::Client->new; $client->request( Uniform::HTTP::Request->new( method => 'GET', target => '/', authority => 'example.com', ), on_response => sub { my ($tx, $response) = @_; print $response->status, "\n"; }, on_body => sub { my ($tx, $response, $bytes) = @_; print $bytes; }, ); Feed bytes received from your transport: $client->input($bytes); Take generated bytes and send them through your transport: while ($client->want_write) { my $bytes = $client->output; $transport->write($bytes); } When the transport reaches EOF: $client->input_eof; A Client serializes requests on one connection. It does not silently enable HTTP/1 pipelining. ## Server use Uniform::HTTP::Response; use Unblock::HTTP1::Server; my $server = Unblock::HTTP1::Server->new( on_request => sub { my ($tx, $request) = @_; $tx->respond( Uniform::HTTP::Response->new( status => 200, body => "hello\n", ) ); }, ); Feed received bytes with input() and drain generated bytes with output(), just as with the client. Request bodies arrive through on_body. on_request_end runs after the complete request body and any trailers have arrived. ## Streaming bodies Pass stream_body when the body length is not known yet: my $tx = $client->request( $request, stream_body => 1, ); $tx->write($chunk); $tx->end($last_chunk); HTTP/1.1 uses chunked framing when needed. HTTP/1.0 streaming requires an explicit Content-Length. The same Transaction write()/end() API is used for streaming server responses. ## Upgrade and CONNECT A 101 response or successful CONNECT ends HTTP framing on the connection. The engine then reports: $engine->is_switched Bytes already read after the HTTP boundary are preserved: my $bytes = $engine->take_remainder; The caller can pass those bytes to the next protocol implementation. ## Backpressure The engine has configurable high-water and low-water output limits. write() returns false when the output queue reaches the high-water mark. on_drain fires after it falls below the low-water mark. ## Limits Default limits are: maximum HTTP head: 65536 bytes maximum header fields: 100 maximum chunk extension bytes: 16384 per message output high water: 65536 bytes output low water: 32768 bytes The limits can be changed when constructing a Client or Server. ## Message objects Unblock::HTTP1 uses Uniform::HTTP directly: Uniform::HTTP::Request Uniform::HTTP::Response It does not define competing HTTP message classes. Received messages preserve ordered duplicate fields, trailers, exact request targets, and the received HTTP version. ## Integration Unblock::HTTP1 does not require a particular event loop or framework. An adapter only needs to: 1. pass received bytes to input() 2. drain output() while want_write() is true 3. call input_eof() when the transport closes 4. stop feeding HTTP bytes when is_switched() becomes true See docs/INTEGRATION.md for the transport boundary. ## Protocol status The HTTP/1 protocol engine is complete for its declared scope and has cross-platform CI coverage on Linux, macOS, and Windows, including Perl 5.16. See docs/PROTOCOL_STATUS.md for the detailed protocol checklist. ## License MIT License.