fix(recover): suppress http.ErrAbortHandler in recover (#4336)

Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Yilong Li 2025-11-27 23:20:52 +08:00 committed by GitHub
parent c358d5656d
commit 63dd3e60ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 0 deletions

View File

@ -68,6 +68,9 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc {
} }
} }
} }
if e, ok := err.(error); ok && errors.Is(e, http.ErrAbortHandler) {
brokenPipe = true
}
if logger != nil { if logger != nil {
const stackSkip = 3 const stackSkip = 3
if brokenPipe { if brokenPipe {

View File

@ -142,6 +142,30 @@ func TestPanicWithBrokenPipe(t *testing.T) {
} }
} }
// TestPanicWithAbortHandler asserts that recovery handles http.ErrAbortHandler as broken pipe
func TestPanicWithAbortHandler(t *testing.T) {
const expectCode = 204
var buf strings.Builder
router := New()
router.Use(RecoveryWithWriter(&buf))
router.GET("/recovery", func(c *Context) {
// Start writing response
c.Header("X-Test", "Value")
c.Status(expectCode)
// Panic with ErrAbortHandler which should be treated as broken pipe
panic(http.ErrAbortHandler)
})
// RUN
w := PerformRequest(router, http.MethodGet, "/recovery")
// TEST
assert.Equal(t, expectCode, w.Code)
out := buf.String()
assert.Contains(t, out, "net/http: abort Handler")
assert.NotContains(t, out, "panic recovered")
}
func TestCustomRecoveryWithWriter(t *testing.T) { func TestCustomRecoveryWithWriter(t *testing.T) {
errBuffer := new(strings.Builder) errBuffer := new(strings.Builder)
buffer := new(strings.Builder) buffer := new(strings.Builder)