Linux::Event::HTTP
Native HTTP/1.x and HTTP/2 client/server support for Linux::Event.
Linux::Event::HTTP is a Linux-focused HTTP protocol layer built on Linux::Event. It provides asynchronous HTTP servers and clients without turning the protocol layer into a web framework.
The same public Request, Response, Transaction, Client, and Server model is used for HTTP/1 and HTTP/2.
- HTTP/1.x is built in.
- HTTP/2 is optional and uses Net::HTTP2::nghttp2/libnghttp2.
- HTTPS and HTTP/2 use Linux::Event TLS.
- HTTP/2 is negotiated with ALPN and falls back to HTTP/1.1 on the same high-level API.
- Request and response bodies are streaming-first and bounded when buffered.
- HTTP/1 Upgrade and CONNECT can hand the same live Linux::Event stream to another protocol.
Server
A basic HTTP/1 server:
use v5.36;
use Linux::Event::Loop;
use Linux::Event::HTTP::Server;
my $loop = Linux::Event::Loop->new;
my $server = Linux::Event::HTTP::Server->new(
loop => $loop,
host => '127.0.0.1',
port => 8080,
on_request => sub ($conn, $req, $res) {
$res->header('Content-Type', 'text/plain');
$res->body("hello\n");
},
);
$loop->run;
The callback receives the persistent HTTP connection, the Request, and the Response for that exchange.
Setting a scalar response body during the callback is enough. The response is committed after the callback returns.
HTTPS with HTTP/2
Enable HTTP/2 on the same Server API:
my $server = Linux::Event::HTTP::Server->new(
loop => $loop,
host => '0.0.0.0',
port => 8443,
http2 => 1,
tls => {
cert_file => '/path/server-cert.pem',
key_file => '/path/server-key.pem',
},
on_request => sub ($conn, $req, $res) {
$res->header('Content-Type', 'text/plain');
$res->body("hello over HTTP " . $req->version . "\n");
},
);
The server advertises h2 before http/1.1. If the peer selects HTTP/2,
Linux::Event::HTTP uses its HTTP/2 executor. Otherwise the connection continues
as HTTP/1.1.
HTTP/2 requires Net::HTTP2::nghttp2 0.011 or newer.
Client
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,
http2 => 1,
);
my $operation = $client->get(
'https://example.com/',
buffer_body => 1_048_576,
on_complete => sub ($tx) {
my $res = $tx->response;
say $res->status;
say $res->body;
$client->close;
$loop->stop;
},
on_error => sub ($tx, $error) {
warn $error;
$client->close;
$loop->stop;
},
);
$loop->run;
With http2 => 1, direct HTTPS requests negotiate HTTP/2 with ALPN and fall
back to HTTP/1.1 when needed. Selected HTTP/2 connections can carry concurrent
streams for the same origin.
Without buffer_body, response bodies are not accumulated automatically.
Use on_body to consume them incrementally.
The object model
Linux::Event::HTTP keeps message data separate from exchange and connection state:
Request + Response
|
v
Transaction one HTTP exchange
|
v
Client::Operation one high-level client action
(may contain multiple Transactions)
Connection persistent transport/protocol executor
Server / Client high-level endpoint policy
The important distinction is:
- Request and Response are HTTP messages.
- Transaction is exactly one Request/Response exchange.
- Client::Operation is one high-level client action. Redirects and automatic authentication retries create additional Transactions.
- Connection owns persistent protocol execution.
- Linux::Event still owns sockets, TLS, readiness, buffering, and transport backpressure.
Request and response bodies
Complete scalar bodies
For a complete body already in memory:
$res->body($bytes);
or:
$client->post(
$url,
body => $bytes,
...
);
Streaming server responses
on_request => sub ($conn, $req, $res) {
my $body = $conn->transaction->response_body(
on_drain => sub ($body) { ... },
on_cancel => sub ($body) { ... },
);
$body->write($chunk);
$body->complete($final_chunk);
},
Streaming client requests
my $operation = $client->post(
$url,
stream_body => {
on_drain => sub ($body) { ... },
on_cancel => sub ($body) { ... },
},
...
);
my $body = $operation->request_body;
$body->write($chunk);
$body->complete;
write follows Linux::Event backpressure semantics:
true = bytes accepted; producer may continue
false = bytes accepted; pause until on_drain
Incoming bodies are incremental-first. If no body callback is installed, the library drains the body rather than silently building an unbounded scalar.
For a bounded client response buffer:
$client->get(
$url,
buffer_body => 4 * 1024 * 1024,
on_complete => sub ($tx) {
my $bytes = $tx->response->body;
...
},
);
Redirects, cookies, and authentication
The high-level Client handles ordinary HTTP client policy without moving that policy into Request or Response objects.
Redirects:
- 301, 302, 303, 307, and 308 are followed by default.
- The default redirect limit is 5.
- Each followed hop is a separate Transaction.
- Streaming request producers are not automatically replayed.
Cookies:
- Cookie policy is supplied by an application-owned
HTTP::CookieJar. - Linux::Event::HTTP does not create a global or implicit cookie store.
Authentication:
- Authentication mechanics are delegated to
Uniform::HTTP::Auth. - Target 401 and proxy 407 retries become additional Transactions.
- Streaming request producers are not automatically replayed.
See the Client POD and docs/CLIENT-POLICY.md for the detailed policy rules.
HTTP/2 behavior
HTTP/2 is intentionally integrated into the existing high-level HTTP API rather than exposed as a separate public library.
Current HTTP/2 support includes:
- TLS ALPN negotiation;
- high-level Server and Client integration;
- multiplexed client requests;
- streaming request and response bodies;
- redirects, cookies, and authentication policy across HTTP/2 exchanges;
- decoded header-list limits;
- per-connection aggregate buffered-response limits;
- GOAWAY draining;
- stream-local failure where the protocol permits it.
Important current boundaries:
- HTTP/2 is enabled explicitly with
http2 => 1. - The production HTTP/2 path is direct HTTPS negotiated with ALPN.
- Cleartext h2c is not provided.
- Forward-proxy requests, HTTP/1 Upgrade, CONNECT stream handoff, and explicit HTTP version selection currently use the HTTP/1 path.
- HTTP/2 currently requires the default high-level connection class.
- Transparent replay after GOAWAY is not attempted without reliable last-stream-id information.
See docs/HTTP2-ARCHITECTURE.md for implementation and protocol boundaries.
Upgrade and CONNECT
HTTP/1.1 Upgrade and CONNECT are lifecycle operations on Transaction rather than methods on Response.
Server Upgrade:
$res->header('Upgrade', 'my-protocol');
$conn->transaction->upgrade('MyProtocolConnection');
Server CONNECT:
if ($req->method eq 'CONNECT') {
$conn->transaction->tunnel('MyTunnelConnection');
}
The live Linux::Event stream is transitioned in place, preserving already-read post-HTTP bytes for the new protocol.
The high-level Client also provides connect_tunnel() for explicit proxy
CONNECT establishment.
Connection reuse
HTTP/1 connections are persistent when normal HTTP framing permits reuse.
HTTP/2 connections are pooled per origin and can carry concurrent streams. Connections that receive GOAWAY stop accepting new operations and drain existing streams.
Public modules
Most applications need only:
Linux::Event::HTTP::ServerLinux::Event::HTTP::ClientLinux::Event::HTTP::RequestLinux::Event::HTTP::ResponseLinux::Event::HTTP::TransactionLinux::Event::HTTP::Client::Operation
Advanced HTTP/1 users may also use the public Client::Connection and Server::Connection classes directly.
Installation
HTTP/1 support uses the normal distribution dependencies.
HTTP/2 additionally requires:
Net::HTTP2::nghttp2 >= 0.011
The HTTP/2 binding is optional so an HTTP/1-only installation does not need libnghttp2.
Build and test
perl Makefile.PL
make
make test
For a release-style distribution check:
make disttest
Design and maintainer documentation
docs/ARCHITECTURE.md- ownership and lifecycle designdocs/HTTP2-ARCHITECTURE.md- HTTP/2 integration and limitsdocs/CLIENT-POLICY.md- redirects, cookies, authentication, and proxy policydocs/CONNECT.md- CONNECT tunnel semanticsdocs/BENCHMARKING.md- benchmark harnesses and measurement rulesdocs/PICOHTTPPARSER-EXPERIMENT.md- HTTP/1 parser provenance and evaluation
Scope
Linux::Event::HTTP is a protocol and communications layer.
It deliberately does not provide routing, templates, sessions, application middleware, or a web-framework object model. Those can be built above the HTTP layer without making the transport and protocol APIs framework-specific.