This is an automated email from the ASF dual-hosted git repository.

AlinsRan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new a3a8138f6 fix(proxy-rewrite): query string discarded when 
use_real_request_uri_… (#12843)
a3a8138f6 is described below

commit a3a8138f6709fd6ebec519a2877e21d7bec84dde
Author: YapWC <[email protected]>
AuthorDate: Wed Jul 8 16:23:22 2026 +0800

    fix(proxy-rewrite): query string discarded when use_real_request_uri_… 
(#12843)
---
 apisix/plugins/proxy-rewrite.lua |  15 +++
 t/plugin/proxy-rewrite.t         | 285 +++++++++++++++++++++++++++++++++++++++
 t/plugin/proxy-rewrite3.t        |  48 ++++++-
 3 files changed, 346 insertions(+), 2 deletions(-)

diff --git a/apisix/plugins/proxy-rewrite.lua b/apisix/plugins/proxy-rewrite.lua
index c1609c612..6bddfa39a 100644
--- a/apisix/plugins/proxy-rewrite.lua
+++ b/apisix/plugins/proxy-rewrite.lua
@@ -284,13 +284,28 @@ function _M.rewrite(conf, ctx)
 
     local upstream_uri = ctx.var.uri
     local separator_escaped = false
+
+    -- resolve_var() below drops the query string, so keep the original one 
from
+    -- real_request_uri to re-append it when conf.uri is set.
+    local query_string = ""
     if conf.use_real_request_uri_unsafe then
         upstream_uri = ctx.var.real_request_uri
+        local index = str_find(upstream_uri, "?")
+        query_string = index and sub_str(upstream_uri, index) or ""
     end
 
     if conf.uri ~= nil then
         separator_escaped = true
         upstream_uri = core.utils.resolve_var(conf.uri, ctx.var, 
escape_separator)
+        if query_string ~= "" then
+            -- merge with '&' when conf.uri already carries its own query 
string,
+            -- otherwise append the original query string as-is
+            if str_find(upstream_uri, "?") then
+                upstream_uri = upstream_uri .. "&" .. sub_str(query_string, 2)
+            else
+                upstream_uri = upstream_uri .. query_string
+            end
+        end
 
     elseif conf.regex_uri ~= nil then
         if not str_find(upstream_uri, "?") then
diff --git a/t/plugin/proxy-rewrite.t b/t/plugin/proxy-rewrite.t
index 276dd02ed..6b75fbe7c 100644
--- a/t/plugin/proxy-rewrite.t
+++ b/t/plugin/proxy-rewrite.t
@@ -1231,3 +1231,288 @@ GET /hello
 uri: /uri
 host: test.com:6443
 x-real-ip: 127.0.0.1
+
+
+
+=== TEST 45: set route(rewrite uri args with unsafe allowed)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/plugin_proxy_rewrite_args",
+                                "use_real_request_uri_unsafe": true
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 46: rewrite uri args
+--- request
+GET /hello?q=apisix&a=iresty HTTP/1.1
+--- response_body
+uri: /plugin_proxy_rewrite_args
+a: iresty
+q: apisix
+
+
+
+=== TEST 47: set route(rewrite uri empty args with unsafe allowed)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/plugin_proxy_rewrite_args",
+                                "use_real_request_uri_unsafe": true
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 48: rewrite uri empty args
+--- request
+GET /hello HTTP/1.1
+--- response_body
+uri: /plugin_proxy_rewrite_args
+
+
+
+=== TEST 49: set route(conf.uri carries its own query, 
use_real_request_uri_unsafe)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/plugin_proxy_rewrite_args?x=1",
+                                "use_real_request_uri_unsafe": true
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 50: merge conf.uri query with incoming query (use '&', not double '?')
+--- request
+GET /hello?q=apisix HTTP/1.1
+--- response_body
+uri: /plugin_proxy_rewrite_args
+q: apisix
+x: 1
+
+
+
+=== TEST 51: set route(use_real_request_uri_unsafe only, no conf.uri)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "use_real_request_uri_unsafe": true
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/plugin_proxy_rewrite_args"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 52: query string reaches upstream exactly once without conf.uri
+--- request
+GET /plugin_proxy_rewrite_args?q=apisix HTTP/1.1
+--- response_body
+uri: /plugin_proxy_rewrite_args
+q: apisix
+
+
+
+=== TEST 53: set route(conf.uri echoing raw request_uri, 
use_real_request_uri_unsafe)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/print_uri_detailed",
+                                "use_real_request_uri_unsafe": true
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 54: query with special characters passed through unchanged (unsafe)
+--- request
+GET /hello?name=a%20b&x=%E4%B8%AD HTTP/1.1
+--- response_body
+ngx.var.uri: /print_uri_detailed
+ngx.var.request_uri: /print_uri_detailed?name=a%20b&x=%E4%B8%AD
+
+
+
+=== TEST 55: query with multiple '?' passed through unchanged (unsafe)
+--- request
+GET /hello?a=1?b=2 HTTP/1.1
+--- response_body
+ngx.var.uri: /print_uri_detailed
+ngx.var.request_uri: /print_uri_detailed?a=1?b=2
+
+
+
+=== TEST 56: set route(same conf.uri with use_real_request_uri_unsafe disabled)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/print_uri_detailed",
+                                "use_real_request_uri_unsafe": false
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 57: query preserved with use_real_request_uri_unsafe disabled (both 
variants consistent)
+--- request
+GET /hello?name=a%20b&x=1 HTTP/1.1
+--- response_body
+ngx.var.uri: /print_uri_detailed
+ngx.var.request_uri: /print_uri_detailed?name=a%20b&x=1
diff --git a/t/plugin/proxy-rewrite3.t b/t/plugin/proxy-rewrite3.t
index 55afe14cc..f16a03810 100644
--- a/t/plugin/proxy-rewrite3.t
+++ b/t/plugin/proxy-rewrite3.t
@@ -199,7 +199,7 @@ plugin_proxy_rewrite get method: POST
 
 
 
-=== TEST 8: set route(unsafe uri not normalized at request)
+=== TEST 8: set route(unsafe uri not normalized at request with unsafe allowed)
 --- config
     location /t {
         content_by_lua_block {
@@ -243,7 +243,7 @@ ngx.var.request_uri: /print%5Furi%5Fdetailed
 
 
 
-=== TEST 10: set route(safe uri not normalized at request)
+=== TEST 10: set route(safe uri not normalized at request with unsafe allowed)
 --- config
     location /t {
         content_by_lua_block {
@@ -999,3 +999,47 @@ GET /hello/%ED%85%8C%EC%8A%A4%ED%8A%B8 HTTP/1.1
     }
 --- response_body
 /hello?unsafe_variable=%ED%85%8C%EC%8A%A4%ED%8A%B8
+
+
+
+=== TEST 42: set route(unsafe uri normalized at request with unsafe not 
allowed)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "methods": ["GET"],
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "use_real_request_uri_unsafe": false
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1980": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/print_uri_detailed"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 43: unsafe uri normalized at request
+--- request
+GET /print%5Furi%5Fdetailed HTTP/1.1
+--- response_body
+ngx.var.uri: /print_uri_detailed
+ngx.var.request_uri: /print_uri_detailed

Reply via email to