| 11 | ) |
| 12 | |
| 13 | func Recover(log slog.Logger) func(h http.Handler) http.Handler { |
| 14 | return func(h http.Handler) http.Handler { |
| 15 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 16 | defer func() { |
| 17 | r := recover() |
| 18 | |
| 19 | // Reverse proxying (among other things) may panic with |
| 20 | // http.ErrAbortHandler when the request is aborted. It's not a |
| 21 | // real panic so we shouldn't log them. |
| 22 | // |
| 23 | //nolint:errorlint // this is how the stdlib does the check |
| 24 | if r != nil && r != http.ErrAbortHandler { |
| 25 | log.Warn(context.Background(), |
| 26 | "panic serving http request (recovered)", |
| 27 | slog.F("panic", r), |
| 28 | slog.F("stack", string(debug.Stack())), |
| 29 | ) |
| 30 | |
| 31 | var hijacked bool |
| 32 | if sw, ok := w.(*tracing.StatusWriter); ok { |
| 33 | hijacked = sw.Hijacked |
| 34 | } |
| 35 | |
| 36 | // Only try to write errors on |
| 37 | // non-hijacked responses. |
| 38 | if !hijacked { |
| 39 | httpapi.InternalServerError(w, nil) |
| 40 | } |
| 41 | } |
| 42 | }() |
| 43 | |
| 44 | h.ServeHTTP(w, r) |
| 45 | }) |
| 46 | } |
| 47 | } |