diff --git a/recovery.go b/recovery.go index fdd463f3..ef110087 100644 --- a/recovery.go +++ b/recovery.go @@ -68,6 +68,12 @@ func CustomRecoveryWithWriter(out io.Writer, handle RecoveryFunc) HandlerFunc { } } } + if e, ok := err.(error); ok { + // ErrAbortHandler should be treated as broken pipe too. + if errors.Is(e, http.ErrAbortHandler) { + brokenPipe = true + } + } if logger != nil { const stackSkip = 3 if brokenPipe { diff --git a/recovery_test.go b/recovery_test.go index 8a9e3475..c0d199b7 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -142,6 +142,28 @@ 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) + assert.Contains(t, buf.String(), "net/http: abort Handler") +} + func TestCustomRecoveryWithWriter(t *testing.T) { errBuffer := new(strings.Builder) buffer := new(strings.Builder)