From 6f6771aa1deecd39405991d9ae4e69d4d93b1e5f Mon Sep 17 00:00:00 2001 From: Tao Date: Sun, 29 Mar 2026 03:10:34 +1000 Subject: [PATCH] rewrite: skip query rename when source key is absent (#7599) --- modules/caddyhttp/rewrite/rewrite.go | 9 +++- modules/caddyhttp/rewrite/rewrite_test.go | 50 +++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/modules/caddyhttp/rewrite/rewrite.go b/modules/caddyhttp/rewrite/rewrite.go index ca5f63bac..ba2ea5407 100644 --- a/modules/caddyhttp/rewrite/rewrite.go +++ b/modules/caddyhttp/rewrite/rewrite.go @@ -529,7 +529,14 @@ func (q *queryOps) do(r *http.Request, repl *caddy.Replacer) { if key == "" || val == "" { continue } - query[val] = query[key] + if key == val { + continue + } + originalValues, ok := query[key] + if !ok { + continue + } + query[val] = originalValues delete(query, key) } diff --git a/modules/caddyhttp/rewrite/rewrite_test.go b/modules/caddyhttp/rewrite/rewrite_test.go index c3b4c1f6c..602e31084 100644 --- a/modules/caddyhttp/rewrite/rewrite_test.go +++ b/modules/caddyhttp/rewrite/rewrite_test.go @@ -16,6 +16,7 @@ package rewrite import ( "net/http" + "reflect" "regexp" "testing" @@ -397,6 +398,55 @@ func TestRewrite(t *testing.T) { } } +func TestQueryOpsRenameNoOpCases(t *testing.T) { + repl := caddy.NewReplacer() + + for i, tc := range []struct { + input *http.Request + expect map[string][]string + ops *queryOps + }{ + { + ops: &queryOps{ + Rename: []queryOpsArguments{{Key: "ID", Val: "id"}}, + }, + input: newRequest(t, "GET", "/?page=test&id=5&test=100"), + expect: map[string][]string{"id": {"5"}, "page": {"test"}, "test": {"100"}}, + }, + { + ops: &queryOps{ + Rename: []queryOpsArguments{{Key: "id", Val: "id"}}, + }, + input: newRequest(t, "GET", "/?page=test&id=5&test=100"), + expect: map[string][]string{"id": {"5"}, "page": {"test"}, "test": {"100"}}, + }, + { + ops: &queryOps{ + Rename: []queryOpsArguments{{Key: "ID", Val: "id"}}, + }, + input: newRequest(t, "GET", "/?page=test&ID=5&test=100"), + expect: map[string][]string{"id": {"5"}, "page": {"test"}, "test": {"100"}}, + }, + { + ops: &queryOps{ + Rename: []queryOpsArguments{{Key: "ID", Val: "id"}}, + }, + input: newRequest(t, "GET", "/?page=test&ID=5&id=7&test=100"), + expect: map[string][]string{"id": {"5"}, "page": {"test"}, "test": {"100"}}, + }, + } { + repl.Set("http.request.uri", tc.input.RequestURI) + repl.Set("http.request.uri.path", tc.input.URL.Path) + repl.Set("http.request.uri.query", tc.input.URL.RawQuery) + + tc.ops.do(tc.input, repl) + + if actual := tc.input.URL.Query(); !reflect.DeepEqual(tc.expect, map[string][]string(actual)) { + t.Errorf("Test %d: Expected query=%v but got %v", i, tc.expect, actual) + } + } +} + func newRequest(t *testing.T, method, uri string) *http.Request { req, err := http.NewRequest(method, uri, nil) if err != nil {