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 URI redirectURI;
|
||||||
volatile int maxRedirects;
|
volatile int maxRedirects;
|
||||||
volatile int redirectCount;
|
volatile int redirectCount;
|
||||||
|
volatile HttpRequest originalRequest;
|
||||||
volatile HttpRequest currentRequest;
|
volatile HttpRequest currentRequest;
|
||||||
volatile AsyncEntityProducer currentEntityProducer;
|
volatile AsyncEntityProducer currentEntityProducer;
|
||||||
volatile RedirectLocations redirectLocations;
|
volatile RedirectLocations redirectLocations;
|
||||||
|
@ -150,7 +151,7 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
||||||
redirectBuilder = BasicRequestBuilder.get();
|
redirectBuilder = BasicRequestBuilder.get();
|
||||||
state.currentEntityProducer = null;
|
state.currentEntityProducer = null;
|
||||||
} else {
|
} else {
|
||||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HttpStatus.SC_SEE_OTHER:
|
case HttpStatus.SC_SEE_OTHER:
|
||||||
|
@ -158,15 +159,16 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
||||||
redirectBuilder = BasicRequestBuilder.get();
|
redirectBuilder = BasicRequestBuilder.get();
|
||||||
state.currentEntityProducer = null;
|
state.currentEntityProducer = null;
|
||||||
} else {
|
} else {
|
||||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
redirectBuilder = BasicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = BasicRequestBuilder.copy(state.originalRequest);
|
||||||
}
|
}
|
||||||
redirectBuilder.setUri(redirectUri);
|
redirectBuilder.setUri(redirectUri);
|
||||||
state.reroute = false;
|
state.reroute = false;
|
||||||
state.redirectURI = redirectUri;
|
state.redirectURI = redirectUri;
|
||||||
|
state.originalRequest = redirectBuilder.build();
|
||||||
state.currentRequest = redirectBuilder.build();
|
state.currentRequest = redirectBuilder.build();
|
||||||
|
|
||||||
if (!Objects.equals(currentRoute.getTargetHost(), newTarget)) {
|
if (!Objects.equals(currentRoute.getTargetHost(), newTarget)) {
|
||||||
|
@ -270,6 +272,7 @@ public final class AsyncRedirectExec implements AsyncExecChainHandler {
|
||||||
final State state = new State();
|
final State state = new State();
|
||||||
state.maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
state.maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
||||||
state.redirectCount = 0;
|
state.redirectCount = 0;
|
||||||
|
state.originalRequest = scope.originalRequest;
|
||||||
state.currentRequest = request;
|
state.currentRequest = request;
|
||||||
state.currentEntityProducer = entityProducer;
|
state.currentEntityProducer = entityProducer;
|
||||||
state.redirectLocations = redirectLocations;
|
state.redirectLocations = redirectLocations;
|
||||||
|
|
|
@ -108,6 +108,7 @@ public final class RedirectExec implements ExecChainHandler {
|
||||||
|
|
||||||
final RequestConfig config = context.getRequestConfig();
|
final RequestConfig config = context.getRequestConfig();
|
||||||
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
||||||
|
ClassicHttpRequest originalRequest = scope.originalRequest;
|
||||||
ClassicHttpRequest currentRequest = request;
|
ClassicHttpRequest currentRequest = request;
|
||||||
ExecChain.Scope currentScope = scope;
|
ExecChain.Scope currentScope = scope;
|
||||||
for (int redirectCount = 0;;) {
|
for (int redirectCount = 0;;) {
|
||||||
|
@ -153,18 +154,18 @@ public final class RedirectExec implements ExecChainHandler {
|
||||||
if (Method.POST.isSame(request.getMethod())) {
|
if (Method.POST.isSame(request.getMethod())) {
|
||||||
redirectBuilder = ClassicRequestBuilder.get();
|
redirectBuilder = ClassicRequestBuilder.get();
|
||||||
} else {
|
} else {
|
||||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HttpStatus.SC_SEE_OTHER:
|
case HttpStatus.SC_SEE_OTHER:
|
||||||
if (!Method.GET.isSame(request.getMethod()) && !Method.HEAD.isSame(request.getMethod())) {
|
if (!Method.GET.isSame(request.getMethod()) && !Method.HEAD.isSame(request.getMethod())) {
|
||||||
redirectBuilder = ClassicRequestBuilder.get();
|
redirectBuilder = ClassicRequestBuilder.get();
|
||||||
} else {
|
} else {
|
||||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
redirectBuilder = ClassicRequestBuilder.copy(scope.originalRequest);
|
redirectBuilder = ClassicRequestBuilder.copy(originalRequest);
|
||||||
}
|
}
|
||||||
redirectBuilder.setUri(redirectUri);
|
redirectBuilder.setUri(redirectUri);
|
||||||
|
|
||||||
|
@ -201,6 +202,7 @@ public final class RedirectExec implements ExecChainHandler {
|
||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug("{} redirecting to '{}' via {}", exchangeId, redirectUri, currentRoute);
|
LOG.debug("{} redirecting to '{}' via {}", exchangeId, redirectUri, currentRoute);
|
||||||
}
|
}
|
||||||
|
originalRequest = redirectBuilder.build();
|
||||||
currentRequest = redirectBuilder.build();
|
currentRequest = redirectBuilder.build();
|
||||||
RequestEntityProxy.enhance(currentRequest);
|
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.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.http.ProtocolException;
|
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.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -357,6 +359,56 @@ public class TestRedirectExec {
|
||||||
Mockito.verify(response1).close();
|
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 static class HttpRequestMatcher implements ArgumentMatcher<ClassicHttpRequest> {
|
||||||
|
|
||||||
private final URI expectedRequestUri;
|
private final URI expectedRequestUri;
|
||||||
|
|
Loading…
Reference in New Issue