Fix request body re-sent on method-rewritten redirect follows#124
Fix request body re-sent on method-rewritten redirect follows#124benjithompson wants to merge 1 commit into
Conversation
When JMeter core follows a 301/302/303 it rewrites POST to GET, but setBody() gated body attachment on the sampler's configured method instead of the method actually being sent (result.getHTTPMethod()). The follow-up GET therefore carried the original POST entity, unlike HTTPSamplerProxy and RFC 9110 semantics. Skip body attachment when the effective method differs from the sampler's configured method and does not admit a body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3q9uueSAmCEz3P8MS8crD
|
Thanks @benjithompson We were casually working on incorporating JMeter regression tests, which would help us detect the issues you reported. This was addressed at the time by PR 134 #134. However, since we saw that JMeter's regression tests didn't cover all redirect states and found that JMeter had unresolved bugs regarding the RFC (which were fixed after the release of version 5.6.3), we worked on creating a PR to fix the JMeter 5.6.3 issue in PR 142 #142. Thanks to your report, we've taken a closer look at JMeter's discrepancy with the RFC. Jetty's core doesn't have these problems when running with Automatic Redirect, but when JMeter is instructed to use Follow Redirect, where JMeter takes control and creates a samples for each redirect, that's where the problems arise because JMeter doesn't comply with the RFC standard. I'm closing this pull request since the fix was formally implemented in pull request 134 and its compatibility was improved in pull request 142. The fixes will be included in the next release. Without your report, we wouldn't have looked into that detail. Thank you very much for your contribution. |
Summary
When "Follow Redirects" is enabled and a request with a body is answered with a
301/302/303, the follow-up request re-sends the original request body. JMeter core rewrites the method toGETfor the follow-up (matching browser behavior and RFC 9110 §15.4), but the sampler still attaches the POST entity to thatGET.Observed on the wire (POST with form parameters, server answers
302 Location: ...):followed by
Why it's wrong
GET, which carries no entity from the original request; browsers and JMeter's stockHTTPSamplerProxy(HC4) apply the same POST→GET rewrite for301/302and drop the body on the rewritten request. This sampler diverges from both, so plans migrated from the stock sampler change their wire behavior.GETleave the stray bytes in the connection buffer; on a keep-alive connection they corrupt the framing of the next request (e.g.501 Unsupported method ('password=...GET')from Python's stdlibhttp.server). Tolerant servers silently accept the mis-shaped traffic, which hides the problem while still distorting load-test fidelity.Root cause
In
HTTP2JettyClient,samplePrepareRequestsets the request line's method from the result (correct —GETon a redirect follow):but
setBodygated body attachment on the sampler's configured method, which is stillPOST:Fix
Fix: isMethodWithBody should check result.getHTTPMethod() — the method actually being sent — not sampler.getMethod():
Same fix applies to the raw-body branch (sampler.getSendParameterValuesAsPostBody()), which has the identical bug — it also needs to gate on the actual outgoing method rather than the sampler's configured one.
It's a one-line change (swap which variable isMethodWithBody is called with), confirmed present in both the pinned v3.0.1 tag and current master.
🤖 Generated with Claude Code