h2
tape
import h2 from "h2";
import hpack from "hpack";
var c: h2.Conn = h2.client();
defer c.free();
let none: [0]hpack.Header = [];
let id: i64 = c.open("GET", "https", "example.com", "/", none[..], never, "", 65536, 1 << 20);
send(c.output()); // your transport: a TLS stream that negotiated "h2"
c.advance_output(c.output().len);
while (true) {
let n: i64 = receive(buf[..]); // what the server sent
if (n == 0) { c.end_of_input(); break; }
c.feed(buf[0..n]) or { break; };
send(c.output()); // answers, window updates
c.advance_output(c.output().len);
let r: ?h2.Reply = c.next_reply();
if (r != null) { io.println("{r!.status}: {r!.body.len} bytes"); break; }
}h2 is HTTP/2 (RFC 9113) for a
client, without the I/O: you feed it what the server sent, send what it
queues, and take finished streams. To make requests, use
http’s Client, which runs h2 over every https
connection whose server picks HTTP/2. h2 is for code that brings its
own transport.
| Function | Does |
|---|---|
client() -> Conn | A connection with its preface, SETTINGS and window update queued: send them first |
c.open(method, scheme, authority, path, fields, sensitive, body, max_head, max_body) -> i64 | A request as a new stream; its id |
c.feed(data) | What the server sent: every whole frame is processed |
c.output(), c.advance_output(n) | What to send, and how much was sent |
c.next_reply() -> ?Reply | The next finished stream |
c.end_of_input() | The transport ended: open streams fail |
c.can_open(), c.active(), c.finished(), c.error() | Whether a stream can open now; streams open; whether none ever can again; the connection’s error |
c.goodbye() | GOAWAY with no error, before you close the transport |
c.free() | Releases it |
tape
pub struct Reply {
id: i64;
status: i64;
headers: hpack.Vec_Header; // without the pseudo-headers, in order
body: string;
err: ?H2Error; // when the stream failed
retry: bool; // the server did not process it: send it again elsewhere
}fieldsare the request’s headers after the pseudo-headers, with lowercase names and none of HTTP/1.1’s connection headers (Connection,Keep-Alive,Transfer-Encoding,Upgrade, …).sensitive(name)says which are never indexed by compression (credentials).- The body is copied and sent as the server’s windows allow; send
output()after everyfeed, since a WINDOW_UPDATE may let more go. - The server may have up to its
MAX_CONCURRENT_STREAMSstreams open;can_open()says whether another fits now.opentraps when it is false. max_headlimits a response’s headers as HTTP/2 counts them (name, value and 32 per field) andmax_bodyits body: past either, the stream is reset and fails (HeadTooLarge,BodyTooLarge); the connection goes on.- Errors:
H2Errorholds RFC 9113’s codes (Protocol,FlowControl,Refused,Cancel,Compression,Calm,Http11Required, …) andGoAway,Closed,HeadTooLarge,BodyTooLarge,Malformed. A connection error is returned byfeedonce, with every open stream failed; a stream error fails only that stream’s reply.
Not covered: server push (refused), priorities, HTTP/2 without TLS
(h2c), the server side.
Last modified: