
httputil
Package httputil houses cross-cutting HTTP helpers that several transport sub-packages share: trusted-proxy-aware client IP extraction, login-attempt throttling, and TLS certificate hot-reloading.
Index
- Constants
- func DecodeJSONBody(w http.ResponseWriter, r *http.Request, dst any, maxBytes int64) bool
- func ExtractClientIP(r *http.Request, trustedProxies []*net.IPNet) string
- func IsTLSRequest(r *http.Request, trustedProxies []*net.IPNet) bool
- func PanicRecover(route string, writeErr ErrorWriter) func(http.Handler) http.Handler
- func ParseTrustedProxies(cidrs []string) []*net.IPNet
- func RequireMethod(w http.ResponseWriter, r *http.Request, methods …string) bool
- func WriteJSON(w http.ResponseWriter, status int, body any)
- func WriteJSONError(w http.ResponseWriter, status int, msg string)
- type CertReloader
- type ErrorWriter
- type LoginThrottle
Constants
func DecodeJSONBody
DecodeJSONBody applies a maxBytes read cap to the request body and decodes it into dst. Returns true on success; on failure it writes a 400 JSON error response and returns false so the caller can return early without duplicating the response boilerplate.
func ExtractClientIP
ExtractClientIP returns the client’s real IP address. When the direct peer is a trusted proxy and X-Forwarded-For is present, the rightmost untrusted IP is returned. Otherwise the direct peer IP is returned.
func IsTLSRequest
IsTLSRequest reports whether the original client connection was over TLS. True when r.TLS is set (TLS terminated at this server) or when the direct peer is a trusted proxy that forwarded X-Forwarded-Proto: https. Returns false when no trusted-proxy chain is configured and r.TLS is nil - callers can opt in to forced-Secure cookies via a separate config flag.
func PanicRecover
PanicRecover returns middleware that recovers panics from h, translates them into a 500 response via writeErr, and emits the three observability signals (slog.ErrorContext + audit + Prometheus counter) plus OTel span error recording when a span is active on the request context.
route is the metric label and the audit event scope (e.g. “s3”, “admin”, “ui”). It must come from a small fixed set per the cardinality rules in docs/style-guide.md - never derive it from the request URL.
func ParseTrustedProxies
ParseTrustedProxies parses CIDR strings into net.IPNet slices. Invalid CIDRs are silently skipped (they are caught during config validation).
func RequireMethod
RequireMethod verifies r.Method matches one of the allowed methods. Returns true when the request may proceed; on mismatch it sets the Allow header, writes a 405 JSON error, and returns false so the caller can return early.
func WriteJSON
WriteJSON serialises body as JSON, sets the JSON content-type header, writes the status code, and emits the encoded payload. Encoder write errors are swallowed because the response is already committed by WriteHeader; logging is the caller’s responsibility when it matters.
func WriteJSONError
WriteJSONError writes a JSON error response with the correct content type and status. Encodes the payload through encoding/json so quote or backslash characters in msg cannot corrupt the response body.
type CertReloader
CertReloader holds a TLS certificate that can be atomically swapped on reload. Safe for concurrent use by the TLS handshake goroutines and a single reloader (SIGHUP handler).
func NewCertReloader
NewCertReloader loads the initial certificate from disk and returns a reloader ready for use as a tls.Config.GetCertificate callback.
func (*CertReloader) GetCertificate
GetCertificate returns the current certificate for TLS handshakes. Intended as the tls.Config.GetCertificate callback.
func (*CertReloader) Reload
Reload reads the certificate and key from disk and swaps the current certificate. If the new files are invalid, the existing certificate is preserved and an error is returned. Logs a warning if the leaf certificate expires within 24 hours.
type ErrorWriter
ErrorWriter writes a route-appropriate 500 response. The middleware stays format-agnostic - each route group passes a writer that matches what its clients expect (S3-XML for the s3api surface, JSON for the admin API, plaintext for the UI). The writer MUST set the status code and write any headers before returning; the middleware only invokes it once per recovered panic.
type LoginThrottle
LoginThrottle tracks failed login attempts per IP and enforces lockout.
func NewLoginThrottle
NewLoginThrottle creates a login throttle with the given limits.
func (*LoginThrottle) Close
Close stops the background cleanup goroutine. Safe to call multiple times.
func (*LoginThrottle) IsLockedOut
IsLockedOut returns true if the given IP is currently locked out. Callers must pass a resolved client IP (e.g. from ExtractClientIP), not a raw remoteAddr.
func (*LoginThrottle) RecordFailure
RecordFailure increments the failure count for the given IP. If the count reaches MaxFailures, the IP is locked out for LockoutDuration. Callers must pass a resolved client IP (e.g. from ExtractClientIP), not a raw remoteAddr.
func (*LoginThrottle) RecordSuccess
RecordSuccess resets the failure counter for the given IP. Callers must pass a resolved client IP (e.g. from ExtractClientIP), not a raw remoteAddr.
Generated by gomarkdoc