项目文件夹

文件
2026-07-13 12:32:21 +08:00

152 行
3.5 KiB
Lua

local bit = require "bit"
local band = bit.band
local fmt = string.format
local ngx_get_phase = ngx.get_phase
local PHASES = {
--init = 0x00000001,
init_worker = 0x00000001,
certificate = 0x00000002,
client_hello = 0x00000008,
--set = 0x00000004,
rewrite = 0x00000010,
access = 0x00000020,
balancer = 0x00000040,
response = 0x00000080,
--content = 0x00000100,
header_filter = 0x00000200,
body_filter = 0x00000400,
--timer = 0x00001000,
log = 0x00002000,
preread = 0x00004000,
error = 0x01000000,
admin_api = 0x10000000,
cluster_listener = 0x00000100,
}
do
local t = {}
for k, v in pairs(PHASES) do
t[k] = v
end
for k, v in pairs(t) do
PHASES[v] = k
end
-- max lshift limit, 2^30 = 0x40000000
PHASES.n = 30
end
local function new_phase(...)
return bit.bor(...)
end
local function get_phases_names(phases)
local names = {}
local n = 1
for _ = 1, PHASES.n do
if band(phases, n) ~= 0 and PHASES[n] then
table.insert(names, PHASES[n])
end
n = bit.lshift(n, 1)
end
return names
end
local function check_phase(accepted_phases)
if not kong or not kong.ctx then
-- no _G.kong, we are likely in tests
return
end
local current_phase = ngx.ctx.KONG_PHASE
if not current_phase then
if ngx_get_phase() == "content" then
-- treat custom content blocks as the Admin API
current_phase = PHASES.admin_api
else
error(fmt("no phase in ngx.ctx.KONG_PHASE, (need one of %s)",
table.concat(get_phases_names(accepted_phases), ", ")), 3)
end
end
if band(current_phase, accepted_phases) ~= 0 then
return
end
local current_phase_name = PHASES[current_phase] or "'unknown phase'"
local accepted_phases_names = get_phases_names(accepted_phases)
error(fmt("function cannot be called in %s phase (only in: %s)",
current_phase_name,
table.concat(accepted_phases_names, ", ")), 3)
end
local function check_not_phase(rejected_phases)
if not kong or not kong.ctx then
-- no _G.kong, we are likely in tests
return
end
local current_phase = ngx.ctx.KONG_PHASE
if not current_phase then
error("no phase in ngx.ctx.KONG_PHASE", 3)
end
if band(current_phase, rejected_phases) == 0 then
return
end
local current_phase_name = PHASES[current_phase] or "'unknown phase'"
local rejected_phases_names = get_phases_names(rejected_phases)
error(fmt("function cannot be called in %s phase (can be called in any " ..
"phases except: %s)",
current_phase_name,
table.concat(rejected_phases_names, ", ")), 3)
end
-- Exact phases + convenience aliases
local public_phases = setmetatable({
request = new_phase(PHASES.rewrite,
PHASES.access,
PHASES.balancer,
PHASES.response,
PHASES.header_filter,
PHASES.body_filter,
PHASES.log,
PHASES.error,
PHASES.admin_api,
PHASES.cluster_listener),
}, {
__index = function(t, k)
error("unknown phase or phase alias: " .. k)
end
})
for k, v in pairs(PHASES) do
public_phases[k] = v
end
return {
new = new_phase,
check = check_phase,
check_not = check_not_phase,
phases = public_phases,
}