A multi-threaded HTTP server framework built from scratch in C. Built on top of Owl, Kraken provides an Express-like API for routing, static file serving, and basic templating.
What's Inside
Core Features
HTTP Server - Implements HTTP request parsing and response formatting. Parses request lines, headers, and bodies, then builds proper HTTP responses with status codes and headers.
Multi-threaded Architecture - Uses a thread pool to handle concurrent client connections. Each incoming request is dispatched to an available worker thread for parallel request processing.
Hash-based Routing - Routes are stored in a hashmap using SipHash-2-4 for O(1) lookup performance. URI matching is handled through custom comparators with minimal overhead.
Static File Server - Serves static files with automatic MIME type detection for common content types (HTML, CSS, JS, images, fonts, audio, video). Supports directory index files and chunked file transfer for large assets.
Server-Side Rendering - Built-in templating system with placeholder substitution ({{variable}}) for dynamic HTML generation. Load templates from files or strings with efficient string replacement.
Request/Response API
Request Parsing - Automatic parsing of HTTP request lines, headers, and body. Headers stored in a hashmap for fast lookup. URI and HTTP version extraction included.
Response Builder - Simple response API with status code helpers, content-type configuration, and custom header support. Includes enums for common HTTP status codes.
Chunked Transfer - Responses are sent in configurable chunks (4KB buffer) to handle arbitrarily large payloads without memory constraints.
Quick Start
Building
Compile Kraken and its dependencies:
makeOr build as a shared library:
make -e SHARED=1The server binary will be created as main, and the library will be in lib/.
Hello World Server
#include "kraken.h"
#define PORT 8000
#define BACKLOG 10
char *index_handler(http_req_t *req, http_res_t *res) {
return "Hello World";
}
int main() {
http_server_t *server = http_server_init(PORT, BACKLOG);
register_route(server, "/", index_handler);
register_static(server, "public");
http_server_listen(server);
http_server_free(server);
}Dynamic Templates
char *home_handler(http_req_t *req, http_res_t *res) {
placeholder_t placeholders[] = {
{"{{title}}", "Welcome to Kraken"},
{"{{content}}", "Built with C"},
};
return res_render_template_file(
"./template.html",
placeholders,
NUM_PLACEHOLDERS(placeholders)
);
}Working with Headers
char *api_handler(http_req_t *req, http_res_t *res) {
res_status(res, HTTP_STATUS_OK);
res_content_type(res, "application/json");
return "{\"message\": \"API response\"}";
}Technical Implementation
Connection Handling
- Accept Loop - Main thread runs an infinite accept loop, blocking until a client connects
- Task Dispatch - Each accepted connection is wrapped in a task and enqueued to the thread pool
- Worker Processing - Available worker threads dequeue tasks and handle the full request-response cycle
- Graceful Cleanup - Connection FDs are closed after response transmission, and resources are freed
Request Processing Pipeline
TCP Connection → Request Buffering → HTTP Parsing → Route Lookup →
Handler Execution → Response Building → Chunked Send → CloseStatic File Strategy
Kraken checks multiple registered static directories in order, supporting:
- Direct file access (
/styles.css→public/styles.css) - Directory index files (
/blog/→public/blog/index.html) - Fallback to 404 if no file matches
Memory Management
- All HTTP requests and responses are heap-allocated with explicit
free()calls - Routes and headers use Owl's hashmap with automatic memory management
- Thread pool cleanup waits for all tasks to complete before freeing resources
- Server gracefully shuts down on interrupt signals (Ctrl+C)
Design Philosophy
- Express-like API - Familiar routing patterns for developers coming from Node.js
- Zero external dependencies - Pure C with only Owl as a statically-linked library
- Educational focus - Clean, readable code demonstrating systems programming concepts
Technical Notes
- Connection backlog is capped at 1000 to prevent resource exhaustion
- Request buffer size is 4096 bytes with automatic line-by-line reading
- Static file serving uses binary mode for non-text content types
- Date headers follow RFC 7231 format (GMT timezone)
Limitations
- No persistent connections support (Connection: close semantics)
- No TLS/HTTPS support (plain HTTP only)
- Query parameters and URL-encoded bodies require manual parsing
- Template system is simple string replacement (no conditionals or loops)
Use Cases
- Learning web server internals and HTTP protocol implementation
- Serving static sites from embedded systems or lightweight environments
- Prototyping C-based web services and REST APIs