API reference

The whole surface, by package.

Every public value, type, method and error, generated from the package interfaces and the comments beside the code.

moonnet/spec

The contract: one exchange, whatever carries it.

pub async fn call(&Conn, Request) -> (Response, Bytes)
pub fn find(Array[Field], String) -> String?

The first field named name, matched without regard to case.

pub fn lines(Array[Field]) -> String

name: value lines, the form a head is shown in by a person reading a log.

pub async fn read_to_end(&Conn, Stream, limit? : Int32) -> Bytes
pub fn table(Array[Field]) -> Map[String, String]

Every field of a head as one lower-cased name to its value, the last one winning, as a map lookup would.

pub(all) enum Body

Where a message's body comes from.

Empty

No body: the message ends where its head does.

Bytes(Bytes)

A body that is at hand, sent in full before the reply is read.

Streaming

A body the caller sends with send after the exchange is open, in pieces whose length is not known when the head goes out.

pub(all) struct Field

One field of a message head: the name, and the value, as they go on the wire.

name : String
value : String
pub fn Field::key(Self) -> String

The name in the form a comparison uses: HTTP field names are case-insensitive (RFC 9110 §5.1), and a lower-case copy is what every lookup compares.

pub fn Field::new(String, String) -> Self
pub(all) suberror Refused

What a connection will not do.

Malformed(String)

The peer's octets are not what the protocol allows.

Unsupported(String)

The request, or the peer, asks for something this connection does not do.

Closed

The connection ended before the exchange did.

Broken(String)

The socket failed under the connection.

pub(all) struct Request

A request: what to ask for, and what to carry along.

verb : String
target : String
fields : Array[Field]
body : Body
pub fn Request::field(Self, String) -> String?
pub fn Request::new(String, String, fields? : Array[Field], body? : Body) -> Self
pub(all) struct Response

A reply head: the status and the fields. The body is read through the connection, because it may be larger than anything worth holding at once.

status : Int32
fields : Array[Field]
pub fn Response::field(Self, String) -> String?
pub(all) struct Stream

One exchange on a connection, named by the connection rather than by the protocol underneath: on a connection that carries one exchange at a time it is 1, and on one that multiplexes it is whatever that connection gave out.

id : Int32
pub(open) trait Conn

The one contract a connection presents, whatever carries it: HTTP/1.1, HTTP/2, HTTP/3 or WebSocket. Code written against this runs on any of them; an implementation is all a new protocol needs.

An exchange is opened, the request body is sent through it, and the reply's head and body are read from it. A connection that carries one exchange at a time says so through is_ready, which a caller waits on before opening the next.

async fn open(Self, Request) -> Stream

Open an exchange on request, and send its head and whatever body came with it.

async fn send(Self, Stream, Bytes, end~ : Bool) -> Unit

Send more of the request's body; end marks the last of it. Only an exchange opened with Body::Streaming takes this.

async fn response(Self, Stream) -> Response

The reply's head, once the peer has sent it.

async fn read(Self, Stream) -> Bytes?

The next run of the reply's body, read as it arrives; None ends it.

fn trailers(Self, Stream) -> Array[Field]

The fields that came after the body, once read has ended it.

fn is_ready(Self) -> Bool

Whether another exchange can start on this connection now. False while one is in flight on a connection that carries them one at a time, and after it has ended.

fn kind(Self) -> String

The protocol the connection settled on, as ALPN names it: http/1.1, h2, h3.

async fn close(Self) -> Unit

End the connection, in whatever way the protocol under it asks for.

moonnet/adapt/h1

HTTP/1.1, RFC 9112.

pub fn client(@tcp.Conn, String) -> Conn

A client over a connection that is already open to authority, the host[:port] the Host field carries.

pub async fn connect(String, port~ : Int32, tls? : @tls.Client, now? : Int64) -> Conn
pub(all) struct Conn

An HTTP/1.1 client connection: one exchange at a time, its head and body framed as RFC 9112 says, over the tcp connection underneath.

sock : @tcp.Conn
authority : String
mut held : Bytes
mut at : Int32
mut next_id : Int32
mut stream : Int32
mut verb : String
mut phase : Phase
mut framing : @http1.Body
mut left : Int32
mut streaming : Bool
mut sent_end : Bool
mut alive : Bool
mut after : Array[@spec.Field]
pub async fn Conn::close(Self) -> Unit
pub fn Conn::is_ready(Self) -> Bool
pub fn Conn::kind(Self) -> String
pub fn Conn::new(@tcp.Conn, String) -> Self
pub async fn Conn::open(Self, @spec.Request) -> @spec.Stream
pub async fn Conn::read(Self, @spec.Stream) -> Bytes?
pub async fn Conn::response(Self, @spec.Stream) -> @spec.Response
pub async fn Conn::send(Self, @spec.Stream, Bytes, end~ : Bool) -> Unit
pub fn Conn::trailers(Self, @spec.Stream) -> Array[@spec.Field]
pub(all) enum Phase

Where an exchange stands.

Idle
Reading
Body
Finished
pub impl @spec.Conn for Conn

moonnet/adapt/h2

HTTP/2, RFC 9113.

pub async fn client(@tcp.Conn, scheme? : String, authority~ : String) -> Conn
pub async fn connect(String, port~ : Int32, tls? : @tls.Client, now? : Int64, authority? : String) -> Conn
pub(all) struct Conn

An HTTP/2 client connection: many exchanges over one connection, each on its own stream, framed as RFC 9113 says.

sock : @tcp.Conn
h2 : @http2.Conn
authority : String
scheme : String
events : Array[@http2.Event]
tails : Map[Int32, Array[@spec.Field]]
mut dead : Bool
pub async fn Conn::close(Self) -> Unit
pub fn Conn::is_ready(Self) -> Bool
pub fn Conn::kind(Self) -> String
pub async fn Conn::open(Self, @spec.Request) -> @spec.Stream
pub async fn Conn::read(Self, @spec.Stream) -> Bytes?
pub async fn Conn::response(Self, @spec.Stream) -> @spec.Response
pub async fn Conn::send(Self, @spec.Stream, Bytes, end~ : Bool) -> Unit
pub fn Conn::trailers(Self, @spec.Stream) -> Array[@spec.Field]
pub impl @spec.Conn for Conn

moonnet/adapt/h3

HTTP/3, RFC 9114, over QUIC.

pub async fn connect(String, port~ : Int32, tls~ : @tls.Client, authority? : String) -> Conn
pub(all) struct Conn

An HTTP/3 client connection: one QUIC connection, a control stream carrying this side's settings, and a bidirectional stream for every exchange (RFC 9114 §6).

quic : @udp.Quic
scheme : String
authority : String
mut next_id : Int32
streams : Map[Int32, UInt64]
held : Map[Int32, Bytes]
body : Map[Int32, Bytes]
heads : Map[Int32, @spec.Response]
tails : Map[Int32, Array[@spec.Field]]
ended : Map[Int32, Bool]
mut dead : Bool
mut quiet : Int64
deadline : Int64
pub async fn Conn::close(Self) -> Unit
pub fn Conn::is_ready(Self) -> Bool
pub fn Conn::kind(Self) -> String
pub async fn Conn::open(Self, @spec.Request) -> @spec.Stream
pub async fn Conn::read(Self, @spec.Stream) -> Bytes?
pub async fn Conn::response(Self, @spec.Stream) -> @spec.Response
pub async fn Conn::send(Self, @spec.Stream, Bytes, end~ : Bool) -> Unit
pub fn Conn::trailers(Self, @spec.Stream) -> Array[@spec.Field]
pub impl @spec.Conn for Conn

moonnet/adapt/ws

WebSocket, RFC 6455.

pub fn client(@tcp.Conn, host~ : String, scheme? : String) -> Conn

A session over a connection that is already open to the server.

pub async fn connect(StringView, tls? : @tls.Client, now? : Int64) -> Conn
pub(all) struct Conn

A WebSocket session over a connection. The exchange is the upgrade: open sends the handshake, response is the 101, and from then on read yields whole messages and send writes them.

sock : @tcp.Conn
scheme : String
host : String
mut target : String
key : String
stream : Int32
mut held : Bytes
reader : @moonbitstack/moonhttp/ws.Reader
mut opened : Bool
mut closed : Bool
mut code : Int32
mut why : String
mut head : @spec.Response?
pub async fn Conn::close(Self) -> Unit
pub fn Conn::close_code(Self) -> Int32

The close code and reason the peer gave, once the session has closed; 0 before.

pub fn Conn::close_reason(Self) -> String

The reason the peer gave with its close, empty when it gave none.

pub fn Conn::is_closed(Self) -> Bool

Whether the session has closed, from either side.

pub fn Conn::is_ready(Self) -> Bool
pub fn Conn::kind(Self) -> String
pub async fn Conn::next(Self) -> @moonbitstack/moonhttp/ws.Message? raise @spec.Refused
pub async fn Conn::open(Self, @spec.Request) -> @spec.Stream
pub async fn Conn::read(Self, @spec.Stream) -> Bytes?
pub async fn Conn::response(Self, @spec.Stream) -> @spec.Response
pub async fn Conn::send(Self, @spec.Stream, Bytes, end~ : Bool) -> Unit
pub async fn Conn::send_binary(Self, Bytes) -> Unit raise @spec.Refused
pub async fn Conn::send_text(Self, String) -> Unit raise @spec.Refused
pub fn Conn::trailers(Self, @spec.Stream) -> Array[@spec.Field]
pub impl @spec.Conn for Conn

moonnet/tcp

TCP, and TLS over it: connections, the listener, the dialler.

pub async fn dial(String, port~ : Int32, tls? : @tls.Client, now? : Int64) -> Conn
pub let handshake : Int32

How long a TLS handshake may take, in milliseconds: asyncio's and hypercorn's 60 seconds. A peer that connects and never finishes holds a connection slot until then.

pub let host : String

The address a server listens on when none is given: loopback only, as uvicorn and Starlette default to, so a development server is not reachable from the network by accident.

pub async fn listen(host? : String, port? : Int32, tls? : @tls.Server, reuse_addr? : Bool, handshake? : Int32?, cleartext? : Bool) -> Listener
pub let port : Int32

The port every server in the family listens on by default.

pub async fn serve(async (Conn, @socket.Addr) -> Unit, host? : String, port? : Int32, tls? : @tls.Server, limit? : Int32, reuse_addr? : Bool, handshake? : Int32?) -> Unit
type Conn

One TCP connection, in the clear or under TLS 1.3. It reads and writes through @io.Reader and @io.Writer either way, so a protocol driver serves both with the same code.

One task may read while another writes. Writes are serialised, so two tasks writing at once put whole messages on the wire, one after the other, and TLS records stay in sequence.

pub async fn Conn::_direct_read(Self, FixedArray[Byte], offset~ : Int32, max_len~ : Int32) -> Int32
pub fn Conn::_get_internal_buffer(Self) -> @io.ReaderBuffer
pub fn Conn::alpn(Self) -> String?

The application protocol ALPN settled on (RFC 7301). None in the clear.

pub async fn Conn::client(@socket.Tcp, @tls.Client, String, rand? : (Int32) -> Bytes, now? : Int64) -> Self
pub fn Conn::close(Self) -> Unit

Close the socket. Call shutdown first for a clean end under TLS.

pub async fn Conn::drop(Self, Int32) -> Int32
pub async fn Conn::is_alive(Self, wait? : Int32) -> Bool
pub fn Conn::is_tls(Self) -> Bool

Whether the connection runs under TLS.

pub async fn Conn::opens_tls(Self) -> Bool
pub fn Conn::peer(Self) -> Array[Bytes]

The certificate chain the peer presented, DER, leaf first. Empty in the clear.

pub fn Conn::plain(@socket.Tcp) -> Self

A connection in the clear.

pub async fn Conn::read(Self, FixedArray[Byte], offset? : Int32, max_len? : Int32) -> Int32
pub async fn Conn::read_all(Self) -> &@io.Data
pub async fn Conn::read_exactly(Self, Int32) -> Bytes
pub async fn Conn::read_some(Self, max_len? : Int32) -> Bytes?
pub async fn Conn::read_until(Self, StringView) -> String?
pub async fn Conn::secure(Self, @tls.Server, rand? : (Int32) -> Bytes, now? : Int64) -> Self
pub async fn Conn::server(@socket.Tcp, @tls.Server, rand? : (Int32) -> Bytes, now? : Int64) -> Self
pub fn Conn::server_name(Self) -> String?

The host name the client asked for (RFC 6066 §3). None in the clear.

pub async fn Conn::shutdown(Self) -> Unit
pub async fn Conn::starts_with(Self, BytesView) -> Bool
pub fn Conn::tls(Self) -> @tls.Conn?

The TLS connection underneath, for what the accessors here do not say: the suite, the key update, the refusal reason. None in the clear.

pub async fn Conn::upgrade(Self, @tls.Client, String, rand? : (Int32) -> Bytes, now? : Int64) -> Self
pub async fn Conn::write(Self, &@io.Data) -> Unit
pub async fn Conn::write_once(Self, Bytes, offset~ : Int32, len~ : Int32) -> Int32
pub async fn Conn::write_reader(Self, &@io.Reader) -> Unit
type Listener

A bound, listening socket. Connections queue from the moment listen returns, so a caller can connect to it, or hand its port out, without racing the server.

pub async fn Listener::accept(Self) -> (Conn, @socket.Addr)
pub fn Listener::addr(Self) -> @socket.Addr

The address listened on; with port 0 asked for, the port the system chose.

pub fn Listener::close(Self) -> Unit

Stop listening.

pub async fn Listener::serve(Self, async (Conn, @socket.Addr) -> Unit, limit? : Int32) -> Unit
pub(all) suberror Refused

What a connection will not do.

Secured

secure or upgrade on a connection that is TLS already.

pub impl @io.Reader for Conn
pub impl @io.Writer for Conn

moonnet/udp

The datagram socket, and the client end of a QUIC connection.

pub async fn bind(host? : String, port? : Int32) -> Socket
pub async fn dial(String, port~ : Int32, tls~ : @tls.Client, idle? : UInt64) -> Quic
pub fn now() -> Int64

The clock QUIC counts in, milliseconds since the epoch.

pub(all) struct Quic

A QUIC connection driven by one task: the client half of what moonquic states and this package puts on a datagram socket. Reading is a poll, because a connection that also carries control and QPACK streams cannot hand every arrival to one caller.

socket : Socket
to : @socket.Addr
client : @conn.Client
mut bi : UInt64
mut uni : UInt64
mut dead : Bool
seen : Map[UInt64, Bool]
pub fn Quic::alpn(Self) -> String?

The ALPN the handshake settled on.

pub fn Quic::close(Self) -> Unit

Close the socket the connection runs on.

pub fn Quic::ended(Self, UInt64) -> Bool

Whether the peer has ended stream, with every octet of it read.

pub fn Quic::open_bi(Self) -> UInt64

The next bidirectional stream this side opens: 0, 4, 8, … as RFC 9000 §2.1 numbers them.

pub fn Quic::open_uni(Self) -> UInt64

The next unidirectional stream, from 2 upwards.

pub async fn Quic::step(Self, timeout? : Int32) -> Bool raise QuicRefused
pub fn Quic::take(Self, UInt64) -> Bytes

The octets that arrived on stream since the last call; empty when none have.

pub fn Quic::write(Self, UInt64, Bytes, fin? : Bool) -> Unit

Put bytes on stream, and end it when fin.

pub(all) suberror QuicRefused

What a QUIC connection will not do.

Timeout

The handshake did not complete in the time this waited.

Broken(String)

The socket or the connection under it failed.

Closed

The connection is over.

pub(all) struct Socket

A datagram socket. One task may receive while others send; two tasks receiving at once would each take half the datagrams, so a connection that needs one reader keeps one.

sock : @socket.UdpServer
pub fn Socket::addr(Self) -> @socket.Addr

The address bound; with port 0 asked for, the port the system chose.

pub fn Socket::close(Self) -> Unit

Stop using the socket.

pub async fn Socket::recv(Self, max? : Int32, timeout? : Int32) -> (Bytes, @socket.Addr)?
pub async fn Socket::send(Self, @socket.Addr, Bytes) -> Unit

moonnet/pool

Connections kept by host, port and ALPN.

pub let defaults : Config

The presets: an idle connection lives half a minute, a key keeps eight, the pool holds sixty-four, a reused one is peeked at, and a caller waits five seconds for a slot. These are the values curl and Go's transport settle near; what matters more is that all five are named and can be changed.

pub(all) struct Config

How a pool behaves. Every one of these is a number a caller will want to change, so all of them are here rather than in the code.

idle : Int32
max_idle : Int32
max_total : Int32
liveness : Liveness
wait : Int32
pub(all) struct Idle

A connection in the pool and the moment it stops being worth reusing.

conn : @tcp.Conn
until : Int64
pub(all) struct Key

What makes two connections interchangeable: the host, the port, and the protocol ALPN settled on. A connection kept under one key is never handed out for another.

host : String
port : Int32
alpn : String
pub fn Key::new(String, Int32, alpn~ : String) -> Self
pub(all) enum Liveness

What a reused connection is asked before it is handed out again.

None_

Nothing: a connection that served an exchange is taken on trust until the next one fails, which is what most clients do.

Peek

A read that does not wait. A peer that has closed is dropped; one that has said something while idle keeps what it said for the next exchange.

pub(all) struct Pool

The connections kept for another exchange. A caller takes one with get and gives it back with put, or closes it and takes another next time; a connection that is not given back is not counted as idle and stays against max_total.

dial : async (Key) -> @tcp.Conn
config : Config
mut idle : Map[String, Array[Idle]]
mut total : Int32
changed : @cond_var.Cond
mut closed : Bool
pub fn Pool::close(Self) -> Unit

Close every idle connection and refuse further use.

pub async fn Pool::get(Self, Key) -> @tcp.Conn raise Refused
pub fn Pool::idle(Self, Key) -> Int32

How many connections are idle under key.

pub fn Pool::new(async (Key) -> @tcp.Conn, config? : Config) -> Self

A pool that opens a connection with dial when it has none to hand out.

pub fn Pool::put(Self, Key, @tcp.Conn) -> Unit

Put a connection back for the next exchange. A pool that is closed, or that already keeps max_idle for this key, closes it instead; either way it stops counting against max_total.

pub fn Pool::total(Self) -> Int32

How many connections the pool holds open, in use or idle.

pub(all) suberror Refused

What a pool will not do.

Busy

The pool is full and no slot came free in time.

Closed

The pool was closed.

Failed(String)

Opening a connection failed.

moonnet

The front door: one import for the connection, the datagram socket and the contract.

pub async fn bind(host? : String, port? : Int32) -> @udp.Socket
pub async fn connect(StringView, alpn? : Array[String], roots? : @x509.Roots, now? : Int64) -> Opened
pub async fn dial(String, port~ : Int32, tls? : @tls.Client, now? : Int64) -> @tcp.Conn
pub async fn listen(host? : String, port? : Int32, tls? : @tls.Server, reuse_addr? : Bool, handshake? : Int32?, cleartext? : Bool) -> @tcp.Listener
pub async fn serve(async (@tcp.Conn, @socket.Addr) -> Unit, host? : String, port? : Int32, tls? : @tls.Server, limit? : Int32, reuse_addr? : Bool, handshake? : Int32?) -> Unit
pub(all) struct Opened

What connect settled on.

conn : @tcp.Conn
alpn : String
target : String