Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 13:30 UTC
caddyhttp: Sync placeholder expansion in `vars` and `vars_regexp` (#7573)
* vars: Expand placeholders in custom variables like in `vars_regexp` * vars: Reuse variables inside match loops
vnxme committed
Mar 17, 2026 at 22:08 UTC
df65455b1f0d230a34d4bd7111213fe6917abe98
1 file changed
+37
-22
modules/caddyhttp/vars.go
+37
-22
@@ -181,33 +181,46 @@ func (m VarsMatcher) MatchWithError(r *http.Request) (bool, error) {
181
vars := r.Context().Value(VarsCtxKey).(map[string]any)
182
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
183
184
+ var fromPlaceholder bool
185
+ var matcherValExpanded, valExpanded, varStr, v string
186
+ var varValue any
187
for key, vals := range m {
185
- var varValue any
188
if strings.HasPrefix(key, "{") &&
189
strings.HasSuffix(key, "}") &&
190
strings.Count(key, "{") == 1 {
191
varValue, _ = repl.Get(strings.Trim(key, "{}"))
192
+ fromPlaceholder = true
193
} else {
194
varValue = vars[key]
195
+ fromPlaceholder = false
196
+ }
197
+
198
+ switch vv := varValue.(type) {
199
+ case string:
200
+ varStr = vv
201
+ case fmt.Stringer:
202
+ varStr = vv.String()
203
+ case error:
204
+ varStr = vv.Error()
205
+ case nil:
206
+ varStr = ""
207
+ default:
208
+ varStr = fmt.Sprintf("%v", vv)
209
+ }
210
+
211
+ // Only expand placeholders in values from literal variable names
212
+ // (e.g. map outputs). Values resolved from placeholder keys are
213
+ // already final and must not be re-expanded, as that would allow
214
+ // user input like {env.SECRET} to be evaluated.
215
+ valExpanded = varStr
216
+ if !fromPlaceholder {
217
+ valExpanded = repl.ReplaceAll(varStr, "")
218
}
219
220
// see if any of the values given in the matcher match the actual value
195
- for _, v := range vals {
196
- matcherValExpanded := repl.ReplaceAll(v, "")
197
- var varStr string
198
- switch vv := varValue.(type) {
199
- case string:
200
- varStr = vv
201
- case fmt.Stringer:
202
- varStr = vv.String()
203
- case error:
204
- varStr = vv.Error()
205
- case nil:
206
- varStr = ""
207
- default:
208
- varStr = fmt.Sprintf("%v", vv)
209
- }
210
- if varStr == matcherValExpanded {
221
+ for _, v = range vals {
222
+ matcherValExpanded = repl.ReplaceAll(v, "")
223
+ if valExpanded == matcherValExpanded {
224
return true, nil
225
}
226
}
@@ -310,9 +323,11 @@ func (m MatchVarsRE) Match(r *http.Request) bool {
323
func (m MatchVarsRE) MatchWithError(r *http.Request) (bool, error) {
324
vars := r.Context().Value(VarsCtxKey).(map[string]any)
325
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
326
+
327
+ var fromPlaceholder, match bool
328
+ var valExpanded, varStr string
329
+ var varValue any
330
for key, val := range m {
314
- var varValue any
315
- var fromPlaceholder bool
331
if strings.HasPrefix(key, "{") &&
332
strings.HasSuffix(key, "}") &&
333
strings.Count(key, "{") == 1 {
@@ -320,9 +335,9 @@ func (m MatchVarsRE) MatchWithError(r *http.Request) (bool, error) {
335
fromPlaceholder = true
336
} else {
337
varValue = vars[key]
338
+ fromPlaceholder = false
339
}
340
325
- var varStr string
341
switch vv := varValue.(type) {
342
case string:
343
varStr = vv
@@ -340,11 +355,11 @@ func (m MatchVarsRE) MatchWithError(r *http.Request) (bool, error) {
355
// (e.g. map outputs). Values resolved from placeholder keys are
356
// already final and must not be re-expanded, as that would allow
357
// user input like {env.SECRET} to be evaluated.
343
- valExpanded := varStr
358
+ valExpanded = varStr
359
if !fromPlaceholder {
360
valExpanded = repl.ReplaceAll(varStr, "")
361
}
347
- if match := val.Match(valExpanded, repl); match {
362
+ if match = val.Match(valExpanded, repl); match {
363
return match, nil
364
}
365
}