local sandbox = require "kong.tools.sandbox" local kong_meta = require "kong.meta" -- handler file for both the pre-function and post-function plugin local config_cache do local no_op = function() end -- compiles the array for a phase into a single function local function compile_phase_array(phase_funcs) if not phase_funcs or #phase_funcs == 0 then -- nothing to do for this phase return no_op else -- compile the functions we got local compiled = {} for i, func_string in ipairs(phase_funcs) do local func = assert(sandbox.sandbox(func_string)) local first_run_complete = false compiled[i] = function() -- this is a temporary closure, that will replace itself if not first_run_complete then first_run_complete = true local result = func() --> this might call ngx.exit() -- if we ever get here, then there was NO early exit from a 0.1.0 -- type config if type(result) == "function" then -- this is a new function (0.2.0+), with upvalues -- the first call to func above only initialized it, so run again func = result compiled[i] = func func() --> this again, may do an early exit end -- if we ever get here, then there was no early exit from either -- 0.1.0 or 0.2.0+ code -- Replace the entry of this closure in the array with the actual -- function, since the closure is no longer needed. compiled[i] = func else -- first run is marked as complete, but we (this temporary closure) -- are being called again. So we are here only if the initial -- function call did an early exit. -- So replace this closure now; compiled[i] = func -- And call it again, for this 2nd run; func() end -- unreachable end end -- now return a function that executes the entire array return function() for _, f in ipairs(compiled) do f() end end end end local phases = { "certificate", "rewrite", "access", "header_filter", "body_filter", "log" } config_cache = setmetatable({}, { __mode = "k", __index = function(self, config) -- config was not found yet, so go and compile our config functions local runtime_funcs = {} for _, phase in ipairs(phases) do local func = compile_phase_array(config[phase]) runtime_funcs[phase] = func end -- store compiled results in cache, and return them self[config] = runtime_funcs return runtime_funcs end }) end return function(priority) local ServerlessFunction = { PRIORITY = priority, VERSION = kong_meta.version, } function ServerlessFunction:certificate(config) config_cache[config].certificate() end function ServerlessFunction:rewrite(config) config_cache[config].rewrite() end function ServerlessFunction:access(config) config_cache[config].access() end function ServerlessFunction:header_filter(config) config_cache[config].header_filter() end function ServerlessFunction:body_filter(config) config_cache[config].body_filter() end function ServerlessFunction:log(config) config_cache[config].log() end return ServerlessFunction end