I wanted to understand what happens between a browser sending a request and a server sending back a response — not at the framework level, but at the socket and thread level. So I built an HTTP server in C, on top of Owl, a small utility library I wrote alongside it.
How it handles requests
The main thread sits in an accept loop, blocking until a client connects. Each incoming connection gets wrapped as a task and dispatched to a thread pool, so multiple requests can be processed in parallel without spawning a new thread for each one.
Once a worker picks up a connection, it reads the raw bytes, parses the request line and headers into a struct, looks up the route in a hashmap (SipHash-2-4 for O(1) lookups), runs the handler, and sends back a chunked response. The 4KB chunk buffer means it can serve large files without loading everything into memory at once.
Routing and templating
I modeled the API after Express — you register routes with a path and a handler function, and the framework takes care of parsing, matching, and response building. It felt like the right level of abstraction for a C server: familiar enough to use, low-level enough to learn from.
http_server_t *server = http_server_init(PORT, BACKLOG);
register_route(server, "/", index_handler);
register_static(server, "public");
http_server_listen(server);There's also a basic templating system with {{variable}} placeholders — enough to render dynamic HTML without pulling in a full template engine. Static file serving handles MIME type detection automatically for common content types.
What I learned
Writing an HTTP server in C forces you to think about things you take for granted in higher-level languages — manual memory management for every request/response cycle, making sure connection file descriptors get closed properly, handling the thread pool shutdown gracefully so in-flight requests finish before the process exits.
The server doesn't support persistent connections or TLS — it's HTTP/1.1 with Connection: close semantics. Those would be interesting additions, but the goal was to understand the fundamentals, and I got what I came for.