@marcel91200 / caddy Mirror · read-only / commits / ed7e3c90
Fork 0

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)