fix: prevent rate limiting on essential real-time endpoints (addresses #419)

The /api/state and /api/guests/metadata endpoints are now excluded from
rate limiting as they are polled frequently by the UI for real-time updates.
This prevents the "Loading..." issue when users with multiple nodes access
the application.

- Added skip list in UniversalRateLimitMiddleware for real-time endpoints
- Removed duplicate rate limiting logic from router's ServeHTTP
- Consolidated all rate limiting into the universal middleware
This commit is contained in:
Pulse Monitor
2025-09-04 20:22:56 +00:00
parent d031d1e35a
commit 2eb7589747
2 changed files with 15 additions and 34 deletions
+13
View File
@@ -127,6 +127,19 @@ func UniversalRateLimitMiddleware(next http.Handler) http.Handler {
return
}
// Skip rate limiting for real-time data endpoints that are polled frequently
// These endpoints are essential for UI functionality and should not be rate limited
skipPaths := []string{
"/api/state", // Real-time state updates
"/api/guests/metadata", // Guest metadata (polled frequently)
}
for _, path := range skipPaths {
if strings.Contains(r.URL.Path, path) {
next.ServeHTTP(w, r)
return
}
}
// Extract client IP
ip := GetClientIP(r)
+2 -34
View File
@@ -906,40 +906,8 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
// Apply rate limiting for API endpoints
if strings.HasPrefix(req.URL.Path, "/api/") {
// Skip rate limiting ONLY for real-time data endpoints
skipRateLimit := false
for _, path := range []string{
"/api/state", // WebSocket updates
"/api/guests/metadata", // Guest metadata (polled frequently)
"/api/health", // Health checks
"/ws", // WebSocket
} {
if strings.Contains(req.URL.Path, path) {
skipRateLimit = true
break
}
}
// Apply stricter rate limiting for auth endpoints (but not status checks)
if (strings.Contains(req.URL.Path, "/api/security/") && req.URL.Path != "/api/security/status") || req.URL.Path == "/api/login" {
clientIP := GetClientIP(req)
// Use auth limiter for security endpoints (10 per minute)
if !authLimiter.Allow(clientIP) {
http.Error(w, "Too many requests. Please wait before trying again.", http.StatusTooManyRequests)
LogAuditEvent("rate_limit", "", clientIP, req.URL.Path, false, "Auth rate limit exceeded")
return
}
} else if !skipRateLimit {
// Use general API limiter for other endpoints (500 per minute)
clientIP := GetClientIP(req)
if !apiLimiter.Allow(clientIP) {
http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
return
}
}
}
// Rate limiting is now handled by UniversalRateLimitMiddleware
// No need for duplicate rate limiting logic here
// Log request
start := time.Now()