aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules/caddyhttp/routes.go
diff options
context:
space:
mode:
Diffstat (limited to 'modules/caddyhttp/routes.go')
-rw-r--r--modules/caddyhttp/routes.go97
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)
}