diff --git a/aliases.go b/aliases.go index cc037359..eca05047 100644 --- a/aliases.go +++ b/aliases.go @@ -506,6 +506,10 @@ var ( // // A shortcut for the `context#IsErrPath`. IsErrPath = context.IsErrPath + // IsErrCanceled reports whether the "err" is caused by a cancellation or timeout. + // + // A shortcut for the `context#IsErrCanceled`. + IsErrCanceled = context.IsErrCanceled // ErrEmptyForm is the type error which API users can make use of // to check if a form was empty on `Context.ReadForm`. // diff --git a/context/context.go b/context/context.go index a04a49f0..1b4e43c7 100644 --- a/context/context.go +++ b/context/context.go @@ -232,14 +232,28 @@ func (ctx *Context) EndRequest() { // Note that it will always return true // when called from a goroutine after the request-response lifecycle. func (ctx *Context) IsCanceled() bool { + var err error if reqCtx := ctx.request.Context(); reqCtx != nil { - err := reqCtx.Err() - if err != nil && errors.Is(err, stdContext.Canceled) { - return true - } + err = reqCtx.Err() + } else { + err = ctx.GetErr() } - return false + return IsErrCanceled(err) +} + +// IsErrCanceled reports whether the "err" is caused by a cancellation or timeout. +func IsErrCanceled(err error) bool { + if err == nil { + return false + } + + var netErr net.Error + return (errors.As(err, &netErr) && netErr.Timeout()) || + errors.Is(err, stdContext.Canceled) || + errors.Is(err, stdContext.DeadlineExceeded) || + errors.Is(err, http.ErrHandlerTimeout) || + err.Error() == "closed pool" } // OnConnectionClose registers the "cb" Handler @@ -1483,6 +1497,7 @@ func (ctx *Context) URLParamSlice(name string) []string { if v == "" { continue } + normalizedValues = append(normalizedValues, v) }