mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-26 05:33:49 +03:00
caddyhttp: Reject conflicting values in query strings
This commit is contained in:
parent
a999b70727
commit
7ce5c0aaac
2 changed files with 43 additions and 8 deletions
|
@ -123,6 +123,7 @@ type (
|
||||||
// keyed by the query keys, with an array of string values to match for that key.
|
// keyed by the query keys, with an array of string values to match for that key.
|
||||||
// Query key matches are exact, but wildcards may be used for value matches. Both
|
// Query key matches are exact, but wildcards may be used for value matches. Both
|
||||||
// keys and values may be placeholders.
|
// keys and values may be placeholders.
|
||||||
|
//
|
||||||
// An example of the structure to match `?key=value&topic=api&query=something` is:
|
// An example of the structure to match `?key=value&topic=api&query=something` is:
|
||||||
//
|
//
|
||||||
// ```json
|
// ```json
|
||||||
|
@ -808,19 +809,29 @@ func (m MatchQuery) Match(r *http.Request) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for param, vals := range m {
|
for param, allowedVals := range m {
|
||||||
param = repl.ReplaceAll(param, "")
|
param = repl.ReplaceAll(param, "")
|
||||||
paramVal, found := parsed[param]
|
incomingVals, found := parsed[param]
|
||||||
if found {
|
if found {
|
||||||
for _, v := range vals {
|
for _, allowedVal := range allowedVals {
|
||||||
v = repl.ReplaceAll(v, "")
|
allowedVal = repl.ReplaceAll(allowedVal, "")
|
||||||
if paramVal[0] == v || v == "*" {
|
if allowedVal == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
matched := true
|
||||||
|
for _, incomingVal := range incomingVals {
|
||||||
|
if incomingVal != allowedVal {
|
||||||
|
matched = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matched {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len(m) == 0 && len(r.URL.Query()) == 0
|
return len(m) == 0 && len(parsed) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// CELLibrary produces options that expose this matcher for use in CEL
|
// CELLibrary produces options that expose this matcher for use in CEL
|
||||||
|
|
|
@ -718,7 +718,7 @@ func TestQueryMatcher(t *testing.T) {
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
scenario: "non match against a wildcarded",
|
scenario: "non match against a wildcard",
|
||||||
match: MatchQuery{"debug": []string{"*"}},
|
match: MatchQuery{"debug": []string{"*"}},
|
||||||
input: "/?other=something",
|
input: "/?other=something",
|
||||||
expect: false,
|
expect: false,
|
||||||
|
@ -765,6 +765,30 @@ func TestQueryMatcher(t *testing.T) {
|
||||||
input: "/?somekey=1",
|
input: "/?somekey=1",
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: "don't match conflicting values",
|
||||||
|
match: MatchQuery{"a": []string{"1"}},
|
||||||
|
input: "/?a=1&a=2",
|
||||||
|
expect: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "conflicting values are ambiguous with multiple match values",
|
||||||
|
match: MatchQuery{"a": []string{"1", "2"}},
|
||||||
|
input: "/?a=1&a=2",
|
||||||
|
expect: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "repeated kv pairs in URI",
|
||||||
|
match: MatchQuery{"a": []string{"1"}},
|
||||||
|
input: "/?a=1&a=1",
|
||||||
|
expect: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: "TODO: it's unclear whether the values should be AND'ed or OR'ed", // perhaps multiple query matchers could be used to "and"
|
||||||
|
match: MatchQuery{"a": []string{"1", "2"}},
|
||||||
|
input: "/?a=2",
|
||||||
|
expect: true,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
|
|
||||||
u, _ := url.Parse(tc.input)
|
u, _ := url.Parse(tc.input)
|
||||||
|
@ -777,7 +801,7 @@ func TestQueryMatcher(t *testing.T) {
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
actual := tc.match.Match(req)
|
actual := tc.match.Match(req)
|
||||||
if actual != tc.expect {
|
if actual != tc.expect {
|
||||||
t.Errorf("Test %d %v: Expected %t, got %t for '%s'", i, tc.match, tc.expect, actual, tc.input)
|
t.Errorf("Test %d %v: Expected %t, got %t for '%s' (%s)", i, tc.match, tc.expect, actual, tc.input, tc.scenario)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue