Http

struct RequestLine

A request's first line, split.

struct RequestHead

A request's head, before its body has been read. leftover_body carries the bytes that arrived alongside the headers.

let request (method: String) (url: String) (headers: Array[Header]) (body: Bytes): Result[Response, String]

Sends a request with a raw byte body over HTTP or HTTPS. Encode text with String.as_bytes(); decode the reply with Response.text. Reads use bounded chunks, but the complete body is buffered in memory. There is currently no total header/body size limit or streaming API.

Sends a request over HTTP or HTTPS. HTTPS verifies the peer's certificate and hostname using the native TLS trust-store integration.

Invalid URL text, methods, header names, and header values return Err before connecting. Caller Host, Content-Length and Transfer-Encoding fields are rejected: the builder owns authority and framing. Methods and names must be nonempty ASCII tokens; values may contain spaces, HTAB, and UTF-8, but no other ASCII controls or DEL. Bodies are not subject to protocol-field validation.

Reads past up to 100 informational responses to the final response. HEAD, 204, and 304 responses have an empty body regardless of framing headers. Protocol upgrades (101) and successful CONNECT tunnels return Err and close the connection; this API cannot hand off a transport.

let get (url: String): Result[Response, String]

Fetches a URL and reads the whole response.

Supports both http:// and https://; HTTPS uses the native TLS transport with platform trust-store and hostname verification.

Redirects are NOT followed: a 301 or 302 comes back as itself, with its Location header, so the caller decides. Following one changes which host you are talking to, which is not a decision a library should make quietly.

let post (url: String) (body: Bytes): Result[Response, String]

POSTs raw bytes and reads the whole response. For text, pass text.as_bytes() and use Response.text on the result. Sets Content-Length; set Content-Type yourself if the server needs one.

Redirects are not followed — see Http.get.

let serve_once (port: Int) (handler: (Request) -> Response): Result[Unit, String]

Handles exactly ONE connection then returns — listens, accepts once, closes both the connection and the listening socket, and gives back whatever http_handle_connection produced. Invalid handler headers return Err without writing response bytes; the connection is closed. Status codes must be 200..599: informational-only handler responses and successful CONNECT tunnels return Err without writing response bytes. HEAD, 204, and 304 suppress the handler's body. HEAD reports its byte length; 204 and 304 omit Content-Length. Caller Content-Length and Transfer-Encoding fields are replaced by this generated framing. Malformed request lines/fields and missing (HTTP/1.1), duplicate, or invalid Host fields receive 400 before body reading or handler dispatch, then return Err. Ambiguous, invalid, or unsupported body framing also receives 400 before reading content or dispatching the handler. Repeated or comma-separated Content-Length values must all agree and use decimal digits within Int range. Requests without framing have an empty body; bytes beyond a declared length are excluded from that request's body. HTTP/1.1 Expect: 100-continue is acknowledged before waiting for content; unsupported expectations receive 417. HTTP/1.0 expectations are ignored. HTTP/1.0 may omit Host. Present Host values use URI host syntax, including empty values, IP literals, and optional decimal ports. Real, useful on its own (a one-shot server, or a test fixture — this is what THIS module's own tests exercise directly), not just a building block for http_ serve below.

let serve (port: Int) (handler: (Request) -> Response): Result[Unit, String]

Serves HTTP on a port, calling handler once per request, forever.

Never returns unless listening or accepting fails. Connections run concurrently. Invalid handler headers close that connection without sending a response; other connections continue to be served. Invalid request heads receive 400 and close, as described by serve_once.