From a9d1c7bd1243c5d9845da24f592c7ba8a8411de9 Mon Sep 17 00:00:00 2001 From: AlinsRan Date: Wed, 23 Sep 2026 08:24:30 +0800 Subject: [PATCH] fix(router): keep the query string when normalize_uri_like_servlet is on With `normalize_uri_like_servlet` enabled, the access phase pins $upstream_uri to the original path so upstreams still receive the parameters after ';'. Assigning $upstream_uri at all switches off nginx's "empty proxy_pass URI" passthrough, and that passthrough is what otherwise hands the client's request line -- query string included -- to the upstream, so every proxied request lost its query string. Re-append $is_args$args to the forwarded path, the same way proxy-rewrite already does when it rewrites the path itself. --- apisix/init.lua | 17 ++++++++++++++--- t/router/servlet-upstream-uri.t | 14 +++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apisix/init.lua b/apisix/init.lua index b25069c7445b..68283a5e2fe2 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -555,6 +555,19 @@ local function normalize_uri_like_servlet(uri) end +-- Forward the original path so servlet upstreams can consume params after ';'. +-- URI-encode it before proxying to keep delimiters as path data. +-- +-- Setting $upstream_uri at all turns off the "empty proxy_pass URI" passthrough +-- that otherwise hands the client's request line -- query string included -- to +-- the upstream unchanged, so the query string has to be re-appended here. +local function set_servlet_upstream_uri(api_ctx, uri) + api_ctx.var.upstream_uri = core.utils.uri_safe_encode(uri) + .. (api_ctx.var.is_args or "") + .. (api_ctx.var.args or "") +end + + -- Percent-decode every %XX in the path. When keep_slash is true, an encoded -- slash (%2F/%2f) is left as the literal text "%2F" instead of being turned -- into a real path separator -- Nginx decodes it into '/' in $uri, which makes @@ -881,9 +894,7 @@ function _M.http_access_phase() end api_ctx.var.uri = new_uri - -- Forward the original path so servlet upstreams can consume params - -- after ';'. URI-encode it before proxying to keep delimiters as path data. - api_ctx.var.upstream_uri = core.utils.uri_safe_encode(uri) + set_servlet_upstream_uri(api_ctx, uri) end end diff --git a/t/router/servlet-upstream-uri.t b/t/router/servlet-upstream-uri.t index a816cd06e4a1..0a5b3efe0608 100644 --- a/t/router/servlet-upstream-uri.t +++ b/t/router/servlet-upstream-uri.t @@ -143,7 +143,19 @@ qr/^path-handler\nroute-marker=[a-f]{6}\nrequest-uri=\/anything%3Fprobe;jsession -=== TEST 4: delete routes +=== TEST 4: query string is forwarded alongside the servlet path +--- request +GET /anything/sub;jsessionid=x?foo=bar&baz=1 +--- more_headers +Host: servlet-uri.test +--- response_body_like eval +qr/^path-handler\nroute-marker=[a-f]{6}\nrequest-uri=\/anything\/sub;jsessionid=x\?foo=bar&baz=1\n$/ +--- no_error_log +[error] + + + +=== TEST 5: delete routes --- config location /t { content_by_lua_block {