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

AlinsRan 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 48fd32b3b9 fix(data-mask): compact JSON array when removing an element 
(#13818)
48fd32b3b9 is described below

commit 48fd32b3b98b4317f8981a5c57a97011fcecb4e3
Author: Arjen10 <[email protected]>
AuthorDate: Fri Aug 14 17:51:24 2026 +0800

    fix(data-mask): compact JSON array when removing an element (#13818)
---
 apisix/plugins/data-mask.lua |  10 +-
 t/plugin/data-mask.t         | 260 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 268 insertions(+), 2 deletions(-)

diff --git a/apisix/plugins/data-mask.lua b/apisix/plugins/data-mask.lua
index de79e740ad..ee390501b1 100644
--- a/apisix/plugins/data-mask.lua
+++ b/apisix/plugins/data-mask.lua
@@ -18,6 +18,7 @@ local ngx       = ngx
 local ipairs    = ipairs
 local next      = next
 local type      = type
+local t_remove  = table.remove
 local re_sub    = ngx.re.sub
 local core      = require("apisix.core")
 local jp        = require("jsonpath")
@@ -173,7 +174,8 @@ local function mask_json(obj, conf)
     end
 
     local masked = false
-    for _, node in ipairs(nodes) do
+    for ni = #nodes, 1, -1 do
+        local node = nodes[ni]
         local nested = obj
         -- first element is root($), last element is the field name
         for i = 2, #node.path - 1 do
@@ -181,7 +183,11 @@ local function mask_json(obj, conf)
         end
         local index = table_index(node.path[#node.path])
         if conf.action == "remove" then
-            nested[index] = nil
+            if type(index) == "number" then
+                t_remove(nested, index)
+            else
+                nested[index] = nil
+            end
             masked = true
         elseif conf.action == "replace" then
             nested[index] = conf.value
diff --git a/t/plugin/data-mask.t b/t/plugin/data-mask.t
index 75fe7f8f25..a3d114fb88 100644
--- a/t/plugin/data-mask.t
+++ b/t/plugin/data-mask.t
@@ -897,3 +897,263 @@ nginx_config:
 GET /hello?password=secret&token=mytoken
 --- access_log eval
 qr/GET \/hello\?token=\*\*\*\*\* HTTP\/\d+\.\d+/
+
+
+
+=== TEST 21: create route for removing a middle JSON array element
+--- 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": {
+                            "data-mask": {
+                                "request": [
+                                    {
+                                        "action": "remove",
+                                        "body_format": "json",
+                                        "name": "$.items[1]",
+                                        "type": "body"
+                                    }
+                                ]
+                            },
+                            "file-logger": {
+                                "include_req_body": true,
+                                "path": "mask-json-array-hole.log"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+
+
+
+=== TEST 22: verify removing a middle array element compacts the array
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin").test
+
+            os.remove("mask-json-array-hole.log")
+            local code = t("/hello", ngx.HTTP_POST, 
[[{"items":["a","drop-me","c"]}]])
+
+            local fd, err = io.open("mask-json-array-hole.log", "r")
+            if not fd then
+                core.log.error("failed to open file: ", err)
+                return
+            end
+            local line = fd:read()
+            local log = core.json.decode(line)
+            os.remove("mask-json-array-hole.log")
+
+            if not log or not log.request or not log.request.body then
+                ngx.say("missing logged request body")
+                return
+            end
+
+            local body = core.json.decode(log.request.body)
+            if not body or type(body.items) ~= "table" then
+                ngx.say("items missing: " .. tostring(log.request.body))
+                return
+            end
+            if #body.items ~= 2 then
+                ngx.say("expected compacted array of 2, got: " .. 
core.json.encode(body.items))
+                return
+            end
+            if body.items[1] ~= "a" or body.items[2] ~= "c" then
+                ngx.say("array not compacted: " .. 
core.json.encode(body.items))
+                return
+            end
+            ngx.say("success")
+        }
+    }
+--- response_body
+success
+
+
+
+=== TEST 23: create route for removing all JSON array elements
+--- 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": {
+                            "data-mask": {
+                                "request": [
+                                    {
+                                        "action": "remove",
+                                        "body_format": "json",
+                                        "name": "$.items[*]",
+                                        "type": "body"
+                                    }
+                                ]
+                            },
+                            "file-logger": {
+                                "include_req_body": true,
+                                "path": "mask-json-array-star.log"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+
+
+
+=== TEST 24: verify removing all array elements yields an empty array
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin").test
+
+            os.remove("mask-json-array-star.log")
+            local code = t("/hello", ngx.HTTP_POST, 
[[{"items":["a","b","c"]}]])
+
+            local fd, err = io.open("mask-json-array-star.log", "r")
+            if not fd then
+                core.log.error("failed to open file: ", err)
+                return
+            end
+            local line = fd:read()
+            local log = core.json.decode(line)
+            os.remove("mask-json-array-star.log")
+
+            if not log or not log.request or not log.request.body then
+                ngx.say("missing logged request body")
+                return
+            end
+
+            local body = core.json.decode(log.request.body)
+            if not body or type(body.items) ~= "table" then
+                ngx.say("items missing: " .. tostring(log.request.body))
+                return
+            end
+            if #body.items ~= 0 then
+                ngx.say("expected empty array, got: " .. 
core.json.encode(body.items))
+                return
+            end
+            ngx.say("success")
+        }
+    }
+--- response_body
+success
+
+
+
+=== TEST 25: create route for removing non-contiguous JSON array elements
+--- 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": {
+                            "data-mask": {
+                                "request": [
+                                    {
+                                        "action": "remove",
+                                        "body_format": "json",
+                                        "name": "$.items[0,2]",
+                                        "type": "body"
+                                    }
+                                ]
+                            },
+                            "file-logger": {
+                                "include_req_body": true,
+                                "path": "mask-json-array-multi.log"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/hello"
+                }]]
+                )
+
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+
+
+
+=== TEST 26: verify removing non-contiguous array elements keeps the unmatched 
item
+--- config
+    location /t {
+        content_by_lua_block {
+            local core = require("apisix.core")
+            local t = require("lib.test_admin").test
+
+            os.remove("mask-json-array-multi.log")
+            local code = t("/hello", ngx.HTTP_POST, 
[[{"items":["a","b","c"]}]])
+
+            local fd, err = io.open("mask-json-array-multi.log", "r")
+            if not fd then
+                core.log.error("failed to open file: ", err)
+                return
+            end
+            local line = fd:read()
+            local log = core.json.decode(line)
+            os.remove("mask-json-array-multi.log")
+
+            if not log or not log.request or not log.request.body then
+                ngx.say("missing logged request body")
+                return
+            end
+
+            local body = core.json.decode(log.request.body)
+            if not body or type(body.items) ~= "table" then
+                ngx.say("items missing: " .. tostring(log.request.body))
+                return
+            end
+            if #body.items ~= 1 then
+                ngx.say("expected compacted array of 1, got: " .. 
core.json.encode(body.items))
+                return
+            end
+            if body.items[1] ~= "b" then
+                ngx.say("wrong remaining element: " .. 
core.json.encode(body.items))
+                return
+            end
+            ngx.say("success")
+        }
+    }
+--- response_body
+success

Reply via email to