HTTP Server

Stone provides the server module for building HTTP servers. This module is only available in native (LLVM) builds — it does not work in the browser/WASM backend.

Quick Start

import server

s = server.serve(8080)
print("Listening on port 8080")

while (true) {
    req = server.await_request(s)
    server.send_response(req, {status = 200, body = "Hello!"})
}

Build and run:

stone build my_server.stn --target llvm
clang -O3 my_server.ll stone_runtime.c stone_server.c -lm -lws2_32 -o my_server.exe  # Windows
clang -O3 my_server.ll stone_runtime.c stone_server.c -lm -o my_server                # Linux/macOS
./my_server

server.serve()

Create an HTTP server listening on a port. Returns a server handle.

import server

s = server.serve(3000)

The server binds to 0.0.0.0 (all interfaces) on the given port. It sets SO_REUSEADDR so you can restart quickly after stopping. On Unix, SIGPIPE is ignored so writing to closed connections won't kill the process.

server.await_request()

Block until an HTTP request arrives. Returns a request record.

req = server.await_request(s)

print(req.method)   // "GET", "POST", etc.
print(req.path)     // "/api/hello"
print(req.body)     // Request body (empty string for GET)

Request Record

FieldTypeDescription
methodstringHTTP method ("GET", "POST", etc.)
pathstringRequest path ("/hello", "/api/users")
bodystringRequest body (empty string if none)
_fdnumInternal connection file descriptor

The function reads the full HTTP request including headers and body (via Content-Length). Maximum request size is 64 KB.

server.send_response()

Send an HTTP response and close the connection.

server.send_response(req, {status = 200, body = "Hello from Stone!"})

Response Record

FieldTypeDefaultDescription
statusnum200HTTP status code
bodystring""Response body

Supported status codes with text: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 500 Internal Server Error. Other codes default to "OK" as status text.

The response is sent with Content-Type: text/plain and Connection: close. The connection is closed after sending.

server.stop()

Close the listening server socket.

server.stop(s)

On Windows, this also cleans up the Winsock subsystem.

Routing Example

Use if/elif on the request path and method to route requests:

import server

s = server.serve(8080)
print("Server running on port 8080")

while (true) {
    req = server.await_request(s)

    response = if (req.path == "/hello") {
        {status = 200, body = "Hello from Stone!"}
    } elif (req.path == "/health") {
        {status = 200, body = "OK"}
    } elif (req.path == "/echo" and req.method == "POST") {
        {status = 200, body = req.body}
    } else {
        {status = 404, body = "Not found"}
    }

    server.send_response(req, response)
}

Test with curl:

curl http://localhost:8080/hello        # "Hello from Stone!"
curl http://localhost:8080/health       # "OK"
curl -X POST -d "hi" localhost:8080/echo  # "hi"
curl http://localhost:8080/nope         # "Not found" (404)

Platform Support

The server module uses POSIX sockets on Linux/macOS and Winsock on Windows. On Windows, link with -lws2_32. The module compiles cross-platform from the same stone_server.c source.

Notes

Import server before calling any server functions. The module only works in LLVM/native builds — calling any server function in the WASM/browser backend throws "server module is only available in native (LLVM) builds". Each await_request blocks the entire program until a connection arrives. Connections are Connection: close (no keep-alive). No chunked transfer encoding — body size is determined by Content-Length.