fix(passthrough): drop configured Accept-Encoding custom headers too

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
mateo 2026-08-14 21:58:25 +00:00
parent c802651b77
commit 02b45552b9
2 changed files with 23 additions and 12 deletions

View file

@ -1,4 +1,5 @@
from collections.abc import Mapping
from itertools import chain
from typing import Final
from urllib.parse import parse_qs
@ -27,7 +28,7 @@ _PASS_THROUGH_PROTECTED_HEADER_PREFIXES: Final[tuple] = ("x-amz-",)
# `accept-encoding` is dropped so httpx negotiates a coding it has a decoder for: one it
# cannot decode leaves the body compressed while Content-Encoding is stripped downstream.
_NON_FORWARDED_REQUEST_HEADERS: Final[frozenset[str]] = frozenset(
_NON_FORWARDED_HEADERS: Final[frozenset[str]] = frozenset(
{
"content-length",
"host",
@ -76,15 +77,14 @@ class BasePassthroughUtils:
with the prefix stripped, regardless of forward_headers setting.
e.g., 'x-pass-anthropic-beta: value' becomes 'anthropic-beta: value'
"""
if forward_headers is True:
custom_header_names: Final = {header_name.lower() for header_name in headers}
forwardable_headers: Final = {
header_name: header_value
for header_name, header_value in request_headers.items()
if header_name.lower() not in _NON_FORWARDED_REQUEST_HEADERS
and header_name.lower() not in custom_header_names
}
headers = {**forwardable_headers, **headers}
custom_header_names: Final = {header_name.lower() for header_name in headers}
client_headers: Final = request_headers.items() if forward_headers is True else ()
merged_headers: Final = {
header_name: header_value
for header_name, header_value in chain(client_headers, headers.items())
if header_name.lower() not in _NON_FORWARDED_HEADERS
and (header_name in headers or header_name.lower() not in custom_header_names)
}
# Process x-pass- prefixed headers (strip prefix and forward)
# Credential and protocol-level headers are excluded from this mechanism.
@ -100,9 +100,9 @@ class BasePassthroughUtils:
header_name,
)
continue
headers[actual_header_name] = header_value
merged_headers[actual_header_name] = header_value
return headers
return merged_headers
class CommonUtils:

View file

@ -39,6 +39,17 @@ def test_client_accept_encoding_is_not_forwarded_via_x_pass_prefix():
assert "accept-encoding" not in headers
def test_configured_custom_accept_encoding_is_dropped():
headers = BasePassthroughUtils.forward_headers_from_request(
request_headers={},
headers={"x-api-key": "sk-anthropic", "Accept-Encoding": "br"},
forward_headers=False,
)
assert "accept-encoding" not in {name.lower() for name in headers}
assert headers["x-api-key"] == "sk-anthropic"
def test_upstream_request_only_advertises_decodable_encodings():
"""A content coding httpx cannot decode would reach the client still compressed,
with Content-Encoding stripped by get_response_headers (LIT-5613)."""