@marcel91200 / caddy Mirror · read-only / commits / 5e295367
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 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",