fix(server,app,proxy,resolver,middleware,lua): add nil guards and safe defaults

- server: reject Start() when config is nil to prevent panic
- app_common: guard empty Servers slice in initHTTP2/3 and logServerAddresses
- proxy/health: handle nil HealthCheckConfig with defaults
- resolver: handle nil ResolverConfig by returning noopResolver
- middleware/headers: skip UpdateConfig when cfg is nil
- middleware/sliding_window: enforce minimum window duration of 1s
- lua/api_log: map EMERG/ALERT/CRIT to Error() instead of Fatal()
  to prevent Lua scripts from killing the entire server process
This commit is contained in:
xfy 2026-06-11 16:23:04 +08:00
parent 818aa23739
commit e733273139
7 changed files with 19 additions and 4 deletions

View File

@ -94,6 +94,9 @@ func (a *App) initVariables() {
func (a *App) logServerAddresses() {
a.logger.LogStartup("Config loaded successfully", map[string]string{"config_path": a.cfgPath})
if len(a.cfg.Servers) == 0 {
return
}
mode := a.cfg.GetMode()
if mode == config.ServerModeMultiServer {
for i, srv := range a.cfg.Servers {
@ -173,7 +176,7 @@ func (a *App) initStreamServers() {
// initHTTP3 starts the HTTP/3 server if enabled.
func (a *App) initHTTP3() {
if !a.cfg.HTTP3.Enabled || a.cfg.Servers[0].SSL.Cert == "" {
if len(a.cfg.Servers) == 0 || !a.cfg.HTTP3.Enabled || a.cfg.Servers[0].SSL.Cert == "" {
return
}
@ -199,7 +202,7 @@ func (a *App) initHTTP3() {
// initHTTP2 starts the HTTP/2 server if enabled.
func (a *App) initHTTP2() {
if !a.cfg.Servers[0].SSL.HTTP2.Enabled || a.cfg.Servers[0].SSL.Cert == "" {
if len(a.cfg.Servers) == 0 || !a.cfg.Servers[0].SSL.HTTP2.Enabled || a.cfg.Servers[0].SSL.Cert == "" {
return
}

View File

@ -248,7 +248,7 @@ func (api *ngxLogAPI) luaLog(L *glua.LState) int {
if api.logger != nil {
switch level {
case LogEmerg, LogAlert, LogCrit:
api.logger.Fatal().Msg(msg)
api.logger.Error().Str("lua_level", "critical").Msg(msg)
case LogErr:
api.logger.Error().Msg(msg)
case LogWarn:

View File

@ -211,6 +211,9 @@ func formatHSTSValue(maxAge int, includeSubDomains bool, preload bool) string {
// 参数:
// - cfg: 新的安全头配置
func (sh *HeadersMiddleware) UpdateConfig(cfg *config.SecurityHeaders) {
if cfg == nil {
return
}
sh.mu.Lock()
sh.config = cfg
sh.formatHSTS()

View File

@ -87,6 +87,9 @@ type windowCounter struct {
// 返回值:
// - *SlidingWindowLimiter: 创建的限流器实例
func NewSlidingWindowLimiter(window time.Duration, limit int, precise bool) *SlidingWindowLimiter {
if window <= 0 {
window = time.Second
}
s := &SlidingWindowLimiter{
window: window,
limit: limit,

View File

@ -78,6 +78,9 @@ type HealthChecker struct {
//
// 返回的 HealthChecker 尚未启动;调用 Start() 开始健康检查。
func NewHealthChecker(targets []*loadbalance.Target, cfg *config.HealthCheckConfig) *HealthChecker {
if cfg == nil {
cfg = &config.HealthCheckConfig{}
}
interval := cfg.Interval
if interval <= 0 {
interval = 10 * time.Second

View File

@ -131,7 +131,7 @@ type DNSCacheEntry struct {
// 返回值:
// - Resolver: DNS 解析器接口实现,禁用时返回 noopResolver
func New(cfg *config.ResolverConfig) Resolver {
if !cfg.Enabled {
if cfg == nil || !cfg.Enabled {
return &noopResolver{}
}

View File

@ -268,6 +268,9 @@ func (s *Server) GetHandler() fasthttp.RequestHandler {
// - 调用前需确保配置已正确加载
// - Goroutine池和文件缓存根据配置自动启用
func (s *Server) Start() error {
if s.config == nil {
return fmt.Errorf("server config is nil")
}
logging.Init(s.config.Logging.Error.Level, s.config.Logging.Format)
// 记录启动时间