mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
Fixing Timeout middleware Context propagation (#1910)
This will let middlewares/handler later on the chain to properly handle the Timeout middleware Context cancellation. Fixes #1909
This commit is contained in:
parent
5e791b0787
commit
02de901d7e
@ -2,9 +2,10 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -87,6 +88,10 @@ type echoHandlerFuncWrapper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
func (t echoHandlerFuncWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
// replace echo.Context Request with the one provided by TimeoutHandler to let later middlewares/handler on the chain
|
||||||
|
// handle properly it's cancellation
|
||||||
|
t.ctx.SetRequest(r)
|
||||||
|
|
||||||
// replace writer with TimeoutHandler custom one. This will guarantee that
|
// replace writer with TimeoutHandler custom one. This will guarantee that
|
||||||
// `writes by h to its ResponseWriter will return ErrHandlerTimeout.`
|
// `writes by h to its ResponseWriter will return ErrHandlerTimeout.`
|
||||||
originalWriter := t.ctx.Response().Writer
|
originalWriter := t.ctx.Response().Writer
|
||||||
|
@ -2,8 +2,6 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -11,6 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTimeoutSkipper(t *testing.T) {
|
func TestTimeoutSkipper(t *testing.T) {
|
||||||
@ -273,3 +274,42 @@ func TestTimeoutWithDefaultErrorMessage(t *testing.T) {
|
|||||||
assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
|
assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
|
||||||
assert.Equal(t, `<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>`, rec.Body.String())
|
assert.Equal(t, `<html><head><title>Timeout</title></head><body><h1>Timeout</h1></body></html>`, rec.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTimeoutCanHandleContextDeadlineOnNextHandler(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
timeout := 1 * time.Millisecond
|
||||||
|
m := TimeoutWithConfig(TimeoutConfig{
|
||||||
|
Timeout: timeout,
|
||||||
|
ErrorMessage: "Timeout! change me",
|
||||||
|
})
|
||||||
|
|
||||||
|
handlerFinishedExecution := make(chan bool)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
e := echo.New()
|
||||||
|
c := e.NewContext(req, rec)
|
||||||
|
|
||||||
|
stopChan := make(chan struct{})
|
||||||
|
err := m(func(c echo.Context) error {
|
||||||
|
// NOTE: when difference between timeout duration and handler execution time is almost the same (in range of 100microseconds)
|
||||||
|
// the result of timeout does not seem to be reliable - could respond timeout, could respond handler output
|
||||||
|
// difference over 500microseconds (0.5millisecond) response seems to be reliable
|
||||||
|
<-stopChan
|
||||||
|
|
||||||
|
// The Request Context should have a Deadline set by http.TimeoutHandler
|
||||||
|
if _, ok := c.Request().Context().Deadline(); !ok {
|
||||||
|
assert.Fail(t, "No timeout set on Request Context")
|
||||||
|
}
|
||||||
|
handlerFinishedExecution <- c.Request().Context().Err() == nil
|
||||||
|
return c.String(http.StatusOK, "Hello, World!")
|
||||||
|
})(c)
|
||||||
|
stopChan <- struct{}{}
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
|
||||||
|
assert.Equal(t, "Timeout! change me", rec.Body.String())
|
||||||
|
assert.False(t, <-handlerFinishedExecution)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user