Browse the docs

silk.http.http2.

A transport-independent HTTP/2 connection for clients and servers (RFC 9113).

Feed incoming bytes to Connection.receive, send Connection.output, and acknowledge sent bytes with Connection.consumeOutput. Each call returns at most one application event. Keep calling with the unconsumed input. SETTINGS and PING acknowledgments are queued automatically.

DATA uses connection and stream flow control. Call Connection.release only after consuming received data. A zero return from Connection.sendData means flow control or queued output blocks progress. Streams can progress independently. Field blocks remain contiguous on the wire.

Use prior knowledge on cleartext transports. On TLS, select h2 with ALPN before creating this connection. The obsolete HTTP/1.1 Upgrade handshake is not part of RFC 9113.

Examples#

Queue two requests on one connection#

silk
import silk.mem.allocator { Allocator, OutOfMemoryError }
import silk.core.effect { Effect }
import silk.http.hpack { Field }
import silk.http.http2 { Connection, Limits, Role }
import silk.http.http2_frame { ProtocolError }
import silk.num.u32
import silk.num.usize

effect fn requests() -> i32
  ! ProtocolError | OutOfMemoryError
  ? &mut Allocator {
  let mut connection = run Connection.make(Role.Client, Limits.defaults())
  let fields = [
    Field { name: b":method", value: b"GET", sensitive: false },
    Field { name: b":scheme", value: b"https", sensitive: false },
    Field { name: b":authority", value: b"example.com", sensitive: false },
    Field { name: b":path", value: b"/", sensitive: false }
  ]
  let first = run Connection.open(&mut connection, &fields, true)
  let second = run Connection.open(&mut connection, &fields, true)

  // Send these queued bytes over the authenticated h2 transport.
  let wire = Connection.output(&connection)
  if first != 1 || second != 3 || wire.length < 24 {
    return 1
  }
  return 0
}

effect fn failed<E>(error: E) -> i32 {
  drop error
  return 1
}

pub fn main() -> i32 {
  let mut allocator = Allocator.systemAllocatorProvider()
  return run Effect.catchAll(requests(), failed) |> Effect.provideMut<Allocator>(&mut allocator)
}

Import as Connection with import silk.http.http2 { Connection }.

Public declarations: 5.

Role#

silk
pub enum Role

The endpoint role. Clients allocate odd stream identifiers; servers allocate even identifiers for push.

Client#

silk
Client

Sends the client preface and initiates requests.

Server#

silk
Server

Checks the client preface and accepts requests.

Limits#

silk
pub struct Limits

Connection resource limits. The receiver advertises the applicable limits in SETTINGS.

Field streams#

silk
pub streams: u32

Maximum simultaneous peer-initiated streams.

Field frameBytes#

silk
pub frameBytes: u32

Maximum accepted frame payload, from 16384 through 16777215 bytes.

Field fields#

silk
pub fields: usize

Maximum decoded field count per block.

Field headerBytes#

silk
pub headerBytes: u32

Maximum decoded field-list size, including 32 bytes per field.

Field compressedBytes#

silk
pub compressedBytes: usize

Maximum compressed field block bytes across HEADERS and CONTINUATION frames.

Field tableBytes#

silk
pub tableBytes: u32

Maximum HPACK dynamic table bytes.

Field windowBytes#

silk
pub windowBytes: u32

Initial receive window for each stream, at most 2147483647 bytes.

Field outputBytes#

silk
pub outputBytes: usize

Maximum unsent wire bytes. Drain output before queuing more application data.

Field push#

silk
pub push: bool

Whether a client accepts push for the exact authority and scheme of the associated request. Servers ignore this field.

Implementation Copy for Limits#

silk
impl Copy for Limits

Implementation Limits#

silk
impl Limits

Associated function defaults#

silk
pub fn defaults() -> Limits

Returns limits of 100 streams, 16 KiB frames, 64 KiB field lists, and 1 MiB queued output.

Event#

silk
pub union Event

One event from the peer. DATA storage belongs to the event until the application drops it.

None#

silk
None

No application event. Continue with the unconsumed input, or wait for more bytes.

Headers#

silk
Headers

A complete initial, informational, or trailing field section.

Field stream#

silk
pub stream: u32

The stream identifier.

Field fields#

silk
pub fields: List<Header>

Decoded fields in wire order.

Field endStream#

silk
pub endStream: bool

True if this section ends the peer's side of the stream.

Data#

silk
Data

Stream body bytes with frame padding removed.

Field stream#

silk
pub stream: u32

The stream identifier.

Field bytes#

silk
pub bytes: Bytes

The body bytes. Call release after consuming them.

Field endStream#

silk
pub endStream: bool

True if the peer finished this stream.

Push#

silk
Push

A server push request. A client can reject it with reset.

Field stream#

silk
pub stream: u32

The associated request stream.

Field promised#

silk
pub promised: u32

The promised even stream identifier.

Field fields#

silk
pub fields: List<Header>

The promised request fields.

Reset#

silk
Reset

The peer reset one stream.

Field stream#

silk
pub stream: u32

The reset stream.

Field code#

silk
pub code: u32

The wire error code, including unknown extension codes.

Pong#

silk
Pong

A PING acknowledgment with its opaque payload.

Field bytes#

silk
pub bytes: Bytes

The eight bytes supplied by the peer.

Goaway#

silk
Goaway

The peer started graceful shutdown. Existing eligible streams can still finish.

Field lastStream#

silk
pub lastStream: u32

The last locally initiated stream the peer might have processed.

Field code#

silk
pub code: u32

The peer's wire error code.

Field debug#

silk
pub debug: Bytes

Opaque diagnostic bytes.

Settings#

silk
Settings

The peer's settings changed or it acknowledged local settings.

StreamError#

silk
StreamError

A rejected stream. RST_STREAM is queued; other streams remain usable.

Field stream#

silk
pub stream: u32

The rejected stream identifier.

Field code#

silk
pub code: u32

The wire error code.

Writable#

silk
Writable

The peer granted connection or stream send credit.

Progress#

silk
pub struct Progress

The result of feeding incoming wire bytes.

Field consumed#

silk
pub consumed: usize

Bytes consumed from the supplied input.

Field event#

silk
pub event: Event

At most one complete event.

Connection#

silk
pub struct Connection

An owned HTTP/2 state machine. It does no I/O and needs no compiler or native protocol support. Connection errors queue GOAWAY and make the connection terminal. Stream errors queue RST_STREAM.

Implementation Connection#

silk
impl Connection

Associated function make#

silk
pub effect fn make(endpoint: Role, limits: Limits) -> Connection
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Creates a connection and queues its preface and initial SETTINGS. Invalid limits fail with PROTOCOL_ERROR. TLS callers must first verify ALPN selected h2.

Method output#

silk
pub fn output(self: &Self) -> &[u8]

Borrows all unsent bytes. Send them in order before calling consumeOutput.

Method consumeOutput#

silk
pub effect fn consumeOutput(self: &mut Self, count: usize) -> ()
    ! ProtocolError

Marks bytes as sent. A count beyond the available output fails with PROTOCOL_ERROR.

Method failed#

silk
pub fn failed(self: &Self) -> bool

True after a connection error. Drain the queued GOAWAY, then close the transport.

Method receive#

silk
pub effect<'call> fn receive<'call>(self: &'call mut Self, input: &'call [u8]) -> Progress
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Consumes a wire fragment and returns at most one event. Partial frames are retained within the frame limit. Stream errors queue RST_STREAM; connection errors queue GOAWAY and reject subsequent input.

Method finishInput#

silk
pub effect fn finishInput(self: &mut Self) -> ()
    ! ProtocolError

Reports EOF. A truncated preface, frame, field block, or open stream fails with PROTOCOL_ERROR.

Method open#

silk
pub effect fn open(self: &mut Self, fields: &[Field], endStream: bool) -> u32
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Opens a client request stream. GOAWAY, exhausted identifiers, and peer stream limits refuse new streams.

Method sendHeaders#

silk
pub effect fn sendHeaders(self: &mut Self, id: u32, fields: &[Field], endStream: bool) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Queues response fields or trailers on an existing stream. Trailers must end the stream. Informational responses leave the stream ready for a final response and cannot end it.

Method sendData#

silk
pub effect fn sendData(self: &mut Self, id: u32, input: &[u8], endStream: bool) -> usize
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Queues as many body bytes as flow control, the frame size, and output space allow. END_STREAM is sent only when all input bytes fit. A zero return with nonempty input means backpressure.

Method release#

silk
pub effect fn release(self: &mut Self, id: u32, count: u32) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Returns consumed DATA credit to the peer. Padding credit is returned automatically. The count cannot exceed unreleased body bytes for this stream. Closed streams return connection credit only.

Method reset#

silk
pub effect fn reset(self: &mut Self, id: u32, code: u32) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Cancels an existing stream and queues RST_STREAM. Queued incoming body credit is returned to the connection.

Method ping#

silk
pub effect fn ping(self: &mut Self, bytes: &[u8]) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Sends a PING with exactly eight opaque bytes. Other lengths fail with FRAME_SIZE_ERROR.

Method shutdown#

silk
pub effect fn shutdown(self: &mut Self, code: u32, debug: &[u8]) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Stops accepting new streams and queues GOAWAY. Existing streams can finish when the code is NO_ERROR.

Method settingsTimeout#

silk
pub effect fn settingsTimeout(self: &mut Self) -> ()
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Fails the connection if the initial SETTINGS acknowledgment has not arrived by the caller's deadline.

Method push#

silk
pub effect fn push(self: &mut Self, associated: u32, fields: &[Field]) -> u32
    ! ProtocolError | OutOfMemoryError
    ? &mut Allocator

Reserves a server push stream and queues PUSH_PROMISE. The request must use GET or HEAD without a body.

Category: HTTP.

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.

View the source of this page