Module http/server
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
An HTTP/1.1 server bound to a TcpListener.
Fields
| Name | Type | Description |
|---|---|---|
listener | TcpListener | |
max_request_bytes | usize | Requests larger than this are answered with |
stopped | bool |
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
| Name | Type | Notes |
|---|---|---|
addr | SocketAddr | |
io | Io |
Returns: Impl : (Future[Future](HttpServer) IoExn : IoExn)
local_addr : (HttpServer) fn(self : HttpServer) -> SocketAddrwith_max_request_bytes : (HttpServer) fn(self : HttpServer, n : usize) -> HttpServerSet the request-size ceiling (builder pattern; 0 = unlimited).
Parameters
| Name | Type | Notes |
|---|---|---|
self | HttpServer | |
n | usize |
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
| Name | Type | Notes |
|---|---|---|
self | HttpServer | |
handler | Impl : (Fn(HttpRequest) -> HttpResponse) | |
io | Io |
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
| Name | Type | Notes |
|---|---|---|
self | HttpServer | |
handler | Impl : (Fn(HttpRequest) -> HttpResponse) | |
io | Io |
stop : (HttpServer) fn(self : HttpServer) -> unitAsk serve to return after the connection it is currently handling.
Parameters
| Name | Type | Notes |
|---|---|---|
self | HttpServer |
Returns: unit
close : (HttpServer) fn(self : HttpServer, io : Io) -> Impl : (Future[Future](unit) IoExn : IoExn)Constants
Default ceiling on a request (headers + body): 16 MiB.
Value: 16777216