--- NOTE: tool is designed to assist with **detecting** request contamination -- issues on CI, during test runs. It does not offer security safeguards. -- -- TODO: need to resolve the following issues in debug mode, -- 1. `:clear` could not clear elements inserted by `table.insert()` -- 2. `table.concat()` couldn't work for elements assigned using `indexing` local table_new = require("table.new") local table_clear = require("table.clear") local get_request_id = require("kong.observability.tracing.request_id").get -- set in new() local is_not_debug_mode local error = error local rawset = rawset local rawget = rawget local setmetatable = setmetatable local ALLOWED_REQUEST_ID_K = "__allowed_request_id" -- Check if access is allowed for table, based on the request ID local function enforce_sequential_access(table) local curr_request_id = get_request_id() if not curr_request_id then -- allow access and reset allowed request ID rawset(table, ALLOWED_REQUEST_ID_K, nil) return end local allowed_request_id = rawget(table, ALLOWED_REQUEST_ID_K) if not allowed_request_id then -- first access. Set allowed request ID and allow access rawset(table, ALLOWED_REQUEST_ID_K, curr_request_id) return end if curr_request_id ~= table[ALLOWED_REQUEST_ID_K] then error("concurrent access from different request to shared table detected", 2) end end local function clear_table(self) if is_not_debug_mode then table_clear(self) return end table_clear(self.__data) rawset(self, ALLOWED_REQUEST_ID_K, nil) end local __proxy_mt = { __index = function(t, k) if k == "clear" then return clear_table end enforce_sequential_access(t) return t.__data[k] end, __newindex = function(t, k, v) if k == "clear" then error("cannot set the 'clear' method of request aware table", 2) end enforce_sequential_access(t) t.__data[k] = v end, } local __direct_mt = { __index = { clear = clear_table }, __newindex = function(t, k, v) if k == "clear" then error("cannot set the 'clear' method of request aware table", 2) end rawset(t, k, v) end, } -- Request aware table constructor -- -- Creates a new table with request-aware access logic to protect the -- underlying data from race conditions. -- The table includes a :clear() method to delete all elements. -- -- The request-aware access logic is turned off when `debug_mode` is disabled. -- -- @param narr (optional) pre allocated array elements -- @param nrec (optional) pre allocated hash elements -- @return The newly created table with request-aware access local function new(narr, nrec) local data = table_new(narr or 0, nrec or 0) if is_not_debug_mode == nil then is_not_debug_mode = (kong.configuration.log_level ~= "debug") end -- return table without proxy when debug_mode is disabled if is_not_debug_mode then return setmetatable(data, __direct_mt) end -- wrap table in proxy (for access checks) when debug_mode is enabled return setmetatable({ __data = data }, __proxy_mt) end return { new = new, }