From 36c2883f6e79f86f3aa881ec83d1d41f0417bfdf Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sun, 12 Jan 2025 22:00:59 -0800 Subject: [PATCH] (proxy perf) - only read request body 1 time per request (#7728) * req body * fix linting --- .../proxy/common_utils/http_parsing_utils.py | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/litellm/proxy/common_utils/http_parsing_utils.py b/litellm/proxy/common_utils/http_parsing_utils.py index 63b904602a..83eb9f74fd 100644 --- a/litellm/proxy/common_utils/http_parsing_utils.py +++ b/litellm/proxy/common_utils/http_parsing_utils.py @@ -21,26 +21,35 @@ async def _read_request_body(request: Optional[Request]) -> Dict: try: if request is None: return {} + + # Check if we already read and parsed the body + _cached_request_body: Optional[dict] = _safe_get_request_parsed_body( + request=request + ) + if _cached_request_body is not None: + return _cached_request_body + _request_headers: dict = _safe_get_request_headers(request=request) content_type = _request_headers.get("content-type", "") + if "form" in content_type: - return dict(await request.form()) + parsed_body = dict(await request.form()) else: # Read the request body body = await request.body() # Return empty dict if body is empty or None if not body: - return {} + parsed_body = {} + parsed_body = orjson.loads(body) - # Attempt JSON parsing (safe for untrusted input) - return orjson.loads(body) + # Cache the parsed result + _safe_set_request_parsed_body(request=request, parsed_body=parsed_body) + return parsed_body except (json.JSONDecodeError, orjson.JSONDecodeError): - # Log detailed information for debugging verbose_proxy_logger.exception("Invalid JSON payload received.") return {} - except Exception as e: # Catch unexpected errors to avoid crashes verbose_proxy_logger.exception( @@ -49,6 +58,28 @@ async def _read_request_body(request: Optional[Request]) -> Dict: return {} +def _safe_get_request_parsed_body(request: Optional[Request]) -> Optional[dict]: + if request is None: + return None + if hasattr(request, "state") and hasattr(request.state, "parsed_body"): + return request.state.parsed_body + return None + + +def _safe_set_request_parsed_body( + request: Optional[Request], + parsed_body: dict, +) -> None: + try: + if request is None: + return + request.state.parsed_body = parsed_body + except Exception as e: + verbose_proxy_logger.debug( + "Unexpected error setting request parsed body - {}".format(e) + ) + + def _safe_get_request_headers(request: Optional[Request]) -> dict: """ [Non-Blocking] Safely get the request headers