A concurrent HTTP/1.1 server built from scratch in C++20 using POSIX sockets, a bounded worker-thread pool, and zero external web frameworks.
This project demonstrates systems-level engineering: raw socket programming, HTTP protocol parsing per RFC 9112, thread-safe concurrency primitives, and operational observability — the skills that matter for backend infrastructure roles.
- HTTP/1.1 request parsing (
GET,HEAD,POST) - Static file serving with MIME type detection
- Built-in routes:
/health,/echo,/metrics - Bounded thread pool with backpressure (rejects under overload instead of OOM)
- Thread-safe task queue using
std::mutex+std::condition_variable - Graceful shutdown on
SIGINT/SIGTERM - Security: request-size limits, path-traversal protection
- Proper error responses:
400,404,405,413,500 - Observability: request count, active connections, latency, error rates
- Tested: 30+ unit/integration tests, sanitizer-clean
# Build
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
# Run
./http_server --port 8080 --workers 4 --doc-root ../public
# Test
curl http://localhost:8080/health
curl http://localhost:8080/metrics| Flag | Default | Purpose |
|---|---|---|
BUILD_TESTS |
ON |
Build GoogleTest suite |
ENABLE_ASAN |
OFF |
AddressSanitizer (memory errors) |
ENABLE_TSAN |
OFF |
ThreadSanitizer (data races) |
# Run with sanitizers
cmake .. -DENABLE_ASAN=ON && make -j$(nproc) && ./http_server
cmake .. -DENABLE_TSAN=ON && make -j$(nproc) && ./http_servercd build
cmake .. -DBUILD_TESTS=ON
make -j$(nproc)
ctest --output-on-failuredocker build -t concurrent-http-server .
docker run -p 8080:8080 concurrent-http-server┌─────────────┐
│ Clients │
└──────┬──────┘
│ TCP connections
┌──────▼──────┐
│ Listener │ accept() loop on main thread
└──────┬──────┘
│ enqueue client fd
┌──────▼──────┐
│ Task Queue │ bounded, thread-safe, backpressure
└──────┬──────┘
│ dequeue
┌──────▼──────┐
│ Thread Pool │ N worker threads
│ ┌────────┐ │
│ │Worker 1│ │ recv → parse → route → send
│ │Worker 2│ │
│ │Worker N│ │
│ └────────┘ │
└──────┬──────┘
│ updates
┌──────▼──────┐
│ Metrics │ atomic counters, GET /metrics
└─────────────┘
| Model | Threads | Memory | Latency at 1K conn | Notes |
|---|---|---|---|---|
| Single-threaded | 1 | Minimal | High (serial) | Baseline only |
| Thread-per-connection | ~1K | ~8 GB stack | Low (parallel) | Doesn't scale |
| Bounded thread pool | N (configurable) | Bounded | Low | This project |
- TLS: Would obscure socket-level learning; use a reverse proxy in production
- HTTP/2: Binary framing is a different project entirely
- Chunked transfer: Adds parser complexity without demonstrating new systems concepts
- Authentication: Application-layer concern, not a server-infrastructure concern
| Call | Purpose |
|---|---|
socket() |
Create a TCP endpoint |
setsockopt() |
Set SO_REUSEADDR to avoid bind failures on restart |
bind() |
Attach socket to an address and port |
listen() |
Mark socket as passive (accepting connections) |
accept() |
Block until a client connects; return a new fd |
recv() |
Read bytes from a connected socket |
send() |
Write bytes to a connected socket |
close() |
Release file descriptor |
See benchmarks/BENCHMARKS.md for full results.
| Day | What shipped | AI usage |
|---|---|---|
| 1 | Repo setup, CMake, design doc | — |
| ... | ... | ... |
MIT