Scarlet Industries

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.