Skip to content

Commit b3af4be

Browse files
committed
Keep body on strict 302 and 307, close AsyncHttpClient#939
1 parent fded6cf commit b3af4be

File tree

5 files changed

+160
-0
lines changed

5 files changed

+160
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.asynchttpclient;
2+
3+
import static org.testng.Assert.*;
4+
5+
import java.io.IOException;
6+
import java.util.concurrent.TimeUnit;
7+
8+
import javax.servlet.ServletException;
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
12+
import org.apache.commons.io.IOUtils;
13+
import org.asynchttpclient.AsyncHttpClientConfig.Builder;
14+
import org.asynchttpclient.filter.FilterContext;
15+
import org.asynchttpclient.filter.FilterException;
16+
import org.asynchttpclient.filter.ResponseFilter;
17+
import org.eclipse.jetty.server.Request;
18+
import org.eclipse.jetty.server.handler.AbstractHandler;
19+
import org.testng.annotations.Test;
20+
21+
public abstract class RedirectBodyTest extends AbstractBasicTest {
22+
23+
@Override
24+
public AbstractHandler configureHandler() throws Exception {
25+
return new AbstractHandler() {
26+
@Override
27+
public void handle(String pathInContext, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException {
28+
29+
String redirectHeader = httpRequest.getHeader("X-REDIRECT");
30+
if (redirectHeader != null) {
31+
httpResponse.setStatus(Integer.valueOf(redirectHeader));
32+
httpResponse.setContentLength(0);
33+
httpResponse.setHeader("Location", getTargetUrl());
34+
35+
} else {
36+
httpResponse.setStatus(200);
37+
int len = request.getContentLength();
38+
httpResponse.setContentLength(len);
39+
if (len > 0) {
40+
byte[] buffer = new byte[len];
41+
IOUtils.read(request.getInputStream(), buffer);
42+
httpResponse.getOutputStream().write(buffer);
43+
}
44+
}
45+
httpResponse.getOutputStream().flush();
46+
httpResponse.getOutputStream().close();
47+
}
48+
};
49+
}
50+
51+
private ResponseFilter redirectOnce = new ResponseFilter() {
52+
@Override
53+
public <T> FilterContext<T> filter(FilterContext<T> ctx) throws FilterException {
54+
ctx.getRequest().getHeaders().remove("X-REDIRECT");
55+
return ctx;
56+
}
57+
};
58+
59+
@Test(groups = { "standalone", "default_provider" })
60+
public void regular301LosesBody() throws Exception {
61+
try (AsyncHttpClient c = getAsyncHttpClient(new Builder().setFollowRedirect(true).addResponseFilter(redirectOnce).build())) {
62+
String body = "hello there";
63+
64+
Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("X-REDIRECT", "301").execute().get(TIMEOUT, TimeUnit.SECONDS);
65+
assertEquals(response.getResponseBody(), "");
66+
}
67+
}
68+
69+
@Test(groups = { "standalone", "default_provider" })
70+
public void regular302LosesBody() throws Exception {
71+
try (AsyncHttpClient c = getAsyncHttpClient(new Builder().setFollowRedirect(true).addResponseFilter(redirectOnce).build())) {
72+
String body = "hello there";
73+
74+
Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("X-REDIRECT", "302").execute().get(TIMEOUT, TimeUnit.SECONDS);
75+
assertEquals(response.getResponseBody(), "");
76+
}
77+
}
78+
79+
@Test(groups = { "standalone", "default_provider" })
80+
public void regular302StrictKeepsBody() throws Exception {
81+
try (AsyncHttpClient c = getAsyncHttpClient(new Builder().setFollowRedirect(true).setStrict302Handling(true).addResponseFilter(redirectOnce).build())) {
82+
String body = "hello there";
83+
84+
Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("X-REDIRECT", "302").execute().get(TIMEOUT, TimeUnit.SECONDS);
85+
assertEquals(response.getResponseBody(), body);
86+
}
87+
}
88+
89+
@Test(groups = { "standalone", "default_provider" })
90+
public void regular307KeepsBody() throws Exception {
91+
try (AsyncHttpClient c = getAsyncHttpClient(new Builder().setFollowRedirect(true).addResponseFilter(redirectOnce).build())) {
92+
String body = "hello there";
93+
94+
Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("X-REDIRECT", "307").execute().get(TIMEOUT, TimeUnit.SECONDS);
95+
assertEquals(response.getResponseBody(), body);
96+
}
97+
}
98+
}

providers/netty3/src/main/java/org/asynchttpclient/netty/handler/Protocol.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.asynchttpclient.netty.channel.ChannelManager;
4646
import org.asynchttpclient.netty.request.NettyRequestSender;
4747
import org.asynchttpclient.uri.Uri;
48+
import org.asynchttpclient.util.MiscUtils;
4849
import org.jboss.netty.channel.Channel;
4950
import org.jboss.netty.handler.codec.http.HttpHeaders;
5051
import org.jboss.netty.handler.codec.http.HttpResponse;
@@ -124,6 +125,7 @@ protected boolean exitAfterHandlingRedirect(//
124125
// 303 must force GET
125126
String originalMethod = request.getMethod();
126127
boolean switchToGet = !originalMethod.equals("GET") && (statusCode == 303 || (statusCode == 302 && !config.isStrict302Handling()));
128+
boolean keepBody = statusCode == 307 || (statusCode == 302 && config.isStrict302Handling());
127129

128130
final RequestBuilder requestBuilder = new RequestBuilder(switchToGet ? "GET" : originalMethod)//
129131
.setCookies(request.getCookies())//
@@ -135,6 +137,20 @@ protected boolean exitAfterHandlingRedirect(//
135137
.setRealm(request.getRealm())//
136138
.setRequestTimeout(request.getRequestTimeout());
137139

140+
if (keepBody) {
141+
requestBuilder.setBodyCharset(request.getBodyCharset());
142+
if (MiscUtils.isNonEmpty(request.getFormParams()))
143+
requestBuilder.setFormParams(request.getFormParams());
144+
if (request.getStringData() != null)
145+
requestBuilder.setBody(request.getStringData());
146+
if (request.getByteData() != null)
147+
requestBuilder.setBody(request.getByteData());
148+
if (request.getByteBufferData() != null)
149+
requestBuilder.setBody(request.getByteBufferData());
150+
if (request.getBodyGenerator() != null)
151+
requestBuilder.setBody(request.getBodyGenerator());
152+
}
153+
138154
requestBuilder.setHeaders(propagatedHeaders(request, realm, switchToGet));
139155

140156
// in case of a redirect from HTTP to HTTPS, future
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.asynchttpclient.netty;
2+
3+
import org.asynchttpclient.AsyncHttpClient;
4+
import org.asynchttpclient.AsyncHttpClientConfig;
5+
import org.asynchttpclient.RedirectBodyTest;
6+
import org.testng.annotations.Test;
7+
8+
@Test
9+
public class NettyRedirectBodyTest extends RedirectBodyTest {
10+
11+
@Override
12+
public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) {
13+
return NettyProviderUtil.nettyProvider(config);
14+
}
15+
}

providers/netty4/src/main/java/org/asynchttpclient/netty/handler/Protocol.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.asynchttpclient.netty.channel.ChannelManager;
4949
import org.asynchttpclient.netty.request.NettyRequestSender;
5050
import org.asynchttpclient.uri.Uri;
51+
import org.asynchttpclient.util.MiscUtils;
5152
import org.slf4j.Logger;
5253
import org.slf4j.LoggerFactory;
5354

@@ -121,6 +122,7 @@ protected boolean exitAfterHandlingRedirect(//
121122

122123
String originalMethod = request.getMethod();
123124
boolean switchToGet = !originalMethod.equals("GET") && (statusCode == 303 || (statusCode == 302 && !config.isStrict302Handling()));
125+
boolean keepBody = statusCode == 307 || (statusCode == 302 && config.isStrict302Handling());
124126

125127
final RequestBuilder requestBuilder = new RequestBuilder(switchToGet ? "GET" : originalMethod)//
126128
.setCookies(request.getCookies())//
@@ -132,6 +134,20 @@ protected boolean exitAfterHandlingRedirect(//
132134
.setRealm(request.getRealm())//
133135
.setRequestTimeout(request.getRequestTimeout());
134136

137+
if (keepBody) {
138+
requestBuilder.setBodyCharset(request.getBodyCharset());
139+
if (MiscUtils.isNonEmpty(request.getFormParams()))
140+
requestBuilder.setFormParams(request.getFormParams());
141+
if (request.getStringData() != null)
142+
requestBuilder.setBody(request.getStringData());
143+
if (request.getByteData() != null)
144+
requestBuilder.setBody(request.getByteData());
145+
if (request.getByteBufferData() != null)
146+
requestBuilder.setBody(request.getByteBufferData());
147+
if (request.getBodyGenerator() != null)
148+
requestBuilder.setBody(request.getBodyGenerator());
149+
}
150+
135151
requestBuilder.setHeaders(propagatedHeaders(request, realm, switchToGet));
136152

137153
// in case of a redirect from HTTP to HTTPS, future
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.asynchttpclient.netty;
2+
3+
import org.asynchttpclient.AsyncHttpClient;
4+
import org.asynchttpclient.AsyncHttpClientConfig;
5+
import org.asynchttpclient.RedirectBodyTest;
6+
import org.testng.annotations.Test;
7+
8+
@Test
9+
public class NettyRedirectBodyTest extends RedirectBodyTest {
10+
11+
@Override
12+
public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) {
13+
return NettyProviderUtil.nettyProvider(config);
14+
}
15+
}

0 commit comments

Comments
 (0)