Files
fn_registry/functions/infra/rate_limit_middleware.go
T
egutierrez c3d9fbd8d3 feat(infra): rate limit middlewares HTTP por IP y por key + tests
Implementa fase 2 del issue 0016:
- rate_limit_middleware: limita por IP (X-Forwarded-For > X-Real-IP > RemoteAddr)
- rate_limiter_by_key: middleware configurable con keyFunc custom (API key, user ID...)
- Cuando se rechaza responde 429 con HTTPError JSON y headers Retry-After + X-RateLimit-*
- Tests con httptest.NewRecorder cubriendo: limite, burst, IPs independientes, XFF prioritario,
  recarga temporal, JSON body, headers IETF, GC stop idempotente, key vacia salta limit
2026-04-18 17:14:25 +02:00

36 lines
1.0 KiB
Go

package infra
import (
"net"
"net/http"
"strings"
)
// rateLimitClientIP extrae la IP del cliente del request.
// Prioridad: X-Forwarded-For (primer valor) > X-Real-IP > RemoteAddr.
// Para X-Forwarded-For multi-hop solo se usa el primer IP (cliente original).
func rateLimitClientIP(r *http.Request) string {
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
parts := strings.Split(xff, ",")
ip := strings.TrimSpace(parts[0])
if ip != "" {
return ip
}
}
if xri := r.Header.Get("X-Real-IP"); xri != "" {
return strings.TrimSpace(xri)
}
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err == nil {
return host
}
return r.RemoteAddr
}
// RateLimitMiddleware retorna un Middleware que aplica rate limiting por IP del cliente.
// Si el request supera el limite responde 429 con headers Retry-After y X-RateLimit-*.
// La IP se extrae con prioridad X-Forwarded-For > X-Real-IP > RemoteAddr.
func RateLimitMiddleware(rl *RateLimiter) Middleware {
return RateLimiterByKey(rl, rateLimitClientIP)
}