SEE OTHER redirect handling fix
This commit is contained in:
parent
3486b47452
commit
83d603c9d8
|
@ -90,6 +90,7 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
volatile URI redirectURI;
|
||||
volatile int maxRedirects;
|
||||
volatile int redirectCount;
|
||||
volatile HttpRequest originalRequest;
|
||||
volatile HttpRequest currentRequest;
|
||||
volatile AsyncEntityProducer currentEntityProducer;
|
||||
volatile RedirectLocations redirectLocations;
|
||||
|
@ -150,7 +151,7 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
redirectBuilder = BasicRequestBuilder.get();
|
||||
state.currentEntityProducer = null;
|
||||
} else {
|
||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||
}
|
||||
break;
|
||||
case HttpStatus.SC_SEE_OTHER:
|
||||
|
@ -158,15 +159,16 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
redirectBuilder = BasicRequestBuilder.get();
|
||||
state.currentEntityProducer = null;
|
||||
} else {
|
||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||
}
|
||||
redirectBuilder.setUri(redirectUri);
|
||||
state.reroute = false;
|
||||
state.redirectURI = redirectUri;
|
||||
state.originalRequest = redirectBuilder.build();
|
||||
state.currentRequest = redirectBuilder.build();
|
||||
|
||||
if (!Objects.equals(currentRoute.getTargetHost(), newTarget)) {
|
||||
|
@ -270,6 +272,7 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
final State state = new State();
|
||||
state.maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
||||
state.redirectCount = 0;
|
||||
state.originalRequest = scope.originalRequest;
|
||||
state.currentRequest = request;
|
||||
state.currentEntityProducer = entityProducer;
|
||||
state.redirectLocations = redirectLocations;
|
||||
|
|
|
@ -108,6 +108,7 @@ public final class RedirectExec implements ExecChainHandler {
|
|||
|
||||
final RequestConfig config = context.getRequestConfig();
|
||||
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
||||
ClassicHttpRequest originalRequest = scope.originalRequest;
|
||||
ClassicHttpRequest currentRequest = request;
|
||||
ExecChain.Scope currentScope = scope;
|
||||
for (int redirectCount = 0;;) {
|
||||
|
@ -153,18 +154,18 @@ public final class RedirectExec implements ExecChainHandler {
|
|||
if (Method.POST.isSame(request.getMethod())) {
|
||||
redirectBuilder = ClassicRequestBuilder.get();
|
||||
} else {
|
||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||
}
|
||||
break;
|
||||
case HttpStatus.SC_SEE_OTHER:
|
||||
if (!Method.GET.isSame(request.getMethod()) && !Method.HEAD.isSame(request.getMethod())) {
|
||||
redirectBuilder = ClassicRequestBuilder.get();
|
||||
} else {
|
||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
||||
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||
}
|
||||
redirectBuilder.setUri(redirectUri);
|
||||
|
||||
|
@ -201,6 +202,7 @@ public final class RedirectExec implements ExecChainHandler {
|
|||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("{} redirecting to '{}' via {}", exchangeId, redirectUri, currentRoute);
|
||||
}
|
||||
originalRequest = redirectBuilder.build();
|
||||
currentRequest = redirectBuilder.build();
|
||||
RequestEntityProxy.enhance(currentRequest);
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ import org.apache.hc.core5.http.HttpHeaders;
|
|||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.ProtocolException;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.io.support.ClassicResponseBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -357,6 +359,56 @@ public class TestRedirectExec {
|
|||
Mockito.verify(response1).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPutSeeOtherRedirect() throws Exception {
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
final URI targetUri = new URI("http://localhost:80/stuff");
|
||||
final ClassicHttpRequest request = ClassicRequestBuilder.put()
|
||||
.setUri(targetUri)
|
||||
.setEntity("stuff")
|
||||
.build();
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
||||
final URI redirect1 = new URI("http://localhost:80/see-something-else");
|
||||
final ClassicHttpResponse response1 = ClassicResponseBuilder.create(HttpStatus.SC_SEE_OTHER)
|
||||
.addHeader(HttpHeaders.LOCATION, redirect1.toASCIIString())
|
||||
.build();
|
||||
final URI redirect2 = new URI("http://localhost:80/other-stuff");
|
||||
final ClassicHttpResponse response2 = ClassicResponseBuilder.create(HttpStatus.SC_MOVED_PERMANENTLY)
|
||||
.addHeader(HttpHeaders.LOCATION, redirect2.toASCIIString())
|
||||
.build();
|
||||
final ClassicHttpResponse response3 = ClassicResponseBuilder.create(HttpStatus.SC_OK)
|
||||
.build();
|
||||
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(targetUri),
|
||||
ArgumentMatchers.any())).thenReturn(response1);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(redirect1),
|
||||
ArgumentMatchers.any())).thenReturn(response2);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(redirect2),
|
||||
ArgumentMatchers.any())).thenReturn(response3);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
final ClassicHttpResponse finalResponse = redirectExec.execute(request, scope, chain);
|
||||
Assertions.assertEquals(200, finalResponse.getCode());
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(chain, Mockito.times(3)).proceed(reqCaptor.capture(), ArgumentMatchers.same(scope));
|
||||
|
||||
final List<ClassicHttpRequest> allValues = reqCaptor.getAllValues();
|
||||
Assertions.assertNotNull(allValues);
|
||||
Assertions.assertEquals(3, allValues.size());
|
||||
final ClassicHttpRequest request1 = allValues.get(0);
|
||||
final ClassicHttpRequest request2 = allValues.get(1);
|
||||
final ClassicHttpRequest request3 = allValues.get(2);
|
||||
Assertions.assertSame(request, request1);
|
||||
Assertions.assertEquals(request1.getMethod(), "PUT");
|
||||
Assertions.assertEquals(request2.getMethod(), "GET");
|
||||
Assertions.assertEquals(request3.getMethod(), "GET");
|
||||
}
|
||||
|
||||
private static class HttpRequestMatcher implements ArgumentMatcher<ClassicHttpRequest> {
|
||||
|
||||
private final URI expectedRequestUri;
|
||||
|
|
Loading…
Reference in New Issue