From e7332731392ae5d1992bd8f8c70d88b1af2f19a5 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 11 Jun 2026 16:23:04 +0800 Subject: [PATCH] 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 --- internal/app/app_common.go | 7 +++++-- internal/lua/api_log.go | 2 +- internal/middleware/security/headers.go | 3 +++ internal/middleware/security/sliding_window.go | 3 +++ internal/proxy/health.go | 3 +++ internal/resolver/resolver.go | 2 +- internal/server/server.go | 3 +++ 7 files changed, 19 insertions(+), 4 deletions(-) diff --git a/internal/app/app_common.go b/internal/app/app_common.go index 0d788b5..6c47406 100644 --- a/internal/app/app_common.go +++ b/internal/app/app_common.go @@ -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 } diff --git a/internal/lua/api_log.go b/internal/lua/api_log.go index ece7112..2d8b1d2 100644 --- a/internal/lua/api_log.go +++ b/internal/lua/api_log.go @@ -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: diff --git a/internal/middleware/security/headers.go b/internal/middleware/security/headers.go index 7f52701..d6336ab 100644 --- a/internal/middleware/security/headers.go +++ b/internal/middleware/security/headers.go @@ -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() diff --git a/internal/middleware/security/sliding_window.go b/internal/middleware/security/sliding_window.go index b19a778..4e8b210 100644 --- a/internal/middleware/security/sliding_window.go +++ b/internal/middleware/security/sliding_window.go @@ -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, diff --git a/internal/proxy/health.go b/internal/proxy/health.go index d962761..a65aeb8 100644 --- a/internal/proxy/health.go +++ b/internal/proxy/health.go @@ -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 diff --git a/internal/resolver/resolver.go b/internal/resolver/resolver.go index fc5a43d..6189ad1 100644 --- a/internal/resolver/resolver.go +++ b/internal/resolver/resolver.go @@ -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{} } diff --git a/internal/server/server.go b/internal/server/server.go index 34ebd9f..1963fa8 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -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) // 记录启动时间