Module http/server

http/server
Stability: unstable — the SHAPE (one connection at a time, one request per connection, `Connection: close` on every response) is expected to change when a connection loop / keep-alive lands; `bind`, `local_addr`, `with_max_request_bytes`, `serve`, `serve_once`, `stop` and `close` are intended to keep their names and meanings. — stable modules only change additively; this one may still change.

Minimal HTTP/1.1 server on TcpListener (plans/archive/STD_API_AUDIT.md §7 P1).

One connection at a time, one request per connection (Connection: close is added to every response) — the shape a CLI, a test fixture or a local tool needs; it shares its wire code (std/http/wire.yo) with the client, so request bodies may be Content-Length or chunked.

{ HttpServer, HttpResponse } :: import "std/http";
server := io.await(HttpServer.bind(SocketAddr.loopback(u16(8080)), io), e);
io.await(server.serve((req) -> HttpResponse.with_status(StatusCode.OK()).with_body(`hi ${req.path}`), io), e);

serve runs until stop() is called (checked after each connection) — from another task, or from the handler itself. serve_once handles exactly one connection, which is what a test wants.

A client's mistake never takes the server down: a request that does not parse gets 400, one that exceeds max_request_bytes gets 413, one with broken framing (Content-Length that is not a number, malformed chunking) gets 400 — and serve goes on to the next connection. An I/O failure on the accepted socket itself still propagates out of serve.

Stability

unstable — the SHAPE (one connection at a time, one request per connection, Connection: close on every response) is expected to change when a connection loop / keep-alive lands; bind, local_addr, with_max_request_bytes, serve, serve_once, stop and close are intended to keep their names and meanings.

Types

HttpServer object
HttpServer

An HTTP/1.1 server bound to a TcpListener.

Fields

NameTypeDescription
listenerTcpListener
max_request_bytesusize

Requests larger than this are answered with 413 Payload Too Large and the connection closed; serve keeps going (0 lifts the ceiling).

stoppedbool
impl(HttpServer, ...)
bind : (HttpServer) fn(addr : SocketAddr, io : Io) -> Impl : (Future[Future](HttpServer) IoExn : IoExn)

Bind a listening socket on addr (port 0 picks a free port — read it back with local_addr()).

Parameters

NameTypeNotes
addrSocketAddr
ioIo

Returns: Impl : (Future[Future](HttpServer) IoExn : IoExn)

local_addr : (HttpServer) fn(self : HttpServer) -> SocketAddr

The address the server is listening on.

Parameters

NameTypeNotes
selfHttpServer

Returns: SocketAddr

with_max_request_bytes : (HttpServer) fn(self : HttpServer, n : usize) -> HttpServer

Set the request-size ceiling (builder pattern; 0 = unlimited).

Parameters

NameTypeNotes
selfHttpServer
nusize

Returns: HttpServer

serve_once : (HttpServer) fn(self : HttpServer, handler : Impl : (Fn(HttpRequest) -> HttpResponse), io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)

Accept ONE connection, read one request, run handler, write the response and close. A request that does not parse gets a 400 Bad Request whose body names the defect, without calling handler; a framing defect (oversize, unreadable Content-Length, malformed chunking) is answered the same way (413 for oversize) instead of being thrown out of the server (issues/fixed/one-malformed-request-killed-http-server-serve.md).

Parameters

NameTypeNotes
selfHttpServer
handlerImpl : (Fn(HttpRequest) -> HttpResponse)
ioIo

Returns: Impl : (Future[Future](unit) IoExn : IoExn)

serve : (HttpServer) fn(self : HttpServer, handler : Impl : (Fn(HttpRequest) -> HttpResponse), io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)

Serve connections one after another until stop() has been called (checked after each connection completes).

Parameters

NameTypeNotes
selfHttpServer
handlerImpl : (Fn(HttpRequest) -> HttpResponse)
ioIo

Returns: Impl : (Future[Future](unit) IoExn : IoExn)

stop : (HttpServer) fn(self : HttpServer) -> unit

Ask serve to return after the connection it is currently handling.

Parameters

NameTypeNotes
selfHttpServer

Returns: unit

close : (HttpServer) fn(self : HttpServer, io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)

Close the listening socket.

Parameters

NameTypeNotes
selfHttpServer
ioIo

Returns: Impl : (Future[Future](unit) IoExn : IoExn)

Constants

DEFAULT_MAX_REQUEST_BYTES constant usize

Default ceiling on a request (headers + body): 16 MiB.

Value: 16777216