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, 22:15 UTC
caddyhttp: add replacer placeholders for escaped values (#7181)
Bang Lee committed
Aug 25, 2025 at 23:07 UTC
5e2953670ed7eecbc34146b5d12cca7dd85ac580
3 files changed
+46
-1
caddyconfig/httpcaddyfile/shorthands.go
+3
@@ -64,10 +64,13 @@ func placeholderShorthands() []string {
64
"{orig_?query}", "{http.request.orig_uri.prefixed_query}",
65
"{method}", "{http.request.method}",
66
"{uri}", "{http.request.uri}",
67
+ "{%uri}", "{http.request.uri_escaped}",
68
"{path}", "{http.request.uri.path}",
69
+ "{%path}", "{http.request.uri.path_escaped}",
70
"{dir}", "{http.request.uri.path.dir}",
71
"{file}", "{http.request.uri.path.file}",
72
"{query}", "{http.request.uri.query}",
73
+ "{%query}", "{http.request.uri.query_escaped}",
74
"{?query}", "{http.request.uri.prefixed_query}",
75
"{remote}", "{http.request.remote}",
76
"{remote_host}", "{http.request.remote.host}",
modules/caddyhttp/replacer.go
+6
@@ -172,8 +172,12 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
172
// current URI, including any internal rewrites
173
case "http.request.uri":
174
return req.URL.RequestURI(), true
175
+ case "http.request.uri_escaped":
176
+ return url.QueryEscape(req.URL.RequestURI()), true
177
case "http.request.uri.path":
178
return req.URL.Path, true
179
+ case "http.request.uri.path_escaped":
180
+ return url.QueryEscape(req.URL.Path), true
181
case "http.request.uri.path.file":
182
_, file := path.Split(req.URL.Path)
183
return file, true
@@ -186,6 +190,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
190
return path.Ext(req.URL.Path), true
191
case "http.request.uri.query":
192
return req.URL.RawQuery, true
193
+ case "http.request.uri.query_escaped":
194
+ return url.QueryEscape(req.URL.RawQuery), true
195
case "http.request.uri.prefixed_query":
196
if req.URL.RawQuery == "" {
197
return "", true
modules/caddyhttp/replacer_test.go
+37
-1
@@ -28,7 +28,7 @@ import (
28
)
29
30
func TestHTTPVarReplacement(t *testing.T) {
31
- req, _ := http.NewRequest(http.MethodGet, "/foo/bar.tar.gz", nil)
31
+ req, _ := http.NewRequest(http.MethodGet, "/foo/bar.tar.gz?a=1&b=2", nil)
32
repl := caddy.NewReplacer()
33
localAddr, _ := net.ResolveTCPAddr("tcp", "192.168.159.1:80")
34
ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl)
@@ -142,6 +142,22 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
142
get: "http.request.host.labels.2",
143
expect: "",
144
},
145
+ {
146
+ get: "http.request.uri",
147
+ expect: "/foo/bar.tar.gz?a=1&b=2",
148
+ },
149
+ {
150
+ get: "http.request.uri_escaped",
151
+ expect: "%2Ffoo%2Fbar.tar.gz%3Fa%3D1%26b%3D2",
152
+ },
153
+ {
154
+ get: "http.request.uri.path",
155
+ expect: "/foo/bar.tar.gz",
156
+ },
157
+ {
158
+ get: "http.request.uri.path_escaped",
159
+ expect: "%2Ffoo%2Fbar.tar.gz",
160
+ },
161
{
162
get: "http.request.uri.path.file",
163
expect: "bar.tar.gz",
@@ -155,6 +171,26 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV
171
get: "http.request.uri.path.file.ext",
172
expect: ".gz",
173
},
174
+ {
175
+ get: "http.request.uri.query",
176
+ expect: "a=1&b=2",
177
+ },
178
+ {
179
+ get: "http.request.uri.query_escaped",
180
+ expect: "a%3D1%26b%3D2",
181
+ },
182
+ {
183
+ get: "http.request.uri.query.a",
184
+ expect: "1",
185
+ },
186
+ {
187
+ get: "http.request.uri.query.b",
188
+ expect: "2",
189
+ },
190
+ {
191
+ get: "http.request.uri.prefixed_query",
192
+ expect: "?a=1&b=2",
193
+ },
194
{
195
get: "http.request.tls.cipher_suite",
196
expect: "TLS_AES_256_GCM_SHA384",