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 typeFlush() 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).