bhuvan-somisetty opened a new issue, #14042:
URL: https://github.com/apache/apisix/issues/14042
### Current Behavior
In `apisix/patch.lua`, `ngx.req.set_body_data` is monkey-patched to
invalidate parsed request body caches and post argument variables whenever a
plugin or handler modifies the request body:
```lua
local _orig_set_body_data = ngx.req.set_body_data
ngx.req.set_body_data = function(data)
local api_ctx = ngx.ctx.api_ctx
if api_ctx and api_ctx._request_body_table then
api_ctx._request_body_table = nil
api_ctx._request_body_type = nil
local var = api_ctx.var
local cache = var and var._cache
if cache then
local keys_to_clear = {}
for key in pairs(cache) do
if type(key) == "string" and key:sub(1, 9) ==
"post_arg." then
keys_to_clear[#keys_to_clear + 1] = key
end
end
for i = 1, #keys_to_clear do
cache[keys_to_clear[i]] = nil
end
end
end
return _orig_set_body_data(data)
end
```
There are two distinct bugs with this cache invalidation:
1. **`api_ctx.req_post_args` is never invalidated**:
In `apisix/core/request.lua`, `core.request.get_post_args(ctx)` caches
parsed form arguments directly onto `ctx.req_post_args`:
```lua
function _M.get_post_args(ctx)
if not ctx then
ctx = ngx.ctx.api_ctx
end
if not ctx.req_post_args then
req_read_body()
local args, err = req_get_post_args(0)
...
ctx.req_post_args = args
end
return ctx.req_post_args
end
```
When `ngx.req.set_body_data(data)` is called (e.g., by `data-mask`,
`body-transformer`, `degraphql`, or custom plugins), `api_ctx.req_post_args` is
left intact with stale data from the previous body. Subsequent calls to
`core.request.get_post_args(ctx)` continue returning the stale pre-rewrite post
arguments.
2. **`post_arg.*` variables in `var._cache` are only cleared if
`api_ctx._request_body_table` was already populated**:
Line 422 gates the cache cleanup with `if api_ctx and
api_ctx._request_body_table then`.
However, if a route rule, access log, or plugin previously looked up a
post argument variable (populating `var._cache["post_arg.foo"]`) but
`api_ctx._request_body_table` was subsequently cleared or was not present at
the moment `set_body_data` is invoked (for instance, if `_request_body_table`
was reset or if multiple modifications occur), any cached `post_arg.*`
variables in `var._cache` are skipped and remain stale.
### Expected Behavior
Calling `ngx.req.set_body_data` should:
1. Always clear `api_ctx.req_post_args`.
2. Clear `api_ctx._request_body_table` and `api_ctx._request_body_type`.
3. Invalidate any cached `post_arg.*` entries in `api_ctx.var._cache`
regardless of whether `api_ctx._request_body_table` was nil or non-nil.
### Error Logs
No crash logs, but silent data discrepancy and stale form arguments / post
variables passed to subsequent plugins or upstreams after body rewrites.
### Steps to Reproduce
1. Create a route with plugins or Lua code that first calls
`core.request.get_post_args(ctx)` (e.g. reading form parameters `a=1&b=2`).
2. Modify the body using `ngx.req.set_body_data("a=99&b=100")`.
3. Call `core.request.get_post_args(ctx)` again.
4. Observe that `get_post_args(ctx)` still returns `a=1` instead of `a=99`.
### Environment
- APISIX version (run `apisix version`): master (3.19.0)
- Operating system (run `uname -a`): Linux 5.15.0-generic x86_64
- OpenResty / Nginx version (run `openresty -V` or `nginx -V`):
openresty/1.25.3.1
- etcd version, if relevant (run `curl
http://127.0.0.1:9090/v1/server_info`): 3.5.11
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]