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

shreemaan-abhishek 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 79a87e559f feat(core): make the readable request header count 
configurable (#14136)
79a87e559f is described below

commit 79a87e559f6bec9a018ca4466e31b43ef9650e81
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Wed Nov 4 14:26:10 2026 +0800

    feat(core): make the readable request header count configurable (#14136)
---
 apisix/cli/config.lua    |  1 +
 apisix/cli/schema.lua    |  7 ++++++
 apisix/core/request.lua  | 27 +++++++++++++++++---
 conf/config.yaml.example |  3 +++
 t/core/request.t         | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/apisix/cli/config.lua b/apisix/cli/config.lua
index 2ce29a0a47..07da7cb2e5 100644
--- a/apisix/cli/config.lua
+++ b/apisix/cli/config.lua
@@ -49,6 +49,7 @@ local _M = {
     normalize_uri_like_servlet = false,
     match_uri_encoded_slash = false,
     max_post_args_readable_size = 64,
+    max_request_headers_readable = 100,
     router = {
       http = "radixtree_host_uri",
       ssl = "radixtree_sni"
diff --git a/apisix/cli/schema.lua b/apisix/cli/schema.lua
index e52453e56c..84c2fba248 100644
--- a/apisix/cli/schema.lua
+++ b/apisix/cli/schema.lua
@@ -288,6 +288,13 @@ local config_schema = {
                     description = "cap (in MB) on the request body read for 
post_arg.* "
                                   .. "route matching; 0 disables the limit",
                 },
+                max_request_headers_readable = {
+                    type = "integer",
+                    minimum = 0,
+                    default = 100,
+                    description = "max number of request headers plugins can 
read; "
+                                  .. "0 disables the limit",
+                },
             }
         },
         nginx_config = {
diff --git a/apisix/core/request.lua b/apisix/core/request.lua
index 97c74cc723..950ef1a8df 100644
--- a/apisix/core/request.lua
+++ b/apisix/core/request.lua
@@ -25,6 +25,8 @@ local json = require("apisix.core.json")
 local io = require("apisix.core.io")
 local multipart = require("multipart")
 local core_str = require("apisix.core.string")
+local config_local = require("apisix.core.config_local")
+local try_read_attr = require("apisix.core.table").try_read_attr
 local req_add_header
 if ngx.config.subsystem == "http" then
     local ngx_req = require "ngx.req"
@@ -51,28 +53,47 @@ local req_set_header = ngx.req.set_header
 local CONTENT_TYPE_JSON = "application/json"
 local CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"
 local CONTENT_TYPE_MULTIPART_FORM = "multipart/form-data"
+local DEFAULT_MAX_HEADERS = 100
 
 
 local _M = {}
 
 
+local max_headers
+local function get_max_headers()
+    if max_headers then
+        return max_headers
+    end
+
+    local local_conf, err = config_local.local_conf()
+    if not local_conf then
+        log.error("failed to get local conf: ", err)
+        return DEFAULT_MAX_HEADERS
+    end
+
+    max_headers = try_read_attr(local_conf, "apisix", 
"max_request_headers_readable")
+                  or DEFAULT_MAX_HEADERS
+    return max_headers
+end
+
+
 local function _headers(ctx)
     if not ctx then
         ctx = ngx.ctx.api_ctx
     end
 
     if not is_apisix_or then
-        return get_headers()
+        return get_headers(get_max_headers())
     end
 
     if a6_request.is_request_header_set() then
         a6_request.clear_request_header()
-        ctx.headers = get_headers()
+        ctx.headers = get_headers(get_max_headers())
     end
 
     local headers = ctx.headers
     if not headers then
-        headers = get_headers()
+        headers = get_headers(get_max_headers())
         ctx.headers = headers
     end
 
diff --git a/conf/config.yaml.example b/conf/config.yaml.example
index c654eb4ca9..25a4780a62 100644
--- a/conf/config.yaml.example
+++ b/conf/config.yaml.example
@@ -77,6 +77,9 @@ apisix:
                                       # original request line, so the upstream 
receives %2F unchanged.
   max_post_args_readable_size: 64     # Cap (in MB) on the request body read 
when matching `post_arg.*`
                                       # route predicates for JSON and 
multipart requests. Set to 0 to disable the limit.
+  max_request_headers_readable: 100   # Max number of request headers plugins 
can read. Headers past this
+                                      # count are invisible to plugins but 
still forwarded to the upstream.
+                                      # Set to 0 to disable the limit.
 
   router:
     http: radixtree_host_uri    # radixtree_host_uri: match route by host and 
URI
diff --git a/t/core/request.t b/t/core/request.t
index a99311aa54..caba0be349 100644
--- a/t/core/request.t
+++ b/t/core/request.t
@@ -611,3 +611,68 @@ header: new
 body: nil
 err: request size 17 is greater than the maximum size 8 allowed
 kind: too_large
+
+
+
+=== TEST 20: plugins read the first 100 request headers by default
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            ngx.ctx.api_ctx = {}
+            local ctx = ngx.ctx.api_ctx
+            local count = 0
+            for _ in pairs(core.request.headers(ctx)) do
+                count = count + 1
+            end
+            ngx.say("count: ", count)
+            ngx.say("x-last: ", core.request.header(ctx, "X-Last"))
+        }
+    }
+--- more_headers eval
+CORE::join("", map { "X-Pad-$_: $_\n" } 1 .. 100) . "X-Last: yes\n"
+--- response_body
+count: 100
+x-last: nil
+
+
+
+=== TEST 21: max_request_headers_readable raises the limit
+--- yaml_config
+apisix:
+    node_listen: 1984
+    max_request_headers_readable: 200
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            ngx.ctx.api_ctx = {}
+            local ctx = ngx.ctx.api_ctx
+            ngx.say("x-last: ", core.request.header(ctx, "X-Last"))
+        }
+    }
+--- more_headers eval
+CORE::join("", map { "X-Pad-$_: $_\n" } 1 .. 100) . "X-Last: yes\n"
+--- response_body
+x-last: yes
+
+
+
+=== TEST 22: max_request_headers_readable 0 reads all headers
+--- yaml_config
+apisix:
+    node_listen: 1984
+    max_request_headers_readable: 0
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            ngx.ctx.api_ctx = {}
+            local ctx = ngx.ctx.api_ctx
+            ngx.say("x-last: ", core.request.header(ctx, "X-Last"))
+        }
+    }
+--- more_headers eval
+CORE::join("", map { "X-Pad-$_: $_\n" } 1 .. 300) . "X-Last: yes\n"
+--- response_body
+x-last: yes

Reply via email to