summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/vars.go
diff options
context:
space:
mode:
authorMatt Holt <mholt@users.noreply.github.com>2021-12-13 13:59:58 -0700
committerGitHub <noreply@github.com>2021-12-13 13:59:58 -0700
commitecac03cdcb6cceae743aac16faca7f32e5da1607 (patch)
tree35cadcb9ae06d7e1aa33a987d5f5ef239c7b5446 /modules/caddyhttp/vars.go
parentc04d24cafa60e522842d5188587ab07af2082e9b (diff)
caddyhttp: Enhance vars matcher (#4433)
* caddyhttp: Enhance vars matcher Enable "or" logic for multiple values. Fall back to checking placeholders if not a var name. * Fix tests (thanks @mohammed90 !)
Diffstat (limited to 'modules/caddyhttp/vars.go')
-rw-r--r--modules/caddyhttp/vars.go76
1 files changed, 52 insertions, 24 deletions
diff --git a/modules/caddyhttp/vars.go b/modules/caddyhttp/vars.go
index 5779b5d..91a2072 100644
--- a/modules/caddyhttp/vars.go
+++ b/modules/caddyhttp/vars.go
@@ -59,8 +59,15 @@ func (t VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next H
}
// VarsMatcher is an HTTP request matcher which can match
-// requests based on variables in the context.
-type VarsMatcher map[string]string
+// requests based on variables in the context. The key is
+// the name of the variable, and the values are possible
+// values the variable can be in order to match (OR'ed).
+//
+// As a special case, this matcher can also match on
+// placeholders generally. If the key is not an HTTP chain
+// variable, it will be checked to see if it is a
+// placeholder name, and if so, will compare its value.
+type VarsMatcher map[string][]string
// CaddyModule returns the Caddy module information.
func (VarsMatcher) CaddyModule() caddy.ModuleInfo {
@@ -73,14 +80,18 @@ func (VarsMatcher) CaddyModule() caddy.ModuleInfo {
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
func (m *VarsMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil {
- *m = make(map[string]string)
+ *m = make(map[string][]string)
}
for d.Next() {
- var field, val string
- if !d.Args(&field, &val) {
- return d.Errf("malformed vars matcher: expected both field and value")
+ var field string
+ if !d.Args(&field) {
+ return d.Errf("malformed vars matcher: expected field name")
+ }
+ vals := d.RemainingArgs()
+ if len(vals) == 0 {
+ return d.Errf("malformed vars matcher: expected at least one value to match against")
}
- (*m)[field] = val
+ (*m)[field] = vals
if d.NextBlock(0) {
return d.Err("malformed vars matcher: blocks are not supported")
}
@@ -88,29 +99,46 @@ func (m *VarsMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return nil
}
-// Match matches a request based on variables in the context.
+// Match matches a request based on variables in the context,
+// or placeholders if the key is not a variable.
func (m VarsMatcher) Match(r *http.Request) bool {
+ if len(m) == 0 {
+ return true
+ }
+
vars := r.Context().Value(VarsCtxKey).(map[string]interface{})
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
- for k, v := range m {
- keyExpanded := repl.ReplaceAll(k, "")
- valExpanded := repl.ReplaceAll(v, "")
- var varStr string
- switch vv := vars[keyExpanded].(type) {
- case string:
- varStr = vv
- case fmt.Stringer:
- varStr = vv.String()
- case error:
- varStr = vv.Error()
- default:
- varStr = fmt.Sprintf("%v", vv)
+
+ for key, vals := range m {
+ // look up the comparison value we will check against with this key
+ matcherVarNameExpanded := repl.ReplaceAll(key, "")
+ varValue, ok := vars[matcherVarNameExpanded]
+ if !ok {
+ // as a special case, if it's not an HTTP variable,
+ // see if it's a placeholder name
+ varValue, _ = repl.Get(matcherVarNameExpanded)
}
- if varStr != valExpanded {
- return false
+
+ // see if any of the values given in the matcher match the actual value
+ for _, v := range vals {
+ matcherValExpanded := repl.ReplaceAll(v, "")
+ var varStr string
+ switch vv := varValue.(type) {
+ case string:
+ varStr = vv
+ case fmt.Stringer:
+ varStr = vv.String()
+ case error:
+ varStr = vv.Error()
+ default:
+ varStr = fmt.Sprintf("%v", vv)
+ }
+ if varStr == matcherValExpanded {
+ return true
+ }
}
}
- return true
+ return false
}
// MatchVarsRE matches the value of the context variables by a given regular expression.