Skip to content
Kavachकवच

Standard Library: std.http

● Intermediate5 min

Every type, method and function of std.http: what the spec lists, then each declaration in its source, with its examples and the line that declares it.

Spec 14.11 · learn it in HTTP.

A declaration below shows what a program writes against: a type's fields, a function's parameters, what it gives, its contracts (require, ensure) and its examples. kavach test runs every example, so each one is true of the code.

What the spec lists

FunctionGives
http.get(url) -> Response ! HttpErrorGET url
http.post(url, body) -> Response ! HttpErrorPOST url with body (Bytes)
http.request(method, url, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpErrorAny method, with the headers given and a body: a form post with basic auth, a bearer token, PUT, PATCH, DELETE, if-none-match. HTTP/2 when the server offers it with TLS, else HTTP/1.1; host, content-length and connection are the client's own, so ones given are left out
http.get3(url) -> Response ! HttpErrorGET url over HTTP/3
http.open(url) -> Session ! HttpErrorA session: one HTTP/1.1 connection to the server of url (http:// or https://; the path is not used), kept open for several requests
s.get(path), s.post(path, body) -> Response ! HttpErrorA request on session s's connection, waiting for its response
s.request(method, path, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpErrorThe same as http.request, on session s's connection
s.close()Closes the session's connection
http.serve(listener, handler, limits: ServeLimits()) ! NetErrorServes HTTP on listener: each connection in a task of its own, on any core (spawn cores, 9.8), its requests answered by handler: fn(Request) -> Response, each client held to limits (below). It runs until the function that called it returns, which cancels it (9.2)
http.text(status, body) -> ResponseA response with text
http.get_json<T>(url) -> T ! HttpErrorGET url, the response's JSON body decoded into a T (json.decode<T>, 2.12)
http.post_json<T>(url, body) -> T ! HttpErrorPOST url with the Json value body, the response's JSON decoded into a T
http.json_response(status, value) -> ResponseA response with the Json value value (write json.of(order) for a typed value)
http.read_json<T>(request) -> T ! JsonErrorA request's JSON body decoded into a T
WrittenGives
form.next() -> FormPart? ! HttpErrorThe next part, or none after the last; data of the part before not read yet is skipped
part.name, part.filename, part.content_typeThe field's name, the file's name (String?, none for a plain field) and its content-type (text/plain when not given)
part.read() -> Bytes? ! HttpErrorThe part's next piece of data, or none at its end
part.text() -> String ! HttpErrorThe rest of the part as text: for small fields
WrittenGives
http.websocket(r, session: fn(WebSocket) ! NetError) -> ResponseAccepts a WebSocket (RFC 6455): 101 Switching Protocols, then session; 400 for a request that isn't one
http.events(r, feed: fn(EventStream) ! NetError) -> ResponseServer-sent events: 200 with text/event-stream, then feed
http.websocket_connect(url) -> WebSocket ! HttpErrorA client's WebSocket to ws:// or wss:// url
ws.receive() -> WsMessage? ! NetErrorThe next message, WsMessage.Text(text) or WsMessage.Binary(data), or none once the other end closed
ws.send_text(text), ws.send_bytes(data)Sends one message
ws.close()Says goodbye and closes the connection
out.send(data, event: "", id: "")Sends one event; each line of data is a data: line
FunctionGives
h2.request(conn, headers, body) -> H2Message ! H2ErrorSends one request on a new connection (headers start with :method, :scheme, :authority, :path) and reads the response
h2.connect(conn) -> H2Client ! H2ErrorStarts a connection that takes many requests, so a service connects once instead of once per call
c.request(headers, body) -> H2Message ! H2ErrorSends one request on c, on a stream of its own, and reads its response. Requests from several tasks are open at once: their sends take turns, in the order they asked, and each answer goes to the task that asked, in whatever order the server sends them. A stream the server resets fails only its own request
c.going_away() -> BoolWhether the server said it is going away (GOAWAY) or the connection broke: a pool replaces such a client with a new one
c.close()Closes the connection once the request being answered is done; a request after it fails with Protocol. A client is also closed when its last holder lets it go, as its connection is (14.10)
h2.accept(conn, data) -> Link ! H2ErrorThe server side of a connection that began with data
h2.next(link) -> Next ! H2ErrorNext(link:, message:): the next whole request, or none once the client is done
h2.respond(link, stream, headers, body) -> Link ! H2ErrorSends the response on stream; headers start with :status
h2.begin(conn, headers) -> Link ! H2ErrorOpens a request on a new connection and leaves its stream open: send_data sends the body piece by piece while pull reads the answer as it arrives
h2.send_data(link, stream, data, end) -> Link ! H2ErrorSends data on stream; end: Bool ends this side of the stream
h2.send_headers(link, stream, headers) -> Link ! H2ErrorSends a response's headers and leaves the stream open
h2.send_trailers(link, stream, trailers) -> Link ! H2ErrorSends header fields after the body, ending the stream
h2.watch(link) -> H2Watched ! H2ErrorThe server side piece by piece: H2Watched(link:, event:), where the event is StreamOpened(stream, headers) as soon as a request's headers arrive, StreamData(stream, data) as its body arrives, StreamEnded(stream), or ClientDone. A server uses watch or next, not both
FunctionGives
h3.request(conn, headers, body) -> H3Message ! H3ErrorSends one request on a new connection from net.connect_quic(address, ["h3"]) (headers start with :method, :scheme, :authority, :path), and reads the response
h3.encode(headers) -> BytesA QPACK header block of Header(name:, value:)s
h3.decode(block) -> [Header] ! H3ErrorThe headers of a QPACK block that uses no dynamic table
FunctionGives
hpack.new_table(limit) -> TableAn empty table of at most limit bytes (HTTP/2 starts with 4096)
hpack.decode(block, table) -> Decoded ! HpackErrorDecoded(headers: [Header], table: Table); Malformed(reason) for a broken block
hpack.encode(headers) -> BytesA block with each Header(name:, value:) as a literal, names in lower case
hpack.huffman(data) -> Bytes ! HpackErrorDecodes Huffman-coded text (RFC 7541 appendix B); QPACK uses the same code

std.http.h2 · h2.kav

use std.http.h2: 4 types and 12 functions. stdlib/http/h2.kav

Next type

What next found: the link, and a request unless the client is done.

pub type Next {
    pub link: Link
    pub message: H2Message?
}

request function

Sends one request on stream 1 of a new connection and reads the response. headers has :method, :scheme, :authority, :path.

pub fn request(conn: Connection, headers: [Header], body: Bytes) -> H2Message ! H2Error uses Net

open function

Opens a request without waiting for the answer: pull then reads it as it arrives (spec 14.14 streams on this).

pub fn open(conn: Connection, headers: [Header], body: Bytes) -> Link ! H2Error uses Net

begin function

Opens a request on stream 1 of a new connection and leaves the stream open: send_data sends its body piece by piece, and pull reads the answer as it arrives, so both can go on at once.

pub fn begin(conn: Connection, headers: [Header]) -> Link ! H2Error uses Net

send_data function

Sends data on stream; end ends this side of the stream.

pub fn send_data(link: Link, stream: Int, data: Bytes, end: Bool) -> Link ! H2Error uses Net

send_headers function

Sends a response's headers on stream and leaves it open for send_data and send_trailers.

pub fn send_headers(link: Link, stream: Int, headers: [Header]) -> Link ! H2Error uses Net

send_trailers function

Sends header fields after the body (trailers), ending the stream.

pub fn send_trailers(link: Link, stream: Int, trailers: [Header]) -> Link ! H2Error uses Net

Pulled type

What pull found: body bytes that arrived (maybe none yet), and the trailing headers once the answer ended.

pub type Pulled {
    pub link: Link
    pub data: Bytes
    pub ended: Bool
    pub trailers: [String: String]
}

pull function

The next piece of the answer on stream 1: waits until bytes arrive or the answer ends.

pub fn pull(link: Link) -> Pulled ! H2Error uses Net

accept function

Starts the server side of a connection that began with data (the preface, or its start).

pub fn accept(conn: Connection, data: Bytes) -> Link ! H2Error uses Net

next function

The next whole request, or none once the client is done.

pub fn next(link: Link) -> Next ! H2Error uses Net

H2Event type

What happened on a server's connection, in the order it happened.

pub type H2Event = StreamOpened(stream: Int, headers: [String: String]) |
    StreamData(stream: Int, data: Bytes) |
    StreamEnded(stream: Int) |
    ClientDone

H2Watched type

What watch found: the link, and the event.

pub type H2Watched {
    pub link: Link
    pub event: H2Event
}

watch function

The server side, piece by piece: a request's headers as soon as they arrive, then its body bytes as they arrive, then its end; ClientDone once the client is done. Use it instead of next, never with it.

pub fn watch(link: Link) -> H2Watched ! H2Error uses Net

respond function

Sends a response on stream; headers starts with :status.

pub fn respond(link: Link, stream: Int, headers: [Header], body: Bytes) -> Link ! H2Error uses Net

respond_with_trailers function

Sends a response on stream with header fields after its body (trailers), as gRPC sends its status.

pub fn respond_with_trailers(
    link: Link,
    stream: Int,
    headers: [Header],
    body: Bytes,
    trailers: [Header],
) -> Link ! H2Error uses Net

std.http.h2.client · h2client.kav

use std.http.h2.client: 1 type and 1 function. stdlib/http/h2client.kav

H2Client type

A connection for many requests, from h2.connect.

pub type H2Client {
    /// The turn to send, with what sending needs.
    send_turn: Receiver<Sending>
    send_back: Sender<Sending>
    /// The connection's reading side, taken by the task that reads.
    read_turn: Receiver<Link>
    read_back: Sender<Link>
    /// What the server lets this side send, as the reader last saw it,
    /// and a signal the reader gives after each frame, for a sender
    /// waiting for credit while another task reads.
    credit: Shared<Credit>
    credit_signal: Receiver<Bool>
    signal_credit: Sender<Bool>
    /// Whether a task is reading, and where each answer still awaited
    /// goes: one task reads at a time and hands each answer to its task
    /// as soon as it is whole, in whatever order the server sends them.
    waiting: Shared<Waiting>
    leaving: Shared<Bool>
}

request method

Sends one request and reads its response. headers has :method, :scheme, :authority, :path.

pub fn request(self, headers: [Header], body: Bytes) -> H2Message ! H2Error uses Net

going_away method

Whether the server said it is going away (GOAWAY), or the connection broke: a pool then replaces it with a new one.

pub fn going_away(self) -> Bool

close method

Closes the connection, once the request being sent is sent. A request after it fails, and so does one still waiting.

pub fn close(self) uses Net

connect function

Starts an HTTP/2 connection on conn for many requests.

pub fn connect(conn: Connection) -> H2Client ! H2Error uses Net

std.http.h2.serving · h2serving.kav

use std.http.h2.serving: 0 types and 1 function. stdlib/http/h2serving.kav

serve function

Serves the HTTP/2 connection conn, which began with data, until the client is done and every stream is answered.

pub fn serve(conn: Connection, data: Bytes, handler: fn(Request) -> Response, follow: Bool = true) ! H2Error uses Net

std.http.h2.wire · h2wire.kav

use std.http.h2.wire: 6 types and 22 functions. stdlib/http/h2wire.kav

H2Error type

Why an HTTP/2 exchange failed.

pub type H2Error = Network(error: NetError) |
    Protocol(reason: String) |
    Reset(stream: Int, code: Int)

H2Message type

A whole message on one stream: headers, names in lower case and with the pseudo-headers such as :status, and the body.

pub type H2Message {
    pub stream: Int
    pub headers: [String: String]
    pub body: Bytes
}

One side of a connection, between frames.

pub type Link {
    pub conn: Connection
    /// Bytes read but not used yet.
    pub buffer: Bytes
    /// The header table for blocks the other side sends.
    pub table: Table
    /// How much this side may still send: on the connection, and per
    /// stream (`initial` for a stream not listed).
    pub window: Int
    pub windows: [Int: Int]
    pub initial: Int
    /// The largest frame the other side takes.
    pub max_frame: Int
    /// Messages being received, then complete ones, in order.
    pub partial: [Int: Partial]
    pub done: [H2Message]
    /// Streams the other side reset, with the reason's code.
    pub resets: [Int: Int]
    /// The stream a header block goes on with, or 0.
    pub continuing: Int
    /// The other side is going away (GOAWAY).
    pub leaving: Bool
    /// Streams `watch` has reported open and not yet ended.
    pub announced: [Int: Bool]
}

Frame type

One frame (RFC 9113 4.1).

pub type Frame {
    pub kind: Int
    pub flags: Int
    pub stream: Int
    pub payload: Bytes
}

Partial type

A message being received.

pub type Partial {
    pub headers: [String: String]
    pub body: Bytes
    /// A header block waiting for its CONTINUATION frames.
    pub block: Bytes
    pub has_headers: Bool
    /// The other side ends the stream with this header block.
    pub ending: Bool
}

Credit type

What the other side has let this side send since the start, on the connection and per stream (initial for a stream not listed), the largest frame it takes, and the streams it reset: what a task that sends needs from the task that reads.

pub type Credit {
    pub window: Int
    pub windows: [Int: Int]
    pub initial: Int
    pub max_frame: Int
    pub resets: [Int: Int]
}

credit_of function

The credit the reading side l has seen.

pub fn credit_of(l: Link) -> Credit

most_streams function

How many streams a server answers at once on one connection, which it tells the client (SETTINGS_MAX_CONCURRENT_STREAMS, RFC 9113 6.5.2).

pub fn most_streams() -> Int

block_frames function

A header block on stream as frames: HEADERS, then CONTINUATION frames of at most most bytes. Written in one write, so no other frame comes between them. end ends this side's stream.

pub fn block_frames(stream: Int, headers: [Header], end: Bool, most: Int) -> Bytes
    require stream >= 0 and stream <= 2_147_483_647
    require most >= 1

big_window function

The windows this side opens: 16 MB, so a sender rarely waits.

pub fn big_window() -> Int

preface function

"PRI * HTTP/2.0", a blank line, "SM" and a blank line.

pub fn preface() -> Bytes

start function

pub fn start(conn: Connection, buffer: Bytes) -> Link

write function

pub fn write(conn: Connection, data: Bytes) ! H2Error uses Net

frame function

A frame's bytes: a 9-byte header, then the payload.

pub fn frame(kind: Int, flags: Int, stream: Int, payload: Bytes) -> Bytes
    require kind >= 0 and kind <= 255
    require flags >= 0 and flags <= 255
    require stream >= 0 and stream <= 2_147_483_647
    require payload.len() <= 16_777_215

four function

A 32-bit number, most significant byte first.

pub fn four(n: Int) -> Bytes
    require n >= 0 and n <= 4_294_967_295
    example four(258) == Bytes([0, 0, 1, 2])

number32 function

The 32-bit number at at.

pub fn number32(data: Bytes, at: Int) -> Int
    require at >= 0 and at <= data.len() - 4
    example number32(Bytes([0, 0, 1, 2]), 0) == 258

setting function

One setting: a 16-bit id and a 32-bit value.

pub fn setting(id: Int, value: Int) -> Bytes
    require id >= 0 and id <= 65_535
    require value >= 0 and value <= 4_294_967_295

step function

Reads one frame and acts on it; none when the connection closed.

pub fn step(l: Link) -> Link? ! H2Error uses Net

handle function

Acts on one frame (RFC 9113 6).

pub fn handle(link: Link, f: Frame) -> Link ! H2Error uses Net

settings function

The other side's settings: window and frame sizes matter here.

pub fn settings(link: Link, payload: Bytes) -> Link ! H2Error

header_frame function

HEADERS and CONTINUATION frames: a header block, maybe in pieces.

pub fn header_frame(link: Link, f: Frame) -> Link ! H2Error uses Net

data_frame function

DATA frames: the body, a piece at a time.

pub fn data_frame(link: Link, f: Frame) -> Link ! H2Error uses Net

unpad function

A frame's payload without its padding (flag 8).

pub fn unpad(f: Frame) -> Bytes ! H2Error

finish function

Moves the message on stream to the complete ones.

pub fn finish(link: Link, stream: Int) -> Link

send function

Sends a header block and body on stream, in frames that fit the other side's windows; waits for WINDOW_UPDATE frames when they are full. trailers, when there are any, end the stream after the body.

pub fn send(link: Link, stream: Int, headers: [Header], body: Bytes, trailers: [Header]) -> Link ! H2Error uses Net

block function

Sends a header block on stream: a HEADERS frame, then CONTINUATION frames when it is bigger than a frame. end ends this side's stream.

pub fn block(link: Link, stream: Int, headers: [Header], end: Bool) -> Link ! H2Error uses Net

data function

Sends body on stream as DATA frames that fit the other side's windows, waiting for WINDOW_UPDATE frames when they are full. end ends this side's stream (with an empty frame when body is empty).

pub fn data(link: Link, stream: Int, body: Bytes, end: Bool) -> Link ! H2Error uses Net

client_hello function

The client's side of a connection: its settings, and room to send.

pub fn client_hello(conn: Connection) ! H2Error uses Net

std.http.h3 · h3.kav

use std.http.h3: 2 types and 3 functions. stdlib/http/h3.kav

H3Error type

Why an HTTP/3 exchange failed.

pub type H3Error = Network(error: NetError) | Protocol(reason: String)

H3Message type

A response: headers, names in lower case and with :status, and the body.

pub type H3Message {
    pub headers: [String: String]
    pub body: Bytes
}

request function

Sends one request on a new connection and reads the response. headers has :method, :scheme, :authority, :path.

pub fn request(conn: Connection, headers: [Header], body: Bytes) -> H3Message ! H3Error uses Net

encode function

A QPACK header block of headers, each a literal with a literal name, names in lower case (RFC 9204 4.5.6).

pub fn encode(headers: [Header]) -> Bytes

decode function

The headers of a QPACK block that uses no dynamic table.

pub fn decode(block: Bytes) -> [Header] ! H3Error

std.http.hpack · hpack.kav

use std.http.hpack: 4 types and 4 functions. stdlib/http/hpack.kav

Header type

One header: its name and value.

pub type Header {
    pub name: String
    pub value: String
}

HpackError type

Why a header block can't be read.

pub type HpackError = Malformed(reason: String)

Table type

The dynamic table: entries oldest first, their size, and its limit.

pub type Table {
    pub entries: [Header]
    pub size: Int
    pub limit: Int
}

Decoded type

A header block's headers, and the table after it.

pub type Decoded {
    pub headers: [Header]
    pub table: Table
}

new_table function

An empty table that holds up to limit bytes (4096 to start with).

pub fn new_table(limit: Int) -> Table

decode function

Reads a header block, with the table the earlier blocks left.

pub fn decode(block: Bytes, table: Table) -> Decoded ! HpackError

encode function

A header block for headers: literals, names in lower case.

pub fn encode(headers: [Header]) -> Bytes

huffman function

Decodes Huffman-coded bytes (RFC 7541 appendix B). The code is canonical: codes of one length are consecutive numbers, in symbol order, so four small tables decode it. QPACK (h3.kav) uses the same code.

pub fn huffman(data: Bytes) -> Bytes ! HpackError

std.http · http.kav

use std.http: 7 types and 16 functions. stdlib/http/http.kav

Request type

An HTTP request, as a server's handler gets it.

pub type Request {
    pub method: String
    pub path: String
    /// In the order they came, names in lower case, repeats kept.
    pub headers: [Header]
    /// The body, when it was read whole (spec 14.11); empty otherwise.
    pub body: Bytes
    /// A body too large to read whole, set by the server: read it with
    /// `read_body`.
    pub stream: BodyStream? = none
    /// The address of whoever opened the connection (`203.0.113.7:51234`),
    /// set by the server; empty for a request made by hand. Behind a proxy
    /// it is the proxy's.
    pub peer: String = ""
    /// With mutual TLS, the names of the certificate the client showed
    /// (decision 0099); `none` otherwise, and for a request made by hand.
    pub client_cert: ClientCert? = none
}

header method

The value of the first header named name, if any.

pub fn header(self, name: String) -> String?

headers_named method

The values of every header named name, in order.

pub fn headers_named(self, name: String) -> [String]

read_body method

The next piece of a large body (spec 14.11), or none once it has all come; none for a body read whole.

pub fn read_body(self) -> Bytes? ! NetError uses Net

BodyStream type

The part of a large request body not read yet, made by the server: kept across tasks, so the server sees how much the handler read.

pub type BodyStream {
    pub conn: Connection
    /// What came with the request's head, not handed out yet.
    pub first: Shared<Bytes>
    /// How many bytes of the body are left.
    pub left: Shared<Int>
    /// What came after the body: the start of the next request.
    pub after: Shared<Bytes>
    /// How long one piece may take to come.
    pub wait: Duration
}

Response type

An HTTP response.

pub type Response {
    pub status: Int
    /// In the order they are sent, names in lower case; a name may come
    /// more than once (`set-cookie`).
    pub headers: [Header]
    pub body: Bytes
    /// Sent after `body` as it is read (spec 14.11): a reader of
    /// `fs.chunks`.
    pub stream: Chunks? = none
    /// What runs on the connection after the head: a WebSocket's
    /// session or an event stream's feed (`http.websocket`, `http.events`).
    pub take_over: TakeOver? = none
}

header method

The value of the first header named name, if any.

pub fn header(self, name: String) -> String?

headers_named method

The values of every header named name, in order.

pub fn headers_named(self, name: String) -> [String]

ServeLimits type

What http.serve allows each client (spec 14.11), so a slow or hostile one can't hold the server: every limit has a safe default.

pub type ServeLimits {
    /// The most a request's line and headers may take: 431 past it.
    pub max_header_bytes: Int = 16_384
    /// The most a request's body may take: 413 past it, refused by its
    /// `content-length` before it is read.
    pub max_body_bytes: Int = 10_000_000
    /// How long a request's line and headers may take to come: 408 past
    /// it (a client sending them a byte at a time can't hold a task).
    pub header_timeout: Duration = 10.seconds
    /// The slowest a body may come, in bytes a second, after a second's
    /// grace: 408 when slower.
    pub min_body_rate: Int = 1_000
    /// How long a kept-open connection may wait for its next request.
    pub idle_timeout: Duration = 5.seconds
    /// The most connections at once: past it, 503 with `retry-after`.
    pub max_connections: Int = 10_000
    /// The most requests being answered at once: past it, 503.
    pub max_in_flight: Int = 1_000
    /// The largest request body read whole into `r.body`; a larger one is
    /// read by the handler with `r.read_body()`.
    pub buffered_body: Int = 1_000_000
    /// What `retry-after` says on a 503, in seconds.
    pub retry_after: Int = 1
    /// On a stop signal, how long to finish the requests under way
    /// (spec 5.8): `http.serve` holds the program's stop that long.
    pub drain_timeout: Duration = 10.seconds
    /// Whether a request's span continues the trace its `traceparent`
    /// names (spec 14.12); `false`, for a server the internet reaches
    /// directly, starts a trace of its own for each request.
    pub follow_trace: Bool = true
}

HttpError type

Why an HTTP request failed: Status and BadJson come from the JSON calls (get_json, post_json).

pub type HttpError = Network(error: NetError) |
    BadUrl(url: String) |
    BadMessage(reason: String) |
    Status(code: Int) |
    BadJson(error: JsonError)

text function

A response with text: http.text(200, "hello").

pub fn text(status: Int, body: String) -> Response

request function

A request with any method, headers and body, over HTTP/2 when the server offers it with TLS, else HTTP/1.1 (spec 14.11).

pub fn request(method: String, url: String, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpError uses Net

get function

GET url.

pub fn get(url: String) -> Response ! HttpError uses Net

post function

POST url with body.

pub fn post(url: String, body: Bytes) -> Response ! HttpError uses Net

get_json function

GET url, its JSON body decoded into a T.

pub fn get_json<T>(url: String) -> T ! HttpError uses Net

post_json function

POST url with the JSON body, the JSON answer decoded into a T.

pub fn post_json<T>(url: String, body: Json) -> T ! HttpError uses Net

file function

A response with the file at path (spec 14.11), sent as it is read: its content-type from its extension, its content-length from its size.

pub fn file(path: String) -> Response ! FsError uses Fs.read

TakeOver type

What a response that takes over runs on the connection, with what came after the request and the largest message allowed.

pub type TakeOver {
    pub run: fn(Connection, Bytes, Int) ! NetError
}

websocket function

Accepts the WebSocket request r and runs session on it (spec 14.11); 400 when r isn't one.

pub fn websocket(r: Request, session: fn(WebSocket) ! NetError) -> Response

events function

Server-sent events, sent by feed (spec 14.11).

pub fn events(r: Request, feed: fn(EventStream) ! NetError) -> Response

websocket_connect function

A WebSocket to url, ws:// or wss:// (spec 14.11).

pub fn websocket_connect(url: String) -> WebSocket ! HttpError uses Net

form function

The multipart/form-data form in r, read part by part (spec 14.11).

pub fn form(r: Request) -> Form ! HttpError

json_response function

A response with JSON: http.json_response(200, json.of(order)).

pub fn json_response(status: Int, value: Json) -> Response

read_json function

A request's JSON body decoded into a T.

pub fn read_json<T>(r: Request) -> T ! JsonError

get3 function

GET url over HTTP/3 (an https:// URL).

pub fn get3(url: String) -> Response ! HttpError uses Net

Session type

One HTTP/1.1 connection kept open for several requests to one server (spec 14.11). For one task at a time.

pub type Session {
    conn: Connection
    host: String
}

get method

GET path on the session's connection.

pub fn get(self, path: String) -> Response ! HttpError uses Net

post method

POST path with body on the session's connection.

pub fn post(self, path: String, body: Bytes) -> Response ! HttpError uses Net

request method

A request with any method, headers and body on the session's connection.

pub fn request(self, method: String, path: String, headers: [Header] = [], body: Bytes = Bytes([])) -> Response ! HttpError uses Net

close method

Closes the session's connection.

pub fn close(self) uses Net

open function

A session with the server of url: one connection, kept open.

pub fn open(url: String) -> Session ! HttpError uses Net

serve function

Serves HTTP on listener: each connection in a task of its own, on any core (spec 14.11), its requests answered by handler, each client held to limits. Runs until the function that called it returns (its tasks are cancelled then, spec 9.2).

pub fn serve(listener: Listener, handler: fn(Request) -> Response, limits: ServeLimits = ServeLimits()) ! NetError uses Net

std.http.message · message.kav

use std.http.message: 1 type and 14 functions. stdlib/http/message.kav

Message type

The first line, headers and body of an HTTP message. Header names are in lower case, in the order they came, repeats kept.

pub type Message {
    pub first: String
    pub headers: [Header]
    pub body: Bytes
}

first_header function

The value of the first header named name (in lower case), if any.

pub fn first_header(headers: [Header], name: String) -> String?

all_headers function

The values of every header named name (in lower case), in order.

pub fn all_headers(headers: [Header], name: String) -> [String]

head_end function

Where the head of a message ends (its blank line), if it has.

pub fn head_end(data: Bytes) -> Int?

parse function

pub fn parse(data: Bytes) -> Message?

plain function

HTTP/2 headers without the pseudo-headers (:status, :path, …).

pub fn plain(headers: [String: String]) -> [Header]

chunked function

Whether a message's body comes in chunks (RFC 9112 7.1).

pub fn chunked(headers: [Header]) -> Bool

dechunk function

The data of a body sent in chunks, without the chunk sizes and the trailers; none until the last chunk (size 0) has come, or when the chunks are not well formed.

pub fn dechunk(body: Bytes) -> Bytes?

whole function

The complete message at the start of data, its body sized by content-length (none means an empty body) or sent in chunks, and how many bytes of data it took; none until all of it has come.

pub fn whole(data: Bytes) -> (message: Message, used: Int)?

unchunk function

A body sent in chunks: its data, and how many bytes of body it took, through the empty line after the trailers; none until all of it has come, or when the chunks are not well formed.

pub fn unchunk(body: Bytes) -> (data: Bytes, used: Int)?

crlf function

A line end in HTTP.

pub fn crlf() -> String

reason function

The reason phrase that goes with status in a status line.

pub fn reason(status: Int) -> String

content_type function

The content-type of a file named path, from its extension.

pub fn content_type(path: String) -> String

hex function

n (0 or more) in hexadecimal, as a chunk's size is written.

pub fn hex(n: Int) -> String
    require n >= 0

hex_digit function

The value of hexadecimal digit b, if it is one.

pub fn hex_digit(b: UInt8) -> Int?

std.http.multipart · multipart.kav

use std.http.multipart: 2 types and 1 function. stdlib/http/multipart.kav

Form type

A multipart/form-data body, read part by part.

pub type Form {
    request: Request
    /// What divides the parts: a line end, `--` and the boundary.
    delimiter: Bytes
    /// What has come and not been handed out yet.
    held: Shared<Bytes>
    /// Whether `request.body` has been taken, for a body read whole.
    taken: Shared<Bool>
    /// Whether a part's data is being read.
    in_part: Shared<Bool>
    /// Whether the last part has ended.
    ended: Shared<Bool>
}

next method

The next part, or none after the last. What is left of the part before is skipped.

pub fn next(self) -> FormPart? ! HttpError uses Net

FormPart type

One part of a form: a field, or a file.

pub type FormPart {
    pub name: String
    /// The file's name; `none` for a plain field.
    pub filename: String?
    pub content_type: String
    form: Form
}

read method

The part's next piece of data, or none at its end.

pub fn read(self) -> Bytes? ! HttpError uses Net

text method

The rest of the part as text: for small fields.

pub fn text(self) -> String ! HttpError uses Net

open function

The form in request r.

pub fn open(r: Request) -> Form ! HttpError

std.http.server · server.kav

use std.http.server: 0 types and 1 function. stdlib/http/server.kav

serve function

pub fn serve(listener: Listener, handler: fn(Request) -> Response, limits: ServeLimits) ! NetError uses Net

std.http.upgrade · upgrade.kav

use std.http.upgrade: 3 types and 6 functions. stdlib/http/upgrade.kav

WsMessage type

A message: text, or bytes.

pub type WsMessage = Text(text: String) | Binary(data: Bytes)

WebSocket type

One end of a WebSocket.

pub type WebSocket {
    conn: Connection
    /// What has come and isn't read yet.
    held: Shared<Bytes>
    /// Whether this end is the client, which masks what it sends.
    client: Bool
    /// The largest message taken, in bytes.
    most: Int
    /// The turn to send: one slot, taken by each send while it writes
    /// its whole frame, so frames from several tasks never mix.
    turn: Receiver<Bool>
    turn_back: Sender<Bool>
}

receive method

The next message, or none once the other end closed. Pings are answered here, and a message larger than allowed closes the socket with 1009.

pub fn receive(self) -> WsMessage? ! NetError uses Net

send_text method

Sends text as one message.

pub fn send_text(self, text: String) ! NetError uses Net

send_bytes method

Sends data as one message.

pub fn send_bytes(self, data: Bytes) ! NetError uses Net

close method

Says goodbye and closes the connection.

pub fn close(self) uses Net

server_end function

The server's end of a WebSocket on conn, first what came after the request.

pub fn server_end(conn: Connection, first: Bytes, most: Int) -> WebSocket

client_end function

The client's end of a WebSocket on conn, first what came after the response.

pub fn client_end(conn: Connection, first: Bytes, most: Int) -> WebSocket

EventStream type

The server-sent events of a response (text/event-stream).

pub type EventStream {
    conn: Connection
}

send method

Sends one event: data (a line each for its lines), with an event name and an id when given.

pub fn send(self, data: String, event: String = "", id: String = "") ! NetError uses Net

event_stream function

The events of a response on conn.

pub fn event_stream(conn: Connection) -> EventStream

accept function

A response accepting the WebSocket request r, then running session; 400 when r isn't one.

pub fn accept(r: Request, session: fn(WebSocket) ! NetError) -> Response

events function

A response of server-sent events, sent by feed.

pub fn events(feed: fn(EventStream) ! NetError) -> Response

connect function

A client's WebSocket to url (ws:// or wss://).

pub fn connect(url: String) -> WebSocket ! HttpError uses Net