From ddd690de4cc133bc728f765b2492ccb54f9d84ca Mon Sep 17 00:00:00 2001
From: James Birtles <jameshbirtles@gmail.com>
Date: Fri, 26 Jun 2020 22:14:47 +0100
Subject: [PATCH] caddyhttp: Support placeholders in query matcher (#3521)

---
 modules/caddyhttp/matchers.go      |  3 +++
 modules/caddyhttp/matchers_test.go | 17 +++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go
index a291242a6..164f4434d 100644
--- a/modules/caddyhttp/matchers.go
+++ b/modules/caddyhttp/matchers.go
@@ -374,10 +374,13 @@ 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 {
+	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
 	for param, vals := range m {
+		param = repl.ReplaceAll(param, "")
 		paramVal, found := r.URL.Query()[param]
 		if found {
 			for _, v := range vals {
+				v = repl.ReplaceAll(v, "")
 				if paramVal[0] == v || v == "*" {
 					return true
 				}
diff --git a/modules/caddyhttp/matchers_test.go b/modules/caddyhttp/matchers_test.go
index 1ac958827..883680f2b 100644
--- a/modules/caddyhttp/matchers_test.go
+++ b/modules/caddyhttp/matchers_test.go
@@ -546,11 +546,28 @@ func TestQueryMatcher(t *testing.T) {
 			input:    "/?",
 			expect:   false,
 		},
+		{
+			scenario: "match against a placeholder value",
+			match:    MatchQuery{"debug": []string{"{http.vars.debug}"}},
+			input:    "/?debug=1",
+			expect:   true,
+		},
+		{
+			scenario: "match against a placeholder key",
+			match:    MatchQuery{"{http.vars.key}": []string{"1"}},
+			input:    "/?somekey=1",
+			expect:   true,
+		},
 	} {
 
 		u, _ := url.Parse(tc.input)
 
 		req := &http.Request{URL: u}
+		repl := caddy.NewReplacer()
+		ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl)
+		repl.Set("http.vars.debug", "1")
+		repl.Set("http.vars.key", "somekey")
+		req = req.WithContext(ctx)
 		actual := tc.match.Match(req)
 		if actual != tc.expect {
 			t.Errorf("Test %d %v: Expected %t, got %t for '%s'", i, tc.match, tc.expect, actual, tc.input)