From 5e2953670ed7eecbc34146b5d12cca7dd85ac580 Mon Sep 17 00:00:00 2001 From: Bang Lee Date: Mon, 25 Aug 2025 23:07:51 +0800 Subject: [PATCH] caddyhttp: add replacer placeholders for escaped values (#7181) --- caddyconfig/httpcaddyfile/shorthands.go | 3 ++ modules/caddyhttp/replacer.go | 6 ++++ modules/caddyhttp/replacer_test.go | 38 ++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/caddyconfig/httpcaddyfile/shorthands.go b/caddyconfig/httpcaddyfile/shorthands.go index ca6e4f92c..bf612e092 100644 --- a/caddyconfig/httpcaddyfile/shorthands.go +++ b/caddyconfig/httpcaddyfile/shorthands.go @@ -64,10 +64,13 @@ func placeholderShorthands() []string { "{orig_?query}", "{http.request.orig_uri.prefixed_query}", "{method}", "{http.request.method}", "{uri}", "{http.request.uri}", + "{%uri}", "{http.request.uri_escaped}", "{path}", "{http.request.uri.path}", + "{%path}", "{http.request.uri.path_escaped}", "{dir}", "{http.request.uri.path.dir}", "{file}", "{http.request.uri.path.file}", "{query}", "{http.request.uri.query}", + "{%query}", "{http.request.uri.query_escaped}", "{?query}", "{http.request.uri.prefixed_query}", "{remote}", "{http.request.remote}", "{remote_host}", "{http.request.remote.host}", diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index 69779e6ed..29cd08ebb 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -172,8 +172,12 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo // current URI, including any internal rewrites case "http.request.uri": return req.URL.RequestURI(), true + case "http.request.uri_escaped": + return url.QueryEscape(req.URL.RequestURI()), true case "http.request.uri.path": return req.URL.Path, true + case "http.request.uri.path_escaped": + return url.QueryEscape(req.URL.Path), true case "http.request.uri.path.file": _, file := path.Split(req.URL.Path) return file, true @@ -186,6 +190,8 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo return path.Ext(req.URL.Path), true case "http.request.uri.query": return req.URL.RawQuery, true + case "http.request.uri.query_escaped": + return url.QueryEscape(req.URL.RawQuery), true case "http.request.uri.prefixed_query": if req.URL.RawQuery == "" { return "", true diff --git a/modules/caddyhttp/replacer_test.go b/modules/caddyhttp/replacer_test.go index 50a2e8c62..c75fe82ed 100644 --- a/modules/caddyhttp/replacer_test.go +++ b/modules/caddyhttp/replacer_test.go @@ -28,7 +28,7 @@ import ( ) func TestHTTPVarReplacement(t *testing.T) { - req, _ := http.NewRequest(http.MethodGet, "/foo/bar.tar.gz", nil) + req, _ := http.NewRequest(http.MethodGet, "/foo/bar.tar.gz?a=1&b=2", nil) repl := caddy.NewReplacer() localAddr, _ := net.ResolveTCPAddr("tcp", "192.168.159.1:80") ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl) @@ -142,6 +142,22 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV get: "http.request.host.labels.2", expect: "", }, + { + get: "http.request.uri", + expect: "/foo/bar.tar.gz?a=1&b=2", + }, + { + get: "http.request.uri_escaped", + expect: "%2Ffoo%2Fbar.tar.gz%3Fa%3D1%26b%3D2", + }, + { + get: "http.request.uri.path", + expect: "/foo/bar.tar.gz", + }, + { + get: "http.request.uri.path_escaped", + expect: "%2Ffoo%2Fbar.tar.gz", + }, { get: "http.request.uri.path.file", expect: "bar.tar.gz", @@ -155,6 +171,26 @@ eqp31wM9il1n+guTNyxJd+FzVAH+hCZE5K+tCgVDdVFUlDEHHbS/wqb2PSIoouLV get: "http.request.uri.path.file.ext", expect: ".gz", }, + { + get: "http.request.uri.query", + expect: "a=1&b=2", + }, + { + get: "http.request.uri.query_escaped", + expect: "a%3D1%26b%3D2", + }, + { + get: "http.request.uri.query.a", + expect: "1", + }, + { + get: "http.request.uri.query.b", + expect: "2", + }, + { + get: "http.request.uri.prefixed_query", + expect: "?a=1&b=2", + }, { get: "http.request.tls.cipher_suite", expect: "TLS_AES_256_GCM_SHA384",