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

nic-6443 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 75bb63148 fix(proxy-mirror): keep the original method path when 
mirroring gRPC requests (#13499)
75bb63148 is described below

commit 75bb63148a9f281cac03f12ab75380350d9c7a4b
Author: Nic <[email protected]>
AuthorDate: Wed Jun 10 14:31:17 2026 +0800

    fix(proxy-mirror): keep the original method path when mirroring gRPC 
requests (#13499)
---
 apisix/cli/ngx_tpl.lua          |  2 ++
 apisix/core/ctx.lua             |  1 +
 apisix/plugins/proxy-mirror.lua | 15 +++++++++++
 t/APISIX.pm                     |  2 ++
 t/plugin/proxy-mirror3.t        | 58 ++++++++++++++++++++++++++++++++++++++---
 5 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 9603eae46..ca6642b9a 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -794,6 +794,7 @@ http {
         location / {
             set $upstream_mirror_host        '';
             set $upstream_mirror_uri         '';
+            set $upstream_mirror_grpc_path   '';
             set $upstream_upgrade            '';
             set $upstream_connection         '';
 
@@ -1046,6 +1047,7 @@ http {
             grpc_send_timeout {* proxy_mirror_timeouts.send *};
                 {% end %}
             {% end %}
+            rewrite ^ $upstream_mirror_grpc_path break;
             grpc_pass $upstream_mirror_host;
         }
         {% end %}
diff --git a/apisix/core/ctx.lua b/apisix/core/ctx.lua
index 92a57629d..07b30d7dd 100644
--- a/apisix/core/ctx.lua
+++ b/apisix/core/ctx.lua
@@ -207,6 +207,7 @@ do
 
         upstream_mirror_host       = true,
         upstream_mirror_uri        = true,
+        upstream_mirror_grpc_path  = true,
 
         upstream_cache_zone        = true,
         upstream_cache_zone_info   = true,
diff --git a/apisix/plugins/proxy-mirror.lua b/apisix/plugins/proxy-mirror.lua
index d6cede6e9..8ffb534ec 100644
--- a/apisix/plugins/proxy-mirror.lua
+++ b/apisix/plugins/proxy-mirror.lua
@@ -16,6 +16,7 @@
 --
 local core          = require("apisix.core")
 local url           = require("net.url")
+local ngx           = ngx
 
 local math_random = math.random
 local has_mod, apisix_ngx_client = pcall(require, "resty.apisix.client")
@@ -130,4 +131,18 @@ function _M.rewrite(conf, ctx)
 end
 
 
+-- The :path of the mirrored gRPC request is taken from the subrequest URI 
rewritten
+-- in the proxy_mirror_grpc location, since grpc_pass cannot carry a URI. It 
must be
+-- captured after all access phase plugins (e.g. grpc-web) have rewritten the 
URI,
+-- which is too late for the rewrite phase above.
+function _M.before_proxy(conf, ctx)
+    if not ctx.enable_mirror then
+        return
+    end
+
+    -- read the var directly as ctx.var.uri may be cached before the rewrite
+    ctx.var.upstream_mirror_grpc_path = ngx.var.uri
+end
+
+
 return _M
diff --git a/t/APISIX.pm b/t/APISIX.pm
index 945305068..540c48f0e 100644
--- a/t/APISIX.pm
+++ b/t/APISIX.pm
@@ -889,6 +889,7 @@ _EOC_
         location / {
             set \$upstream_mirror_host        '';
             set \$upstream_mirror_uri         '';
+            set \$upstream_mirror_grpc_path   '';
             set \$upstream_upgrade            '';
             set \$upstream_connection         '';
 
@@ -1004,6 +1005,7 @@ _EOC_
     }
 
     $config .= <<_EOC_;
+            rewrite ^ \$upstream_mirror_grpc_path break;
             grpc_pass \$upstream_mirror_host;
         }
 _EOC_
diff --git a/t/plugin/proxy-mirror3.t b/t/plugin/proxy-mirror3.t
index 2fdc90d3b..b730cc49e 100644
--- a/t/plugin/proxy-mirror3.t
+++ b/t/plugin/proxy-mirror3.t
@@ -35,6 +35,28 @@ _EOC_
 
     $block->set_value("yaml_config", $yaml_config);
 
+    # a h2c server that records the mirrored gRPC request
+    my $http_config = $block->http_config // <<_EOC_;
+    server {
+        listen 19797;
+        http2 on;
+        location / {
+            content_by_lua_block {
+                ngx.req.read_body()
+                local body = ngx.req.get_body_data()
+                ngx.log(ngx.WARN, "grpc mirror server got request: path=",
+                        ngx.var.request_uri,
+                        " content_type=", ngx.var.http_content_type or "",
+                        " body_len=", body and #body or 0)
+                ngx.header["Content-Type"] = "application/grpc"
+                ngx.exit(200)
+            }
+        }
+    }
+_EOC_
+
+    $block->set_value("http_config", $http_config);
+
     if (!$block->request) {
         $block->set_value("request", "POST /hello");
     }
@@ -45,7 +67,6 @@ run_tests;
 __DATA__
 
 === TEST 1: grpc mirror
---- log_level: debug
 --- http2
 --- apisix_yaml
 routes:
@@ -68,9 +89,40 @@ routes:
 #END
 --- exec
 grpcurl -import-path ./t/grpc_server_example/proto -proto helloworld.proto 
-plaintext -d '{"name":"apisix"}' 127.0.0.1:1984 helloworld.Greeter.SayHello
+sleep 0.5
 --- response_body
 {
   "message": "Hello apisix"
 }
---- error_log eval
-qr/Connection refused\) while connecting to upstream/
+--- error_log
+grpc mirror server got request: path=/helloworld.Greeter/SayHello 
content_type=application/grpc body_len=13
+
+
+
+=== TEST 2: grpc mirror keeps the URI rewritten by access phase plugins 
(grpc-web)
+--- apisix_yaml
+routes:
+  -
+    id: 1
+    uris:
+        - /grpc/web/*
+    plugins:
+        grpc-web: {}
+        proxy-mirror:
+            host: grpc://127.0.0.1:19797
+            sample_ratio: 1
+    upstream:
+      scheme: grpc
+      nodes:
+        "127.0.0.1:10051": 1
+      type: roundrobin
+#END
+--- exec
+printf '\000\000\000\000\010\012\006apisix' | curl -s -o /dev/null -w 
"code=%{http_code}" -X POST \
+    -H 'Content-Type: application/grpc-web+proto' --data-binary @- \
+    http://127.0.0.1:1984/grpc/web/helloworld.Greeter/SayHello
+sleep 0.5
+--- response_body chomp
+code=200
+--- error_log
+grpc mirror server got request: path=/helloworld.Greeter/SayHello 
content_type=application/grpc body_len=13

Reply via email to