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 070853d6a feat: bound request and response body buffering in plugins 
(#13705)
070853d6a is described below

commit 070853d6a1c98b4c2e69c502a0ed577c3d5570bc
Author: Shreemaan Abhishek <[email protected]>
AuthorDate: Thu Jul 23 11:38:08 2026 +0800

    feat: bound request and response body buffering in plugins (#13705)
---
 apisix/plugins/ai-prompt-decorator.lua         | 13 +++++--
 apisix/plugins/ai-prompt-guard.lua             |  9 ++++-
 apisix/plugins/ai-prompt-template.lua          | 13 +++++--
 apisix/plugins/ai-proxy/schema.lua             |  4 +-
 apisix/plugins/ai-request-rewrite.lua          |  9 ++++-
 apisix/plugins/authz-keycloak.lua              |  9 ++++-
 apisix/plugins/body-transformer.lua            | 22 ++++++++++-
 apisix/plugins/cas-auth.lua                    |  9 ++++-
 apisix/plugins/degraphql.lua                   | 11 +++++-
 apisix/plugins/grpc-transcode.lua              | 10 ++++-
 apisix/plugins/grpc-transcode/response.lua     |  5 ++-
 apisix/plugins/grpc-web.lua                    |  9 ++++-
 apisix/plugins/http-dubbo.lua                  | 26 +++++++++++--
 apisix/plugins/oas-validator.lua               |  9 ++++-
 apisix/plugins/openwhisk.lua                   | 14 ++++++-
 apisix/plugins/proxy-cache/init.lua            |  8 ++++
 apisix/plugins/proxy-cache/memory_handler.lua  |  9 ++++-
 apisix/plugins/request-validation.lua          |  9 ++++-
 apisix/plugins/response-rewrite.lua            | 10 ++++-
 apisix/plugins/serverless/generic-upstream.lua |  9 ++++-
 docs/en/latest/plugins/ai-prompt-decorator.md  |  1 +
 docs/en/latest/plugins/ai-prompt-guard.md      |  1 +
 docs/en/latest/plugins/ai-prompt-template.md   |  1 +
 docs/en/latest/plugins/ai-request-rewrite.md   |  1 +
 docs/en/latest/plugins/authz-keycloak.md       |  1 +
 docs/en/latest/plugins/aws-lambda.md           |  1 +
 docs/en/latest/plugins/azure-functions.md      |  1 +
 docs/en/latest/plugins/body-transformer.md     |  2 +
 docs/en/latest/plugins/cas-auth.md             |  1 +
 docs/en/latest/plugins/degraphql.md            |  1 +
 docs/en/latest/plugins/grpc-transcode.md       |  1 +
 docs/en/latest/plugins/grpc-web.md             |  1 +
 docs/en/latest/plugins/http-dubbo.md           |  1 +
 docs/en/latest/plugins/oas-validator.md        |  1 +
 docs/en/latest/plugins/openfunction.md         |  1 +
 docs/en/latest/plugins/openwhisk.md            |  1 +
 docs/en/latest/plugins/proxy-cache.md          |  1 +
 docs/en/latest/plugins/request-validation.md   |  1 +
 docs/en/latest/plugins/response-rewrite.md     |  1 +
 t/plugin/request-validation.t                  | 53 ++++++++++++++++++++++++++
 t/plugin/response-rewrite.t                    | 48 +++++++++++++++++++++++
 41 files changed, 309 insertions(+), 29 deletions(-)

diff --git a/apisix/plugins/ai-prompt-decorator.lua 
b/apisix/plugins/ai-prompt-decorator.lua
index ba9cbe6a5..a48cd7deb 100644
--- a/apisix/plugins/ai-prompt-decorator.lua
+++ b/apisix/plugins/ai-prompt-decorator.lua
@@ -40,6 +40,13 @@ local prompts = {
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         prepend = prompts,
         append = prompts,
     },
@@ -64,8 +71,8 @@ function _M.check_schema(conf)
 end
 
 
-local function get_request_body_table()
-    local body, err = core.request.get_body()
+local function get_request_body_table(max_size)
+    local body, err = core.request.get_body(max_size)
     if not body then
         return nil, { message = "could not get body: " .. (err or "request 
body is empty") }
     end
@@ -80,7 +87,7 @@ end
 
 
 function _M.rewrite(conf, ctx)
-    local body_tab, err = get_request_body_table()
+    local body_tab, err = get_request_body_table(conf.max_req_body_size)
     if not body_tab then
         return 400, err
     end
diff --git a/apisix/plugins/ai-prompt-guard.lua 
b/apisix/plugins/ai-prompt-guard.lua
index 56cec2f8a..909c6bf04 100644
--- a/apisix/plugins/ai-prompt-guard.lua
+++ b/apisix/plugins/ai-prompt-guard.lua
@@ -28,6 +28,13 @@ local plugin_name = "ai-prompt-guard"
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         match_all_roles = {
             type = "boolean",
             default = false,
@@ -98,7 +105,7 @@ end
 
 
 function _M.access(conf, ctx)
-    local body = core.request.get_body()
+    local body = core.request.get_body(conf.max_req_body_size)
     if not body then
         core.log.error("Empty request body")
         return 400, {message = "Empty request body"}
diff --git a/apisix/plugins/ai-prompt-template.lua 
b/apisix/plugins/ai-prompt-template.lua
index 0fe47617e..2c9451be8 100644
--- a/apisix/plugins/ai-prompt-template.lua
+++ b/apisix/plugins/ai-prompt-template.lua
@@ -41,6 +41,13 @@ local prompts = {
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         templates = {
             type = "array",
             minItems = 1,
@@ -90,8 +97,8 @@ function _M.check_schema(conf)
 end
 
 
-local function get_request_body_table()
-    local body, err = core.request.get_body()
+local function get_request_body_table(max_size)
+    local body, err = core.request.get_body(max_size)
     if not body then
         return nil, { message = "could not get body: " .. (err or "request 
body is empty") }
     end
@@ -115,7 +122,7 @@ local function find_template(conf, template_name)
 end
 
 function _M.rewrite(conf, ctx)
-    local body_tab, err = get_request_body_table()
+    local body_tab, err = get_request_body_table(conf.max_req_body_size)
     if not body_tab then
         return 400, err
     end
diff --git a/apisix/plugins/ai-proxy/schema.lua 
b/apisix/plugins/ai-proxy/schema.lua
index 5ffd6ef85..a7833f0c1 100644
--- a/apisix/plugins/ai-proxy/schema.lua
+++ b/apisix/plugins/ai-proxy/schema.lua
@@ -248,7 +248,7 @@ _M.ai_proxy_schema = {
             minimum = 1,
             default = 67108864,
             description = "maximum request body size in bytes the plugin reads 
"
-                       .. "into memory; larger requests are rejected with 413. 
"
+                       .. "into memory; larger request bodies are rejected. "
                        .. "Prevents unbounded memory buffering of large 
bodies.",
         },
         max_stream_duration_ms = {
@@ -373,7 +373,7 @@ _M.ai_proxy_multi_schema = {
             minimum = 1,
             default = 67108864,
             description = "maximum request body size in bytes the plugin reads 
"
-                       .. "into memory; larger requests are rejected with 413. 
"
+                       .. "into memory; larger request bodies are rejected. "
                        .. "Prevents unbounded memory buffering of large 
bodies.",
         },
         max_stream_duration_ms = {
diff --git a/apisix/plugins/ai-request-rewrite.lua 
b/apisix/plugins/ai-request-rewrite.lua
index 5bef20771..a2b9b41fd 100644
--- a/apisix/plugins/ai-request-rewrite.lua
+++ b/apisix/plugins/ai-request-rewrite.lua
@@ -60,6 +60,13 @@ local model_options_schema = {
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         prompt = {
             type = "string",
             description = "The prompt to rewrite client request."
@@ -172,7 +179,7 @@ function _M.check_schema(conf)
 end
 
 function _M.access(conf, ctx)
-    local client_request_body, err = core.request.get_body()
+    local client_request_body, err = 
core.request.get_body(conf.max_req_body_size)
     if err then
         core.log.warn("failed to get request body: ", err)
         return HTTP_BAD_REQUEST
diff --git a/apisix/plugins/authz-keycloak.lua 
b/apisix/plugins/authz-keycloak.lua
index b75f334f7..c1ea88723 100644
--- a/apisix/plugins/authz-keycloak.lua
+++ b/apisix/plugins/authz-keycloak.lua
@@ -27,6 +27,13 @@ local pairs = pairs
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         discovery = {type = "string", minLength = 1, maxLength = 4096},
         token_endpoint = {type = "string", minLength = 1, maxLength = 4096},
         resource_registration_endpoint = {type = "string", minLength = 1, 
maxLength = 4096},
@@ -694,7 +701,7 @@ end
 local function generate_token_using_password_grant(conf,ctx)
     log.debug("generate_token_using_password_grant Function Called")
 
-    local body, err = core.request.get_body()
+    local body, err = core.request.get_body(conf.max_req_body_size)
     if err or not body then
         log.error("Failed to get request body: ", err)
         return 503
diff --git a/apisix/plugins/body-transformer.lua 
b/apisix/plugins/body-transformer.lua
index b0debcbea..fefc6221d 100644
--- a/apisix/plugins/body-transformer.lua
+++ b/apisix/plugins/body-transformer.lua
@@ -48,6 +48,20 @@ local schema = {
     properties = {
         request = transform_schema,
         response = transform_schema,
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
+        max_resp_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum response body size in bytes buffered into "
+                       .. "memory; larger responses are truncated",
+        },
     },
     anyOf = {
         {required = {"request"}},
@@ -233,7 +247,11 @@ function _M.rewrite(conf, ctx)
         local request_method  = ngx.var.request_method
         conf = core.table.deepcopy(conf)
         ctx.body_transformer_conf = conf
-        local body = core.request.get_body()
+        local body, err = core.request.get_body(conf.max_req_body_size)
+        if err then
+            core.log.error("failed to get request body: ", err)
+            return 413
+        end
         set_input_format(conf, "request", ctx.var.http_content_type, 
request_method)
         local out, status, err = transform(conf, body, "request", ctx, 
request_method)
         if not out then
@@ -262,7 +280,7 @@ function _M.body_filter(_, ctx)
         return
     end
     if conf.response then
-        local body = core.response.hold_body_chunk(ctx)
+        local body = core.response.hold_body_chunk(ctx, false, 
conf.max_resp_body_size)
         if ngx.arg[2] == false and not body then
             return
         end
diff --git a/apisix/plugins/cas-auth.lua b/apisix/plugins/cas-auth.lua
index f179c9f92..dfc166037 100644
--- a/apisix/plugins/cas-auth.lua
+++ b/apisix/plugins/cas-auth.lua
@@ -40,6 +40,13 @@ local plugin_name = "cas-auth"
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         idp_uri = {type = "string"},
         cas_callback_uri = {
             type = "string",
@@ -358,7 +365,7 @@ function _M.access(conf, ctx)
     end
 
     if method == "POST" and uri == cas_callback_path then
-        local data = core.request.get_body()
+        local data = core.request.get_body(conf.max_req_body_size)
         local ticket = data and 
data:match("<samlp:SessionIndex>(.+)</samlp:SessionIndex>")
         if ticket == nil then
             return ngx.HTTP_BAD_REQUEST,
diff --git a/apisix/plugins/degraphql.lua b/apisix/plugins/degraphql.lua
index e47a276a8..f7e2b5b0f 100644
--- a/apisix/plugins/degraphql.lua
+++ b/apisix/plugins/degraphql.lua
@@ -25,6 +25,13 @@ local type = type
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         query = {
             type = "string",
             minLength = 1,
@@ -75,7 +82,7 @@ end
 
 
 local function fetch_post_variables(conf)
-    local req_body, err = core.request.get_body()
+    local req_body, err = core.request.get_body(conf.max_req_body_size)
     if err ~= nil then
         core.log.error("failed to get request body: ", err)
         return nil, 503
@@ -146,7 +153,7 @@ function _M.access(conf, ctx)
     if meth == "POST" then
         if not conf.variables then
             -- the set_body_data requires to read the body first
-            core.request.get_body()
+            core.request.get_body(conf.max_req_body_size)
         end
 
         core.request.set_header(ctx, "Content-Type", "application/json")
diff --git a/apisix/plugins/grpc-transcode.lua 
b/apisix/plugins/grpc-transcode.lua
index 625018fb7..3b5d58046 100644
--- a/apisix/plugins/grpc-transcode.lua
+++ b/apisix/plugins/grpc-transcode.lua
@@ -47,6 +47,13 @@ local pb_option_def = {
 local schema = {
     type = "object",
     properties = {
+        max_resp_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum response body size in bytes buffered into "
+                       .. "memory for transcoding; larger responses are 
truncated",
+        },
         proto_id  = schema_def.id_schema,
         service = {
             description = "the grpc service name",
@@ -200,7 +207,8 @@ function _M.body_filter(conf, ctx)
     end
 
     local err = response(ctx, proto_obj, conf.service, conf.method, 
conf.pb_option,
-                         conf.show_status_in_body, conf.status_detail_type)
+                         conf.show_status_in_body, conf.status_detail_type,
+                         conf.max_resp_body_size)
     if err then
         core.log.error("transform response error: ", err)
         return
diff --git a/apisix/plugins/grpc-transcode/response.lua 
b/apisix/plugins/grpc-transcode/response.lua
index 9dd6780f0..fd8dbfa6c 100644
--- a/apisix/plugins/grpc-transcode/response.lua
+++ b/apisix/plugins/grpc-transcode/response.lua
@@ -93,8 +93,9 @@ local function handle_error_response(status_detail_type, 
proto)
 end
 
 
-return function(ctx, proto, service, method, pb_option, show_status_in_body, 
status_detail_type)
-    local buffer = core.response.hold_body_chunk(ctx)
+return function(ctx, proto, service, method, pb_option, show_status_in_body, 
status_detail_type,
+                max_resp_body_size)
+    local buffer = core.response.hold_body_chunk(ctx, false, 
max_resp_body_size)
     if not buffer then
         return nil
     end
diff --git a/apisix/plugins/grpc-web.lua b/apisix/plugins/grpc-web.lua
index da059822e..8ca0c3f88 100644
--- a/apisix/plugins/grpc-web.lua
+++ b/apisix/plugins/grpc-web.lua
@@ -41,6 +41,13 @@ local plugin_name = "grpc-web"
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         cors_allow_headers = {
             description =
             "multiple header use ',' to split. default: 
content-type,x-grpc-web,x-user-agent.",
@@ -143,7 +150,7 @@ function _M.access(conf, ctx)
     end
 
     -- set grpc body
-    local body, err = core.request.get_body()
+    local body, err = core.request.get_body(conf.max_req_body_size)
     if err or not body then
         core.log.error("failed to read request body, err: ", err)
         return exit(ctx, 400)
diff --git a/apisix/plugins/http-dubbo.lua b/apisix/plugins/http-dubbo.lua
index f068654ba..c4be4c19c 100644
--- a/apisix/plugins/http-dubbo.lua
+++ b/apisix/plugins/http-dubbo.lua
@@ -32,6 +32,13 @@ local plugin_name = "http-dubbo"
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         service_name = {
             type = "string",
             minLength = 1,
@@ -174,7 +181,12 @@ local function get_dubbo_request(conf, ctx)
         serialized = serialization_header == "true"
     end
     if serialized then
-        params = core.request.get_body()
+        local body, err = core.request.get_body(conf.max_req_body_size)
+        if err then
+            core.log.error("failed to get request body: ", err)
+            return nil, 413
+        end
+        params = body
         if params then
             local end_of_params = core.string.sub(params, -1)
             if end_of_params ~= "\n" then
@@ -182,7 +194,11 @@ local function get_dubbo_request(conf, ctx)
             end
         end
     else
-        local body_data = core.request.get_body()
+        local body_data, err = core.request.get_body(conf.max_req_body_size)
+        if err then
+            core.log.error("failed to get request body: ", err)
+            return nil, 413
+        end
         if body_data then
             local lua_object = core.json.decode(body_data);
             for _, v in pairs(lua_object) do
@@ -231,7 +247,11 @@ function _M.before_proxy(conf, ctx)
         core.log.error("failed to connect to upstream ", err)
         return 502
     end
-    local request = get_dubbo_request(conf, ctx)
+    local request, err_code = get_dubbo_request(conf, ctx)
+    if not request then
+        sock:close()
+        return err_code
+    end
     local bytes, _ = sock:send(request)
     if bytes > 0 then
         local header, _ = sock:receiveany(16);
diff --git a/apisix/plugins/oas-validator.lua b/apisix/plugins/oas-validator.lua
index 0cdd5b4a0..602585d5d 100644
--- a/apisix/plugins/oas-validator.lua
+++ b/apisix/plugins/oas-validator.lua
@@ -35,6 +35,13 @@ local DEFAULT_SPEC_URL_TTL = 3600
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         spec = {
             description = "schema against which the request/response will be 
validated",
             type = "string",
@@ -244,7 +251,7 @@ function _M.access(conf, ctx)
 
     local req_body
     if not conf.skip_request_body_validation then
-        local body, body_err = core.request.get_body()
+        local body, body_err = core.request.get_body(conf.max_req_body_size)
         if body_err ~= nil then
             core.log.error("failed reading request body, err: " .. body_err)
             return 500, {message = "error reading the request body. err: " .. 
body_err}
diff --git a/apisix/plugins/openwhisk.lua b/apisix/plugins/openwhisk.lua
index f1399254c..035bc61f3 100644
--- a/apisix/plugins/openwhisk.lua
+++ b/apisix/plugins/openwhisk.lua
@@ -25,6 +25,13 @@ local name_pattern = [[\A([\w]|[\w][\w@ .-]*[\[email protected]]+)\z]]
 local schema = {
     type = "object",
     properties = {
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         api_host = {type = "string"},
         ssl_verify = {
             type = "boolean",
@@ -77,9 +84,14 @@ end
 
 
 function _M.access(conf, ctx)
+    local body, err = core.request.get_body(conf.max_req_body_size)
+    if err then
+        core.log.error("failed to get request body: ", err)
+        return 413
+    end
     local params = {
         method = "POST",
-        body = core.request.get_body(),
+        body = body,
         query = {
             blocking = "true",
             result = tostring(conf.result),
diff --git a/apisix/plugins/proxy-cache/init.lua 
b/apisix/plugins/proxy-cache/init.lua
index 3ccacf7cd..cf23b05bd 100644
--- a/apisix/plugins/proxy-cache/init.lua
+++ b/apisix/plugins/proxy-cache/init.lua
@@ -50,6 +50,14 @@ end
 local schema = {
     type = "object",
     properties = {
+        max_resp_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum response body size in bytes buffered into "
+                       .. "memory by the memory cache strategy; larger "
+                       .. "responses are streamed through without being 
cached",
+        },
         cache_zone = {
             type = "string",
             minLength = 1,
diff --git a/apisix/plugins/proxy-cache/memory_handler.lua 
b/apisix/plugins/proxy-cache/memory_handler.lua
index cba8febef..95599cff3 100644
--- a/apisix/plugins/proxy-cache/memory_handler.lua
+++ b/apisix/plugins/proxy-cache/memory_handler.lua
@@ -525,11 +525,18 @@ function _M.body_filter(conf, ctx)
         return
     end
 
-    local res_body = core.response.hold_body_chunk(ctx, true)
+    local res_body = core.response.hold_body_chunk(ctx, true, 
conf.max_resp_body_size)
     if not res_body then
         return
     end
 
+    if conf.max_resp_body_size and #res_body >= conf.max_resp_body_size then
+        -- response exceeds the buffering cap; stream it through without
+        -- caching so we never store a truncated body
+        ctx.cache = nil
+        return
+    end
+
     local entry = {
         status    = ngx.status,
         body      = res_body,
diff --git a/apisix/plugins/request-validation.lua 
b/apisix/plugins/request-validation.lua
index 02f2f51c3..d94a72810 100644
--- a/apisix/plugins/request-validation.lua
+++ b/apisix/plugins/request-validation.lua
@@ -25,6 +25,13 @@ local schema = {
     properties = {
         header_schema = {type = "object"},
         body_schema = {type = "object"},
+        max_req_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum request body size in bytes buffered into "
+                       .. "memory; larger request bodies are rejected",
+        },
         rejected_code = {type = "integer", minimum = 200, maximum = 599, 
default = 400},
         rejected_msg = {type = "string", minLength = 1, maxLength = 256}
     },
@@ -81,7 +88,7 @@ function _M.rewrite(conf, ctx)
 
     if conf.body_schema then
         local req_body
-        local body, err = core.request.get_body()
+        local body, err = core.request.get_body(conf.max_req_body_size)
         if not body then
             if err then
                 core.log.error("failed to get body: ", err)
diff --git a/apisix/plugins/response-rewrite.lua 
b/apisix/plugins/response-rewrite.lua
index b86604a36..df4fa889d 100644
--- a/apisix/plugins/response-rewrite.lua
+++ b/apisix/plugins/response-rewrite.lua
@@ -38,6 +38,14 @@ local lrucache = core.lrucache.new({
 local schema = {
     type = "object",
     properties = {
+        max_resp_body_size = {
+            type = "integer",
+            minimum = 1,
+            default = 67108864,
+            description = "maximum response body size in bytes buffered into "
+                       .. "memory when filters are applied; larger responses "
+                       .. "are truncated",
+        },
         headers = {
             description = "new headers for response",
             anyOf = {
@@ -257,7 +265,7 @@ function _M.body_filter(conf, ctx)
 
     if conf.filters then
 
-        local body = core.response.hold_body_chunk(ctx)
+        local body = core.response.hold_body_chunk(ctx, false, 
conf.max_resp_body_size)
         if not body then
             return
         end
diff --git a/apisix/plugins/serverless/generic-upstream.lua 
b/apisix/plugins/serverless/generic-upstream.lua
index 52a0cb3ea..5c3a6c587 100644
--- a/apisix/plugins/serverless/generic-upstream.lua
+++ b/apisix/plugins/serverless/generic-upstream.lua
@@ -32,6 +32,13 @@ return function(plugin_name, version, priority, 
request_processor, authz_schema,
     local schema = {
         type = "object",
         properties = {
+            max_req_body_size = {
+                type = "integer",
+                minimum = 1,
+                default = 67108864,
+                description = "maximum request body size in bytes buffered 
into "
+                           .. "memory; larger request bodies are rejected",
+            },
             function_uri = {type = "string"},
             authorization = authz_schema,
             timeout = {type = "integer", minimum = 100, default = 3000},
@@ -62,7 +69,7 @@ return function(plugin_name, version, priority, 
request_processor, authz_schema,
         local uri_args = core.request.get_uri_args(ctx)
         local headers = core.request.headers(ctx) or {}
 
-        local req_body, err = core.request.get_body()
+        local req_body, err = core.request.get_body(conf.max_req_body_size)
 
         if err then
             core.log.error("error while reading request body: ", err)
diff --git a/docs/en/latest/plugins/ai-prompt-decorator.md 
b/docs/en/latest/plugins/ai-prompt-decorator.md
index 454392278..ae351dd11 100644
--- a/docs/en/latest/plugins/ai-prompt-decorator.md
+++ b/docs/en/latest/plugins/ai-prompt-decorator.md
@@ -42,6 +42,7 @@ The `ai-prompt-decorator` Plugin modifies user input prompts 
by prefixing and ap
 
 | Name | Type | Required | Default | Valid values | Description |
 | --- | --- | --- | --- | --- | --- |
+| `max_req_body_size` | integer | False | 67108864 | >= 1 | Maximum request 
body size in bytes buffered into memory. Requests with a larger body are 
rejected. |
 | `prepend` | array | Conditionally\* | | | An array of prompt objects to be 
prepended. |
 | `prepend.role` | string | True | | [`system`, `user`, `assistant`] | Role of 
the message. |
 | `prepend.content` | string | True | | length >= 1 | Content of the message 
(prompt). |
diff --git a/docs/en/latest/plugins/ai-prompt-guard.md 
b/docs/en/latest/plugins/ai-prompt-guard.md
index b5ebd17cc..7950fd3a5 100644
--- a/docs/en/latest/plugins/ai-prompt-guard.md
+++ b/docs/en/latest/plugins/ai-prompt-guard.md
@@ -44,6 +44,7 @@ When both `allow_patterns` and `deny_patterns` are 
configured, the Plugin first
 
 | Name | Type | Required | Default | Valid values | Description |
 | --- | --- | --- | --- | --- | --- |
+| `max_req_body_size` | integer | False | 67108864 | >= 1 | Maximum request 
body size in bytes buffered into memory. Requests with a larger body are 
rejected. |
 | `match_all_roles` | boolean | False | false | | If `true`, validate messages 
from all roles. If `false`, validate the message from `user` role only. |
 | `match_all_conversation_history` | boolean | False | false | | If `true`, 
concatenate and check all messages in the conversation history. If `false`, 
only check the content of the last message. |
 | `allow_patterns` | array | False | [] | | An array of regex patterns that 
messages should match. When configured, messages must match at least one 
pattern to be considered valid. |
diff --git a/docs/en/latest/plugins/ai-prompt-template.md 
b/docs/en/latest/plugins/ai-prompt-template.md
index 2d3e80de8..b176aec94 100644
--- a/docs/en/latest/plugins/ai-prompt-template.md
+++ b/docs/en/latest/plugins/ai-prompt-template.md
@@ -42,6 +42,7 @@ The `ai-prompt-template` Plugin supports pre-configuring 
prompt templates that o
 
 | Name | Type | Required | Default | Valid values | Description |
 | --- | --- | --- | --- | --- | --- |
+| `max_req_body_size` | integer | False | 67108864 | >= 1 | Maximum request 
body size in bytes buffered into memory. Requests with a larger body are 
rejected. |
 | `templates` | array | True | | | An array of template objects. |
 | `templates.name` | string | True | | | Name of the template. When requesting 
the Route, the request should include the template name that corresponds to the 
configured template. |
 | `templates.template` | object | True | | | Template specification. |
diff --git a/docs/en/latest/plugins/ai-request-rewrite.md 
b/docs/en/latest/plugins/ai-request-rewrite.md
index df518598d..cdeddb008 100644
--- a/docs/en/latest/plugins/ai-request-rewrite.md
+++ b/docs/en/latest/plugins/ai-request-rewrite.md
@@ -42,6 +42,7 @@ The `ai-request-rewrite` Plugin processes client requests by 
forwarding them to
 
 | Name | Type | Required | Default | Valid values | Description |
 | --- | --- | --- | --- | --- | --- |
+| `max_req_body_size` | integer | False | 67108864 | >= 1 | Maximum request 
body size in bytes buffered into memory. Requests with a larger body are 
rejected. |
 | `prompt` | string | True | | | The prompt to send to the LLM service for 
rewriting the client request. |
 | `provider` | string | True | | [openai, deepseek, azure-openai, aimlapi, 
gemini, vertex-ai, anthropic, openrouter, openai-compatible] | LLM service 
provider. When set to `aimlapi`, the Plugin uses the OpenAI-compatible driver 
and proxies the request to `https://api.aimlapi.com/v1/chat/completions`. When 
set to `openai-compatible`, the Plugin proxies requests to the custom endpoint 
configured in `override`. When set to `azure-openai`, the Plugin also proxies 
requests to the custom endpo [...]
 | `auth` | object | True | | | Authentication configurations. |
diff --git a/docs/en/latest/plugins/authz-keycloak.md 
b/docs/en/latest/plugins/authz-keycloak.md
index 194bdc770..a5a83f22f 100644
--- a/docs/en/latest/plugins/authz-keycloak.md
+++ b/docs/en/latest/plugins/authz-keycloak.md
@@ -45,6 +45,7 @@ While the Plugin was developed for Keycloak, it could 
theoretically be used with
 
 | Name                                         | Type          | Required | 
Default                                       | Valid values                    
                                       | Description                            
                                                                                
                                                                                
                                               |
 
|----------------------------------------------|---------------|----------|-----------------------------------------------|------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | discovery                                    | string        | False    |    
                                           | 
https://host.domain/realms/foo/.well-known/uma2-configuration      | URL to 
[discovery 
document](https://www.keycloak.org/docs/latest/authorization_services/index.html)
 of Keycloak Authorization Services.                                            
                                                                   |
 | token_endpoint                               | string        | False    |    
                                           | 
https://host.domain/realms/foo/protocol/openid-connect/token       | An 
OAuth2-compliant token endpoint that supports the 
`urn:ietf:params:oauth:grant-type:uma-ticket` grant type. If provided, 
overrides the value from discovery.                                             
                                          |
 | resource_registration_endpoint               | string        | False    |    
                                           | 
https://host.domain/realms/foo/authz/protection/resource_set       | A 
UMA-compliant resource registration endpoint. If provided, overrides the value 
from discovery.                                                                 
                                                                                
     |
diff --git a/docs/en/latest/plugins/aws-lambda.md 
b/docs/en/latest/plugins/aws-lambda.md
index 3538ec6b7..6e094eb95 100644
--- a/docs/en/latest/plugins/aws-lambda.md
+++ b/docs/en/latest/plugins/aws-lambda.md
@@ -44,6 +44,7 @@ The Plugin supports authentication and authorization with AWS 
via IAM user crede
 
 | Name                         | Type    | Required | Default       | Valid 
values | Description                                                            
                                                                                
            |
 
|------------------------------|---------|----------|---------------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | function_uri                 | string  | True     |               |          
    | AWS Lambda function URL or Amazon API Gateway endpoint that triggers the 
Lambda function.                                                                
          |
 | authorization                | object  | False    |               |          
    | Credentials used in authentication and authorization on AWS to invoke 
Lambda function.                                                                
             |
 | authorization.apikey         | string  | False    |               |          
    | API key for the REST API Gateway when API key is selected as the security 
mechanism.                                                                      
         |
diff --git a/docs/en/latest/plugins/azure-functions.md 
b/docs/en/latest/plugins/azure-functions.md
index 07663eb07..142b8deb9 100644
--- a/docs/en/latest/plugins/azure-functions.md
+++ b/docs/en/latest/plugins/azure-functions.md
@@ -37,6 +37,7 @@ When enabled, the Plugin terminates the ongoing request to 
the configured URI an
 
 | Name                   | Type    | Required | Default | Valid values | 
Description                                                                     
                                                      |
 
|------------------------|---------|----------|---------|--------------|---------------------------------------------------------------------------------------------------------------------------------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | function_uri           | string  | True     |         |              | Azure 
FunctionS endpoint which triggers the serverless function. For example, 
`http://test-apisix.azurewebsites.net/api/HttpTrigger`. |
 | authorization          | object  | False    |         |              | 
Authorization credentials to access Azure Functions.                            
                                                      |
 | authorization.apikey   | string  | False    |         |              | 
Generated API key to authorize requests.                                        
                                                      |
diff --git a/docs/en/latest/plugins/body-transformer.md 
b/docs/en/latest/plugins/body-transformer.md
index 3fde732ab..195e37a3f 100644
--- a/docs/en/latest/plugins/body-transformer.md
+++ b/docs/en/latest/plugins/body-transformer.md
@@ -40,6 +40,8 @@ The `body-transformer` Plugin performs template-based 
transformations to transfo
 
 | Name          | Type    | Required | Default | Valid values | Description    
                            |
 | ------------- | ------- | -------- | ------- | ------------ | 
------------------------------------------ |
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
+| max_resp_body_size | integer | False | 67108864 | >= 1 | Maximum response 
body size in bytes buffered into memory. Larger responses are truncated. |
 | `request`      | object       | False      | | | Request body transformation 
configuration.      |
 | `request.input_format`      | string       | False      | | 
[`xml`,`json`,`encoded`,`args`,`plain`,`multipart`] | Request body original 
media type. If unspecified, the value would be determined by the `Content-Type` 
header to apply the corresponding decoder. The `xml` option corresponds to 
`text/xml` media type. The `json` option corresponds to `application/json` 
media type. The `encoded` option corresponds to 
`application/x-www-form-urlencoded` media type. The `args` option correspond 
[...]
 | `request.template`      | string       | True      | | | Request body 
transformation template. The template uses 
[lua-resty-template](https://github.com/bungle/lua-resty-template) syntax. See 
the [template 
syntax](https://github.com/bungle/lua-resty-template#template-syntax) for more 
details. You can also use auxiliary functions `_escape_json()` and 
`_escape_xml()` to escape special characters such as double quotes, `_body` to 
access request body, and `_ctx` to access context variables.    |
diff --git a/docs/en/latest/plugins/cas-auth.md 
b/docs/en/latest/plugins/cas-auth.md
index 3d64e226c..d5bb98fa1 100644
--- a/docs/en/latest/plugins/cas-auth.md
+++ b/docs/en/latest/plugins/cas-auth.md
@@ -37,6 +37,7 @@ to do authentication, from the SP (service provider) 
perspective.
 
 | Name      | Type | Required      | Default | Description |
 | ----------- | ----------- | ----------- | ----------- | ----------- |
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | `idp_uri`      | string       | True      | | URI of IdP.       |
 | `cas_callback_uri`      | string       | True      | | redirect uri used to 
callback the SP from IdP after login or logout.       |
 | `logout_uri`      | string       | True      | | logout uri to trigger 
logout.       |
diff --git a/docs/en/latest/plugins/degraphql.md 
b/docs/en/latest/plugins/degraphql.md
index bd0d55ca8..984265539 100644
--- a/docs/en/latest/plugins/degraphql.md
+++ b/docs/en/latest/plugins/degraphql.md
@@ -39,6 +39,7 @@ The `degraphql` Plugin supports communicating with upstream 
GraphQL services ove
 
 | Name             | Type         | Required | Description                     
                                                                   |
 | ---------------- | ------------ | -------- | 
--------------------------------------------------------------------------------------------------
 |
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | `query`          | string       | True     | The GraphQL query sent to the 
Upstream.                                                            |
 | `operation_name` | string       | False    | The name of the operation, only 
required if multiple operations are present in the query.          |
 | `variables`      | array[string]| False    | The names of variables used in 
the GraphQL query, extracted from the request body or query string. |
diff --git a/docs/en/latest/plugins/grpc-transcode.md 
b/docs/en/latest/plugins/grpc-transcode.md
index 425fc9520..4b756d363 100644
--- a/docs/en/latest/plugins/grpc-transcode.md
+++ b/docs/en/latest/plugins/grpc-transcode.md
@@ -42,6 +42,7 @@ With this Plugin enabled, APISIX accepts an HTTP request from 
the client, transc
 
 | Name                 | Type                                                  
 | Required | Default                                                           
          | Description                                                         
                                                                                
                                                                      |
 
|----------------------|--------------------------------------------------------|----------|-----------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| max_resp_body_size | integer | False | 67108864 | >= 1 | Maximum response 
body size in bytes buffered into memory for transcoding. Larger responses are 
truncated. |
 | proto_id             | string/integer                                        
 | True     |                                                                   
          | ID of the proto resource, which contains the protocol buffer 
definitions.                                                                    
                                                                             |
 | service              | string                                                
 | True     |                                                                   
          | Name of the gRPC service.                                           
                                                                                
                                                                      |
 | method               | string                                                
 | True     |                                                                   
          | Method name of the gRPC service.                                    
                                                                                
                                                                      |
diff --git a/docs/en/latest/plugins/grpc-web.md 
b/docs/en/latest/plugins/grpc-web.md
index ff2e4c1a5..f1c55663c 100644
--- a/docs/en/latest/plugins/grpc-web.md
+++ b/docs/en/latest/plugins/grpc-web.md
@@ -42,6 +42,7 @@ The `grpc-web` Plugin translates gRPC-Web requests into 
native gRPC calls and fo
 
 | Name                 | Type    | Required | Default                          
         | Description                                                          
                                   |
 
|----------------------|---------|----------|-------------------------------------------|---------------------------------------------------------------------------------------------------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | cors_allow_headers   | string  | False    | 
`content-type,x-grpc-web,x-user-agent`   | Comma-separated list of request 
headers allowed for cross-origin requests.                              |
 
 ## Request Handling
diff --git a/docs/en/latest/plugins/http-dubbo.md 
b/docs/en/latest/plugins/http-dubbo.md
index 9cced1bce..3441536a3 100755
--- a/docs/en/latest/plugins/http-dubbo.md
+++ b/docs/en/latest/plugins/http-dubbo.md
@@ -38,6 +38,7 @@ Dubbo 2.x, the serialization type of the upstream service 
must be fastjson).
 
 | Name                     | Type    | Required | Default | Valid values | 
Description                                                                     
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
 
|--------------------------|---------|----------|---------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 [...]
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | service_name             | string  | True     |         |              | 
Dubbo service name                                                              
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
 | service_version          | string  | False    | 0.0.0   |              | 
Dubbo service version                                                           
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
 | method                   | string  | True     |         |              | 
Dubbo service method name                                                       
                                                                                
                                                                                
                                                                                
                                                                                
                  [...]
diff --git a/docs/en/latest/plugins/oas-validator.md 
b/docs/en/latest/plugins/oas-validator.md
index a96fe2c3e..d4292508e 100644
--- a/docs/en/latest/plugins/oas-validator.md
+++ b/docs/en/latest/plugins/oas-validator.md
@@ -43,6 +43,7 @@ The OpenAPI spec can be provided as an inline JSON string or 
fetched from a remo
 
 | Name | Type | Required | Default | Valid values | Description |
 |------|------|----------|---------|--------------|-------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | spec | string | No* | | | Inline OpenAPI 3.x specification in JSON format. 
Required if `spec_url` is not set. |
 | spec_url | string | No* | | `^https?://` | URL to fetch the OpenAPI 
specification from. Required if `spec` is not set. |
 | spec_url_request_headers | object | No | | | Custom HTTP request headers 
sent when fetching `spec_url`. Useful for authenticated specification 
endpoints. |
diff --git a/docs/en/latest/plugins/openfunction.md 
b/docs/en/latest/plugins/openfunction.md
index 12340ee1d..fa338f076 100644
--- a/docs/en/latest/plugins/openfunction.md
+++ b/docs/en/latest/plugins/openfunction.md
@@ -37,6 +37,7 @@ This Plugin can be configured on a Route and requests will be 
sent to the config
 
 | Name                        | Type    | Required | Default | Valid values | 
Description                                                                     
                           |
 | --------------------------- | ------- | -------- | ------- | ------------ | 
----------------------------------------------------------------------------------------------------------
 |
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | function_uri                | string  | True     |         |              | 
function uri. For example, `https://localhost:30858/default/function-sample`.   
                           |
 | ssl_verify                  | boolean | False    | true    |              | 
When set to `true` verifies the SSL certificate.                                
                           |
 | authorization               | object  | False    |         |              | 
Authorization credentials to access functions of OpenFunction.                  
                    |
diff --git a/docs/en/latest/plugins/openwhisk.md 
b/docs/en/latest/plugins/openwhisk.md
index c3371f261..78f624eb7 100644
--- a/docs/en/latest/plugins/openwhisk.md
+++ b/docs/en/latest/plugins/openwhisk.md
@@ -37,6 +37,7 @@ This Plugin can be configured on a Route and requests will be 
send to the config
 
 | Name              | Type    | Required | Default | Valid values | 
Description                                                                     
                           |
 | ----------------- | ------- | -------- | ------- | ------------ | 
----------------------------------------------------------------------------------------------------------
 |
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | api_host          | string  | True     |         |              | OpenWhisk 
API host address. For example, `https://localhost:3233`.                        
                 |
 | ssl_verify        | boolean | False    | true    |              | When set 
to `true` verifies the SSL certificate.                                         
                  |
 | service_token     | string  | True     |         |              | OpenWhisk 
service token. The format is `xxx:xxx` and it is passed through basic auth when 
calling the API. |
diff --git a/docs/en/latest/plugins/proxy-cache.md 
b/docs/en/latest/plugins/proxy-cache.md
index c44e07a3b..e43142a31 100644
--- a/docs/en/latest/plugins/proxy-cache.md
+++ b/docs/en/latest/plugins/proxy-cache.md
@@ -43,6 +43,7 @@ Responses can be conditionally cached based on request HTTP 
methods, response st
 
 | Name               | Type           | Required | Default                   | 
Valid values            | Description                                           
                                                                                
                                                                                
                                                                                
|
 
|--------------------|----------------|----------|---------------------------|-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| max_resp_body_size | integer | False | 67108864 | >= 1 | Maximum response 
body size in bytes buffered into memory by the `memory` cache strategy. Larger 
responses are streamed through without being cached. |
 | cache_strategy     | string         | False    | disk                      | 
["disk","memory"]       | Caching strategy. Cache on disk or in memory.         
 |
 | cache_zone         | string         | False    | disk_cache_one            | 
                        | Cache zone used with the caching strategy. The value 
should match one of the cache zones defined in the [configuration 
files](#static-configurations) and should correspond to the caching strategy. 
For example, when using the in-memory caching strategy, you should use an 
in-memory cache zone. |
 | cache_key          | array[string]  | False    | ["$host", "$request_uri"] | 
                        | Key to use for caching. Support [NGINX 
variables](https://nginx.org/en/docs/varindex.html) and constant strings in 
values. Variables should be prefixed with a `$` sign.    |
diff --git a/docs/en/latest/plugins/request-validation.md 
b/docs/en/latest/plugins/request-validation.md
index 83ec7eaf3..e136339e5 100644
--- a/docs/en/latest/plugins/request-validation.md
+++ b/docs/en/latest/plugins/request-validation.md
@@ -43,6 +43,7 @@ See [JSON schema 
specification](https://json-schema.org/specification) to learn
 
 | Name          | Type    | Required | Default | Valid values  | Description   
                                    |
 
|---------------|---------|----------|---------|---------------|---------------------------------------------------|
+| max_req_body_size | integer | False | 67108864 | >= 1 | Maximum request body 
size in bytes buffered into memory. Requests with a larger body are rejected. |
 | header_schema | object  | False    |         |               | Schema for 
the request header data.               |
 | body_schema   | object  | False    |         |               | Schema for 
the request body data.                 |
 | rejected_code | integer | False    | 400     | [200,...,599] | Status code 
to return when rejecting requests. |
diff --git a/docs/en/latest/plugins/response-rewrite.md 
b/docs/en/latest/plugins/response-rewrite.md
index ec3bd8a7a..74bc7beb7 100644
--- a/docs/en/latest/plugins/response-rewrite.md
+++ b/docs/en/latest/plugins/response-rewrite.md
@@ -51,6 +51,7 @@ You can also use the [redirect](./redirect.md) Plugin to set 
up redirects.
 
 | Name            | Type    | Required | Default | Valid values                
                                                                                
  | Description                                                                 
                                                                                
                                                                                
                                        |
 
|-----------------|---------|----------|---------|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| max_resp_body_size | integer | False | 67108864 | >= 1 | Maximum response 
body size in bytes buffered into memory when `filters` are applied. Larger 
responses are truncated. |
 | status_code     | integer | False    |         | [200, 598]                  
                                                                                
  | New HTTP status code in the response. If unset, falls back to the original 
status code.                                                                    
                                                                                
                                         |
 | body            | string  | False    |         |                             
                                                                                
  | New response body. The `Content-Length` header would also be reset. Should 
not be configured with `filters`.                                               
                                                                                
                                                                                
    |
 | body_base64     | boolean | False    | false   |                             
                                                                                
  | If true, decode the response body configured in `body` before sending to 
client, which is useful for image and protobuf decoding. Note that this 
configuration cannot be used to decode Upstream response.                       
                                                                            |
diff --git a/t/plugin/request-validation.t b/t/plugin/request-validation.t
index 790ccdea7..6d525a822 100644
--- a/t/plugin/request-validation.t
+++ b/t/plugin/request-validation.t
@@ -1866,3 +1866,56 @@ POST /echo
 duplicated content-type
 --- error_log
 duplicated Content-Type header
+
+
+
+=== TEST 57: add route with a small max_req_body_size
+--- 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": {
+                        "request-validation": {
+                            "max_req_body_size": 10,
+                            "body_schema": {
+                                "type": "object",
+                                "required": ["required_payload"],
+                                "properties": {
+                                    "required_payload": {"type": "string"}
+                                }
+                            }
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uri": "/echo"
+                }]])
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 58: body larger than max_req_body_size is rejected
+--- more_headers
+Content-Type: application/json
+--- request
+POST /echo
+{"required_payload": "this body is well over ten bytes"}
+--- error_code: 400
+--- error_log
+request size
diff --git a/t/plugin/response-rewrite.t b/t/plugin/response-rewrite.t
index fda43bedc..bf9645ce8 100644
--- a/t/plugin/response-rewrite.t
+++ b/t/plugin/response-rewrite.t
@@ -733,3 +733,51 @@ GET /hello
 GET /t
 --- response_body
 passed
+
+
+
+=== TEST 28: filters with a small max_resp_body_size
+--- 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": {
+                        "response-rewrite": {
+                            "max_resp_body_size": 5,
+                            "filters": [
+                                {
+                                    "regex": "hello",
+                                    "scope": "once",
+                                    "replace": "HELLO"
+                                }
+                            ]
+                        }
+                    },
+                    "upstream": {
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        },
+                        "type": "roundrobin"
+                    },
+                    "uris": ["/hello"]
+                }]]
+                )
+
+            ngx.say(body)
+        }
+    }
+--- request
+GET /t
+--- response_body
+passed
+
+
+
+=== TEST 29: response body is truncated to max_resp_body_size before filtering
+--- request
+GET /hello
+--- response_body chomp
+HELLO

Reply via email to