Recompute Content-Length when repeat_request replaces body#614
Recompute Content-Length when repeat_request replaces body#614Hardikrepo wants to merge 2 commits into
Conversation
… body
Problem:
apply_modifications() let modifications={"body": ...} replace the request
body but left the original Content-Length header untouched.
build_raw_request() only fills in Content-Length when the header is
absent, so the stale, smaller value from the original request was sent
on the wire alongside the new, larger body.
Impact:
A server reading exactly Content-Length bytes truncates the replayed
body (or stalls waiting for more), silently discarding the
modified/injected payload. This defeats parameter-tampering and
injection replays, which is the core use case of repeat_request, and
produces misleading negative results during testing.
Resolution:
When modifications["body"] is present, drop any existing Content-Length
header from the carried-over headers (matched case-insensitively),
unless the caller explicitly supplies Content-Length in this same call's
modifications["headers"]. This lets build_raw_request's existing
"fill in if absent" logic recompute the correct length from the new
body.
Testing:
Added tests/test_caido_api.py covering: stale header dropped on body
replacement, explicit caller-supplied Content-Length respected, headers
left untouched when body isn't modified, and an end-to-end check that
build_raw_request emits the recomputed length in the raw HTTP request.
Verified RED (failing on pre-fix code, reproducing the exact stale
Content-Length: 3 scenario from the bug report) before GREEN.
Resolves usestrix#603
Greptile SummaryThis PR fixes a bug in
Confidence Score: 4/5Safe to merge; the fix correctly resolves the stale Content-Length bug across all the meaningful call patterns. The logic in apply_modifications is correct for all documented scenarios. One pre-existing gap becomes slightly more visible: build_raw_request's The Important Files Changed
|
build_raw_request's Content-Length guard was "if body and ...", so a falsy empty-string body (a valid replacement via repeat_request's modifications["body"]) skipped Content-Length injection entirely. Sending no Content-Length is valid HTTP/1.1, but some strict servers or WAFs expect an explicit Content-Length: 0, so silently omitting it can still cause inconsistent replay behavior. Change the guard to "body is not None" so an empty body still gets Content-Length: 0 while a None body (not applicable here, but kept for clarity) is still skipped. Adds test_build_raw_request_sets_content_length_zero_for_empty_body, verified RED against the prior "if body and ..." guard before GREEN. Addresses review feedback from usestrix#614.
Summary
apply_modifications()instrix/tools/proxy/caido_api.pyreplaced the request body viamodifications={"body": ...}but left the originalContent-Lengthheader untouched.build_raw_request()only computesContent-Lengthwhen the header is absent, so the stale, smaller value from the original request was sent alongside the new, larger body.Content-Lengthbytes truncates the replayed body (or stalls), silently dropping the modified/injected payload — defeating parameter-tampering / injection replays, which is the core use case ofrepeat_request, and producing misleading negative results.Fix
When
modifications["body"]is present, drop any existingContent-Lengthheader from the carried-over headers (matched case-insensitively), unless the caller explicitly suppliesContent-Lengthin that same call'smodifications["headers"]. This letsbuild_raw_request's existing "fill in if absent" logic recompute the correct length from the new body.Test plan
tests/test_caido_api.py: stale header dropped on body replacement, explicit caller-suppliedContent-Lengthrespected, headers untouched when body isn't modified, and an end-to-end check thatbuild_raw_requestemits the recomputed length in the raw HTTP request.Content-Length: 3scenario from the bug report), then GREEN after the fix.uv run pytest tests/) has no new failures.ruff checkandmypyclean on changed files.Resolves #603