Seed from go-template-repo, renamed to simplexcalc
The template's files at a77fd30, without its history or LICENSE, after script/rename simplexcalc. Model: opus-5-5
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// panicBody is the entire response a recovered panic produces. No
|
||||
// template, no detail: the client learns that the request failed, and
|
||||
// everything about why goes to the log and to Sentry, where it is not
|
||||
// attacker-readable.
|
||||
const panicBody = "internal server error"
|
||||
|
||||
// Recoverer turns a panicking handler into a 500 rather than a dropped
|
||||
// connection.
|
||||
//
|
||||
// net/http already recovers panics, but what it does is close the
|
||||
// connection without a response, so the client sees a transport error
|
||||
// and no status. Answering 500 is the difference between "the service
|
||||
// is broken" and "the network is broken" for everyone downstream.
|
||||
//
|
||||
// A panic after the response has started cannot be turned into a 500 —
|
||||
// the status is already on the wire — so in that case the connection is
|
||||
// deliberately dropped by re-panicking to net/http, which is the only
|
||||
// honest signal left that the body is truncated. A truncated 200 that
|
||||
// looks complete is worse than a broken connection.
|
||||
func (m *Middleware) Recoverer() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rec := newResponseRecorder(w)
|
||||
|
||||
defer func() {
|
||||
v := recover()
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// http.ErrAbortHandler is net/http's documented way for
|
||||
// a handler to abandon a response on purpose. It is not
|
||||
// a bug, so it is not reported; it is re-raised for
|
||||
// net/http to handle as it always does.
|
||||
//nolint:errorlint,err113 // a sentinel value, compared as net/http documents.
|
||||
if v == http.ErrAbortHandler {
|
||||
panic(v)
|
||||
}
|
||||
|
||||
m.params.Sentry.CapturePanic(v, debug.Stack())
|
||||
|
||||
if rec.Written() {
|
||||
panic(v)
|
||||
}
|
||||
|
||||
http.Error(rec, panicBody, http.StatusInternalServerError)
|
||||
}()
|
||||
|
||||
next.ServeHTTP(rec, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user