Skip to content

Fix zstd decompression for multi-frame responses#12268

Open
r266-tech wants to merge 1 commit intoaio-libs:masterfrom
r266-tech:fix-zstd-multi-frame
Open

Fix zstd decompression for multi-frame responses#12268
r266-tech wants to merge 1 commit intoaio-libs:masterfrom
r266-tech:fix-zstd-multi-frame

Conversation

@r266-tech
Copy link
Copy Markdown

What do these changes do?

Fix zstd decompression failing with ClientPayloadError when a server sends zstd-encoded data in multiple frames (e.g., chunked transfer encoding with separate flushes per chunk).

The root cause is that compression.zstd.ZstdDecompressor cannot handle inputs containing multiple compressed frames — it raises EOFError: Already at the end of a Zstandard frame when encountering a second frame after the first one ends.

This fix:

  • Catches EOFError when a frame ends and creates a new ZstdDecompressor for the next frame
  • Handles multiple frames arriving in a single chunk by checking unused_data
  • Adds a regression test for multi-frame zstd decompression

Are there changes in behavior for the user?

Servers that send zstd responses in multiple frames (which is valid per the zstd spec) will now work correctly instead of raising ClientPayloadError.

Related issue number

Fixes #12234

Checklist

  • Tests added
  • Changes described in CHANGES/12234.bugfix.rst (if applicable)

ZstdDecompressor from compression.zstd cannot handle inputs containing
multiple compressed frames. When a server sends zstd-encoded data in
multiple frames (e.g., chunked transfer encoding with separate flushes),
the decompressor raises EOFError: 'Already at the end of a Zstandard frame'.

This fix:
- Catches EOFError when a frame ends and creates a new decompressor
- Handles multiple frames arriving in a single chunk via unused_data
- Adds a regression test for multi-frame zstd decompression

Fixes aio-libs#12234
@r266-tech r266-tech requested a review from asvetlov as a code owner March 23, 2026 14:50
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 23, 2026

Codecov Report

❌ Patch coverage is 85.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.10%. Comparing base (166f48d) to head (0d4e114).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
aiohttp/compression_utils.py 70.00% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #12268   +/-   ##
=======================================
  Coverage   99.10%   99.10%           
=======================================
  Files         130      130           
  Lines       45432    45451   +19     
  Branches     2400     2401    +1     
=======================================
+ Hits        45024    45043   +19     
  Misses        276      276           
  Partials      132      132           
Flag Coverage Δ
CI-GHA 98.95% <85.00%> (+<0.01%) ⬆️
OS-Linux 98.70% <85.00%> (+<0.01%) ⬆️
OS-Windows 96.97% <85.00%> (-0.01%) ⬇️
OS-macOS 97.85% <85.00%> (-0.01%) ⬇️
Py-3.10.11 97.40% <85.00%> (-0.01%) ⬇️
Py-3.10.20 97.89% <85.00%> (+<0.01%) ⬆️
Py-3.11.15 98.09% <85.00%> (-0.01%) ⬇️
Py-3.11.9 97.61% <85.00%> (-0.01%) ⬇️
Py-3.12.10 97.70% <85.00%> (-0.01%) ⬇️
Py-3.12.13 98.18% <85.00%> (+<0.01%) ⬆️
Py-3.13.12 98.42% <85.00%> (-0.01%) ⬇️
Py-3.14.3 98.48% <85.00%> (-0.01%) ⬇️
Py-3.14.3t 97.47% <85.00%> (-0.01%) ⬇️
Py-pypy3.11.13-7.3.20 97.49% <10.00%> (-0.04%) ⬇️
VM-macos 97.85% <85.00%> (-0.01%) ⬇️
VM-ubuntu 98.70% <85.00%> (+<0.01%) ⬆️
VM-windows 96.97% <85.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 23, 2026

Merging this PR will not alter performance

✅ 59 untouched benchmarks


Comparing r266-tech:fix-zstd-multi-frame (0d4e114) with master (2602b71)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (166f48d) during the generation of this report, so 2602b71 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link
Copy Markdown
Member

@Dreamsorcerer Dreamsorcerer Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not had the time to review the actual code approach compared to #12266, but this testing is inadequate for the task. It needs to cover edge cases with data being fed chunks at the frame boundary and across the frame boundary. I think #12266 already does this in the tests there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClientPayloadError: 400, message: Can not decode content-encoding: zstd - Already at the end of a Zstandard frame

2 participants