mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
fix(proxy): count an upstream guardrail header the proxy can't replace toward the header limit
This commit is contained in:
parent
263012bd96
commit
e89c462d7a
2 changed files with 28 additions and 20 deletions
|
|
@ -298,29 +298,23 @@ def _is_sendable_header_value(value: str) -> bool:
|
|||
)
|
||||
|
||||
|
||||
def _with_header_in_budget(
|
||||
kept: Mapping[str, str], header: tuple[str, str], budget: int = _GUARDRAIL_HEADERS_MAX_BYTES
|
||||
) -> Mapping[str, str]:
|
||||
def _with_header_in_budget(kept: Mapping[str, str], header: tuple[str, str]) -> Mapping[str, str]:
|
||||
size: Final = sum(len(name) + len(value) for name, value in (*kept.items(), header))
|
||||
return MappingProxyType({**kept, header[0]: header[1]}) if size <= budget else kept
|
||||
return MappingProxyType({**kept, header[0]: header[1]}) if size <= _GUARDRAIL_HEADERS_MAX_BYTES else kept
|
||||
|
||||
|
||||
def _with_header_in_response_limit(headers: Mapping[str, str], header: tuple[str, str]) -> Mapping[str, str]:
|
||||
merged: Final = {**headers, header[0]: header[1]}
|
||||
size: Final = sum(len(name) + len(value) + _HEADER_FRAMING_BYTES for name, value in merged.items())
|
||||
return merged if size <= _RESPONSE_HEADERS_MAX_BYTES else headers
|
||||
|
||||
|
||||
def _guardrail_headers_with_room(
|
||||
guardrail_headers: Mapping[str, str], response_headers: Mapping[str, str]
|
||||
) -> Mapping[str, str]:
|
||||
"""``guardrail_headers``, without one the response's other headers leave no room for, so adding them can't cost a
|
||||
client the response"""
|
||||
others: Final = sum(
|
||||
len(name) + len(value) + _HEADER_FRAMING_BYTES
|
||||
for name, value in response_headers.items()
|
||||
if name not in guardrail_headers
|
||||
)
|
||||
no_headers: Final[Mapping[str, str]] = MappingProxyType({})
|
||||
return reduce(
|
||||
partial(_with_header_in_budget, budget=_RESPONSE_HEADERS_MAX_BYTES - others),
|
||||
guardrail_headers.items(),
|
||||
no_headers,
|
||||
)
|
||||
"""``response_headers`` with each of ``guardrail_headers`` that fits, so adding them can't cost a client the
|
||||
response. One that doesn't fit leaves the header of that name as it was."""
|
||||
return reduce(_with_header_in_response_limit, guardrail_headers.items(), response_headers)
|
||||
|
||||
|
||||
def _add_callback_headers(
|
||||
|
|
@ -333,10 +327,10 @@ def _add_callback_headers(
|
|||
for name, value in response_headers.items()
|
||||
if name in _GUARDRAIL_HEADER_NAMES and name not in callback_headers
|
||||
}
|
||||
response_headers.update(callback_headers)
|
||||
kept: Final = _guardrail_headers_with_room(guardrail_headers, response_headers)
|
||||
for name in guardrail_headers.keys() - kept.keys():
|
||||
for name in guardrail_headers:
|
||||
response_headers.pop(name)
|
||||
response_headers.update(callback_headers)
|
||||
response_headers.update(_guardrail_headers_with_room(guardrail_headers, response_headers))
|
||||
|
||||
|
||||
def _recorded_guardrail_headers(
|
||||
|
|
|
|||
|
|
@ -13896,6 +13896,20 @@ class TestGuardrailResponseHeaders:
|
|||
assert "x-litellm-applied-guardrails" not in headers
|
||||
assert len(headers) == 1_500
|
||||
|
||||
def test_an_upstream_guardrail_header_a_larger_one_cannot_replace_still_counts(self):
|
||||
names: Final = [f"guardrail-{index:03d}" for index in range(280)]
|
||||
upstream: Final = {"x-upstream": "u" * 10_000, "x-litellm-applied-policies": "p" * 4_000}
|
||||
headers: Final = HttpPassThroughEndpointHelpers.get_response_headers(
|
||||
headers=httpx.Headers(upstream),
|
||||
guardrail_request_data=(
|
||||
{},
|
||||
{"litellm_params": {"metadata": {"applied_guardrails": names, "applied_policies": names}}},
|
||||
),
|
||||
)
|
||||
|
||||
assert sum(len(name) + len(value) + 4 for name, value in headers.items()) <= 15360
|
||||
assert headers["x-upstream"] == upstream["x-upstream"]
|
||||
|
||||
def test_an_upstream_guardrail_header_the_proxy_replaces_takes_no_room(self):
|
||||
headers: Final = HttpPassThroughEndpointHelpers.get_response_headers(
|
||||
headers=httpx.Headers({"x-litellm-applied-guardrails": "u" * 15_400}),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue