mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-05 02:41:56 +00:00
fix(fallbacks): ignore preserve_litellm_internal_headers for raw httpx.Headers inputs
This commit is contained in:
parent
068e4ade1b
commit
3fa2bd34bb
2 changed files with 37 additions and 7 deletions
|
|
@ -247,15 +247,25 @@ def process_response_headers(
|
|||
preserve_litellm_internal_headers: bool = False,
|
||||
) -> dict:
|
||||
"""
|
||||
`preserve_litellm_internal_headers` must only be True when the input dict is
|
||||
a LiteLLM-owned structure (e.g. `_hidden_params["additional_headers"]` that
|
||||
has already been through one round of processing). For raw upstream
|
||||
provider headers it must remain False, otherwise a malicious provider
|
||||
returning `x-litellm-*` could spoof LiteLLM-internal markers
|
||||
(e.g. `x-litellm-attempted-fallbacks`).
|
||||
`preserve_litellm_internal_headers` must only be True when the input is a
|
||||
LiteLLM-owned dict (e.g. `_hidden_params["additional_headers"]` that has
|
||||
already been through one round of processing). For raw upstream provider
|
||||
headers — whether passed as `httpx.Headers` or a plain dict — it must
|
||||
remain False, otherwise a malicious provider returning `x-litellm-*` could
|
||||
spoof LiteLLM-internal markers (e.g. `x-litellm-attempted-fallbacks`).
|
||||
|
||||
When the input is an `httpx.Headers` object the flag is always treated as
|
||||
False regardless of what the caller requested, because `httpx.Headers` is
|
||||
always a raw provider response and can never be LiteLLM-owned.
|
||||
"""
|
||||
from litellm.types.utils import OPENAI_RESPONSE_HEADERS
|
||||
|
||||
# Raw httpx.Headers objects come directly from provider HTTP responses and
|
||||
# must never be treated as LiteLLM-owned, regardless of caller intent.
|
||||
_preserve = preserve_litellm_internal_headers and isinstance(
|
||||
response_headers, dict
|
||||
)
|
||||
|
||||
openai_headers = {}
|
||||
processed_headers = {}
|
||||
additional_headers = {}
|
||||
|
|
@ -267,7 +277,7 @@ def process_response_headers(
|
|||
"llm_provider-"
|
||||
): # return raw provider headers (incl. openai-compatible ones)
|
||||
processed_headers[k] = v
|
||||
elif preserve_litellm_internal_headers and k.startswith("x-litellm-"):
|
||||
elif _preserve and k.startswith("x-litellm-"):
|
||||
# LiteLLM's own internal headers (e.g. x-litellm-attempted-fallbacks,
|
||||
# x-litellm-model-group) are not LLM provider headers and must not be
|
||||
# prefixed. Downstream consumers (proxy override, callers checking
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""Tests for litellm.litellm_core_utils.fallback_utils."""
|
||||
|
||||
import pytest
|
||||
import httpx
|
||||
|
||||
import litellm
|
||||
from litellm.litellm_core_utils.core_helpers import process_response_headers
|
||||
|
|
@ -147,3 +148,22 @@ def test_process_response_headers_prefixes_x_litellm_from_raw_provider():
|
|||
assert "x-litellm-attempted-fallbacks" not in result
|
||||
assert result["llm_provider-x-litellm-attempted-fallbacks"] == 99
|
||||
assert result["llm_provider-x-stainless-arch"] == "arm64"
|
||||
|
||||
|
||||
def test_process_response_headers_ignores_preserve_flag_for_httpx_headers():
|
||||
"""
|
||||
Some providers store raw httpx.Headers directly in _hidden_params["additional_headers"]
|
||||
without a prior normalization pass. If preserve_litellm_internal_headers=True were
|
||||
honored for httpx.Headers inputs, a provider returning x-litellm-attempted-fallbacks
|
||||
could spoof it as a bare LiteLLM-internal marker and make the proxy skip
|
||||
stamping the correct response model. The flag must be ignored for httpx.Headers.
|
||||
"""
|
||||
raw = httpx.Headers(
|
||||
{
|
||||
"x-litellm-attempted-fallbacks": "1",
|
||||
"content-type": "application/json",
|
||||
}
|
||||
)
|
||||
result = process_response_headers(raw, preserve_litellm_internal_headers=True)
|
||||
assert "x-litellm-attempted-fallbacks" not in result
|
||||
assert result["llm_provider-x-litellm-attempted-fallbacks"] == "1"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue