← ~/work/systems /case_study
Case_Study // [SYS][00] live — serving this page

c-copper: a web framework in C, from the socket up.

The page you're reading was routed, rendered, and sent by ~1,600 lines of C99 with zero runtime dependencies. Not because C is the right tool for a portfolio — because owning every layer from accept() to template interpolation is the most honest way to show what "full stack" means.

01 // Problem

Every framework hides the interesting parts. After years of shipping on .NET and Angular, the question was: can I build the whole request lifecycle myself — socket loop, thread dispatch, routing, middleware, templating, static files — small enough to hold in one head, robust enough to run in production on Cloud Run?

Constraints: C99 + pthreads only. No libevent, no framework, no runtime dependencies. Every byte of the HTTP response is assembled by code in this repo.

02 // Decisions

  • Thread-per-request over an event loop. Simpler invariants, no callback state machines; throughput ceiling accepted consciously (measured below).
  • Linked-list middleware chain (logging → static → rate-limit → CSRF → router) — each layer can short-circuit.
  • Handlebars-style templates with {{key}}, #if, #each and a two-pass layout render — enough for real pages, nothing speculative.
  • strtok_r pattern matching for routes with {param} binding — thread-safe, first-match-wins.
  • Build-time assets: Tailwind compiled to a static 40KB file; browser interactivity is Lua compiled to WASM, loaded per route.

03 // Architecture

/static/app.css

middleware chain (linked list)

logging

static/*

rate-limit

csrf

client

accept()

pthread dispatch

request parser

public/ file

router — strcmp / {param} bind

controller ACTION

view engine — 2-pass render

layout.html body slot

response_flush() → write()

04 // Numbers

~1,900/s
dynamic renders (full template)
~3,700/s
static file responses
23ms / 65ms
p50 / p99 dynamic latency
0
runtime dependencies
1,559
lines of C, framework core
15
http routes registered
~190KB
stripped server binary
40KB
total CSS shipped

Benchmark: hey, 50 concurrent connections, 10s runs (median of 3), Intel N100 (4 cores) under WSL2 — laptop-class hardware, not the Cloud Run deployment. Numbers are for honesty, not bragging: a thread-per-request C server on a small box outruns what this site will ever need.

src→ github.com/aag2807/copper-portfolio back to ~/work/systems