RateLimit returns middleware that limits requests per client by type.
(rdb *hostctx.RedisResolver, resolved *config.ResolvedConfig, typ RateLimitType)
| 43 | |
| 44 | // RateLimit returns middleware that limits requests per client by type. |
| 45 | func RateLimit(rdb *hostctx.RedisResolver, resolved *config.ResolvedConfig, typ RateLimitType) func(http.Handler) http.Handler { |
| 46 | return func(next http.Handler) http.Handler { |
| 47 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 48 | if rdb == nil || resolved == nil { |
| 49 | rateLimitUnavailable(w, r, typ) |
| 50 | if rateLimitSecurityCritical(typ) { |
| 51 | return |
| 52 | } |
| 53 | next.ServeHTTP(w, r) |
| 54 | return |
| 55 | } |
| 56 | client := rdb.RDB(r.Context()) |
| 57 | if client == nil { |
| 58 | rateLimitUnavailable(w, r, typ) |
| 59 | if rateLimitSecurityCritical(typ) { |
| 60 | return |
| 61 | } |
| 62 | next.ServeHTTP(w, r) |
| 63 | return |
| 64 | } |
| 65 | var windowMs, max int |
| 66 | var keyPrefix string |
| 67 | switch typ { |
| 68 | case RateLimitGeneral: |
| 69 | windowMs = resolved.RateLimitWindowMs |
| 70 | max = resolved.RateLimitMax |
| 71 | keyPrefix = "ratelimit:general:" |
| 72 | case RateLimitAuth: |
| 73 | windowMs = resolved.AuthRateLimitWindowMs |
| 74 | max = resolved.AuthRateLimitMax |
| 75 | keyPrefix = "ratelimit:auth:" |
| 76 | case RateLimitAgent: |
| 77 | windowMs = resolved.AgentRateLimitWindowMs |
| 78 | max = resolved.AgentRateLimitMax |
| 79 | keyPrefix = "ratelimit:agent:" |
| 80 | case RateLimitPassword: |
| 81 | windowMs = resolved.PasswordRateLimitWindowMs |
| 82 | max = resolved.PasswordRateLimitMax |
| 83 | keyPrefix = "ratelimit:password:" |
| 84 | default: |
| 85 | next.ServeHTTP(w, r) |
| 86 | return |
| 87 | } |
| 88 | if windowMs <= 0 || max <= 0 { |
| 89 | next.ServeHTTP(w, r) |
| 90 | return |
| 91 | } |
| 92 | clientIP := rateLimitClientIP(r) |
| 93 | key := hostctx.TenantKey(r.Context(), keyPrefix+clientIP) |
| 94 | ctx := r.Context() |
| 95 | count, err := client.Incr(ctx, key).Result() |
| 96 | if err != nil { |
| 97 | rateLimitUnavailable(w, r, typ) |
| 98 | if rateLimitSecurityCritical(typ) { |
| 99 | return |
| 100 | } |
| 101 | next.ServeHTTP(w, r) |
| 102 | return |
nothing calls this directly
no test coverage detected