Skip to content

Validate Content-Length format in ClientRequest#12385

Merged
Dreamsorcerer merged 4 commits intoaio-libs:masterfrom
jmestwa-coder:fix-content-length-validation
Apr 22, 2026
Merged

Validate Content-Length format in ClientRequest#12385
Dreamsorcerer merged 4 commits intoaio-libs:masterfrom
jmestwa-coder:fix-content-length-validation

Conversation

@jmestwa-coder
Copy link
Copy Markdown
Contributor

What do these changes do?

This change adds strict validation for the Content-Length header in ClientRequest.

Currently, _get_content_length() uses Python’s int() for parsing, which accepts non-RFC-compliant values such as negative numbers or values with whitespace. This patch introduces a DIGITS-only validation to ensure the header follows the same format already enforced by the HTTP parser.

Are there changes in behavior for the user?

Yes, but only for invalid inputs.

  • Valid Content-Length values (e.g., "0", "100") are unaffected.
  • Non-compliant values (e.g., "-100", " 100", "+100") will now raise a ValueError instead of being accepted.

This aligns behavior across send and receive paths and avoids unexpected behavior when invalid values are provided.

Is it a substantial burden for the maintainers to support this?

No.

  • The change is minimal and localized to a single method.
  • It reuses the same validation approach already used in the HTTP parser.
  • No new abstractions or dependencies are introduced.
  • The behavior is consistent with existing expectations for header validation.

This should not increase maintenance overhead.

Related issue number

N/A

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
  • Add a new news fragment into the CHANGES/ folder

@jmestwa-coder jmestwa-coder requested a review from asvetlov as a code owner April 17, 2026 07:03
@Dreamsorcerer
Copy link
Copy Markdown
Member

Could you add an end-to-end test in test_web_functional.py? I think this code is actually unreachable and even the current check can be removed. I'm pretty sure we already validate it in the parser.

@Dreamsorcerer Dreamsorcerer added the pr-unfinished The PR is unfinished and may need a volunteer to complete it label Apr 17, 2026
@jmestwa-coder jmestwa-coder force-pushed the fix-content-length-validation branch 2 times, most recently from 49f902f to 4296e72 Compare April 20, 2026 07:12
Comment thread aiohttp/client_reqrep.py Fixed
@jmestwa-coder jmestwa-coder force-pushed the fix-content-length-validation branch 2 times, most recently from dd083ea to a66944d Compare April 20, 2026 07:58
@jmestwa-coder
Copy link
Copy Markdown
Contributor Author

Added an end-to-end test in test_web_functional.py to cover this case.
Invalid Content-Length values are now rejected, while valid ones work as before.

Let me know if you'd like any changes.

@github-actions github-actions Bot removed the pr-unfinished The PR is unfinished and may need a volunteer to complete it label Apr 20, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.92%. Comparing base (b0601d6) to head (7aba64b).
⚠️ Report is 1 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #12385   +/-   ##
=======================================
  Coverage   98.92%   98.92%           
=======================================
  Files         134      134           
  Lines       46741    46751   +10     
  Branches     2429     2430    +1     
=======================================
+ Hits        46239    46249   +10     
  Misses        373      373           
  Partials      129      129           
Flag Coverage Δ
CI-GHA 98.98% <100.00%> (+<0.01%) ⬆️
OS-Linux 98.72% <100.00%> (+<0.01%) ⬆️
OS-Windows 96.98% <100.00%> (+<0.01%) ⬆️
OS-macOS 97.89% <100.00%> (-0.01%) ⬇️
Py-3.10.11 97.39% <100.00%> (+<0.01%) ⬆️
Py-3.10.20 97.86% <100.00%> (+<0.01%) ⬆️
Py-3.11.15 98.11% <100.00%> (-0.01%) ⬇️
Py-3.11.9 97.65% <100.00%> (-0.01%) ⬇️
Py-3.12.10 97.74% <100.00%> (+<0.01%) ⬆️
Py-3.12.13 98.20% <100.00%> (-0.01%) ⬇️
Py-3.13.13 98.45% <100.00%> (+<0.01%) ⬆️
Py-3.14.4 98.50% <100.00%> (-0.01%) ⬇️
Py-3.14.4t 97.52% <100.00%> (+<0.01%) ⬆️
Py-pypy3.11.15-7.3.21 97.35% <100.00%> (+<0.01%) ⬆️
VM-macos 97.89% <100.00%> (-0.01%) ⬇️
VM-ubuntu 98.72% <100.00%> (+<0.01%) ⬆️
VM-windows 96.98% <100.00%> (+<0.01%) ⬆️
cython-coverage 38.08% <13.33%> (-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 Apr 20, 2026

Merging this PR will not alter performance

✅ 67 untouched benchmarks
⏩ 4 skipped benchmarks1


Comparing jmestwa-coder:fix-content-length-validation (7aba64b) with master (b0601d6)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Comment thread tests/test_client_request.py Outdated
@Dreamsorcerer
Copy link
Copy Markdown
Member

Added an end-to-end test in test_web_functional.py to cover this case. Invalid Content-Length values are now rejected, while valid ones work as before.

Let me know if you'd like any changes.

Sorry, I thought this was validating the response. I've just realised this is validating the request, i.e. the data from the developer. I guess this looks fine as a simple improvement to sanity checking then.

@jmestwa-coder jmestwa-coder force-pushed the fix-content-length-validation branch from ee47a1b to 7074a06 Compare April 22, 2026 06:43
Reject non-RFC-compliant Content-Length values to align with HTTP parser behavior and ensure consistent validation.
@jmestwa-coder jmestwa-coder force-pushed the fix-content-length-validation branch from 7074a06 to 991105b Compare April 22, 2026 06:44
Comment thread tests/test_web_functional.py Outdated
Comment thread tests/test_client_request.py Outdated
@Dreamsorcerer Dreamsorcerer added backport-3.14 Trigger automatic backporting to the 3.14 release branch by Patchback robot bot:chronographer:skip This PR does not need to include a change note labels Apr 22, 2026
@Dreamsorcerer Dreamsorcerer merged commit 365f717 into aio-libs:master Apr 22, 2026
81 of 82 checks passed
@patchback
Copy link
Copy Markdown
Contributor

patchback Bot commented Apr 22, 2026

Backport to 3.14: 💔 cherry-picking failed — conflicts found

❌ Failed to cleanly apply 365f717 on top of patchback/backports/3.14/365f717faf6df82108971b847264e9b28d4d1b07/pr-12385

Backporting merged PR #12385 into master

  1. Ensure you have a local repo clone of your fork. Unless you cloned it
    from the upstream, this would be your origin remote.
  2. Make sure you have an upstream repo added as a remote too. In these
    instructions you'll refer to it by the name upstream. If you don't
    have it, here's how you can add it:
    $ git remote add upstream https://github.com/aio-libs/aiohttp.git
  3. Ensure you have the latest copy of upstream and prepare a branch
    that will hold the backported code:
    $ git fetch upstream
    $ git checkout -b patchback/backports/3.14/365f717faf6df82108971b847264e9b28d4d1b07/pr-12385 upstream/3.14
  4. Now, cherry-pick PR Validate Content-Length format in ClientRequest #12385 contents into that branch:
    $ git cherry-pick -x 365f717faf6df82108971b847264e9b28d4d1b07
    If it'll yell at you with something like fatal: Commit 365f717faf6df82108971b847264e9b28d4d1b07 is a merge but no -m option was given., add -m 1 as follows instead:
    $ git cherry-pick -m1 -x 365f717faf6df82108971b847264e9b28d4d1b07
  5. At this point, you'll probably encounter some merge conflicts. You must
    resolve them in to preserve the patch from PR Validate Content-Length format in ClientRequest #12385 as close to the
    original as possible.
  6. Push this branch to your fork on GitHub:
    $ git push origin patchback/backports/3.14/365f717faf6df82108971b847264e9b28d4d1b07/pr-12385
  7. Create a PR, ensure that the CI is green. If it's not — update it so that
    the tests and any other checks pass. This is it!
    Now relax and wait for the maintainers to process your pull request
    when they have some cycles to do reviews. Don't worry — they'll tell you if
    any improvements are necessary when the time comes!

🤖 @patchback
I'm built with octomachinery and
my source is open — https://github.com/sanitizers/patchback-github-app.

@Dreamsorcerer
Copy link
Copy Markdown
Member

If you could follow the above instructions for a backport, that'd be really helpful.

@jmestwa-coder
Copy link
Copy Markdown
Contributor Author

Sure, I’ll work on the backport following the instructions.

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

Labels

backport-3.14 Trigger automatic backporting to the 3.14 release branch by Patchback robot bot:chronographer:skip This PR does not need to include a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants