feat: rate limit leggero (30/min per IP) su /v1/status pubblico
- endpoint pubblico per healthcheck, protetto da abusi - verificato sul server: 36 richieste → 30x200 + 6x429 (istanza di test)
This commit is contained in:
+14
-1
@@ -94,6 +94,10 @@ qdrant = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
|
||||
# Rate limit in-memory: {key: [timestamps]}
|
||||
_ratelimit: dict[str, list[float]] = {}
|
||||
|
||||
# Rate limit /v1/status (pubblico, per IP): {ip: [timestamps]}
|
||||
_STATUS_RATE_LIMIT_PER_MIN = 30
|
||||
_status_ratelimit: dict[str, list[float]] = {}
|
||||
|
||||
# Idempotency in-memory: {api_key:key: {hash, response, ts}} (TTL 24h)
|
||||
_IDEMPOTENCY_TTL_SECONDS = 24 * 3600
|
||||
_idempotency: dict[str, dict[str, Any]] = {}
|
||||
@@ -416,7 +420,16 @@ async def meta_overview(key: str = Depends(require_auth)) -> dict:
|
||||
|
||||
|
||||
@app.get("/v1/status")
|
||||
async def status() -> dict:
|
||||
async def status(request: Request) -> dict:
|
||||
# Endpoint pubblico (healthcheck): rate limit leggero per IP
|
||||
ip = request.client.host if request.client else "unknown"
|
||||
now = time.monotonic()
|
||||
window = _status_ratelimit.setdefault(ip, [])
|
||||
window[:] = [t for t in window if now - t < 60]
|
||||
if len(window) >= _STATUS_RATE_LIMIT_PER_MIN:
|
||||
raise HTTPException(status_code=429, detail="Rate limit superato")
|
||||
window.append(now)
|
||||
|
||||
info = qdrant.get_collection(COLLECTION)
|
||||
return {
|
||||
"status": "ok",
|
||||
|
||||
Reference in New Issue
Block a user