diff --git a/modules/caddyhttp/celmatcher.go b/modules/caddyhttp/celmatcher.go index 0118cc7c8..e01995039 100644 --- a/modules/caddyhttp/celmatcher.go +++ b/modules/caddyhttp/celmatcher.go @@ -243,25 +243,29 @@ func (m *MatchExpression) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // CEL expression (e.g. strings) and we should retain that if d.CountRemainingArgs() > 1 { m.Expr = strings.Join(d.RemainingArgsRaw(), " ") - return nil + } else { + // there should at least be one arg + if !d.NextArg() { + return d.ArgErr() + } + + // if there's only one token, then we can safely grab the + // cleaned token (no quotes) and use that as the expression + // because there's no valid CEL expression that is only a + // quoted string; commonly quotes are used in Caddyfile to + // define the expression + m.Expr = d.Val() + + // use the named matcher's name, to fill regexp + // matchers names by default + m.Name = d.GetContextString(caddyfile.MatcherNameCtxKey) } - // there should at least be one arg - if !d.NextArg() { - return d.ArgErr() + // a matcher set holds only one expression matcher + if d.Next() { + return d.Err("repeated expression matchers are not supported, combine them into one expression with &&") } - // if there's only one token, then we can safely grab the - // cleaned token (no quotes) and use that as the expression - // because there's no valid CEL expression that is only a - // quoted string; commonly quotes are used in Caddyfile to - // define the expression - m.Expr = d.Val() - - // use the named matcher's name, to fill regexp - // matchers names by default - m.Name = d.GetContextString(caddyfile.MatcherNameCtxKey) - return nil } diff --git a/modules/caddyhttp/celmatcher_test.go b/modules/caddyhttp/celmatcher_test.go index 3e44fbbc9..7c8e706d3 100644 --- a/modules/caddyhttp/celmatcher_test.go +++ b/modules/caddyhttp/celmatcher_test.go @@ -21,9 +21,11 @@ import ( "encoding/pem" "net/http" "net/http/httptest" + "strings" "testing" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" ) var ( @@ -605,3 +607,20 @@ func TestMatchExpressionProvision(t *testing.T) { }) } } + +func TestMatchExpressionUnmarshalCaddyfileRepeated(t *testing.T) { + for _, input := range []string{` + expression {http.request.method} == 'GET' + expression {http.request.uri.path}.startsWith('/public/') + `, ` + expression "{http.request.method} == 'GET'" + expression {http.request.uri.path}.startsWith('/public/') + `} { + d := caddyfile.NewTestDispenser(input) + m := new(MatchExpression) + err := m.UnmarshalCaddyfile(d) + if err == nil || !strings.Contains(err.Error(), "repeated expression matchers are not supported") { + t.Errorf("UnmarshalCaddyfile() error = %v, want repeated expression error (expression: %s)", err, m.Expr) + } + } +}