diff options
Diffstat (limited to 'modules/caddyhttp/routes.go')
-rw-r--r-- | modules/caddyhttp/routes.go | 97 |
1 files changed, 78 insertions, 19 deletions
diff --git a/modules/caddyhttp/routes.go b/modules/caddyhttp/routes.go index 939d01e55..ccb5f2515 100644 --- a/modules/caddyhttp/routes.go +++ b/modules/caddyhttp/routes.go @@ -254,18 +254,13 @@ func wrapRoute(route Route) Middleware { nextCopy := next // route must match at least one of the matcher sets - if !route.MatcherSets.AnyMatch(req) { + matches, err := route.MatcherSets.AnyMatchWithError(req) + if err != nil { // allow matchers the opportunity to short circuit // the request and trigger the error handling chain - err, ok := GetVar(req.Context(), MatcherErrorVarKey).(error) - if ok { - // clear out the error from context, otherwise - // it will cascade to the error routes (#4916) - SetVar(req.Context(), MatcherErrorVarKey, nil) - // return the matcher's error - return err - } - + return err + } + if !matches { // call the next handler, and skip this one, // since the matcher didn't match return nextCopy.ServeHTTP(rw, req) @@ -341,19 +336,58 @@ func wrapMiddleware(ctx caddy.Context, mh MiddlewareHandler, metrics *Metrics) M // MatcherSet is a set of matchers which // must all match in order for the request // to be matched successfully. -type MatcherSet []RequestMatcher +type MatcherSet []any // Match returns true if the request matches all // matchers in mset or if there are no matchers. func (mset MatcherSet) Match(r *http.Request) bool { for _, m := range mset { - if !m.Match(r) { - return false + if me, ok := m.(RequestMatcherWithError); ok { + match, _ := me.MatchWithError(r) + if !match { + return false + } + continue + } + if me, ok := m.(RequestMatcher); ok { + if !me.Match(r) { + return false + } + continue } + return false } return true } +// MatchWithError returns true if r matches m. +func (mset MatcherSet) MatchWithError(r *http.Request) (bool, error) { + for _, m := range mset { + if me, ok := m.(RequestMatcherWithError); ok { + match, err := me.MatchWithError(r) + if err != nil || !match { + return match, err + } + continue + } + if me, ok := m.(RequestMatcher); ok { + if !me.Match(r) { + // for backwards compatibility + err, ok := GetVar(r.Context(), MatcherErrorVarKey).(error) + if ok { + // clear out the error from context since we've consumed it + SetVar(r.Context(), MatcherErrorVarKey, nil) + return false, err + } + return false, nil + } + continue + } + return false, fmt.Errorf("matcher is not a RequestMatcher or RequestMatcherWithError: %#v", m) + } + return true, nil +} + // RawMatcherSets is a group of matcher sets // in their raw, JSON form. type RawMatcherSets []caddy.ModuleMap @@ -366,25 +400,50 @@ type MatcherSets []MatcherSet // AnyMatch returns true if req matches any of the // matcher sets in ms or if there are no matchers, // in which case the request always matches. +// +// Deprecated: Use AnyMatchWithError instead. func (ms MatcherSets) AnyMatch(req *http.Request) bool { for _, m := range ms { - if m.Match(req) { - return true + match, err := m.MatchWithError(req) + if err != nil { + SetVar(req.Context(), MatcherErrorVarKey, err) + return false + } + if match { + return match } } return len(ms) == 0 } +// AnyMatchWithError returns true if req matches any of the +// matcher sets in ms or if there are no matchers, in which +// case the request always matches. If any matcher returns +// an error, we cut short and return the error. +func (ms MatcherSets) AnyMatchWithError(req *http.Request) (bool, error) { + for _, m := range ms { + match, err := m.MatchWithError(req) + if err != nil || match { + return match, err + } + } + return len(ms) == 0, nil +} + // FromInterface fills ms from an 'any' value obtained from LoadModule. func (ms *MatcherSets) FromInterface(matcherSets any) error { for _, matcherSetIfaces := range matcherSets.([]map[string]any) { var matcherSet MatcherSet for _, matcher := range matcherSetIfaces { - reqMatcher, ok := matcher.(RequestMatcher) - if !ok { - return fmt.Errorf("decoded module is not a RequestMatcher: %#v", matcher) + if m, ok := matcher.(RequestMatcherWithError); ok { + matcherSet = append(matcherSet, m) + continue + } + if m, ok := matcher.(RequestMatcher); ok { + matcherSet = append(matcherSet, m) + continue } - matcherSet = append(matcherSet, reqMatcher) + return fmt.Errorf("decoded module is not a RequestMatcher or RequestMatcherWithError: %#v", matcher) } *ms = append(*ms, matcherSet) } |