Skip to content

fix: preserve HTTP method on 307 and 308 redirects#6658

Merged
vlsi merged 3 commits intoapache:masterfrom
dlwldnjs1009:gh6080-fix-307-308-redirect-method
Mar 19, 2026
Merged

fix: preserve HTTP method on 307 and 308 redirects#6658
vlsi merged 3 commits intoapache:masterfrom
dlwldnjs1009:gh6080-fix-307-308-redirect-method

Conversation

@dlwldnjs1009
Copy link
Contributor

@dlwldnjs1009 dlwldnjs1009 commented Mar 17, 2026

Summary

Fixes #6080

This change fixes redirect handling in JMeter's Follow Redirects path for HTTP 307 and 308 responses.

At the moment, JMeter only treats 307 as a redirect for GET and HEAD, so requests such as POST 307 are not followed. In addition, redirected requests for 307/308 can still lose the original HTTP method.

This change updates HTTPSampleResult.isRedirect() so 307 is recognized as a redirect for all HTTP methods, and updates redirect method selection so 307/308 preserve the original method while keeping the existing 301/302/303 behavior unchanged.

It also uses lastRes.getResponseCode() in followRedirects(), so mixed redirect chains such as 307 -> 301 are handled correctly.

Tests

  • updated testRedirect for 307 redirect recognition
  • added redirect method preservation coverage in TestRedirects
  • added a mixed redirect chain test (307 -> 301)
  • ran ./gradlew :src:protocol:http:check

Previously, 307 Temporary Redirect was only recognized as a redirect
for GET and HEAD requests, and 308 Permanent Redirect converted all
methods to GET. Both violate the method preservation requirement of
RFC 9110 §15.4.8 (307) and RFC 7538 §3 (308).

- HTTPSampleResult.isRedirect(): recognize 307 as redirect for all
  HTTP methods, removing the GET/HEAD restriction
- HTTPSamplerBase.computeMethodForRedirect(): accept response code
  parameter; preserve original method for 307 and 308
- HTTPSamplerBase.followRedirects(): pass current hop's response code
  (lastRes, not res) to support mixed redirect chains (e.g. 307->301)

This is a behavior change: POST/PUT requests receiving 307 or 308 will
now be redirected with the original method preserved, whereas previously
307 POST was not followed and 308 POST was converted to GET.

Fixes apache#6080
@dlwldnjs1009 dlwldnjs1009 force-pushed the gh6080-fix-307-308-redirect-method branch from dbe46fd to a3ff630 Compare March 17, 2026 02:40
@dlwldnjs1009 dlwldnjs1009 changed the title Fix redirect method handling for 307 and 308 responses fix: preserve HTTP method on 307 and 308 redirects Mar 17, 2026
Copy link
Contributor

@FSchumacher FSchumacher left a comment

Choose a reason for hiding this comment

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

Only looked at the changes, but they look good to me.

for (int statusCode : Arrays.asList(301, 302, 303, 307, 308)) {
for (String method : httpMethods) {
boolean shouldRedirect = statusCode != 307 || ("GET".equals(method) || "HEAD".equals(method));
boolean shouldRedirect = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

If this is always true, why not inline it into the next line?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well. If the value is shouldRedirect=true, should we rather remove the parameter then?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, good point. I inlined true in the redirect block.

I kept the parameter because the non-redirect cases in the second loop (300, 304, 305, 306) still use false.

Arrays.stream(HTTPSamplerFactory.getImplementations()).forEach(httpImpl -> {
for (int statusCode : Arrays.asList(301, 302, 303, 307, 308)) {
for (String method : httpMethods) {
String expectedMethod;
Copy link
Contributor

Choose a reason for hiding this comment

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

As we now use Java 17, we could use a switch expression:

String expectedMethod = switch (statusCode) {
   case 307, 308 -> method;
   default -> switch (method) {
     case "HEAD" -> "HEAD";
     default -> "GET";
   };
};

The inner switch could even be replaced with "HEAD".equals(method) ? "HEAD" : "GET". But I think the switch would be nicer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good suggestion, updated to use a switch expression here.

For the default branch I kept the HEAD check as a ternary since there are only two cases.

- Inline shouldRedirect variable directly into Arguments.of()
- Use Java 17 switch expression for expectedMethod computation
Comment on lines +88 to +90
// Nested for depth is 2 (max allowed is 1). [NestedForDepth]
List<String> httpMethods = Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE");
Arrays.stream(HTTPSamplerFactory.getImplementations()).forEach(httpImpl -> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is ugly, and I am gravitating towards lifting NestedForDepth requirements. It can be in a separate PR though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, the stream wrapper makes the setup less readable. I'll remove the NestedForDepth comments here. I'd prefer to keep this PR focused on the redirect fix, and leave any cleanup around that for a separate PR.

@vlsi vlsi merged commit 32f1af6 into apache:master Mar 19, 2026
5 of 7 checks passed
@vlsi
Copy link
Collaborator

vlsi commented Mar 19, 2026

Thanks for the PR!

@dlwldnjs1009 dlwldnjs1009 deleted the gh6080-fix-307-308-redirect-method branch March 19, 2026 15:25
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.

JMeter does not comply with RFC9110#15.4.8(307 Temporary Redirect)

3 participants