struct HttpServerA blocking HTTP/1.1 server with exact-path GET routing.
Routes are prepended, so later registrations shadow earlier equal paths. Each accepted connection serves one request of at most 8192 bytes and then closes. This is a minimal server, not a streaming or production HTTP stack.
Properties
let routes: RouteNode?
The head of the reverse-registration-order route chain.
Methods
mut func get(consume path: String, consume handler: () -> String) -> ()
Registers an exact-path GET handler; later registrations take precedence.
View Source
pub mut func get(consume path: String, consume handler: () -> String) -> () {
let wrapped = RouteHandler(invoke: handler)
let node = RouteNode(path: path, handler: wrapped, next: self.routes)
self.routes = Optional.some(node)
self.route_count = self.route_count + 1
()
}func dispatch(path: Substring) -> Response
Invokes the first exact-path route, returning a 404 response when none matches.
View Source
pub func dispatch(path: Substring) -> Response {
route_walk(current: self.routes, path: path)
}func render(response: Response) -> String
Serializes a response as HTTP/1.1 plain text.
Status text is defined for 200 and 404; all other codes use Error. The byte count, not grapheme count, becomes Content-Length, and every response advertises connection close.
View Source
pub func render(response: Response) -> String {
let text: String = match response.status {
200 -> "OK",
404 -> "Not Found",
_ -> "Error"
}
let status_line_a: String = "HTTP/1.1 ".add(response.status.show())
let status_line_b: String = status_line_a.add(" ")
let status_line_c: String = status_line_b.add(text)
let status_line: String = status_line_c.add("\r\n")
let content_type = "Content-Type: text/plain; charset=utf-8\r\n"
let content_length_a: String = "Content-Length: ".add(
response.body.byte_count.show()
)
let content_length: String = content_length_a.add("\r\n")
let connection = "Connection: close\r\n"
let wire_a: String = status_line.add(content_type)
let wire_b: String = wire_a.add(content_length)
let wire_c: String = wire_b.add(connection)
let wire_d: String = wire_c.add("\r\n")
wire_d.add(response.body)
}func handle(raw_request: String) -> String
Handles one raw GET request; unsupported methods and unknown paths return 404.
View Source
pub func handle(raw_request: String) -> String {
let method: Substring = self.extract_method(raw_request: raw_request)
if method.equals_string("GET") == false { return self.render(
response: Response(status: 404, body: "Not Found")
) }
let path: Substring = self.extract_path(raw_request: raw_request)
self.render(response: self.dispatch(path: path))
}func run(port: Int) -> ()
Runs forever on all IPv4 interfaces using a blocking accept loop.
Connections are handled serially, one request each, with an 8192-byte read cap. Socket setup and I/O errors currently surface only through raw host results; there is no graceful shutdown path.
View Source
pub func run(port: Int) -> () {
#unsafe {
let listener_fd = _io_socket(domain: AF_INET, socktype: SOCK_STREAM, proto: 0)
_io_bind(fd: listener_fd, addr: 0, port: port)
_io_listen(fd: listener_fd, backlog: 128)
loop {
let client_fd = _io_accept(fd: listener_fd)
if client_fd < 0 {
continue
}
let max_request_size = 8192
let buf = _alloc<Byte>(count: max_request_size)
let n = _io_read(fd: client_fd, buf: buf, count: max_request_size)
if n <= 0 {
_io_close(fd: client_fd)
continue
}
let n = _io_clamp(count: n, capacity: max_request_size)
let raw_request = String(
base: ByteStorage(base: buf),
byte_count: n,
capacity: max_request_size
)
let wire = self.handle(raw_request: raw_request)
_io_write(fd: client_fd, buf: wire.storage.base, count: wire.byte_count)
_io_close(fd: client_fd)
}
}
}