Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 12:15 UTC
vars: Add matcher placeholder handling tests (#7640)
* vars: add matcher placeholder handling tests * vars: add query placeholder matcher coverage
Zen Dodd committed
Apr 11, 2026 at 08:27 UTC
7dcc041eec7e6221e99b8f13225b7afba6cacb8b
1 file changed
+159
modules/caddyhttp/vars_test.go
new
+159
@@ -0,0 +1,159 @@
1
+// Copyright 2015 Matthew Holt and The Caddy Authors
2
+//
3
+// Licensed under the Apache License, Version 2.0 (the "License");
4
+// you may not use this file except in compliance with the License.
5
+// You may obtain a copy of the License at
6
+//
7
+// http://www.apache.org/licenses/LICENSE-2.0
8
+//
9
+// Unless required by applicable law or agreed to in writing, software
10
+// distributed under the License is distributed on an "AS IS" BASIS,
11
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+// See the License for the specific language governing permissions and
13
+// limitations under the License.
14
+
15
+package caddyhttp
16
+
17
+import (
18
+ "context"
19
+ "net/http"
20
+ "net/http/httptest"
21
+ "testing"
22
+
23
+ "github.com/caddyserver/caddy/v2"
24
+)
25
+
26
+func newVarsTestRequest(t *testing.T, target string, headers http.Header, vars map[string]any) (*http.Request, *caddy.Replacer) {
27
+ t.Helper()
28
+
29
+ if target == "" {
30
+ target = "https://example.com/test"
31
+ }
32
+
33
+ req := httptest.NewRequest(http.MethodGet, target, nil)
34
+ req.Header = headers
35
+
36
+ repl := caddy.NewReplacer()
37
+ ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl)
38
+ if vars == nil {
39
+ vars = make(map[string]any)
40
+ }
41
+ // Inject vars directly so these tests exercise matcher-side handling of
42
+ // already-resolved values, not VarsMiddleware placeholder expansion.
43
+ ctx = context.WithValue(ctx, VarsCtxKey, vars)
44
+ req = req.WithContext(ctx)
45
+
46
+ addHTTPVarsToReplacer(repl, req, httptest.NewRecorder())
47
+
48
+ return req, repl
49
+}
50
+
51
+func TestVarsMatcherDoesNotExpandResolvedValues(t *testing.T) {
52
+ t.Setenv("CADDY_VARS_TEST_SECRET", "topsecret")
53
+
54
+ for _, tc := range []struct {
55
+ name string
56
+ target string
57
+ match VarsMatcher
58
+ headers http.Header
59
+ vars map[string]any
60
+ expect bool
61
+ }{
62
+ {
63
+ name: "literal variable value containing placeholder syntax is not re-expanded",
64
+ match: VarsMatcher{"secret": []string{"topsecret"}},
65
+ vars: map[string]any{"secret": "{env.CADDY_VARS_TEST_SECRET}"},
66
+ expect: false,
67
+ },
68
+ {
69
+ name: "placeholder key value containing placeholder syntax is not re-expanded",
70
+ match: VarsMatcher{"{http.request.header.X-Input}": []string{"topsecret"}},
71
+ headers: http.Header{"X-Input": []string{"{env.CADDY_VARS_TEST_SECRET}"}},
72
+ expect: false,
73
+ },
74
+ {
75
+ name: "query placeholder value containing placeholder syntax is not re-expanded",
76
+ target: "https://example.com/test?foo=%7Benv.CADDY_VARS_TEST_SECRET%7D",
77
+ match: VarsMatcher{"{http.request.uri.query.foo}": []string{"topsecret"}},
78
+ expect: false,
79
+ },
80
+ {
81
+ name: "matcher values still expand placeholders",
82
+ match: VarsMatcher{"secret": []string{"{env.CADDY_VARS_TEST_SECRET}"}},
83
+ vars: map[string]any{"secret": "topsecret"},
84
+ expect: true,
85
+ },
86
+ } {
87
+ t.Run(tc.name, func(t *testing.T) {
88
+ t.Parallel()
89
+
90
+ req, _ := newVarsTestRequest(t, tc.target, tc.headers, tc.vars)
91
+
92
+ actual, err := tc.match.MatchWithError(req)
93
+ if err != nil {
94
+ t.Fatalf("MatchWithError() error = %v", err)
95
+ }
96
+
97
+ if actual != tc.expect {
98
+ t.Fatalf("MatchWithError() = %t, want %t", actual, tc.expect)
99
+ }
100
+ })
101
+ }
102
+}
103
+
104
+func TestMatchVarsREDoesNotExpandResolvedValues(t *testing.T) {
105
+ t.Setenv("CADDY_VARS_TEST_SECRET", "topsecret")
106
+
107
+ for _, tc := range []struct {
108
+ name string
109
+ target string
110
+ match MatchVarsRE
111
+ headers http.Header
112
+ vars map[string]any
113
+ expect bool
114
+ }{
115
+ {
116
+ name: "literal variable value containing placeholder syntax is not re-expanded",
117
+ match: MatchVarsRE{"secret": &MatchRegexp{Pattern: "^topsecret$"}},
118
+ vars: map[string]any{"secret": "{env.CADDY_VARS_TEST_SECRET}"},
119
+ expect: false,
120
+ },
121
+ {
122
+ name: "placeholder key value containing placeholder syntax is not re-expanded",
123
+ match: MatchVarsRE{"{http.request.header.X-Input}": &MatchRegexp{Pattern: "^topsecret$"}},
124
+ headers: http.Header{"X-Input": []string{"{env.CADDY_VARS_TEST_SECRET}"}},
125
+ expect: false,
126
+ },
127
+ {
128
+ name: "query placeholder value containing placeholder syntax is not re-expanded",
129
+ target: "https://example.com/test?foo=%7Benv.CADDY_VARS_TEST_SECRET%7D",
130
+ match: MatchVarsRE{"{http.request.uri.query.foo}": &MatchRegexp{Pattern: "^topsecret$"}},
131
+ expect: false,
132
+ },
133
+ } {
134
+ t.Run(tc.name, func(t *testing.T) {
135
+ t.Parallel()
136
+
137
+ err := tc.match.Provision(caddy.Context{})
138
+ if err != nil {
139
+ t.Fatalf("Provision() error = %v", err)
140
+ }
141
+
142
+ err = tc.match.Validate()
143
+ if err != nil {
144
+ t.Fatalf("Validate() error = %v", err)
145
+ }
146
+
147
+ req, _ := newVarsTestRequest(t, tc.target, tc.headers, tc.vars)
148
+
149
+ actual, err := tc.match.MatchWithError(req)
150
+ if err != nil {
151
+ t.Fatalf("MatchWithError() error = %v", err)
152
+ }
153
+
154
+ if actual != tc.expect {
155
+ t.Fatalf("MatchWithError() = %t, want %t", actual, tc.expect)
156
+ }
157
+ })
158
+ }
159
+}