The HTTP server
A handler is a plain fn(Request) Response. The library owns the parsing,
keep-alive, pipelining, and body framing, and runs each connection in its own process.
Handlers
Everything the parser hands a handler is a zero-copy slice of the bytes that came off the socket.
pub type Method {
Get
Post
Put
Delete
Patch
Head
Options
Other(name Binary)
}
pub type Request {
method Method
target Binary
version Version
headers Headers
flags HeadFlags
trailers Headers
body Body
}
pub type Response {
status Int
headers Headers
body ResponseBody
}
Route on the method and the path, both matched as values: the method is an enum, the
path a Binary matched against byte literals.
fn route(req Request) Response {
match req.method {
Get -> match http.path(req) {
<<'/'>> -> http.text('scarlet http server')
_ -> http.not_found()
}
_ -> http.not_found()
}
}
pub fn main() {
match http.serve('0.0.0.0', 8080, route) {
Ok(_) -> println('Listening on http://localhost:8080')
Err(e) -> println('serve failed: ${e}')
}
}
http.path and http.query split the request target as O(1)
slices. http.text(s) builds a text/plain response with the length pinned;
http.ok(b) wraps a body; http.not_found() is a 404;
http.with_header sets a field, replacing any duplicate.
body.collect(req.body, max) buffers a request body, bounded.
Responses
A ResponseBody is Fixed(len, b) or Unsized(b).
Fixed promises exactly len bytes; the driver emits the
Content-Length header itself and verifies the stream delivered that many.
Unsized makes no promise and the driver frames it at send time. A handler
cannot desync the connection by advertising one length and writing another.
Limits
The driver reads a request body into a bounded buffer before the handler runs. A body
over the cap (1 MB by default) is refused with 413 before a byte is read, and head and
body reads each carry a 30000 ms absolute deadline that a byte-dribbling peer cannot
reset. http.serve returns as soon as the acceptors are running; they keep
the program alive.
TCP underneath
Beneath it, scarlet/net and scarlet/net/socket expose TCP
directly: read_exact reads until it has the bytes it was promised or errs
with UnexpectedEof, read_within and read_until
bound a read by timeout or shared deadline, and write_parts sends several
binaries in one vectored syscall.
To reach an HTTPS peer rather than serve one, see the TLS client.