Unblock::HTTP3
Unblock::HTTP3 is a non-blocking HTTP/3 protocol engine for Perl.
It handles HTTP/3 framing, QPACK, request streams, trailers, informational responses, Extended CONNECT, HTTP Datagrams, Capsules, priorities, graceful shutdown, and replay-aware 0-RTT state.
It does not own UDP sockets, TLS, timers, or an event loop. Net::QUIC owns the QUIC transport.
application or HTTP library
|
Uniform::HTTP messages
|
Unblock::HTTP3
|
Net::QUIC
|
UDP
Installation
From CPAN:
cpanm Unblock::HTTP3
Unblock::HTTP3 0.10 requires:
Perl 5.20+
Alien::nghttp3 0.01+
Net::QUIC 0.04+
Uniform::HTTP 0.06+
Version 0.10 intentionally breaks the earlier 0.03 Perl API. Client and Server
now use new(), final responses use respond(), and the old
Connection->client(), Connection->server(), and send_response()
entry points are removed. There are no compatibility aliases.
Start here
The public API is built around three objects:
Unblock::HTTP3::Client- one client HTTP/3 connectionUnblock::HTTP3::Server- one server HTTP/3 connectionUnblock::HTTP3::Transaction- one request and response exchange
The common application vocabulary intentionally matches the other Unblock HTTP engines:
Client->new
Server->new
request()
respond()
write()
end()
send_informational()
HTTP/3 protocol concepts keep their HTTP/3 names.
Exact canonical Uniform::HTTP::Request and Uniform::HTTP::Response
objects use the Uniform::HTTP native fast path. Uniform-compatible adapters and
subclasses use the portable Perl message contract.
Client
use Uniform::HTTP::Request;
use Unblock::HTTP3::Client;
my $client = Unblock::HTTP3::Client->new(
quic => $quic,
);
$client->start;
my $transaction = $client->request(
Uniform::HTTP::Request->new(
method => 'GET',
target => '/',
scheme => 'https',
authority => 'example.com',
),
on_response => sub {
my ($transaction, $response) = @_;
print $response->status, "\n";
},
on_body => sub {
my ($transaction, $response, $bytes) = @_;
process_bytes($bytes);
},
on_complete => sub {
my ($transaction) = @_;
print "done\n";
},
);
Many Transactions can be active on one Client at the same time.
The existing pull interface remains available through next_transaction()
and next_informational() for integrations that prefer polling.
Server
use Uniform::HTTP::Response;
use Unblock::HTTP3::Server;
my $server = Unblock::HTTP3::Server->new(
quic => $quic,
on_request => sub {
my ($transaction, $request) = @_;
$transaction->respond(
Uniform::HTTP::Response->new(
status => 200,
body => "hello\n",
),
);
},
);
$server->start;
on_body receives request body chunks. on_request_end runs after the
request body and trailers have completed.
Streaming bodies
Buffered bodies can live directly on the Uniform message object.
For a streaming client request:
my $transaction = $client->request(
$request,
stream_body => 1,
on_drain => sub {
my ($transaction) = @_;
produce_more($transaction);
},
);
$transaction->write($chunk);
$transaction->end($last_chunk);
A streaming server response uses the same Transaction API:
$transaction->respond(
$response,
stream_body => 1,
on_drain => sub {
my ($transaction) = @_;
produce_more($transaction);
},
);
$transaction->write($chunk);
$transaction->end;
For advanced HTTP/3 body control, Body::Stream and Body::Reader remain
available. They expose explicit receive credit, cancellation, and body-specific
callbacks without changing the common Transaction API.
Informational responses
A server can send a 1xx response before the final response:
$transaction->send_informational(
Uniform::HTTP::Response->new(
status => 103,
),
);
$transaction->respond($final_response);
HTTP/3 does not use status 101.
Transaction state
The common lifecycle methods are:
state
error
is_complete
is_cancelled
is_error
is_terminal
HTTP/3-specific reset and STOP_SENDING details remain available separately on the Transaction.
CONNECT, Capsules, and Datagrams
Ordinary CONNECT and generic Extended CONNECT are supported.
Extended CONNECT uses the Uniform protocol field. Higher-level modules
decide what a protocol such as WebSocket, WebTransport, or MASQUE means.
An Extended CONNECT Transaction can use the RFC 9297 Capsule Protocol through:
my $capsules = $transaction->capsules;
RFC 9297 HTTP Datagrams use Net::QUIC DATAGRAM support. Enable them on the Client or Server with:
enable_http_datagrams => 1
A client marks a request as using Datagrams with:
my $transaction = $client->request(
$request,
datagrams => 1,
);
The Transaction provides send_datagram(), next_datagram(),
on_datagram(), and max_datagram_payload_size().
Priority and ORIGIN
RFC 9218 priority state is available through Transaction->priority().
Servers can advertise RFC 9412 origins with the origins constructor option.
Clients read the received set with peer_origins().
0-RTT
Net::QUIC owns QUIC/TLS early-data state. Unblock::HTTP3 owns the remembered HTTP/3 SETTINGS needed to validate early requests.
Save the QUIC and HTTP/3 state from the same successful session:
my $quic_state = $quic->early_data_state;
my $h3_state = $client->peer_settings_state;
An early client request must opt in explicitly:
my $transaction = $client->request(
$request,
early_data => 1,
);
0-RTT can be replayed. Unblock::HTTP3 does not automatically retry a rejected early request.
Native integrations
XS event frameworks and HTTP libraries can use
Unblock::HTTP3::NativeABI.
Native integrations can discover the installed ABI with:
definition
native_include_dir
header_path
c_header
ABI version 1 accepts exact Unblock::HTTP3::Client,
Unblock::HTTP3::Server, and Unblock::HTTP3::Transaction objects.
Adapters and subclasses use the portable Perl API.
The native ABI does not expose libnghttp3 internals and does not take ownership of the QUIC transport.
See docs/NATIVE-ABI.md.
What Unblock::HTTP3 does not own
Unblock::HTTP3 does not own:
- UDP sockets
- DNS
- TLS
- QUIC packet processing
- congestion control
- retransmission
- connection migration
- timers
- event loops
- connection pools
- redirects
- cookies
- authentication policy
- retry policy
- WebSocket, WebTransport, or MASQUE semantics
Those belong to Net::QUIC, the event-loop adapter, the application, or a higher-level protocol module.
Testing
The normal suite uses real kernel UDP sockets, TLS, QUIC, and HTTP/3.
CI tests released dependencies on several Perl versions and validates the built distribution. Separate interoperability tests cover both client and server directions against independent HTTP/3 implementations.
More documentation
Unblock::HTTP3::ClientUnblock::HTTP3::ServerUnblock::HTTP3::TransactionUnblock::HTTP3::Body::StreamUnblock::HTTP3::Body::ReaderUnblock::HTTP3::NativeABIdocs/ARCHITECTURE.mddocs/NATIVE-ABI.mddocs/RFC-COMPLIANCE.md
License
MIT.