Skip to content

Commit

Permalink
matchers: query now ANDs multiple keys (#6054)
Browse files Browse the repository at this point in the history
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
  • Loading branch information
armadi1809 and francislavoie committed Jan 22, 2024
1 parent c0273f1 commit ed7e3c9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 7 deletions.
27 changes: 20 additions & 7 deletions modules/caddyhttp/matchers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"golang.org/x/exp/slices"

"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
Expand Down Expand Up @@ -789,6 +790,12 @@ func (m *MatchQuery) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {

// Match returns true if r matches m. An empty m matches an empty query string.
func (m MatchQuery) Match(r *http.Request) bool {
// If no query keys are configured, this only
// matches an empty query string.
if len(m) == 0 {
return len(r.URL.Query()) == 0
}

repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)

// parse query string just once, for efficiency
Expand All @@ -806,19 +813,25 @@ func (m MatchQuery) Match(r *http.Request) bool {
return false
}

// Count the amount of matched keys, to ensure we AND
// between all configured query keys; all keys must
// match at least one value.
matchedKeys := 0
for param, vals := range m {
param = repl.ReplaceAll(param, "")
paramVal, found := parsed[param]
if found {
for _, v := range vals {
v = repl.ReplaceAll(v, "")
if paramVal[0] == v || v == "*" {
return true
}
if !found {
return false
}
for _, v := range vals {
v = repl.ReplaceAll(v, "")
if slices.Contains(paramVal, v) || v == "*" {
matchedKeys++
break
}
}
}
return len(m) == 0 && len(r.URL.Query()) == 0
return matchedKeys == len(m)
}

// CELLibrary produces options that expose this matcher for use in CEL
Expand Down
36 changes: 36 additions & 0 deletions modules/caddyhttp/matchers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,42 @@ func TestQueryMatcher(t *testing.T) {
input: "/?somekey=1",
expect: true,
},
{
scenario: "do not match when not all query params are present",
match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
input: "/?debug=1",
expect: false,
},
{
scenario: "match when all query params are present",
match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
input: "/?debug=1&foo=bar",
expect: true,
},
{
scenario: "do not match when the value of a query param does not match",
match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
input: "/?debug=2&foo=bar",
expect: false,
},
{
scenario: "do not match when all the values the query params do not match",
match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
input: "/?debug=2&foo=baz",
expect: false,
},
{
scenario: "match against two values for the same key",
match: MatchQuery{"debug": []string{"1"}},
input: "/?debug=1&debug=2",
expect: true,
},
{
scenario: "match against two values for the same key",
match: MatchQuery{"debug": []string{"2", "1"}},
input: "/?debug=2&debug=1",
expect: true,
},
} {

u, _ := url.Parse(tc.input)
Expand Down

0 comments on commit ed7e3c9

Please sign in to comment.