# Unblock::HTTP3

[![CPAN version](https://badge.fury.io/pl/Unblock-HTTP3.svg)](https://metacpan.org/dist/Unblock-HTTP3)
[![CPANTS Kwalitee](https://cpants.cpanauthors.org/dist/Unblock-HTTP3.svg)](https://cpants.cpanauthors.org/dist/Unblock-HTTP3)
[![CI](https://github.com/haxmeister/perl-Unblock-HTTP3/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/haxmeister/perl-Unblock-HTTP3/actions/workflows/test.yml)
[![Public HTTP/3 interop](https://github.com/haxmeister/perl-Unblock-HTTP3/actions/workflows/interop.yml/badge.svg?branch=main)](https://github.com/haxmeister/perl-Unblock-HTTP3/actions/workflows/interop.yml)
[![License](https://img.shields.io/cpan/l/Unblock-HTTP3.svg)](https://github.com/haxmeister/perl-Unblock-HTTP3/blob/main/LICENSE)
[![Perl](https://img.shields.io/badge/perl-5.20%2B-blue.svg)](https://www.perl.org/)
[![nghttp3](https://img.shields.io/badge/nghttp3-1.18.0-blue.svg)](https://github.com/ngtcp2/nghttp3)
[![HTTP/3](https://img.shields.io/badge/HTTP%2F3-RFC%209114-blue.svg)](https://www.rfc-editor.org/rfc/rfc9114)

Unblock::HTTP3 is a non-blocking HTTP/3 protocol engine for Perl.

HTTP/3 is HTTP carried over QUIC. Unblock::HTTP3 handles the HTTP/3 layer while
Net::QUIC handles QUIC and TLS.

```text
application or HTTP library
        |
  Uniform::HTTP messages
        |
   Unblock::HTTP3
        |
      Net::QUIC
        |
        UDP
```

Unblock::HTTP3 does not own a UDP socket, timer, TLS configuration, or event
loop. Those stay below Net::QUIC, so the HTTP/3 engine can be used with
different operating systems and event loops.

Uniform::HTTP supplies the request and response objects. Alien::nghttp3
supplies libnghttp3 for HTTP/3 framing and QPACK.

## Installation

From CPAN:

```text
cpanm Unblock::HTTP3
```

Unblock::HTTP3 0.01 requires:

```text
Perl            5.20+
Alien::nghttp3  0.01+
Net::QUIC       0.04+
Uniform::HTTP   0.04+
```

## Start here

Most code works with three things:

- `Unblock::HTTP3::Connection` - one HTTP/3 connection
- `Unblock::HTTP3::Transaction` - one request and its response
- `Uniform::HTTP::Request` and `Uniform::HTTP::Response` - HTTP messages

`Unblock::HTTP3::Request` and `Unblock::HTTP3::Response` are optional thin
subclasses with a few HTTP/3-specific helpers.

An HTTP/3 Connection wraps an existing `Net::QUIC::Connection`:

```perl
use Unblock::HTTP3::Connection;

my $h3 = Unblock::HTTP3::Connection->client(
    quic => $quic,
);

$h3->start;
```

Your event-loop adapter continues to drive Net::QUIC. Unblock::HTTP3 never
blocks waiting for network activity.

## Sending a request

A client can submit a normal `Uniform::HTTP::Request`:

```perl
use Uniform::HTTP::Request;

my $request = Uniform::HTTP::Request->new(
    method    => 'GET',
    target    => '/',
    scheme    => 'https',
    authority => 'example.com',
);

my $tx = $h3->request($request);
```

When the final response headers arrive, the Transaction becomes available from
the Connection:

```perl
while (my $ready = $h3->next_transaction) {
    my $response = $ready->response;

    print $response->status, "\n";
    print $response->body if $response->has_buffered_body;
}
```

Many Transactions can be active at once. Each Transaction keeps its own request
and response paired even when responses arrive out of order.

## Receiving a request

A server receives new requests as Transactions:

```perl
while (my $tx = $h3->next_transaction) {
    my $request  = $tx->request;
    my $response = $tx->response;

    $response->status(200);
    $response->header('Content-Type', 'text/plain');
    $response->body("hello\n");

    $tx->send_response;
}
```

The server-side Response is mutable until it is sent.

## Bodies

Buffered bodies are the default.

A buffered request or response body lives on the Uniform message object:

```perl
my $body = $response->body;
```

For large or incremental bodies, use streaming instead.

A server can stream a response:

```perl
my $body = $tx->response_body(
    on_drain  => sub { ... },
    on_cancel => sub { ... },
);

$body->write($chunk);
$body->complete;
```

`write()` returns false when the bytes were accepted but the producer should
pause until `on_drain` runs.

A client can receive a response without buffering the complete body:

```perl
my $tx = $h3->request(
    $request,
    receive_body => {
        on_data => sub {
            my ($reader, $chunk) = @_;
            process($chunk);
        },
        on_end => sub {
            my ($reader) = @_;
            ...
        },
    },
);
```

Streaming receive credit is returned as the application consumes data.

## Trailers and informational responses

Request and response trailers are supported.

Uniform::HTTP keeps trailers separate from normal headers and preserves field
order and duplicates.

Servers can also send 1xx informational responses before the final response:

```perl
$tx->send_informational(
    Unblock::HTTP3::Response->new(
        status => 103,
    ),
);
```

HTTP/3 does not use status 101.

## CONNECT

Basic CONNECT tunnels are supported.

Generic Extended CONNECT is also supported. A server enables it with:

```perl
my $h3 = Unblock::HTTP3::Connection->server(
    quic                    => $quic,
    enable_extended_connect => 1,
);
```

An Extended CONNECT request uses the Uniform `protocol` field.

Unblock::HTTP3 does not assign meaning to protocol names. Higher-level modules
decide what protocols such as WebTransport, WebSocket, or MASQUE mean.

Extended CONNECT Transactions can also use the generic RFC 9297 Capsule
Protocol through:

```perl
my $capsules = $tx->capsules;
```

## HTTP Datagrams

RFC 9297 HTTP Datagrams are supported over Net::QUIC's QUIC DATAGRAM support.

Enable them on the HTTP/3 connection:

```perl
my $h3 = Unblock::HTTP3::Connection->client(
    quic                  => $quic,
    enable_http_datagrams => 1,
);
```

A client marks a request as using HTTP Datagrams when it creates the
Transaction:

```perl
my $tx = $h3->request(
    $request,
    datagrams => 1,
);

$tx->send_datagram($bytes);
```

The Transaction also provides `next_datagram`, `on_datagram`, and
`max_datagram_payload_size`.

The higher-level protocol still decides what the Datagram payload means.

## Request priority

RFC 9218 priority can be set on a request:

```perl
my $request = Unblock::HTTP3::Request->new(
    method    => 'GET',
    target    => '/',
    scheme    => 'https',
    authority => 'example.com',
    priority  => {
        urgency     => 1,
        incremental => 1,
    },
);
```

It can also be changed on a live Transaction:

```perl
$tx->priority(
    urgency     => 0,
    incremental => 0,
);
```

Urgency is from 0 through 7, where 0 is most urgent.

## 0-RTT

Net::QUIC owns QUIC/TLS early-data state. Unblock::HTTP3 owns the remembered
HTTP/3 SETTINGS needed to decide what can safely be sent before the new server
SETTINGS frame arrives.

Save both values from the same successful session:

```perl
my $quic_state = $quic->early_data_state;
my $h3_state   = $h3->peer_settings_state;
```

On a resumed connection, give each value back to the layer that created it.

An HTTP/3 request sent before the handshake finishes must opt in explicitly:

```perl
my $tx = $h3->request(
    $request,
    early_data => 1,
);
```

0-RTT can be replayed. Unblock::HTTP3 does not automatically retry an early
request if QUIC rejects it.

See `Unblock::HTTP3::Connection` and `docs/ARCHITECTURE.md` for the complete
SETTINGS persistence rules.

## Correctness and limits

Unblock::HTTP3 validates HTTP/3 message rules before sending and while receiving.

This includes:

- pseudo-header and routing rules
- Host and `:authority`
- Content-Length
- trailers
- bodyless responses
- CONNECT rules
- peer field-section limits

It also provides configurable limits for buffered bodies, streaming receive
queues, field sections, QPACK, and HTTP Datagram queues.

Protocol errors are kept at the narrowest correct scope when possible. A bad
request stream does not automatically destroy unrelated multiplexed requests.

## Extensions

The engine provides generic extension hooks without assigning application
semantics to them:

- extension SETTINGS
- extension unidirectional streams
- Extended CONNECT protocol names
- Capsules
- HTTP Datagrams

This is the intended foundation for higher-level HTTP/3 protocols.

## What Unblock::HTTP3 does not own

Unblock::HTTP3 does not own:

- UDP sockets
- TLS
- QUIC packet processing
- congestion control
- retransmission
- QUIC connection migration
- timers
- event-loop scheduling
- web-framework behavior

Those responsibilities stay in Net::QUIC, the event-loop adapter, or the
application.

HTTP/3 Server Push is not exposed because the libnghttp3 version used by this
release does not implement it.

## Testing

The normal test suite uses real kernel UDP sockets, TLS, QUIC, and HTTP/3.

CI tests released CPAN dependencies on Perl 5.20, 5.28, 5.36, and 5.44 and
also validates the built distribution.

Public interoperability tests talk to independent HTTP/3 servers but stay
outside normal CPAN installation tests.

## More documentation

- `Unblock::HTTP3::Connection` - connection setup and configuration
- `Unblock::HTTP3::Transaction` - one request/response stream
- `Unblock::HTTP3::Body::Stream` - outgoing streaming bodies
- `Unblock::HTTP3::Body::Reader` - incoming streaming bodies
- `Unblock::HTTP3::Capsule` - RFC 9297 Capsules
- `Unblock::HTTP3::Extension::Stream` - generic extension streams
- `docs/ARCHITECTURE.md` - protocol ownership and internal data flow

## License

MIT.
