Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 18:15 UTC
matchers: `query` now ANDs multiple keys (#6054)
Co-authored-by: Francis Lavoie <lavofr@gmail.com>
Aziz Rmadi committed
Jan 21, 2024 at 20:36 UTC
ed7e3c906ab7ab8a91b5ce4d4345c46e4a351d2a
2 files changed
+56
-7
modules/caddyhttp/matchers.go
+20
-7
@@ -33,6 +33,7 @@ import (
33
"github.com/google/cel-go/cel"
34
"github.com/google/cel-go/common/types"
35
"github.com/google/cel-go/common/types/ref"
36
+ "golang.org/x/exp/slices"
37
38
"github.com/caddyserver/caddy/v2"
39
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -789,6 +790,12 @@ func (m *MatchQuery) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
790
791
// Match returns true if r matches m. An empty m matches an empty query string.
792
func (m MatchQuery) Match(r *http.Request) bool {
793
+ // If no query keys are configured, this only
794
+ // matches an empty query string.
795
+ if len(m) == 0 {
796
+ return len(r.URL.Query()) == 0
797
+ }
798
+
799
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
800
801
// parse query string just once, for efficiency
@@ -806,19 +813,25 @@ func (m MatchQuery) Match(r *http.Request) bool {
813
return false
814
}
815
816
+ // Count the amount of matched keys, to ensure we AND
817
+ // between all configured query keys; all keys must
818
+ // match at least one value.
819
+ matchedKeys := 0
820
for param, vals := range m {
821
param = repl.ReplaceAll(param, "")
822
paramVal, found := parsed[param]
812
- if found {
813
- for _, v := range vals {
814
- v = repl.ReplaceAll(v, "")
815
- if paramVal[0] == v || v == "*" {
816
- return true
817
- }
823
+ if !found {
824
+ return false
825
+ }
826
+ for _, v := range vals {
827
+ v = repl.ReplaceAll(v, "")
828
+ if slices.Contains(paramVal, v) || v == "*" {
829
+ matchedKeys++
830
+ break
831
}
832
}
833
}
821
- return len(m) == 0 && len(r.URL.Query()) == 0
834
+ return matchedKeys == len(m)
835
}
836
837
// CELLibrary produces options that expose this matcher for use in CEL
modules/caddyhttp/matchers_test.go
+36
@@ -763,6 +763,42 @@ func TestQueryMatcher(t *testing.T) {
763
input: "/?somekey=1",
764
expect: true,
765
},
766
+ {
767
+ scenario: "do not match when not all query params are present",
768
+ match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
769
+ input: "/?debug=1",
770
+ expect: false,
771
+ },
772
+ {
773
+ scenario: "match when all query params are present",
774
+ match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
775
+ input: "/?debug=1&foo=bar",
776
+ expect: true,
777
+ },
778
+ {
779
+ scenario: "do not match when the value of a query param does not match",
780
+ match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
781
+ input: "/?debug=2&foo=bar",
782
+ expect: false,
783
+ },
784
+ {
785
+ scenario: "do not match when all the values the query params do not match",
786
+ match: MatchQuery{"debug": []string{"1"}, "foo": []string{"bar"}},
787
+ input: "/?debug=2&foo=baz",
788
+ expect: false,
789
+ },
790
+ {
791
+ scenario: "match against two values for the same key",
792
+ match: MatchQuery{"debug": []string{"1"}},
793
+ input: "/?debug=1&debug=2",
794
+ expect: true,
795
+ },
796
+ {
797
+ scenario: "match against two values for the same key",
798
+ match: MatchQuery{"debug": []string{"2", "1"}},
799
+ input: "/?debug=2&debug=1",
800
+ expect: true,
801
+ },
802
} {
803
804
u, _ := url.Parse(tc.input)