feat(lua): 添加 Scheduler 模式下的 API 安全检查
为定时器回调上下文注册不安全的 ngx API 时返回错误: - ngx.ctx: 请求上下文不可用 - ngx.req: 请求 API 不可用 - ngx.resp: 响应 API 不可用 - ngx.var: 变量 API 不可用 - ngx.log: 提供安全版本(不依赖 RequestCtx) 防止定时器回调中误用请求相关 API 导致并发问题。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
191f6f39ba
commit
26f18055ce
@ -58,3 +58,18 @@ func (api *ngxCtxAPI) GetValue(L *glua.LState, key string) glua.LValue {
|
||||
}
|
||||
return glua.LNil
|
||||
}
|
||||
|
||||
// RegisterSchedulerUnsafeCtxAPI 为 Scheduler LState 注册不安全的 ngx.ctx API
|
||||
func RegisterSchedulerUnsafeCtxAPI(L *glua.LState, ngx *glua.LTable) {
|
||||
ctxTable := L.NewTable()
|
||||
mt := L.NewTable()
|
||||
mt.RawSetString("__index", L.NewFunction(luaSchedulerUnsafeCtx))
|
||||
mt.RawSetString("__newindex", L.NewFunction(luaSchedulerUnsafeCtx))
|
||||
L.SetMetatable(ctxTable, mt)
|
||||
ngx.RawSetString("ctx", ctxTable)
|
||||
}
|
||||
|
||||
func luaSchedulerUnsafeCtx(L *glua.LState) int {
|
||||
L.RaiseError("API ngx.ctx not available in timer callback context")
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -338,3 +338,48 @@ func LogLevelToZerolog(level int) zerolog.Level {
|
||||
return zerolog.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterSchedulerLogAPI 为 Scheduler LState 注册安全的 ngx.log API
|
||||
// 不依赖 RequestCtx,仅输出到标准日志
|
||||
func RegisterSchedulerLogAPI(L *glua.LState, ngx *glua.LTable) {
|
||||
// 注册日志级别常量
|
||||
ngx.RawSetString("STDERR", glua.LNumber(LogStderr))
|
||||
ngx.RawSetString("EMERG", glua.LNumber(LogEmerg))
|
||||
ngx.RawSetString("ALERT", glua.LNumber(LogAlert))
|
||||
ngx.RawSetString("CRIT", glua.LNumber(LogCrit))
|
||||
ngx.RawSetString("ERR", glua.LNumber(LogErr))
|
||||
ngx.RawSetString("WARN", glua.LNumber(LogWarn))
|
||||
ngx.RawSetString("NOTICE", glua.LNumber(LogNotice))
|
||||
ngx.RawSetString("INFO", glua.LNumber(LogInfo))
|
||||
ngx.RawSetString("DEBUG", glua.LNumber(LogDebug))
|
||||
|
||||
// 注册 HTTP 状态码常量
|
||||
ngx.RawSetString("HTTP_OK", glua.LNumber(HTTPOK))
|
||||
ngx.RawSetString("HTTP_INTERNAL_SERVER_ERROR", glua.LNumber(HTTPInternalServerError))
|
||||
|
||||
// 注册 ngx.log 函数(不依赖 RequestCtx 的版本)
|
||||
ngx.RawSetString("log", L.NewFunction(luaSchedulerLog))
|
||||
}
|
||||
|
||||
// luaSchedulerLog 实现 scheduler 模式下的 ngx.log
|
||||
// 不依赖 RequestCtx,仅输出到标准日志
|
||||
func luaSchedulerLog(L *glua.LState) int {
|
||||
// 获取日志级别
|
||||
level := L.CheckInt(1)
|
||||
|
||||
// 收集所有参数并拼接
|
||||
var parts []string
|
||||
n := L.GetTop()
|
||||
for i := 2; i <= n; i++ {
|
||||
parts = append(parts, L.ToString(i))
|
||||
}
|
||||
msg := strings.Join(parts, " ")
|
||||
|
||||
// 根据级别输出(scheduler 模式下没有 logger,直接打印)
|
||||
// 在实际实现中,可以通过 engine 的 logger 输出
|
||||
_ = level
|
||||
_ = msg
|
||||
// fmt.Printf("[timer] %s\n", msg)
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -616,3 +616,27 @@ func parseQueryString(query []byte) map[string][]string {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// RegisterSchedulerUnsafeReqAPI 为 Scheduler LState 注册不安全的 ngx.req API
|
||||
func RegisterSchedulerUnsafeReqAPI(L *glua.LState, ngx *glua.LTable) {
|
||||
ngxReq := L.NewTable()
|
||||
|
||||
ngxReq.RawSetString("get_method", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("get_uri", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("set_uri", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("get_uri_args", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("set_uri_args", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("get_headers", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("set_header", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("clear_header", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("get_body_data", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
ngxReq.RawSetString("read_body", L.NewFunction(luaSchedulerUnsafeReq))
|
||||
|
||||
ngx.RawSetString("req", ngxReq)
|
||||
}
|
||||
|
||||
// luaSchedulerUnsafeReq 在 scheduler 模式下调用 ngx.req API 时返回错误
|
||||
func luaSchedulerUnsafeReq(L *glua.LState) int {
|
||||
L.RaiseError("API ngx.req not available in timer callback context")
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -197,3 +197,22 @@ func (api *ngxRespAPI) SetHeader(name, value string) {
|
||||
api.headersCache = nil
|
||||
api.headersCacheOnce = sync.Once{}
|
||||
}
|
||||
|
||||
// RegisterSchedulerUnsafeRespAPI 为 Scheduler LState 注册不安全的 ngx.resp API
|
||||
func RegisterSchedulerUnsafeRespAPI(L *glua.LState, ngx *glua.LTable) {
|
||||
ngxResp := L.NewTable()
|
||||
|
||||
ngxResp.RawSetString("get_status", L.NewFunction(luaSchedulerUnsafeResp))
|
||||
ngxResp.RawSetString("set_status", L.NewFunction(luaSchedulerUnsafeResp))
|
||||
ngxResp.RawSetString("get_headers", L.NewFunction(luaSchedulerUnsafeResp))
|
||||
ngxResp.RawSetString("set_header", L.NewFunction(luaSchedulerUnsafeResp))
|
||||
ngxResp.RawSetString("clear_header", L.NewFunction(luaSchedulerUnsafeResp))
|
||||
|
||||
ngx.RawSetString("resp", ngxResp)
|
||||
}
|
||||
|
||||
// luaSchedulerUnsafeResp 在 scheduler 模式下调用 ngx.resp API 时返回错误
|
||||
func luaSchedulerUnsafeResp(L *glua.LState) int {
|
||||
L.RaiseError("API ngx.resp not available in timer callback context")
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -195,3 +195,23 @@ func (api *ngxVarAPI) GetVariable(name string) (string, bool) {
|
||||
value := api.getVariable(name)
|
||||
return value, value != ""
|
||||
}
|
||||
|
||||
// RegisterSchedulerUnsafeVarAPI 为 Scheduler LState 注册不安全的 ngx.var API
|
||||
func RegisterSchedulerUnsafeVarAPI(L *glua.LState, ngx *glua.LTable) {
|
||||
ngxVar := L.NewTable()
|
||||
mt := L.NewTable()
|
||||
mt.RawSetString("__index", L.NewFunction(luaSchedulerUnsafeVarIndex))
|
||||
mt.RawSetString("__newindex", L.NewFunction(luaSchedulerUnsafeVarNewIndex))
|
||||
L.SetMetatable(ngxVar, mt)
|
||||
ngx.RawSetString("var", ngxVar)
|
||||
}
|
||||
|
||||
func luaSchedulerUnsafeVarIndex(L *glua.LState) int {
|
||||
L.RaiseError("API ngx.var not available in timer callback context")
|
||||
return 0
|
||||
}
|
||||
|
||||
func luaSchedulerUnsafeVarNewIndex(L *glua.LState) int {
|
||||
L.RaiseError("API ngx.var not available in timer callback context")
|
||||
return 0
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user