mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-10 17:32:15 +01:00
fix(webhook): detach async goroutine from pooled echo.Context
This commit is contained in:
@@ -337,7 +337,10 @@ func basicAuthMiddleware(username, password string) echo.MiddlewareFunc {
|
||||
func contextMiddleware(fs *gotenberg.FileSystem, timeout time.Duration, bodyLimit int64, downloadFromCfg downloadFromConfig) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
logger := c.Get("logger").(*slog.Logger)
|
||||
logger, _ := c.Get("logger").(*slog.Logger)
|
||||
if logger == nil {
|
||||
return errors.New("no logger in context (possible pool reuse)")
|
||||
}
|
||||
|
||||
// We create a context with a timeout so that underlying processes are
|
||||
// able to stop early and correctly handle a timeout scenario.
|
||||
@@ -395,7 +398,14 @@ func contextMiddleware(fs *gotenberg.FileSystem, timeout time.Duration, bodyLimi
|
||||
func hardTimeoutMiddleware(hardTimeout time.Duration) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
logger := c.Get("logger").(*slog.Logger)
|
||||
// Guard the type assertion so a pooled [echo.Context] whose
|
||||
// store has been recycled under us does not crash the process.
|
||||
// See the webhook async handler for the race this protects
|
||||
// against.
|
||||
logger, _ := c.Get("logger").(*slog.Logger)
|
||||
if logger == nil {
|
||||
return errors.New("no logger in context (possible pool reuse)")
|
||||
}
|
||||
|
||||
// Define a hard timeout if the route handler fails to timeout as
|
||||
// expected.
|
||||
|
||||
39
pkg/modules/api/middlewares_test.go
Normal file
39
pkg/modules/api/middlewares_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func TestHardTimeoutMiddleware_MissingLoggerReturnsErrorInsteadOfPanicking(t *testing.T) {
|
||||
mw := hardTimeoutMiddleware(100 * time.Millisecond)
|
||||
handler := mw(func(c echo.Context) error { return nil })
|
||||
|
||||
e := echo.New()
|
||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
c := e.NewContext(req, rec)
|
||||
|
||||
// c has no "logger" key, mimicking a pooled context whose store was
|
||||
// recycled under a concurrently running webhook goroutine. The
|
||||
// middleware must surface an error instead of panicking on the
|
||||
// unchecked type assertion the pre-fix code relied on.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Fatalf("hardTimeoutMiddleware panicked: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
err := handler(c)
|
||||
if err == nil {
|
||||
t.Fatal("expected an error for missing logger, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "logger") {
|
||||
t.Fatalf("error = %q, want a message mentioning logger", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user