* fix(proxy): decompress Codex request body before forward, support zstd
Codex Desktop sends zstd-compressed request bodies when authenticated
against the Codex backend, which broke local proxy routing because the
handlers parsed the raw bytes with serde_json directly.
Reworked on top of current main so it preserves the response_processor
behavior that landed after this PR was first opened:
- Extract content-encoding helpers into a shared proxy::content_encoding
module. decompress_body keeps returning Option<Vec<u8>> so unknown
encodings stay pass-through with their content-encoding header intact,
and keeps the deflate zlib-then-raw fallback (RFC 9110).
- Add zstd/zst support (zstd 0.13) and disable reqwest's auto zstd
decompression via .no_zstd() for parity with gzip/br/deflate.
- Decompress the request body before JSON parsing in the three Codex
handlers (chat_completions / responses / responses_compact) and strip
the stale content-encoding / content-length / transfer-encoding headers
so the forwarder regenerates them.
- Support stacked codings (e.g. "gzip, zstd") by decoding in reverse
order and merge repeated Content-Encoding headers via get_all.
Fixes#3764Fixes#3696
Co-authored-by: chenx-dust <16610294+chenx-dust@users.noreply.github.com>
* fix(proxy): decompress upstream error bodies before reading them
The forwarder error branch consumes non-2xx responses via String::from_utf8
directly, bypassing read_decoded_body. reqwest has no auto-decompression
feature enabled, so a compressed error body (gzip/br/deflate/zstd) arrives
as raw bytes, fails from_utf8, and gets dropped, hiding upstream rate-limit
and auth details from the client.
Decode the error body with the shared proxy::content_encoding helper,
mirroring the success path. Falls back to the raw bytes when the encoding is
unsupported or decoding fails.
Co-authored-by: chenx-dust <16610294+chenx-dust@users.noreply.github.com>
---------
Co-authored-by: Jason <farion1231@gmail.com>
Co-authored-by: chenx-dust <16610294+chenx-dust@users.noreply.github.com>