DCAYING_MINDS_ZERODEPS_C

Mini HTTP Server + Static Site Server

Track C — Web & Network (stdlib-net) · Zero Dependency Hackathon

A small HTTP/1.1 server, written in Go, that serves static files and a couple of JSON endpoints. Built entirely on net/http, os, path/filepath, mime, sync/atomic, context, and log — nothing else.

What it does

How to run it

Requires Go 1.21+ (uses only the standard library, no go mod tidy needed — go.mod has no require block).

make build       # builds ./webserver
make run         # builds and runs on :8080, serving ./public
make test        # runs the test suite
make deps-proof  # regenerates deps-proof.txt

Or directly:

go build -o webserver .
./webserver -addr :8080 -public ./public

Flags:

Flag Default Purpose
-addr :8080 listen address
-public ./public directory to serve static files from
-shutdown-timeout 5s grace period for in-flight requests

Try it:

curl http://localhost:8080/
curl http://localhost:8080/health
curl http://localhost:8080/about
curl -I http://localhost:8080/css/style.css   # check Content-Type
curl http://localhost:8080/nope               # 404
curl -N http://localhost:8080/stats/events    # watch raw SSE ticks

Or open http://localhost:8080/stats in a browser to see the live dashboard.

Project layout

.
├── main.go                     entrypoint: flags, server, graceful shutdown
├── internal/server/
│   ├── router.go                route table, /health and /about handlers, shared atomic counter
│   ├── static.go                 static file handler: path safety, content-type, Range requests, 404s
│   ├── middleware.go              logging + panic-recovery middleware + NewHandler wiring
│   └── stats.go                    live dashboard: SSE stream (/stats/events) + HTML page (/stats)
├── tests/
│   ├── server_test.go             stdlib-only test suite, imports internal/server directly
│   └── loadtest/main.go            standalone sustained-load tool (stdlib, no ab/wrk needed)
├── public/                         sample static site served by default
├── STDLIB.md                        package-you'd-normally-install -> stdlib-you-used-instead
├── CONCURRENCY.md                   honest writeup of the concurrency model + real load test results
├── Makefile
└── deps-proof.txt                   output proving zero third-party deps

Handler logic lives in internal/server (not the root package) specifically so tests/server_test.go can import "webserver/internal/server" and test the real code path — main.go and the tests both call the exact same server.NewHandler(...), so there’s no drift between what’s tested and what’s deployed.

The innovation piece

/stats is a live, self-updating dashboard — the one part of this project that goes beyond “serve files correctly.” It streams a JSON snapshot every second over Server-Sent Events (/stats/events) using nothing but net/http’s http.Flusher interface: no WebSocket package, no polling setInterval loop on the client, no external JS. The browser opens a single long-lived HTTP connection via the standard EventSource API and the server writes data: {...}\n\n lines to it, flushing after each one.

This also surfaced a real bug worth knowing about: the logging middleware wraps http.ResponseWriter in a statusRecorder to capture the status code, but Go only promotes methods declared on an embedded interface type — Flush() isn’t part of http.ResponseWriter, so the wrapped writer silently stopped satisfying http.Flusher even though the underlying writer supported it. First request to /stats/events returned “streaming not supported.” Fixed by adding an explicit Flush() passthrough on statusRecorder (see internal/server/middleware.go), and TestStatsEventsStreams in the test suite now specifically guards against this regressing silently again.

Testing & verification actually performed

Not just written — run, for real, in this repo:

The security pass

internal/server/security.go covers the “HTTP acknowledgement / security hardening” piece, stdlib-only (net/http, crypto/sha256, crypto/subtle, os):

All of it is covered by tests/security_test.go: headers asserted on both a JSON route and a static file response, 401 on missing/wrong credentials, 200 with the correct ones, 413 on an oversized body actually sent over the wire, and 405 on the wrong method. Nothing here is a claim without a test behind it.

CSP trade-off, stated plainly: the /stats dashboard uses an inline <script>/<style> block (see internal/server/stats.go), so the CSP needs 'unsafe-inline' for script-src/style-src or that page breaks. A stricter nonce-based CSP would need moving that markup into public/ first — left as a known gap, not silently worked around.

Honest limits

This is a hackathon build, not a production web server. Known gaps:

Team split (Track C, 4 people)

This repo now covers Setup, Core Server, Static Files, Concurrency + Polish, Testing & Docs, and HTTP acknowledgement / security hardening — the security piece originally left for a teammate is now implemented in internal/server/security.go and covered by tests/security_test.go (see “The security pass” above).