diff --git a/middleware/timeout.go b/middleware/timeout.go index 68f464e4..99d436ac 100644 --- a/middleware/timeout.go +++ b/middleware/timeout.go @@ -106,6 +106,11 @@ func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Reques // so on timeout writer stays what http.TimeoutHandler uses and prevents writing headers/body t.ctx.Response().Writer = originalWriter if err != nil { + // call global error handler to write error to the client. This is needed or `http.TimeoutHandler` will send status code by itself + // and after that our tries to write status code will not work anymore + t.ctx.Error(err) + // we pass error from handler to middlewares up in handler chain to act on it if needed. But this means that + // global error handler is probably be called twice as `t.ctx.Error` already does that. t.errChan <- err } } diff --git a/middleware/timeout_test.go b/middleware/timeout_test.go index af4c6264..8f8fa304 100644 --- a/middleware/timeout_test.go +++ b/middleware/timeout_test.go @@ -71,10 +71,34 @@ func TestTimeoutErrorOutInHandler(t *testing.T) { c := e.NewContext(req, rec) err := m(func(c echo.Context) error { - return errors.New("err") + return echo.NewHTTPError(http.StatusTeapot, "err") })(c) assert.Error(t, err) + assert.Equal(t, http.StatusTeapot, rec.Code) + assert.Equal(t, "{\"message\":\"err\"}\n", rec.Body.String()) +} + +func TestTimeoutSuccessfulRequest(t *testing.T) { + t.Parallel() + m := TimeoutWithConfig(TimeoutConfig{ + // Timeout has to be defined or the whole flow for timeout middleware will be skipped + Timeout: 50 * time.Millisecond, + }) + + req := httptest.NewRequest(http.MethodGet, "/", nil) + rec := httptest.NewRecorder() + + e := echo.New() + c := e.NewContext(req, rec) + + err := m(func(c echo.Context) error { + return c.JSON(http.StatusCreated, map[string]string{"data": "ok"}) + })(c) + + assert.NoError(t, err) + assert.Equal(t, http.StatusCreated, rec.Code) + assert.Equal(t, "{\"data\":\"ok\"}\n", rec.Body.String()) } func TestTimeoutOnTimeoutRouteErrorHandler(t *testing.T) {