Found while working on the robots.txt change. internal/server/middlewares has several issues; both files carry a // TODO rewrite this already.
Log (log.go)
go w.logRequest(bytes) on every Write (line 64). A handler that writes the body in chunks spawns one goroutine per chunk, all reading the same *LogWriter fields (statusCode, start, req) with no synchronisation — a data race, and the request emits multiple log lines. logRequest should run once, after the handler returns (call it from Log.ServeHTTP after l.next.ServeHTTP, not from Write).
Bodiless responses are never logged.logRequest is only reached from Write. A handler that calls WriteHeader and returns (204, 304, a redirect, an error with an empty body) produces no log line at all.
Nil *zerolog.Event deref (line 79–97). The if/else if chain has no final else. A statusCode below 100 (e.g. a 0 that slipped through) leaves e == nil, then e.Str(...) panics. Give it a default branch.
LogWriter drops optional ResponseWriter interfaces. It wraps http.ResponseWriter but doesn't forward http.Flusher, http.Hijacker or io.ReaderFrom. The static file server and the ReadFile audio handler lose ReadFrom (slower copies), and anything streaming loses Flush.
CorsOrigin (cors.go)
c.next is stored on a single shared instance (line 19).router.Use calls Middleware once at setup so this happens to work, but the instance is not safe to register on more than one router / chain, and it's the reason for the // TODO. The mux idiom is return http.HandlerFunc(func(w, r){ ...; next.ServeHTTP(w, r) }).
origin field / NewCorsOrigin(origin string) argument are dead.ServeHTTP hardcodes Access-Control-Allow-Origin: * (line 26) and never reads c.origin. Either honour the argument or drop it.
The comment on line 24–25 flags that * is a dev-only setting that should be tightened before deployment — zampler.aneur.in is deployed, so this is worth closing out.
Same l.next = next shared-instance pattern in Log.Middleware.
Found while working on the robots.txt change. `internal/server/middlewares` has several issues; both files carry a `// TODO rewrite this` already.
## `Log` (`log.go`)
- **`go w.logRequest(bytes)` on every `Write` (line 64).** A handler that writes the body in chunks spawns one goroutine per chunk, all reading the same `*LogWriter` fields (`statusCode`, `start`, `req`) with no synchronisation — a data race, and the request emits multiple log lines. `logRequest` should run once, after the handler returns (call it from `Log.ServeHTTP` after `l.next.ServeHTTP`, not from `Write`).
- **Bodiless responses are never logged.** `logRequest` is only reached from `Write`. A handler that calls `WriteHeader` and returns (204, 304, a redirect, an error with an empty body) produces no log line at all.
- **Nil `*zerolog.Event` deref (line 79–97).** The `if/else if` chain has no final `else`. A `statusCode` below 100 (e.g. a `0` that slipped through) leaves `e == nil`, then `e.Str(...)` panics. Give it a default branch.
- **`LogWriter` drops optional `ResponseWriter` interfaces.** It wraps `http.ResponseWriter` but doesn't forward `http.Flusher`, `http.Hijacker` or `io.ReaderFrom`. The static file server and the `ReadFile` audio handler lose `ReadFrom` (slower copies), and anything streaming loses `Flush`.
## `CorsOrigin` (`cors.go`)
- **`c.next` is stored on a single shared instance (line 19).** `router.Use` calls `Middleware` once at setup so this happens to work, but the instance is not safe to register on more than one router / chain, and it's the reason for the `// TODO`. The mux idiom is `return http.HandlerFunc(func(w, r){ ...; next.ServeHTTP(w, r) })`.
- **`origin` field / `NewCorsOrigin(origin string)` argument are dead.** `ServeHTTP` hardcodes `Access-Control-Allow-Origin: *` (line 26) and never reads `c.origin`. Either honour the argument or drop it.
- The comment on line 24–25 flags that `*` is a dev-only setting that should be tightened before deployment — `zampler.aneur.in` is deployed, so this is worth closing out.
Same `l.next = next` shared-instance pattern in `Log.Middleware`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found while working on the robots.txt change.
internal/server/middlewareshas several issues; both files carry a// TODO rewrite thisalready.Log(log.go)go w.logRequest(bytes)on everyWrite(line 64). A handler that writes the body in chunks spawns one goroutine per chunk, all reading the same*LogWriterfields (statusCode,start,req) with no synchronisation — a data race, and the request emits multiple log lines.logRequestshould run once, after the handler returns (call it fromLog.ServeHTTPafterl.next.ServeHTTP, not fromWrite).logRequestis only reached fromWrite. A handler that callsWriteHeaderand returns (204, 304, a redirect, an error with an empty body) produces no log line at all.*zerolog.Eventderef (line 79–97). Theif/else ifchain has no finalelse. AstatusCodebelow 100 (e.g. a0that slipped through) leavese == nil, thene.Str(...)panics. Give it a default branch.LogWriterdrops optionalResponseWriterinterfaces. It wrapshttp.ResponseWriterbut doesn't forwardhttp.Flusher,http.Hijackerorio.ReaderFrom. The static file server and theReadFileaudio handler loseReadFrom(slower copies), and anything streaming losesFlush.CorsOrigin(cors.go)c.nextis stored on a single shared instance (line 19).router.UsecallsMiddlewareonce at setup so this happens to work, but the instance is not safe to register on more than one router / chain, and it's the reason for the// TODO. The mux idiom isreturn http.HandlerFunc(func(w, r){ ...; next.ServeHTTP(w, r) }).originfield /NewCorsOrigin(origin string)argument are dead.ServeHTTPhardcodesAccess-Control-Allow-Origin: *(line 26) and never readsc.origin. Either honour the argument or drop it.*is a dev-only setting that should be tightened before deployment —zampler.aneur.inis deployed, so this is worth closing out.Same
l.next = nextshared-instance pattern inLog.Middleware.Fixed in
7a6e1aa(PR #15).