fiber/middleware/timeout/timeout.go
RW 05f8ac0255
🔥 feat: Add config for Timeout middleware (#3604)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-07-20 15:22:08 +02:00

62 lines
1.5 KiB
Go

package timeout
import (
"context"
"errors"
"github.com/gofiber/fiber/v3"
)
// New enforces a timeout for each incoming request. If the timeout expires or
// any of the specified errors occur, fiber.ErrRequestTimeout is returned.
func New(h fiber.Handler, config ...Config) fiber.Handler {
cfg := configDefault(config...)
return func(ctx fiber.Ctx) error {
if cfg.Next != nil && cfg.Next(ctx) {
return h(ctx)
}
timeout := cfg.Timeout
if timeout <= 0 {
return runHandler(ctx, h, cfg)
}
tCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
err := runHandler(ctx, h, cfg)
if errors.Is(tCtx.Err(), context.DeadlineExceeded) {
if cfg.OnTimeout != nil {
return cfg.OnTimeout(ctx)
}
return fiber.ErrRequestTimeout
}
return err
}
}
// runHandler executes the handler and returns fiber.ErrRequestTimeout if it
// sees a deadline exceeded error or one of the custom "timeout-like" errors.
func runHandler(c fiber.Ctx, h fiber.Handler, cfg Config) error {
err := h(c)
if err != nil && (errors.Is(err, context.DeadlineExceeded) || (len(cfg.Errors) > 0 && isCustomError(err, cfg.Errors))) {
if cfg.OnTimeout != nil {
return cfg.OnTimeout(c)
}
return fiber.ErrRequestTimeout
}
return err
}
// isCustomError checks whether err matches any error in errList using errors.Is.
func isCustomError(err error, errList []error) bool {
for _, e := range errList {
if errors.Is(err, e) {
return true
}
}
return false
}