Practical recipes for common tasks. Each example is a complete, working program or a self-contained pattern you can paste into your project.
A minimal HTTP server that serves JSON responses with routing:
#[derive(json)]
struct Health {
ok: bool
version: string
}
fn handle_health(c: int) {
let body = "{\"ok\":true,\"version\":\"0.1.0\"}\n"
let _ = http_respond_ct(c, 200, "application/json", body)
}
fn handle_create_user(c: int) {
let body = http_body(c)
// Parse and validate the request body
let name = json_get_string(body, "name")
if str_eq(name, "") {
let _ = http_respond_ct(c, 400, "application/json",
"{\"error\":\"name required\"}\n")
return
}
let response = json_ss("name", name)
let _ = http_respond_ct(c, 201, "application/json", response)
}
fn main() {
let port = 8080
let fd = http_bind(port)
if fd < 0 {
print("bind failed")
return
}
print("listening on :8080")
let mut running = true
while running {
let c = http_accept(fd)
if c < 0 {
continue
}
let method = http_method(c)
let path = http_path(c)
if str_eq(path, "/health") {
handle_health(c)
} else {
if str_eq(method, "POST") and str_eq(path, "/users") {
handle_create_user(c)
} else {
let _ = http_respond(c, 404, "{\"error\":\"not found\"}\n")
}
}
let _ = http_close(c)
}
let _ = http_close_listener(fd)
}
Build and test:
mako build api.mko -o out/api
out/api &
curl -s http://127.0.0.1:8080/health
# {"ok":true,"version":"0.1.0"}
curl -s -X POST -d '{"name":"Ada"}' http://127.0.0.1:8080/users
# {"name":"Ada"}
A single-client WebSocket echo that upgrades HTTP and echoes text frames:
fn main() {
let code = ws_echo_once(18092)
print_int(code)
}
The ws_echo_once builtin handles the RFC 6455 upgrade handshake, reads one
text frame, echoes it back, and closes the connection. For a multi-client loop:
fn main() {
let port = 18092
let mut i = 0
while i < 10 {
let code = ws_echo_once(port)
if code < 0 {
break
}
i = i + 1
}
print("ws server done")
}
Test with a WebSocket client:
mako build ws_server.mko -o out/ws_server
out/ws_server &
echo "hello" | websocat ws://127.0.0.1:18092
# hello
fn main() {
// Write a file
let path = "/tmp/mako_example.txt"
let _ = write_file(path, "hello from mako\n")
// Read it back
let content = read_file(path)
print(content)
// Append to a file
let log_path = "/tmp/mako_log.txt"
let _ = append_file(log_path, "line 1\n")
let _ = append_file(log_path, "line 2\n")
// Check existence
if file_exists(path) {
print("file exists")
}
// Directory operations
let _ = mkdir("/tmp/mako_dir")
if is_dir("/tmp/mako_dir") {
print("dir created")
}
// Clean up
let _ = remove_file(path)
let _ = remove_file(log_path)
}
fn load_config(path: string) -> Result[string, string] {
if not file_exists(path) {
return error("config file not found: " + path)
}
let content = read_file(path)
if str_eq(content, "") {
return error("config file is empty")
}
return Ok(content)
}
fn main() {
match load_config("app.toml") {
Ok(c) => print(c),
Err(e) => {
log_error(e)
}
}
}
fn main() {
let a = args()
let n = argc()
if n < 2 {
print("usage: app <command> [options]")
exit(1)
}
let cmd = arg_get(1)
if str_eq(cmd, "serve") {
let mut port = 8080
if n > 2 {
match parse_int(arg_get(2)) {
Ok(v) => { port = v }
Err(_) => {
print("invalid port")
exit(1)
}
}
}
print("serving on port:")
print_int(port)
} else {
if str_eq(cmd, "version") {
print("app v0.1.0")
} else {
if str_eq(cmd, "help") {
print("commands: serve, version, help")
} else {
print("unknown command: " + cmd)
exit(1)
}
}
}
}
mako run cli.mko -- serve 9090
# serving on port:
# 9090
mako run cli.mko -- version
# app v0.1.0
fn main() {
let db = "/tmp/mako_app.sqlite"
// Create table
let _ = sqlite_query_int(db, "create table if not exists users(id integer primary key, name text, age integer)")
// Insert
let _ = sqlite_query_int(db, "insert into users(name, age) values ('Ada', 36)")
let _ = sqlite_query_int(db, "insert into users(name, age) values ('Bob', 28)")
// Read
let count = sqlite_query_int(db, "select count(*) from users")
print("user count:")
print_int(count)
let name = sqlite_query_text(db, "select name from users where age > 30 limit 1")
print("first user over 30: " + name)
// Update
let _ = sqlite_query_int(db, "update users set age = 37 where name = 'Ada'")
// Delete
let _ = sqlite_query_int(db, "delete from users where name = 'Bob'")
// Verify
let final_count = sqlite_query_int(db, "select count(*) from users")
print("final count:")
print_int(final_count)
// Clean up
let _ = remove_file(db)
}
Use sql_exec_str4 for text inserts and sql_query_str for text lookups via
the unified SqlDB handle:
fn main() {
let db = sql_open_sqlite("/tmp/mako_crud.db")
// Create table (no parameters needed)
let _ = sql_exec_plain(db, "CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT, email TEXT, role TEXT, team TEXT)")
// Insert rows with string parameters
let _ = sql_exec_str4(db, "INSERT INTO users(name, email, role, team) VALUES ($1, $2, $3, $4)", "Ada", "ada@example.com", "engineer", "platform")
let _ = sql_exec_str4(db, "INSERT INTO users(name, email, role, team) VALUES ($1, $2, $3, $4)", "Grace", "grace@example.com", "lead", "infra")
// Query a single text value
let role = sql_query_str(db, "SELECT role FROM users WHERE name = $1", "Ada")
print(role) // engineer
// Update with string params (unused params can be empty strings)
let _ = sql_exec_str4(db, "UPDATE users SET role = $1 WHERE name = $2", "senior engineer", "Ada", "", "")
// Verify update
let updated = sql_query_str(db, "SELECT role FROM users WHERE name = $1", "Ada")
print(updated) // senior engineer
// Delete
let _ = sql_exec_plain(db, "DELETE FROM users WHERE name = 'Grace'")
sql_close(db)
let _ = remove_file("/tmp/mako_crud.db")
}
fn main() {
let handle = pg_connect("host=127.0.0.1 port=5432 dbname=mydb")
if pg_ok(handle) == 0 {
print("postgres not available")
return
}
let _ = pg_exec(handle, "create table if not exists items(id serial, name text)")
let _ = pg_exec(handle, "insert into items(name) values ('mako')")
let rows = pg_exec_row_count(handle, "select * from items")
print_int(rows)
pg_close(handle)
}
Process items in parallel using a crew with multiple kicked jobs:
fn process_item(id: int) -> int {
// Simulate work
sleep_ms(10)
return id * id
}
fn main() {
let items = [1, 2, 3, 4, 5, 6, 7, 8]
let n = len(items)
// Channel to collect results
let results = chan_new(n)
crew t {
// Kick one job per item
for i in range items {
let _ = t.kick(worker(results, items[i]))
}
}
// Collect results
let mut total = 0
for _ in range items {
let v = results.recv()
total = total + v
}
print("total:")
print_int(total)
}
fn worker(out: chan[int], item: int) -> int {
let result = process_item(item)
let _ = out.send(result)
return 0
}
fan for Simple Data ParallelismWhen each item maps independently to a result:
fn main() {
let xs = [1, 2, 3, 4, 5, 6, 7, 8]
let squares = fan(xs, |x| x * x)
for v in squares {
print_int(v)
}
}
fan distributes work across available cores automatically.
Use CMap as a shared cache across worker tasks -- no channels or mutexes needed:
fn fetch_and_cache(cache: CMap, key: string) -> int {
// Check cache first
if cmap_has(cache, key) == 1 {
return 0
}
// Simulate expensive computation
sleep_ms(10)
let value = "result_for_" + key
cmap_set(cache, key, value)
let _ = cmap_incr(cache, "misses", 1)
return 1
}
fn main() {
let cache = cmap_new()
let keys = ["user:1", "user:2", "user:3", "user:1", "user:2"]
crew t {
for i in range keys {
let _ = t.kick(fetch_and_cache(cache, keys[i]))
}
}
// After all workers complete:
print(cmap_get(cache, "user:1")) // "result_for_user:1"
print(cmap_get(cache, "user:2")) // "result_for_user:2"
print(cmap_get(cache, "user:3")) // "result_for_user:3"
print_int(cmap_len(cache)) // 4 (3 keys + "misses" counter)
print_int(cmap_incr(cache, "misses", 0)) // 3 (read counter)
}
CMap handles all synchronization internally. Multiple tasks can read and write
the same keys concurrently. Use cmap_incr for atomic counters (e.g., cache
hit/miss stats).
For server workloads, allocate all per-request memory from an arena:
struct Request {
method: string
path: string
body: string
}
struct Response {
status: int
body: string
}
fn handle(req: Request) -> Response {
if str_eq(req.path, "/health") {
return Response { status: 200, body: "{\"ok\":true}\n" }
}
return Response { status: 404, body: "not found\n" }
}
fn main() {
let fd = http_bind(8080)
if fd < 0 {
return
}
let mut n = 0
while n < 100 {
arena a {
let c = http_accept(fd)
if c >= 0 {
// All temporary allocations live in the arena
let mut headers = make([]string, 0, 16)
let mut buf = make([]byte, 0, 4096)
let req = Request {
method: http_method(c),
path: http_path(c),
body: http_body(c),
}
let resp = handle(req)
let _ = http_respond(c, resp.status, resp.body)
let _ = http_close(c)
n = n + 1
}
}
// Arena freed here -- one deallocation per request
}
let _ = http_close_listener(fd)
}
? Operator for Propagationfn read_config(path: string) -> Result[string, string] {
if not file_exists(path) {
return error("file not found: " + path)
}
return Ok(read_file(path))
}
fn parse_port(config: string) -> Result[int, string] {
match parse_int(config) {
Ok(v) => {
if v < 1 or v > 65535 {
return error("port out of range")
}
return Ok(v)
}
Err(e) => return error("invalid port number")
}
}
fn load_port(path: string) -> Result[int, string] {
let content = read_config(path)? // propagates Err automatically
let port = parse_port(content)? // same here
return Ok(port)
}
fn main() {
match load_port("/tmp/port.txt") {
Ok(p) => {
print("port:")
print_int(p)
}
Err(e) => {
log_error(e)
exit(1)
}
}
}
fn connect_db(url: string) -> Result[int, string] {
let handle = pg_connect(url)
if pg_ok(handle) == 0 {
return error("connection failed")
}
return Ok(handle)
}
fn init_app() -> Result[int, string] {
let db = wrap_err(connect_db("host=localhost dbname=app"), "init_app")?
return Ok(db)
}
fn main() {
match init_app() {
Ok(db) => print("connected"),
Err(e) => {
// e is "init_app: connection failed"
log_error(e)
}
}
}
error_isfn main() {
let e = errorf("missing %s", "config.toml")
if error_is(e, "config.toml") {
print("config error detected")
}
let msg = error_string(wrap_err(e, "startup"))
print(msg) // "startup: missing config.toml"
}
#[derive(json)]#[derive(json)]
struct User {
name: string
age: int
}
#[derive(json)]
struct Address {
city: string
zip: int
}
fn main() {
// Serialize
let user_json = User_to_json("Ada", 36)
print(user_json)
// {"name":"Ada","age":36}
// Deserialize fields
let name = User_name_from_json(user_json)
let age = User_age_from_json(user_json)
print(name)
print_int(age)
// Nested JSON
let addr_json = Address_to_json("Paris", 75001)
let nested = json_nest("address", addr_json)
let doc = json_merge(user_json, nested)
print(doc)
// Extract nested field
let city = json_path_string(doc, "address", "city")
print(city) // "Paris"
}
fn main() {
// Array of ints
let nums = json_array_ints3(10, 20, 30)
let more = json_array_push_int(nums, 40)
print(more)
// Array of strings
let names = json_array_strings2("alice", "bob")
let all = json_array_push_string(names, "carol")
print(all)
// Object from map
let mut m = make(map[string]string, 4)
m["host"] = "localhost"
m["port"] = "8080"
let obj = json_object_from_map_ss(m)
print(obj)
}
Chain producers and consumers through channels:
fn generate(out: chan[int], n: int) -> int {
for i in range n {
let _ = out.send(i + 1)
}
out.close()
return n
}
fn square(input: chan[int], out: chan[int]) -> int {
let mut count = 0
for v in range input {
let _ = out.send(v * v)
count = count + 1
}
out.close()
return count
}
fn sum_all(input: chan[int]) -> int {
let mut total = 0
for v in range input {
total = total + v
}
return total
}
fn main() {
let ch1 = chan_new(8)
let ch2 = chan_new(8)
crew t {
let _ = t.kick(generate(ch1, 5))
let _ = t.kick(square(ch1, ch2))
let result = t.kick(sum_all(ch2))
let total = result.join()
print("sum of squares 1..5:")
print_int(total) // 1+4+9+16+25 = 55
}
}
Multiplexing multiple channels with a timeout:
fn delayed_send(ch: chan[int], val: int, ms: int) -> int {
sleep_ms(ms)
let _ = ch.send(val)
return 0
}
fn main() {
let fast = chan_new(2)
let slow = chan_new(2)
crew t {
let _ = t.kick(delayed_send(fast, 1, 10))
let _ = t.kick(delayed_send(slow, 2, 200))
// Wait for first available, up to 100ms
select timeout 100 {
fast => {
print("fast arrived:")
print_int(chan_select_value())
}
slow => {
print("slow arrived:")
print_int(chan_select_value())
}
default => {
print("nothing ready")
}
}
}
}
fn main() {
crew t {
// Start a mock redis server
let mock = t.kick(redis_mock_once(16379))
sleep_ms(40)
// Ping it
let reply = redis_ping("127.0.0.1", 16379)
print(reply) // "PONG"
let _ = mock.join()
}
}
fn main() {
crew t {
let mock = t.kick(redis_mock_kv(16380))
sleep_ms(40)
let _ = redis_set("127.0.0.1", 16380, "name", "mako")
let val = redis_get("127.0.0.1", 16380, "name")
print(val) // "mako"
let exists = redis_exists("127.0.0.1", 16380, "name")
print_int(exists) // 1
let _ = redis_del("127.0.0.1", 16380, "name")
let gone = redis_exists("127.0.0.1", 16380, "name")
print_int(gone) // 0
let _ = mock.join()
}
}
fn main() {
log_info("server starting")
log_kv("info", "port", "8080")
log_warn("no TLS configured")
log_error("bind failed on :80")
// Custom timestamp formatting
let t = now_ms()
print(time_format(t)) // RFC 3339 UTC
}
Output:
[1720000000000 info] server starting
[1720000000000 info] port=8080
[1720000000001 warn] no TLS configured
[1720000000001 error] bind failed on :80
2026-07-10T00:00:00Z
fn main() {
// Split and join
let parts = str_split("a,b,c", ",")
let joined = str_join(parts, " | ")
print(joined) // "a | b | c"
// Builder for efficient concatenation
let mut b = str_builder()
builder_write(b, "hello")
builder_write(b, " ")
builder_write(b, "world")
builder_write_byte(b, byte(33))
print(builder_string(b)) // "hello world!"
// Formatting
let msg = fmt_sprintf("user %s has %d items", "ada")
print(msg)
// Regex
if regex_match("^[a-z]+@[a-z]+\\.[a-z]+$", "user@example.com") {
print("valid email pattern")
}
let captured = regex_capture("(\\d+)\\.(\\d+)", "version 3.14", 1)
print(captured) // "3"
// Base64
let encoded = base64_encode("hello mako")
print(encoded)
let decoded = base64_decode(encoded)
print(decoded)
}
fn main() {
// Environment variables
let _ = env_set("APP_MODE", "production")
let mode = env_get("APP_MODE")
print(mode)
// Path operations
let p = path_join("data", "users.db")
print(p) // "data/users.db"
let clean = path_clean("/a/b/../c/./d")
print(clean) // "/a/c/d"
// Timing
let start = now_ms()
sleep_ms(50)
let elapsed = elapsed_ms(start)
print("elapsed ms:")
print_int(elapsed)
}
fn add(a: int, b: int) -> int {
return a + b
}
fn TestAddTable() {
let inputs_a = [1, 0, -1, 100]
let inputs_b = [2, 0, -1, -100]
let expected = [3, 0, -2, 0]
for i in range 4 {
t_run("case")
assert_eq(add(inputs_a[i], inputs_b[i]), expected[i])
}
}
fn TestFileOperations() {
let path = "/tmp/mako_test_file.txt"
// Setup
let _ = write_file(path, "test data")
defer {
let _ = remove_file(path)
}
// Test
t_run("read")
let content = read_file(path)
assert_eq_str(content, "test data")
t_run("exists")
assert(file_exists(path))
}
mako test . -r TestFile -v
A simple key-value store using memory-mapped files for persistence. Records are stored at fixed-size slots, enabling O(1) access by index:
fn slot_offset(index: int) -> int {
// Each slot is 256 bytes (fixed-width record)
return index * 256
}
fn store_put(m: MMap, index: int, key: string, value: string) {
let record = key + "=" + value
let _ = mmap_write(m, slot_offset(index), record)
}
fn store_get(m: MMap, index: int, max_len: int) -> string {
return mmap_read(m, slot_offset(index), max_len)
}
fn main() {
let path = "/tmp/mako_kvstore.dat"
let slot_size = 256
let max_slots = 1024
let total_size = slot_size * max_slots // 256 KB
// Create the store
let m = mmap_create(path, total_size)
// Write some records
store_put(m, 0, "user:1", "Alice")
store_put(m, 1, "user:2", "Bob")
store_put(m, 2, "user:3", "Carol")
// Flush to disk for durability
let _ = mmap_sync(m, 0)
// Read back
let rec = store_get(m, 1, 64)
print(rec) // "user:2=Bob"
let _ = mmap_close(m)
// Re-open and verify persistence
let m2 = mmap_open(path, 0)
let rec2 = store_get(m2, 0, 64)
print(rec2) // "user:1=Alice"
let _ = mmap_close(m2)
// Clean up
let _ = remove_file(path)
}
This pattern forms the basis of embedded storage engines: fixed-size pages with known offsets enable lock-free concurrent reads (each reader maps the file independently). For production use, add a free-list or append-only log for crash recovery.
Parse and build a custom binary protocol (e.g., for a message queue or RPC
frame). This recipe demonstrates the Buf type for structured binary I/O:
// Protocol: [magic:u16be][version:u8][type:u8][length:u32be][payload:bytes][checksum:u32]
fn encode_message(msg_type: int, payload: string) -> string {
let b = buf_pack_new(256)
// Header
buf_write_u16be(b, 0x4D4B) // "MK" magic
buf_write_u8(b, 1) // version 1
buf_write_u8(b, msg_type) // message type
buf_write_u32be(b, len(payload)) // payload length (network order)
// Payload
buf_write_str(b, payload)
// Simple checksum (sum of payload bytes mod 2^32)
let mut sum = 0
for i in range len(payload) {
sum = sum + int(payload[i])
}
buf_write_u32(b, sum)
let wire = buf_to_string(b)
buf_free(b)
return wire
}
fn decode_message(wire: string) -> string {
let r = buf_from_string(wire)
// Parse header
let magic = buf_read_u16be(r)
if magic != 0x4D4B {
buf_free(r)
print("error: invalid magic")
return ""
}
let version = buf_read_u8(r)
let msg_type = buf_read_u8(r)
let length = buf_read_u32be(r)
// Read payload
let payload = buf_read_str(r, length)
// Verify checksum
let checksum = buf_read_u32(r)
let mut sum = 0
for i in range len(payload) {
sum = sum + int(payload[i])
}
if sum != checksum {
buf_free(r)
print("error: checksum mismatch")
return ""
}
buf_free(r)
print_int(version) // 1
print_int(msg_type) // message type
return payload
}
fn main() {
// Encode a request message (type=1)
let wire = encode_message(1, "{\"action\":\"ping\"}")
// Decode it
let payload = decode_message(wire)
print(payload) // {"action":"ping"}
// Encode a response (type=2)
let resp = encode_message(2, "{\"status\":\"ok\"}")
let resp_payload = decode_message(resp)
print(resp_payload) // {"status":"ok"}
}
This pattern applies to any length-prefixed binary protocol: database wire
formats, game networking packets, sensor data streams, or custom RPC frames.
The Buf type handles byte ordering so you can focus on the protocol logic.
A non-blocking server using the event loop that handles many connections without one thread per client:
fn main() {
let el = evloop_new()
let server = nb_listen(8080)
let _ = evloop_add(el, server, 1)
print("event-driven server on :8080")
let mut served = 0
while served < 100 {
let n = evloop_wait(el, 1000)
let mut i = 0
while i < n {
let fd = evloop_event_fd(el, i)
if fd == server {
let client = nb_accept(server)
if client >= 0 {
let _ = evloop_add(el, client, 1)
}
} else {
let data = nb_read(fd)
if len(data) > 0 {
let _ = nb_write(fd, "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nok\n")
}
let _ = evloop_del(el, fd)
let _ = nb_close(fd)
served = served + 1
}
i = i + 1
}
}
let _ = nb_close(server)
let _ = evloop_close(el)
}
Build and test:
mako build evserver.mko -o out/evserver
out/evserver &
curl http://127.0.0.1:8080/
# ok
A fixed-timestep game loop using tick_now_us and tick_sleep_us to maintain
a consistent tick rate:
fn main() {
let u = game_udp_bind(27015)
let tick_rate_us = 16666 // ~60 ticks per second
let max_ticks = 600 // run for ~10 seconds
let mut tick = 0
while tick < max_ticks {
let start = tick_now_us()
// Process incoming packets
let data = game_udp_recv(u)
if len(data) > 0 {
let peer = game_udp_sender(u)
// Echo back with tick number
let _ = game_udp_send(u, peer, "tick:" + string(tick))
}
// Broadcast world state to all connected peers
if game_udp_peers(u) > 0 {
let _ = game_udp_broadcast(u, "state:" + string(tick))
}
tick = tick + 1
// Sleep the remainder of the tick interval
let _ = tick_sleep_us(start, tick_rate_us)
}
print("game server done, ticks:")
print_int(tick)
game_udp_close(u)
}
The tick_sleep_us function calculates how long has elapsed since start and
sleeps only the remaining time to hit the target interval. If the tick took
longer than the interval, it returns immediately (no negative sleep).
Protect an HTTP endpoint with a token-bucket rate limiter:
fn main() {
let fd = http_bind(8080)
if fd < 0 {
print("bind failed")
return
}
// Allow 10 requests/second with a burst of 5
let rl = ratelimit_new(10, 5)
let mut n = 0
while n < 50 {
let c = http_accept(fd)
if c < 0 {
continue
}
if ratelimit_allow(rl) == 1 {
let remaining = ratelimit_remaining(rl)
let body = "{\"ok\":true,\"remaining\":" + string(remaining) + "}\n"
let _ = http_respond_json(c, 200, body)
} else {
let _ = http_respond_json(c, 429, "{\"error\":\"rate limit exceeded\"}\n")
}
let _ = http_close(c)
n = n + 1
}
ratelimit_free(rl)
let _ = http_close_listener(fd)
}
Build and test:
mako build ratelimit_api.mko -o out/ratelimit_api
out/ratelimit_api &
# First 5 requests succeed (burst), then throttled to 10/sec
for i in $(seq 1 8); do curl -s http://127.0.0.1:8080/; done
Wrap calls to an unreliable downstream service with a circuit breaker to fail fast when the service is unhealthy:
fn call_service(cb: CircuitBreaker) -> int {
if breaker_allow(cb) == 0 {
// Circuit is open -- fail fast
return -1
}
// Simulate calling a downstream service
// In real code, this would be http_get or similar
let success = 0 // simulate failure for demo
if success == 1 {
breaker_success(cb)
return 1
} else {
breaker_failure(cb)
return 0
}
}
fn main() {
// Open after 3 failures, 5-second timeout, 2 half-open probes
let cb = breaker_new(3, 5000, 2)
// Simulate requests
let mut i = 0
while i < 10 {
let result = call_service(cb)
let state = breaker_state(cb)
if state == 0 {
print("closed - attempting request")
} else {
if state == 1 {
print("open - failing fast")
} else {
print("half-open - probing")
}
}
print_int(result)
i = i + 1
sleep_ms(100)
}
// Manual reset for recovery
breaker_reset(cb)
print_int(breaker_state(cb)) // 0 (closed)
breaker_free(cb)
}
The circuit breaker transitions: 1. Closed (normal): requests pass through, failures counted 2. Open (protecting): after threshold failures, all requests rejected 3. Half-open (probing): after timeout, limited requests allowed to test recovery
This pattern prevents cascading failures in microservice architectures.
A complete server with login, session creation, cookie management, protected
routes, CSRF tokens, role checking, and logout. Uses CMap as a thread-safe
session store.
let sessions = cmap_new() // sid -> user
let roles = cmap_new() // user -> comma-separated roles
let csrf_store = cmap_new() // sid -> csrf_token
fn handle_login(c: int) {
let body = http_body(c)
let user = json_get_string(body, "user")
let pass = json_get_string(body, "pass")
// In production, verify credentials against a database.
// Here we accept a hardcoded demo user.
if str_eq(user, "admin") == 0 or str_eq(pass, "s3cret") == 0 {
let _ = http_respond_json(c, 401, "{\"error\":\"bad credentials\"}")
return
}
// Create session
let sid = session_id_new()
cmap_set(sessions, sid, user)
cmap_set(roles, user, "admin,editor")
// Generate CSRF token and store it
let token = csrf_token()
cmap_set(csrf_store, sid, token)
// Set HttpOnly cookie (SameSite=Lax, Path=/, 24h expiry)
let cookie = cookie_make("sid", sid, 86400)
let resp = json_ss("csrf_token", token)
let _ = http_respond_ct(c, 200, "application/json", resp, cookie)
}
fn require_session(c: int) -> string {
let cookie_hdr = http_header(c, "Cookie")
let sid = cookie_get(cookie_hdr, "sid")
if cmap_has(sessions, sid) == 0 {
return ""
}
return sid
}
fn handle_profile(c: int) {
let sid = require_session(c)
if str_eq(sid, "") {
let _ = http_respond_json(c, 401, "{\"error\":\"unauthorized\"}")
return
}
let user = cmap_get(sessions, sid)
let user_roles = cmap_get(roles, user)
let resp = json_ss("user", user, "roles", user_roles)
let _ = http_respond_json(c, 200, resp)
}
fn handle_admin_action(c: int) {
let sid = require_session(c)
if str_eq(sid, "") {
let _ = http_respond_json(c, 401, "{\"error\":\"unauthorized\"}")
return
}
// Check CSRF token (constant-time)
let body = http_body(c)
let submitted_csrf = json_get_string(body, "csrf_token")
let expected_csrf = cmap_get(csrf_store, sid)
if csrf_check(expected_csrf, submitted_csrf) == 0 {
let _ = http_respond_json(c, 403, "{\"error\":\"CSRF token mismatch\"}")
return
}
// Check role
let user = cmap_get(sessions, sid)
let user_roles = cmap_get(roles, user)
if authz_allow_role(user_roles, "admin") == 0 {
let _ = http_respond_json(c, 403, "{\"error\":\"admin role required\"}")
return
}
let _ = http_respond_json(c, 200, "{\"action\":\"completed\"}")
}
fn handle_logout(c: int) {
let sid = require_session(c)
if str_eq(sid, "") == 0 {
let _ = cmap_del(csrf_store, sid)
let _ = cmap_del(sessions, sid)
}
let expired = cookie_make("sid", "", 0) // expire the cookie
let _ = http_respond_ct(c, 200, "application/json", "{\"ok\":true}", expired)
}
fn route(c: int) {
let method = http_method(c)
let path = http_path(c)
if str_eq(method, "POST") and str_eq(path, "/login") {
handle_login(c)
} else {
if str_eq(method, "GET") and str_eq(path, "/profile") {
handle_profile(c)
} else {
if str_eq(method, "POST") and str_eq(path, "/admin/action") {
handle_admin_action(c)
} else {
if str_eq(method, "POST") and str_eq(path, "/logout") {
handle_logout(c)
} else {
let _ = http_respond_json(c, 404, "{\"error\":\"not found\"}")
}
}
}
}
}
fn main() {
let fd = http_bind(8080)
if fd < 0 {
print("bind failed")
return
}
print("auth server on :8080")
while 1 == 1 {
let c = http_accept(fd)
if c >= 0 {
route(c)
let _ = http_close(c)
}
}
let _ = http_close_listener(fd)
}
Build and test:
mako build auth_server.mko -o out/auth_server
out/auth_server &
# Login and get session cookie + CSRF token
curl -s -c cookies.txt -X POST http://127.0.0.1:8080/login \
-d '{"user":"admin","pass":"s3cret"}'
# {"csrf_token":"..."}
# Access protected route with session cookie
curl -s -b cookies.txt http://127.0.0.1:8080/profile
# {"user":"admin","roles":"admin,editor"}
# Admin action with CSRF token
curl -s -b cookies.txt -X POST http://127.0.0.1:8080/admin/action \
-d '{"csrf_token":"<token from login response>"}'
# {"action":"completed"}
# Logout (expires cookie, removes session)
curl -s -b cookies.txt -X POST http://127.0.0.1:8080/logout
# {"ok":true}
This recipe demonstrates:
- Session creation with cryptographic session IDs (session_id_new)
- Cookie management with secure defaults (cookie_make: HttpOnly, SameSite=Lax, Path=/)
- CSRF protection with per-session tokens and constant-time verification (csrf_token, csrf_check)
- Role-based access control checking user roles against required roles (authz_allow_role)
- Logout by deleting session data and expiring the cookie
- Thread-safe state using CMap for concurrent session storage
For bearer-token APIs (mobile clients, service-to-service), replace the cookie
flow with auth_check_bearer. For signed stateless tokens, use
auth_token_sign / auth_token_check.
Next: Appendix.