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 9ef7709d1 fix: split global rules phase execution for client-control 
compatibility (#13345)
9ef7709d1 is described below

commit 9ef7709d189d82136a02f7de772d346e539a022b
Author: Nic <[email protected]>
AuthorDate: Mon May 11 16:50:47 2026 +0800

    fix: split global rules phase execution for client-control compatibility 
(#13345)
---
 apisix/init.lua           |  11 +++-
 apisix/plugin.lua         |  12 ++--
 t/plugin/client-control.t | 145 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+), 11 deletions(-)

diff --git a/apisix/init.lua b/apisix/init.lua
index 3e2db0d67..5bffaa316 100644
--- a/apisix/init.lua
+++ b/apisix/init.lua
@@ -754,7 +754,8 @@ function _M.http_access_phase()
         match_span:finish(ngx.ctx)
         -- run global rule when there is no matching route
         local global_rules, conf_version = apisix_global_rules.global_rules()
-        plugin.run_global_rules(api_ctx, global_rules, conf_version, nil)
+        plugin.run_global_rules(api_ctx, global_rules, conf_version, "rewrite")
+        plugin.run_global_rules(api_ctx, global_rules, conf_version, "access")
 
         core.log.info("not find any matched route")
         return core.response.exit(404,
@@ -806,12 +807,15 @@ function _M.http_access_phase()
     api_ctx.route_id = route.value.id
     api_ctx.route_name = route.value.name
 
-    -- run global rule
+    -- Split global rule execution: run rewrite first so route/service plugins
+    -- can set overrides (e.g., client-control FFI) before global rule access
+    -- phase runs (e.g., logger body collection).
     local global_rules, conf_version = apisix_global_rules.global_rules()
-    plugin.run_global_rules(api_ctx, global_rules, conf_version, nil)
+    plugin.run_global_rules(api_ctx, global_rules, conf_version, "rewrite")
 
     if route.value.script then
         script.load(route, api_ctx)
+        plugin.run_global_rules(api_ctx, global_rules, conf_version, "access")
         script.run("access", api_ctx)
 
     else
@@ -850,6 +854,7 @@ function _M.http_access_phase()
                 plugin.run_plugin(phase, api_ctx.plugins, api_ctx)
             end
         end
+        plugin.run_global_rules(api_ctx, global_rules, conf_version, "access")
         plugin.run_plugin("access", plugins, api_ctx)
     end
     span:finish(ngx_ctx)
diff --git a/apisix/plugin.lua b/apisix/plugin.lua
index 6c89a034b..4f7410a25 100644
--- a/apisix/plugin.lua
+++ b/apisix/plugin.lua
@@ -1432,12 +1432,13 @@ end
 
 function _M.run_global_rules(api_ctx, global_rules, conf_version, phase_name)
     if global_rules and #global_rules > 0 then
-        local span = tracer.start(api_ctx.ngx_ctx, "run_global_rules", 
tracer.kind.internal)
+        local span_name = "run_global_rules." .. phase_name
+        local span = tracer.start(api_ctx.ngx_ctx, span_name, 
tracer.kind.internal)
         local orig_conf_type = api_ctx.conf_type
         local orig_conf_version = api_ctx.conf_version
         local orig_conf_id = api_ctx.conf_id
 
-        if phase_name == nil then
+        if phase_name == "rewrite" then
             api_ctx.global_rules = global_rules
         end
 
@@ -1456,12 +1457,7 @@ function _M.run_global_rules(api_ctx, global_rules, 
conf_version, phase_name)
         core.table.clear(plugins)
         plugins = _M.filter(api_ctx, dummy_global_rule, plugins, route)
 
-        if phase_name == nil then
-            _M.run_plugin("rewrite", plugins, api_ctx)
-            _M.run_plugin("access", plugins, api_ctx)
-        else
-            _M.run_plugin(phase_name, plugins, api_ctx)
-        end
+        _M.run_plugin(phase_name, plugins, api_ctx)
         core.tablepool.release("plugins", plugins)
 
         api_ctx.conf_type = orig_conf_type
diff --git a/t/plugin/client-control.t b/t/plugin/client-control.t
index 3f174ebbe..48dca8b0d 100644
--- a/t/plugin/client-control.t
+++ b/t/plugin/client-control.t
@@ -28,6 +28,7 @@ if ($version !~ m/\/apisix-nginx-module/) {
 repeat_each(1);
 log_level('info');
 no_root_location();
+no_long_string();
 no_shuffle();
 
 add_block_preprocessor(sub {
@@ -185,3 +186,147 @@ passed
 --- request
 POST /hello
 1
+
+
+
+=== TEST 8: setup global rule with body reader and route with client-control
+The global rule reads the body in access phase (simulates a logger with
+include_req_body). The route has client-control raising the body size limit
+above test-nginx's hardcoded 30M so the body read succeeds.
+--- upstream_server_config
+    client_max_body_size 0;
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+
+            -- global rule: read body in access phase
+            local code, body = t('/apisix/admin/global_rules/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "plugins": {
+                        "serverless-post-function": {
+                            "phase": "access",
+                            "functions": ["return function(conf, ctx) 
ngx.req.read_body() end"]
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            -- route with client-control raising the limit above 30M
+            code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "client-control": {
+                            "max_body_size": 52428800
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say("passed")
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 9: client-control should override body limit before global rule reads 
body
+With the global rules phase split, client-control runs in route rewrite
+(setting FFI override to 50MB) before the global rule access phase reads
+the body. The body exceeds test-nginx's hardcoded 30M but is within the
+50MB override, so the request should succeed.
+--- upstream_server_config
+    client_max_body_size 0;
+--- request eval
+"POST /hello\n" . "A" x (31 * 1024 * 1024)
+--- error_code: 200
+--- timeout: 30
+
+
+
+=== TEST 10: remove client-control from route
+--- upstream_server_config
+    client_max_body_size 0;
+--- 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,
+                [[{
+                    "uri": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+            ngx.say("passed")
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 11: without client-control, body exceeds hardcoded 30M limit
+Without client-control the FFI override is not set, so the global rule's
+read_body() triggers the hardcoded 30M body size check. The same body
+that succeeded in TEST 9 now gets rejected with 413.
+--- upstream_server_config
+    client_max_body_size 0;
+--- request eval
+"POST /hello\n" . "A" x (31 * 1024 * 1024)
+--- error_code: 413
+--- error_log
+client intended to send too large body
+--- timeout: 30
+
+
+
+=== TEST 12: cleanup global rules
+--- upstream_server_config
+    client_max_body_size 0;
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/global_rules/1', 
ngx.HTTP_DELETE)
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed

Reply via email to