Initial implementation of lightmux-contrib, a sibling module to lightmux that hosts opinionated middlewares with one sub-package per middleware: - realip: resolves the originating client IP from CF-Connecting-IP, True-Client-IP, X-Real-IP, or X-Forwarded-For. Optional peer-CIDR allowlist via netip.Prefix. - requestlog: emits a structured http.request record (method, path, status, duration, client) per request via splinter. - recoverer: catches panics, wraps with errx under op "recoverer", logs with stack, and writes a 500 response. Each package exposes a single New(...) constructor returning func(http.Handler) http.Handler. The contrib module intentionally does not import lightmux — middlewares interoperate via the standard stdlib middleware shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
36 lines
829 B
Go
36 lines
829 B
Go
// Package recoverer catches panics inside HTTP handlers, logs them with stack
|
|
// trace, and writes a 500 response.
|
|
package recoverer
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"runtime/debug"
|
|
|
|
"git.juancwu.dev/juancwu/errx"
|
|
)
|
|
|
|
const op = "recoverer"
|
|
|
|
// New returns a panic-recovery middleware.
|
|
func New() func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
defer func() {
|
|
rec := recover()
|
|
if rec == nil {
|
|
return
|
|
}
|
|
var err error
|
|
if e, ok := rec.(error); ok {
|
|
err = errx.Wrap(op, e)
|
|
} else {
|
|
err = errx.Newf(op, "panic: %v", rec)
|
|
}
|
|
log.Printf("%v\n%s", err, debug.Stack())
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
}()
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|