Skip to content
CryoCryo home
Stdlibnet::http2

connection

import std::net::http2::connection; · source

Types

Http2Connection<S>

type struct Http2Connection<S> {
    conn:                  BufStream<S>;
    encoder:               HpackEncoder;
    decoder:               HpackDecoder;
    is_client:             boolean;
    next_stream_id:        u32;
    goaway_received:       boolean;
    remote_max_frame:      u64;
    remote_initial_window: i64;
    conn_send_window:      i64;
    stream_send_window:    i64;

    static new_client(conn: BufStream<S>) -> Http2Connection<S>;
    static new_server(conn: BufStream<S>) -> Http2Connection<S>;
    connection(mut &this) -> BufStream<S>*;
    goaway_seen(&this) -> boolean;

    async handshake_client(mut &this) -> Result<(), IoError>
    where S: AsyncTransport;

    async handshake_server(mut &this) -> Result<(), IoError>
    where S: AsyncTransport;

    async await_peer_settings(mut &this) -> Result<(), IoError>
    where S: AsyncTransport;

    queue_settings(mut &this) -> Result<(), IoError>;
    process_control(mut &this, fr: &Frame) -> Result<boolean, IoError>;
    queue_header_block(mut &this, stream_id: u32, block: Slice<u8>, end_stream: boolean) -> Result<(), IoError>;

    async send_body(mut &this, stream_id: u32, body: Array<u8>, end_stream: boolean) -> Result<(), IoError>
    where S: AsyncTransport;

    async ensure_send_window(mut &this) -> Result<(), IoError>
    where S: AsyncTransport;

    queue_ack_data(mut &this, stream_id: u32, n: u64) -> Result<(), IoError>;

    async request(mut &this, req: Request, scheme: Str, authority: Str) -> Result<Response, IoError>
    where S: AsyncTransport;

    async read_response(mut &this, sid: u32) -> Result<Response, IoError>
    where S: AsyncTransport;

    async serve(mut &this, handler: (Request) -> Response) -> Result<(), IoError>
    where S: AsyncTransport;

    async read_request(mut &this) -> Result<Option<RequestOnStream>, IoError>
    where S: AsyncTransport;

    async send_response(mut &this, sid: u32, resp: Response) -> Result<(), IoError>
    where S: AsyncTransport;

    async send_goaway(mut &this, last_stream_id: u32, error_code: u32) -> Result<(), IoError>
    where S: AsyncTransport;

    encode_request_headers(mut &this, out: mut &Array<u8>, req: &Request, scheme: Str, authority: Str) -> void;
    encode_response_headers(mut &this, out: mut &Array<u8>, resp: &Response) -> void;
    encode_regular_headers(mut &this, out: mut &Array<u8>, h: &Headers) -> void;
}

One HTTP/2 connection over any async transport S — a TcpStream for h2c, a TlsStream for h2. It owns the HPACK encoder and decoder, performs the connection preface and SETTINGS handshake, and exposes request (client side) and serve (server side). Requests and responses are the same Request / Response types the HTTP/1.1 layer uses, so handlers and clients are written once.

mut conn: Http2Connection<TcpStream> = Http2Connection::<TcpStream>::new_client(stream);
await conn.handshake_client()?;
const first: Response = await conn.request(req_a, Str::new("http"), authority)?;
const second: Response = await conn.request(req_b, Str::new("http"), authority)?;

It owns its BufStream<S>, as WebSocket<S> does and for the same reason: the type carries per-connection protocol state — the HPACK tables, the flow-control windows, the next stream id — and an async method may only re-address its own receiver between polls. Owning the connection is also what gives the read side one buffer for the whole connection: bytes of the next frame that arrived in the same fill as the previous one are still there to be parsed rather than lost. connection() surfaces the transport for socket options or the negotiated ALPN protocol, not for reading or writing.

The write side is synchronous throughout — the queue_* methods only append to the connection's pending buffer — so a whole HEADERS block plus its CONTINUATION fragments is assembled with no suspension point inside it, and the connection suspends exactly once, in flush.

Scope. Streams are processed sequentially within a connection — one outstanding request/response at a time, the common keep-alive pattern. Flow control is honoured in both directions for that single active stream plus the connection window; true concurrent multiplexing and server push are out of scope. goaway_seen() reports whether the peer has signalled it is done; send_goaway says so in the other direction.

Properties

PropertyType
connBufStream<S>
encoderHpackEncoder
decoderHpackDecoder
is_clientboolean
next_stream_idu32
goaway_receivedboolean
remote_max_frameu64
remote_initial_windowi64
conn_send_windowi64
stream_send_windowi64

Constructors

static new_client(conn: BufStream<S>) -> Http2Connection<S>;

New client-side connection taking ownership of conn. Call handshake_client before issuing requests.

static new_server(conn: BufStream<S>) -> Http2Connection<S>;

New server-side connection over an accepted, already-buffered transport.

Methods

connection(mut &this) -> BufStream<S>*;

The buffered connection, for callers that need the transport itself (socket options, the negotiated ALPN protocol). Not for reading or writing — that would desynchronize the framing.

goaway_seen(&this) -> boolean;

Has the peer sent a GOAWAY on this connection?

async handshake_client(mut &this) -> Result<(), IoError> where S: AsyncTransport;

Client preface + SETTINGS exchange. Queues the magic and our SETTINGS and sends both in one flush, then reads frames (acking the peer's SETTINGS) until the peer's initial SETTINGS frame has been seen.

async handshake_server(mut &this) -> Result<(), IoError> where S: AsyncTransport;

Server side: validate the client preface, send our SETTINGS, then read frames (acking the peer's SETTINGS) until the client's initial SETTINGS frame has been seen.

async await_peer_settings(mut &this) -> Result<(), IoError> where S: AsyncTransport;

Read frames until the peer's initial (non-ACK) SETTINGS frame arrives, handling every control frame that precedes it.

queue_settings(mut &this) -> Result<(), IoError>;

Queue our advertised SETTINGS frame. Synchronous; the caller flushes.

process_control(mut &this, fr: &Frame) -> Result<boolean, IoError>;

Handle a connection-level control frame. Returns true if the frame was fully handled here (SETTINGS, PING, WINDOW_UPDATE, GOAWAY, PRIORITY, PUSH_PROMISE); false for stream frames the caller must process (HEADERS, CONTINUATION, DATA, RST_STREAM).

queue_header_block(mut &this, stream_id: u32, block: Slice<u8>, end_stream: boolean) -> Result<(), IoError>;

Queue a header block on stream_id, splitting into HEADERS + CONTINUATION frames to respect the peer's max frame size. Sets END_STREAM on the HEADERS frame when end_stream is set.

async send_body(mut &this, stream_id: u32, body: Array<u8>, end_stream: boolean) -> Result<(), IoError> where S: AsyncTransport;

Send a message body as DATA frames on stream_id, honouring the connection and stream send windows and the peer's max frame size, and put everything queued on the wire.

async ensure_send_window(mut &this) -> Result<(), IoError> where S: AsyncTransport;

Wait until both the stream and connection send windows are positive, processing incoming control frames (chiefly WINDOW_UPDATE) while we wait.

queue_ack_data(mut &this, stream_id: u32, n: u64) -> Result<(), IoError>;

Queue the WINDOW_UPDATEs that replenish our receive windows after consuming n octets of DATA. Synchronous; the caller flushes.

async request(mut &this, req: Request, scheme: Str, authority: Str) -> Result<Response, IoError> where S: AsyncTransport;

Issue one request and read its response. scheme is "http" (h2c) or "https" (h2); authority becomes the :authority pseudo- header. Consumes req.

async read_response(mut &this, sid: u32) -> Result<Response, IoError> where S: AsyncTransport;

Read frames until the response on sid completes, assembling its header block and body.

async serve(mut &this, handler: (Request) -> Response) -> Result<(), IoError> where S: AsyncTransport;

Serve requests on this connection, dispatching each to handler, until the peer closes the connection or sends GOAWAY. Performs the server handshake first.

async read_request(mut &this) -> Result<Option<RequestOnStream>, IoError> where S: AsyncTransport;

Read frames until one stream completes (END_STREAM), returning the assembled request. None means the connection closed cleanly.

async send_response(mut &this, sid: u32, resp: Response) -> Result<(), IoError> where S: AsyncTransport;

Send a response on sid. Consumes resp.

async send_goaway(mut &this, last_stream_id: u32, error_code: u32) -> Result<(), IoError> where S: AsyncTransport;

Send a GOAWAY with the given last-stream-id and error code, then stop. Best-effort; transport teardown is the caller's.

encode_request_headers(mut &this, out: mut &Array<u8>, req: &Request, scheme: Str, authority: Str) -> void;
encode_response_headers(mut &this, out: mut &Array<u8>, resp: &Response) -> void;
encode_regular_headers(mut &this, out: mut &Array<u8>, h: &Headers) -> void;

Emit every stored header except the HTTP/1-only connection- specific fields that are forbidden in HTTP/2 (RFC 7540 section 8.1.2.2).

Constants

Settings

const PREFACE_LEN:                u64 = 24;
const LOCAL_HEADER_TABLE_SIZE:    u32 = 4096;
const LOCAL_ENABLE_PUSH:          u32 = 0;
const LOCAL_INITIAL_WINDOW_SIZE:  u32 = 1048576;
const LOCAL_MAX_FRAME_SIZE:       u32 = 16384;
const LOCAL_MAX_HEADER_LIST_SIZE: u32 = 262144;
const LOCAL_MAX_BODY_SIZE:        u64 = 16777216;
const DEFAULT_CONNECTION_WINDOW:  i64 = 65535;

The values advertised in the local SETTINGS frame, and the body cap enforced on the receive side.