Content Rate Limiting#

The ContentRateLimiter throttles download requests on a per-IP, per-route basis using a sliding window. This prevents a single IP from hammering payload delivery endpoints, which could indicate automated retrieval or a blue team pulling your staged files repeatedly.

How It Works#

Each combination of client IP and route path gets its own sliding window of request timestamps. When a new request arrives, the limiter:

  1. Prunes timestamps older than the window duration
  2. Checks if the remaining count exceeds the configured limit
  3. If over the limit, the request is blocked with a 429 response

The window slides forward continuously, so there is no fixed reset boundary that clients can time around.

Configuration#

Rate limits are set per content route:

content_routes:
  - uri: "/downloads/*"
    backend:
      type: "filesystem"
      root: "/opt/payloads"
    rate_limit:
      requests: 5            # max requests per window
      window_seconds: 3600   # 1-hour sliding window

Memory Management#

The limiter tracks timestamps in a defaultdict(deque) keyed by (ip, route). To prevent unbounded memory growth from long-running deployments with many unique visitors:

  • When the total number of tracked keys exceeds 50,000, stale entries (those with no recent timestamps) are pruned
  • Each key’s deque only holds timestamps within the current window, so old entries are cleaned up on every access

Example#

With requests: 5 and window_seconds: 3600:

Request #TimeResult
100:00Allowed
200:15Allowed
300:30Allowed
400:45Allowed
501:00Allowed
601:10Blocked (429)
701:01Allowed (request #1 aged out of the window)

Integration with Content Router#

The rate limiter sits between the ContentRouteResolver (which matches the request to a route) and the content backend (which serves the file). A rate-limited request never reaches the backend.

Request --> ContentRouteResolver --> ContentRateLimiter --> Backend
                                          |
                                     over limit?
                                          |
                                       429 Too Many Requests