Compare commits

..

2 Commits

Author SHA1 Message Date
OHZEKI Naoki
0f268400d4
Merge 75b09bd1895c6047cc71ba99b45d738872bd4427 into 63dd3e60cab89c27fb66bce1423bd268d52abad1 2025-11-28 01:31:32 +08:00
Yilong Li
63dd3e60ca
fix(recover): suppress http.ErrAbortHandler in recover (#4336)
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
2025-11-27 23:20:52 +08:00
2 changed files with 27 additions and 0 deletions

View File

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

View File

@ -143,6 +143,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) {
errBuffer := new(strings.Builder)
buffer := new(strings.Builder)