fix: round 10 critical fixes - WebSocket race, rate limiting, XSS protection, Caddyfile, and input validation
This commit is contained in:
@@ -236,17 +236,59 @@ func (h *Hub) Run() {
|
||||
client.UserID, client.SessionID, len(h.clients))
|
||||
|
||||
case message := <-h.broadcast:
|
||||
// 两阶段广播:Phase 1 在 RLock 下收集失效客户端,Phase 2 在 Lock 下清理
|
||||
var staleClients []*Client
|
||||
h.mu.RLock()
|
||||
for client := range h.clients {
|
||||
select {
|
||||
case client.Send <- message:
|
||||
default:
|
||||
// 客户端发送通道已满,跳过
|
||||
close(client.Send)
|
||||
delete(h.clients, client)
|
||||
// 客户端发送通道已满,标记为失效
|
||||
staleClients = append(staleClients, client)
|
||||
}
|
||||
}
|
||||
h.mu.RUnlock()
|
||||
|
||||
// Phase 2: 在写锁下清理失效客户端
|
||||
if len(staleClients) > 0 {
|
||||
h.mu.Lock()
|
||||
for _, client := range staleClients {
|
||||
// 二次检查:客户端可能已被 unregister 移除
|
||||
if _, ok := h.clients[client]; !ok {
|
||||
continue
|
||||
}
|
||||
delete(h.clients, client)
|
||||
close(client.Send)
|
||||
|
||||
// 清理用户索引
|
||||
if h.userClients[client.UserID] != nil {
|
||||
delete(h.userClients[client.UserID], client)
|
||||
if len(h.userClients[client.UserID]) == 0 {
|
||||
delete(h.userClients, client.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查该 session 是否还有其他连接
|
||||
hasOtherConn := false
|
||||
if clients, ok := h.userClients[client.UserID]; ok {
|
||||
for c := range clients {
|
||||
if c.SessionID == client.SessionID {
|
||||
hasOtherConn = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasOtherConn {
|
||||
if s, ok := h.sessions[client.SessionID]; ok {
|
||||
s.State = "idle"
|
||||
}
|
||||
}
|
||||
}
|
||||
h.mu.Unlock()
|
||||
|
||||
log.Printf("[WS] 广播清理 %d 个失效客户端 (当前连接数: %d)",
|
||||
len(staleClients), len(h.clients))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user