From 7a2c889ec20da38e6878cc62eeda286aa0d0d408 Mon Sep 17 00:00:00 2001 From: Ryan Crabbe Date: Tue, 17 Feb 2026 16:10:29 -0800 Subject: [PATCH] perf: use cached _safe_get_request_headers instead of dict(request.headers) Replace 15 call sites across 9 files that called dict(request.headers) with _safe_get_request_headers(request) which caches the result on request.state. Mutation sites use .copy() to protect the shared cache. --- .../proxy/_experimental/mcp_server/rest_endpoints.py | 5 +++-- litellm/proxy/auth/user_api_key_auth.py | 2 +- litellm/proxy/custom_hooks/custom_ui_sso_hook.py | 3 ++- litellm/proxy/management_endpoints/scim/scim_v2.py | 3 ++- .../llm_passthrough_endpoints.py | 11 ++++++----- .../pass_through_endpoints/pass_through_endpoints.py | 7 +++++-- litellm/proxy/proxy_server.py | 5 +++-- .../proxy/vertex_ai_endpoints/langfuse_endpoints.py | 3 ++- 8 files changed, 24 insertions(+), 15 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py index aed81afd25..2fb0aee00e 100644 --- a/litellm/proxy/_experimental/mcp_server/rest_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/rest_endpoints.py @@ -10,6 +10,7 @@ from litellm.proxy._experimental.mcp_server.ui_session_utils import ( ) from litellm.proxy._experimental.mcp_server.utils import merge_mcp_headers from litellm.proxy._types import UserAPIKeyAuth +from litellm.proxy.common_utils.http_parsing_utils import _safe_get_request_headers from litellm.proxy.auth.ip_address_utils import IPAddressUtils from litellm.proxy.auth.user_api_key_auth import user_api_key_auth from litellm.types.mcp import MCPAuth @@ -645,7 +646,7 @@ if MCP_AVAILABLE: return await _execute_with_mcp_client( new_mcp_server_request, _test_connection_operation, - raw_headers=dict(request.headers), + raw_headers=_safe_get_request_headers(request), ) @router.post("/test/tools/list") @@ -700,5 +701,5 @@ if MCP_AVAILABLE: _list_tools_operation, mcp_auth_header=mcp_auth_header, oauth2_headers=oauth2_headers, - raw_headers=dict(request.headers), + raw_headers=_safe_get_request_headers(request), ) diff --git a/litellm/proxy/auth/user_api_key_auth.py b/litellm/proxy/auth/user_api_key_auth.py index 77d96e2d39..2ec1036d6d 100644 --- a/litellm/proxy/auth/user_api_key_auth.py +++ b/litellm/proxy/auth/user_api_key_auth.py @@ -559,7 +559,7 @@ async def _user_api_key_auth_builder( # noqa: PLR0915 user_api_key_cache=user_api_key_cache, proxy_logging_obj=proxy_logging_obj, parent_otel_span=parent_otel_span, - request_headers=dict(request.headers), + request_headers=_safe_get_request_headers(request), ) is_proxy_admin = result["is_proxy_admin"] diff --git a/litellm/proxy/custom_hooks/custom_ui_sso_hook.py b/litellm/proxy/custom_hooks/custom_ui_sso_hook.py index cad0e62ff5..8bb6b27409 100644 --- a/litellm/proxy/custom_hooks/custom_ui_sso_hook.py +++ b/litellm/proxy/custom_hooks/custom_ui_sso_hook.py @@ -3,6 +3,7 @@ from fastapi_sso.sso.base import OpenID from litellm._logging import verbose_logger from litellm.integrations.custom_logger import CustomLogger +from litellm.proxy.common_utils.http_parsing_utils import _safe_get_request_headers class CustomSSOLoginHandler(CustomLogger): @@ -18,7 +19,7 @@ class CustomSSOLoginHandler(CustomLogger): self, request: Request, ) -> OpenID: - request_headers_dict = dict(request.headers) + request_headers_dict = _safe_get_request_headers(request) verbose_logger.debug("inside custom ui sso sign in hook...") return OpenID( id=request_headers_dict.get("x-litellm-user-id") or "123", diff --git a/litellm/proxy/management_endpoints/scim/scim_v2.py b/litellm/proxy/management_endpoints/scim/scim_v2.py index e67e1eae74..4a5c6b04e5 100644 --- a/litellm/proxy/management_endpoints/scim/scim_v2.py +++ b/litellm/proxy/management_endpoints/scim/scim_v2.py @@ -21,6 +21,7 @@ from typing_extensions import TypedDict import litellm from litellm._logging import verbose_proxy_logger +from litellm.proxy.common_utils.http_parsing_utils import _safe_get_request_headers from litellm._uuid import uuid from litellm.litellm_core_utils.safe_json_dumps import safe_dumps from litellm.proxy._types import ( @@ -724,7 +725,7 @@ async def get_service_provider_config(request: Request): "SCIM ServiceProviderConfig request: method=%s url=%s headers=%s", request.method, request.url, - dict(request.headers), + _safe_get_request_headers(request), ) meta = { "resourceType": "ServiceProviderConfig", diff --git a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py index 81144ad9f3..339523603c 100644 --- a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py @@ -28,6 +28,7 @@ from litellm.proxy.auth.route_checks import RouteChecks from litellm.proxy.auth.user_api_key_auth import user_api_key_auth from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, + _safe_get_request_headers, _safe_set_request_parsed_body, get_form_data, get_request_body, @@ -60,7 +61,7 @@ def create_request_copy(request: Request): return { "method": request.method, "url": str(request.url), - "headers": dict(request.headers), + "headers": _safe_get_request_headers(request), "cookies": request.cookies, "query_params": dict(request.query_params), } @@ -329,7 +330,7 @@ async def vllm_proxy_route( method=request.method, endpoint=endpoint, request_query_params=request.query_params, - request_headers=dict(request.headers), + request_headers=_safe_get_request_headers(request), stream=request_body.get("stream", False), content=None, data=None, @@ -1307,7 +1308,7 @@ async def azure_proxy_route( method=request.method, endpoint=endpoint, request_query_params=request.query_params, - request_headers=dict(request.headers), + request_headers=_safe_get_request_headers(request), stream=request_body.get("stream", False), content=None, data=None, @@ -1505,7 +1506,7 @@ def get_vertex_ai_allowed_incoming_headers(request: Request) -> dict: Returns: dict: Headers dictionary with only allowed headers """ - incoming_headers = dict(request.headers) or {} + incoming_headers = _safe_get_request_headers(request) headers = {} for header_name in ALLOWED_VERTEX_AI_PASSTHROUGH_HEADERS: if header_name in incoming_headers: @@ -1621,7 +1622,7 @@ async def _prepare_vertex_auth_headers( if ( vertex_credentials is None or vertex_credentials.vertex_project is None ) and router_credentials is None: - headers = dict(request.headers) or {} + headers = _safe_get_request_headers(request).copy() headers_passed_through = True verbose_proxy_logger.debug( "default_vertex_config not set, incoming request headers %s", headers diff --git a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py index 56b513554a..f7e0caed44 100644 --- a/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/pass_through_endpoints.py @@ -50,7 +50,10 @@ from litellm.proxy._types import ( ) from litellm.proxy.auth.user_api_key_auth import user_api_key_auth from litellm.proxy.common_request_processing import ProxyBaseLLMRequestProcessing -from litellm.proxy.common_utils.http_parsing_utils import _read_request_body +from litellm.proxy.common_utils.http_parsing_utils import ( + _read_request_body, + _safe_get_request_headers, +) from litellm.proxy.utils import get_server_root_path from litellm.secret_managers.main import get_secret_str from litellm.types.llms.custom_http import httpxSpecialProvider @@ -644,7 +647,7 @@ async def pass_through_request( # noqa: PLR0915 url = httpx.URL(target) headers = custom_headers headers = HttpPassThroughEndpointHelpers.forward_headers_from_request( - request_headers=dict(request.headers), + request_headers=_safe_get_request_headers(request).copy(), headers=headers, forward_headers=forward_headers, ) diff --git a/litellm/proxy/proxy_server.py b/litellm/proxy/proxy_server.py index e332dd1763..3b6a214383 100644 --- a/litellm/proxy/proxy_server.py +++ b/litellm/proxy/proxy_server.py @@ -292,6 +292,7 @@ from litellm.proxy.common_utils.encrypt_decrypt_utils import ( from litellm.proxy.common_utils.html_forms.ui_login import build_ui_login_form from litellm.proxy.common_utils.http_parsing_utils import ( _read_request_body, + _safe_get_request_headers, check_file_size_under_limit, get_form_data, ) @@ -10167,7 +10168,7 @@ async def async_queue_request( data["proxy_server_request"] = { "url": str(request.url), "method": request.method, - "headers": dict(request.headers), + "headers": _safe_get_request_headers(request), "body": copy.copy(data), # use copy instead of deepcopy } @@ -10188,7 +10189,7 @@ async def async_queue_request( data["metadata"] = {} data["metadata"]["user_api_key"] = user_api_key_dict.api_key data["metadata"]["user_api_key_metadata"] = user_api_key_dict.metadata - _headers = dict(request.headers) + _headers = _safe_get_request_headers(request).copy() _headers.pop( "authorization", None ) # do not store the original `sk-..` api key in the db diff --git a/litellm/proxy/vertex_ai_endpoints/langfuse_endpoints.py b/litellm/proxy/vertex_ai_endpoints/langfuse_endpoints.py index ce27c830f6..bff770b7ea 100644 --- a/litellm/proxy/vertex_ai_endpoints/langfuse_endpoints.py +++ b/litellm/proxy/vertex_ai_endpoints/langfuse_endpoints.py @@ -19,6 +19,7 @@ from fastapi import APIRouter, Request, Response import litellm from litellm.proxy._types import * from litellm.proxy.auth.user_api_key_auth import user_api_key_auth +from litellm.proxy.common_utils.http_parsing_utils import _safe_get_request_headers from litellm.proxy.litellm_pre_call_utils import _get_dynamic_logging_metadata from litellm.proxy.pass_through_endpoints.pass_through_endpoints import ( create_pass_through_route, @@ -32,7 +33,7 @@ def create_request_copy(request: Request): return { "method": request.method, "url": str(request.url), - "headers": dict(request.headers), + "headers": _safe_get_request_headers(request), "cookies": request.cookies, "query_params": dict(request.query_params), }