caddyhttp: Accept placeholders in vars matcher key

Until now, the vars matcher has unintentionally lacked parity with the
map directive: the destination placeholders of the map directive would
be expressed as placeholders, i.e. {foo}. But the vars matcher would
not use { }: vars foo value

This looked weird, and was confusing, since it implied that the key
could be dynamic, which doesn't seem helpful here.

I think this is a proper bug fix, since we're not used to accessing
placeholders literally without { } in the Caddyfile.
This commit is contained in:
Matthew Holt 2022-09-01 16:49:18 -06:00
parent 1edc1a45e3
commit 7c35bfa57c
No known key found for this signature in database
GPG Key ID: 2A349DD577D586A5
2 changed files with 24 additions and 19 deletions

View File

@ -18,6 +18,7 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@ -62,11 +63,10 @@ func (m VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next H
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax: // UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
// //
// vars [<name> <val>] { // vars [<name> <val>] {
// <name> <val> // <name> <val>
// ... // ...
// } // }
//
func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if *m == nil { if *m == nil {
*m = make(VarsMiddleware) *m = make(VarsMiddleware)
@ -109,14 +109,17 @@ func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
} }
// VarsMatcher is an HTTP request matcher which can match // VarsMatcher is an HTTP request matcher which can match
// requests based on variables in the context. The key is // requests based on variables in the context or placeholder
// the name of the variable, and the values are possible // values. The key is the placeholder or name of the variable,
// values the variable can be in order to match (OR'ed). // and the values are possible values the variable can be in
// order to match (logical OR'ed).
// //
// As a special case, this matcher can also match on // If the key is surrounded by `{ }` it is assumed to be a
// placeholders generally. If the key is not an HTTP chain // placeholder. Otherwise, it will be considered a variable
// variable, it will be checked to see if it is a // name.
// placeholder name, and if so, will compare its value. //
// Placeholders in the keys are not expanded, but
// placeholders in the values are.
type VarsMatcher map[string][]string type VarsMatcher map[string][]string
// CaddyModule returns the Caddy module information. // CaddyModule returns the Caddy module information.
@ -160,13 +163,13 @@ func (m VarsMatcher) Match(r *http.Request) bool {
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
for key, vals := range m { for key, vals := range m {
// look up the comparison value we will check against with this key var varValue any
matcherVarNameExpanded := repl.ReplaceAll(key, "") if strings.HasPrefix(key, "{") &&
varValue, ok := vars[matcherVarNameExpanded] strings.HasSuffix(key, "}") &&
if !ok { strings.Count(key, "{") == 1 {
// as a special case, if it's not an HTTP variable, varValue, _ = repl.Get(strings.Trim(key, "{}"))
// see if it's a placeholder name } else {
varValue, _ = repl.Get(matcherVarNameExpanded) varValue = vars[key]
} }
// see if any of the values given in the matcher match the actual value // see if any of the values given in the matcher match the actual value

View File

@ -238,6 +238,8 @@ func toString(val any) string {
return v return v
case fmt.Stringer: case fmt.Stringer:
return v.String() return v.String()
case error:
return v.Error()
case byte: case byte:
return string(v) return string(v)
case []byte: case []byte: