summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/matchers.go
diff options
context:
space:
mode:
authorFrancis Lavoie <lavofr@gmail.com>2022-07-13 16:15:00 -0400
committerGitHub <noreply@github.com>2022-07-13 14:15:00 -0600
commit7d1f7771c9961dc6607a6ac5894b9c3195c25fcf (patch)
tree6e2afea66b04fd5ba5231ef475497e17d50d5c3e /modules/caddyhttp/matchers.go
parent04a14ee37ac6192d734518fa9082d6eb93971bc6 (diff)
reverseproxy: Implement retry count, alternative to try_duration (#4756)
* reverseproxy: Implement retry count, alternative to try_duration * Add Caddyfile support for `retry_match` * Refactor to deduplicate matcher parsing logic * Fix lint
Diffstat (limited to 'modules/caddyhttp/matchers.go')
-rw-r--r--modules/caddyhttp/matchers.go103
1 files changed, 54 insertions, 49 deletions
diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go
index 4c35802..430318a 100644
--- a/modules/caddyhttp/matchers.go
+++ b/modules/caddyhttp/matchers.go
@@ -1003,57 +1003,12 @@ func (MatchNot) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
- // first, unmarshal each matcher in the set from its tokens
- type matcherPair struct {
- raw caddy.ModuleMap
- decoded MatcherSet
- }
for d.Next() {
- var mp matcherPair
- matcherMap := make(map[string]RequestMatcher)
-
- // in case there are multiple instances of the same matcher, concatenate
- // their tokens (we expect that UnmarshalCaddyfile should be able to
- // handle more than one segment); otherwise, we'd overwrite other
- // instances of the matcher in this set
- tokensByMatcherName := make(map[string][]caddyfile.Token)
- for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
- matcherName := d.Val()
- tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
- }
- for matcherName, tokens := range tokensByMatcherName {
- mod, err := caddy.GetModule("http.matchers." + matcherName)
- if err != nil {
- return d.Errf("getting matcher module '%s': %v", matcherName, err)
- }
- unm, ok := mod.New().(caddyfile.Unmarshaler)
- if !ok {
- return d.Errf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
- }
- err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
- if err != nil {
- return err
- }
- rm, ok := unm.(RequestMatcher)
- if !ok {
- return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
- }
- matcherMap[matcherName] = rm
- mp.decoded = append(mp.decoded, rm)
- }
-
- // we should now have a functional 'not' matcher, but we also
- // need to be able to marshal as JSON, otherwise config
- // adaptation will be missing the matchers!
- mp.raw = make(caddy.ModuleMap)
- for name, matcher := range matcherMap {
- jsonBytes, err := json.Marshal(matcher)
- if err != nil {
- return fmt.Errorf("marshaling %T matcher: %v", matcher, err)
- }
- mp.raw[name] = jsonBytes
+ matcherSet, err := ParseCaddyfileNestedMatcherSet(d)
+ if err != nil {
+ return err
}
- m.MatcherSetsRaw = append(m.MatcherSetsRaw, mp.raw)
+ m.MatcherSetsRaw = append(m.MatcherSetsRaw, matcherSet)
}
return nil
}
@@ -1352,6 +1307,56 @@ func (mre *MatchRegexp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return nil
}
+// ParseCaddyfileNestedMatcher parses the Caddyfile tokens for a nested
+// matcher set, and returns its raw module map value.
+func ParseCaddyfileNestedMatcherSet(d *caddyfile.Dispenser) (caddy.ModuleMap, error) {
+ matcherMap := make(map[string]RequestMatcher)
+
+ // in case there are multiple instances of the same matcher, concatenate
+ // their tokens (we expect that UnmarshalCaddyfile should be able to
+ // handle more than one segment); otherwise, we'd overwrite other
+ // instances of the matcher in this set
+ tokensByMatcherName := make(map[string][]caddyfile.Token)
+ for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); {
+ matcherName := d.Val()
+ tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
+ }
+
+ for matcherName, tokens := range tokensByMatcherName {
+ mod, err := caddy.GetModule("http.matchers." + matcherName)
+ if err != nil {
+ return nil, d.Errf("getting matcher module '%s': %v", matcherName, err)
+ }
+ unm, ok := mod.New().(caddyfile.Unmarshaler)
+ if !ok {
+ return nil, d.Errf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
+ }
+ err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
+ if err != nil {
+ return nil, err
+ }
+ rm, ok := unm.(RequestMatcher)
+ if !ok {
+ return nil, fmt.Errorf("matcher module '%s' is not a request matcher", matcherName)
+ }
+ matcherMap[matcherName] = rm
+ }
+
+ // we should now have a functional matcher, but we also
+ // need to be able to marshal as JSON, otherwise config
+ // adaptation will be missing the matchers!
+ matcherSet := make(caddy.ModuleMap)
+ for name, matcher := range matcherMap {
+ jsonBytes, err := json.Marshal(matcher)
+ if err != nil {
+ return nil, fmt.Errorf("marshaling %T matcher: %v", matcher, err)
+ }
+ matcherSet[name] = jsonBytes
+ }
+
+ return matcherSet, nil
+}
+
var (
wordRE = regexp.MustCompile(`\w+`)
)