mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""
|
|
Per-IP rate limits for internal FastAPI apps (messaging, file_storage).
|
|
|
|
Complements the main service's endpoint-specific limits. Uses a generous default
|
|
because traffic is mostly from the main backend (single Docker bridge IP).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from fastapi import FastAPI, Request
|
|
from slowapi import Limiter, _rate_limit_exceeded_handler
|
|
from slowapi.errors import RateLimitExceeded
|
|
from slowapi.middleware import SlowAPIMiddleware
|
|
from slowapi.util import get_remote_address
|
|
|
|
|
|
def _client_ip_key(request: Request) -> str:
|
|
if request is None:
|
|
return "unknown"
|
|
headers = request.headers
|
|
real = (headers.get("x-real-ip") or headers.get("X-Real-IP") or "").strip()
|
|
if real:
|
|
return real
|
|
forwarded = headers.get("x-forwarded-for") or headers.get("X-Forwarded-For")
|
|
if forwarded:
|
|
first = forwarded.split(",")[0].strip()
|
|
if first:
|
|
return first
|
|
if request.client and request.client.host:
|
|
return request.client.host
|
|
return get_remote_address(request)
|
|
|
|
|
|
def attach_internal_service_rate_limit(
|
|
app: FastAPI,
|
|
*,
|
|
default_limit: str = "6000/minute",
|
|
) -> Limiter:
|
|
"""
|
|
Register SlowAPI on ``app`` with a default limit for all routes.
|
|
Use ``@limiter.exempt`` on ``/health`` (and similar) so probes are not throttled.
|
|
"""
|
|
limiter = Limiter(
|
|
key_func=_client_ip_key,
|
|
default_limits=[default_limit],
|
|
storage_uri="memory://",
|
|
)
|
|
app.state.limiter = limiter
|
|
app.add_middleware(SlowAPIMiddleware)
|
|
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
return limiter
|