HTTPCLIENT-1893: Moved HttpContext state logic out of DefaultRedirectStrategy to the redirect execution interceptors; redesigned RedirectLocations class; refactored classic redirect execution interceptor unit tests
This commit is contained in:
parent
71060c7ee1
commit
47a0eb8b65
|
@ -29,12 +29,12 @@ package org.apache.hc.client5.testing.sync;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRequestRetryHandler;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.utils.URIUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
|
@ -252,8 +252,8 @@ public class TestClientRequestExecution extends LocalServerTestBase {
|
|||
final HttpRequest request = context.getRequest();
|
||||
Assert.assertEquals("/stuff", request.getRequestUri());
|
||||
|
||||
final List<URI> redirectLocations = context.getRedirectLocations();
|
||||
final URI location = URIUtils.resolve(uri, target, redirectLocations);
|
||||
final RedirectLocations redirectLocations = context.getRedirectLocations();
|
||||
final URI location = URIUtils.resolve(uri, target, redirectLocations.getAll());
|
||||
Assert.assertEquals(uri, location);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.CircularRedirectException;
|
||||
import org.apache.hc.client5.http.ClientProtocolException;
|
||||
|
@ -42,6 +41,7 @@ import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
|||
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||
import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.utils.URIUtils;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
|
@ -282,8 +282,9 @@ public class TestRedirects extends LocalServerTestBase {
|
|||
Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode());
|
||||
Assert.assertEquals(URIUtils.create(target, "/oldlocation/"), reqWrapper.getUri());
|
||||
|
||||
final List<URI> redirects = context.getRedirectLocations();
|
||||
Assert.assertNull(redirects);
|
||||
final RedirectLocations redirects = context.getRedirectLocations();
|
||||
Assert.assertNotNull(redirects);
|
||||
Assert.assertEquals(0, redirects.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -304,7 +305,7 @@ public class TestRedirects extends LocalServerTestBase {
|
|||
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
|
||||
Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri());
|
||||
|
||||
final List<URI> redirects = context.getRedirectLocations();
|
||||
final RedirectLocations redirects = context.getRedirectLocations();
|
||||
Assert.assertNotNull(redirects);
|
||||
Assert.assertEquals(1, redirects.size());
|
||||
|
||||
|
|
|
@ -30,13 +30,7 @@ package org.apache.hc.client5.http.impl;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.hc.client5.http.CircularRedirectException;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.protocol.RedirectStrategy;
|
||||
import org.apache.hc.client5.http.utils.URIUtils;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
|
@ -52,8 +46,6 @@ import org.apache.hc.core5.http.protocol.HttpContext;
|
|||
import org.apache.hc.core5.net.URIBuilder;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.hc.core5.util.TextUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RedirectStrategy}. This strategy honors the restrictions
|
||||
|
@ -64,27 +56,11 @@ import org.apache.logging.log4j.Logger;
|
|||
*
|
||||
* @since 4.1
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
||||
@Contract(threading = ThreadingBehavior.STATELESS)
|
||||
public class DefaultRedirectStrategy implements RedirectStrategy {
|
||||
|
||||
private final Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
public static final DefaultRedirectStrategy INSTANCE = new DefaultRedirectStrategy();
|
||||
|
||||
private final ConcurrentMap<String, Boolean> safeMethods;
|
||||
|
||||
public DefaultRedirectStrategy(final String... safeMethods) {
|
||||
super();
|
||||
this.safeMethods = new ConcurrentHashMap<>();
|
||||
for (final String safeMethod: safeMethods) {
|
||||
this.safeMethods.put(safeMethod.toUpperCase(Locale.ROOT), Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultRedirectStrategy() {
|
||||
this("GET", "HEAD", "OPTIONS", "TRACE");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedirected(
|
||||
final HttpRequest request,
|
||||
|
@ -117,20 +93,12 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
|
|||
Args.notNull(response, "HTTP response");
|
||||
Args.notNull(context, "HTTP context");
|
||||
|
||||
final HttpClientContext clientContext = HttpClientContext.adapt(context);
|
||||
|
||||
//get the location header to find out where to redirect to
|
||||
final Header locationHeader = response.getFirstHeader("location");
|
||||
if (locationHeader == null) {
|
||||
throw new HttpException("Redirect location is missing");
|
||||
}
|
||||
final String location = locationHeader.getValue();
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Redirect requested to location '" + location + "'");
|
||||
}
|
||||
|
||||
final RequestConfig config = clientContext.getRequestConfig();
|
||||
|
||||
URI uri = createLocationURI(location);
|
||||
try {
|
||||
if (!uri.isAbsolute()) {
|
||||
|
@ -141,18 +109,6 @@ public class DefaultRedirectStrategy implements RedirectStrategy {
|
|||
throw new ProtocolException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
RedirectLocations redirectLocations = (RedirectLocations) clientContext.getAttribute(
|
||||
HttpClientContext.REDIRECT_LOCATIONS);
|
||||
if (redirectLocations == null) {
|
||||
redirectLocations = new RedirectLocations();
|
||||
context.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
|
||||
}
|
||||
if (!config.isCircularRedirectsAllowed()) {
|
||||
if (redirectLocations.contains(uri)) {
|
||||
throw new CircularRedirectException("Circular redirect to '" + uri + "'");
|
||||
}
|
||||
}
|
||||
redirectLocations.add(uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@ package org.apache.hc.client5.http.impl.async;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.CircularRedirectException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.RedirectException;
|
||||
import org.apache.hc.client5.http.StandardMethods;
|
||||
|
@ -40,6 +40,7 @@ import org.apache.hc.client5.http.auth.AuthExchange;
|
|||
import org.apache.hc.client5.http.auth.AuthScheme;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.protocol.RedirectStrategy;
|
||||
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
||||
import org.apache.hc.client5.http.utils.URIUtils;
|
||||
|
@ -53,6 +54,7 @@ import org.apache.hc.core5.http.ProtocolException;
|
|||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||
import org.apache.hc.core5.http.nio.AsyncDataConsumer;
|
||||
import org.apache.hc.core5.http.nio.AsyncEntityProducer;
|
||||
import org.apache.hc.core5.util.LangUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
@ -75,6 +77,7 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
volatile int redirectCount;
|
||||
volatile HttpRequest currentRequest;
|
||||
volatile AsyncEntityProducer currentEntityProducer;
|
||||
volatile RedirectLocations redirectLocations;
|
||||
volatile AsyncExecChain.Scope currentScope;
|
||||
volatile boolean reroute;
|
||||
|
||||
|
@ -107,6 +110,16 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
state.redirectCount++;
|
||||
|
||||
final URI redirectUri = redirectStrategy.getLocationURI(request, response, clientContext);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Redirect requested to location '" + redirectUri + "'");
|
||||
}
|
||||
if (!config.isCircularRedirectsAllowed()) {
|
||||
if (state.redirectLocations.contains(redirectUri)) {
|
||||
throw new CircularRedirectException("Circular redirect to '" + redirectUri + "'");
|
||||
}
|
||||
}
|
||||
state.redirectLocations.add(redirectUri);
|
||||
|
||||
final int statusCode = response.getCode();
|
||||
|
||||
switch (statusCode) {
|
||||
|
@ -128,27 +141,27 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
throw new ProtocolException("Redirect URI does not specify a valid host name: " + redirectUri);
|
||||
}
|
||||
|
||||
if (!currentRoute.getTargetHost().equals(newTarget)) {
|
||||
log.debug("New route required");
|
||||
state.reroute = true;
|
||||
final AuthExchange targetAuthExchange = clientContext.getAuthExchange(currentRoute.getTargetHost());
|
||||
log.debug("Resetting target auth state");
|
||||
targetAuthExchange.reset();
|
||||
if (currentRoute.getProxyHost() != null) {
|
||||
final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
|
||||
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
|
||||
if (authScheme != null && authScheme.isConnectionBased()) {
|
||||
log.debug("Resetting proxy auth state");
|
||||
proxyAuthExchange.reset();
|
||||
}
|
||||
}
|
||||
state.reroute = false;
|
||||
state.redirectURI = redirectUri;
|
||||
|
||||
if (!LangUtils.equals(currentRoute.getTargetHost(), newTarget)) {
|
||||
final HttpRoute newRoute = routePlanner.determineRoute(newTarget, clientContext);
|
||||
state.currentScope = new AsyncExecChain.Scope(scope.exchangeId, newRoute,
|
||||
scope.originalRequest, scope.future, clientContext, scope.execRuntime);
|
||||
state.redirectURI = redirectUri;
|
||||
} else {
|
||||
state.reroute = false;
|
||||
state.redirectURI = redirectUri;
|
||||
if (!LangUtils.equals(currentRoute, newRoute)) {
|
||||
state.reroute = true;
|
||||
final AuthExchange targetAuthExchange = clientContext.getAuthExchange(currentRoute.getTargetHost());
|
||||
log.debug("Resetting target auth state");
|
||||
targetAuthExchange.reset();
|
||||
if (currentRoute.getProxyHost() != null) {
|
||||
final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
|
||||
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
|
||||
if (authScheme != null && authScheme.isConnectionBased()) {
|
||||
log.debug("Resetting proxy auth state");
|
||||
proxyAuthExchange.reset();
|
||||
}
|
||||
}
|
||||
state.currentScope = new AsyncExecChain.Scope(scope.exchangeId, newRoute,
|
||||
scope.originalRequest, scope.future, clientContext, scope.execRuntime);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.redirectURI != null) {
|
||||
|
@ -200,10 +213,13 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
final AsyncExecChain chain,
|
||||
final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
|
||||
final HttpClientContext clientContext = scope.clientContext;
|
||||
final List<URI> redirectLocations = clientContext.getRedirectLocations();
|
||||
if (redirectLocations != null) {
|
||||
redirectLocations.clear();
|
||||
RedirectLocations redirectLocations = clientContext.getRedirectLocations();
|
||||
if (redirectLocations == null) {
|
||||
redirectLocations = new RedirectLocations();
|
||||
clientContext.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
|
||||
}
|
||||
redirectLocations.clear();
|
||||
|
||||
final RequestConfig config = clientContext.getRequestConfig();
|
||||
|
||||
final State state = new State();
|
||||
|
@ -211,6 +227,7 @@ class AsyncRedirectExec implements AsyncExecChainHandler {
|
|||
state.redirectCount = 0;
|
||||
state.currentRequest = request;
|
||||
state.currentEntityProducer = entityProducer;
|
||||
state.redirectLocations = redirectLocations;
|
||||
state.currentScope = scope;
|
||||
|
||||
internalExecute(state, chain, asyncExecCallback);
|
||||
|
|
|
@ -29,8 +29,8 @@ package org.apache.hc.client5.http.impl.classic;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.CircularRedirectException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.RedirectException;
|
||||
import org.apache.hc.client5.http.StandardMethods;
|
||||
|
@ -42,6 +42,7 @@ import org.apache.hc.client5.http.classic.methods.HttpGet;
|
|||
import org.apache.hc.client5.http.classic.methods.RequestBuilder;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.protocol.RedirectStrategy;
|
||||
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
||||
import org.apache.hc.client5.http.utils.URIUtils;
|
||||
|
@ -56,6 +57,7 @@ import org.apache.hc.core5.http.HttpStatus;
|
|||
import org.apache.hc.core5.http.ProtocolException;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.hc.core5.util.LangUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
@ -97,11 +99,12 @@ final class RedirectExec implements ExecChainHandler {
|
|||
Args.notNull(scope, "Scope");
|
||||
|
||||
final HttpClientContext context = scope.clientContext;
|
||||
|
||||
final List<URI> redirectLocations = context.getRedirectLocations();
|
||||
if (redirectLocations != null) {
|
||||
redirectLocations.clear();
|
||||
RedirectLocations redirectLocations = context.getRedirectLocations();
|
||||
if (redirectLocations == null) {
|
||||
redirectLocations = new RedirectLocations();
|
||||
context.setAttribute(HttpClientContext.REDIRECT_LOCATIONS, redirectLocations);
|
||||
}
|
||||
redirectLocations.clear();
|
||||
|
||||
final RequestConfig config = context.getRequestConfig();
|
||||
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
|
||||
|
@ -122,6 +125,16 @@ final class RedirectExec implements ExecChainHandler {
|
|||
redirectCount++;
|
||||
|
||||
final URI redirectUri = this.redirectStrategy.getLocationURI(currentRequest, response, context);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Redirect requested to location '" + redirectUri + "'");
|
||||
}
|
||||
if (!config.isCircularRedirectsAllowed()) {
|
||||
if (redirectLocations.contains(redirectUri)) {
|
||||
throw new CircularRedirectException("Circular redirect to '" + redirectUri + "'");
|
||||
}
|
||||
}
|
||||
redirectLocations.add(redirectUri);
|
||||
|
||||
final ClassicHttpRequest originalRequest = scope.originalRequest;
|
||||
ClassicHttpRequest redirect = null;
|
||||
final int statusCode = response.getCode();
|
||||
|
@ -147,28 +160,29 @@ final class RedirectExec implements ExecChainHandler {
|
|||
redirectUri);
|
||||
}
|
||||
|
||||
HttpRoute currentRoute = currentScope.route;
|
||||
final boolean crossSiteRedirect = !currentRoute.getTargetHost().equals(newTarget);
|
||||
if (crossSiteRedirect) {
|
||||
|
||||
final AuthExchange targetAuthExchange = context.getAuthExchange(currentRoute.getTargetHost());
|
||||
this.log.debug("Resetting target auth state");
|
||||
targetAuthExchange.reset();
|
||||
if (currentRoute.getProxyHost() != null) {
|
||||
final AuthExchange proxyAuthExchange = context.getAuthExchange(currentRoute.getProxyHost());
|
||||
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
|
||||
if (authScheme != null && authScheme.isConnectionBased()) {
|
||||
this.log.debug("Resetting proxy auth state");
|
||||
proxyAuthExchange.reset();
|
||||
final HttpRoute currentRoute = currentScope.route;
|
||||
if (!LangUtils.equals(currentRoute.getTargetHost(), newTarget)) {
|
||||
final HttpRoute newRoute = this.routePlanner.determineRoute(newTarget, context);
|
||||
if (!LangUtils.equals(currentRoute, newRoute)) {
|
||||
log.debug("New route required");
|
||||
final AuthExchange targetAuthExchange = context.getAuthExchange(currentRoute.getTargetHost());
|
||||
this.log.debug("Resetting target auth state");
|
||||
targetAuthExchange.reset();
|
||||
if (currentRoute.getProxyHost() != null) {
|
||||
final AuthExchange proxyAuthExchange = context.getAuthExchange(currentRoute.getProxyHost());
|
||||
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
|
||||
if (authScheme != null && authScheme.isConnectionBased()) {
|
||||
this.log.debug("Resetting proxy auth state");
|
||||
proxyAuthExchange.reset();
|
||||
}
|
||||
}
|
||||
currentScope = new ExecChain.Scope(
|
||||
currentScope.exchangeId,
|
||||
newRoute,
|
||||
currentScope.originalRequest,
|
||||
currentScope.execRuntime,
|
||||
currentScope.clientContext);
|
||||
}
|
||||
currentRoute = this.routePlanner.determineRoute(newTarget, context);
|
||||
currentScope = new ExecChain.Scope(
|
||||
currentScope.exchangeId,
|
||||
currentRoute,
|
||||
currentScope.originalRequest,
|
||||
currentScope.execRuntime,
|
||||
currentScope.clientContext);
|
||||
}
|
||||
|
||||
if (this.log.isDebugEnabled()) {
|
||||
|
|
|
@ -27,9 +27,7 @@
|
|||
|
||||
package org.apache.hc.client5.http.protocol;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
|
@ -67,7 +65,7 @@ public class HttpClientContext extends HttpCoreContext {
|
|||
public static final String HTTP_ROUTE = "http.route";
|
||||
|
||||
/**
|
||||
* Attribute name of a {@link List} object that represents a collection of all
|
||||
* Attribute name of a {@link RedirectLocations} object that represents a collection of all
|
||||
* redirect locations received in the process of request execution.
|
||||
*/
|
||||
public static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";
|
||||
|
@ -156,9 +154,8 @@ public class HttpClientContext extends HttpCoreContext {
|
|||
return getAttribute(HTTP_ROUTE, HttpRoute.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<URI> getRedirectLocations() {
|
||||
return getAttribute(REDIRECT_LOCATIONS, List.class);
|
||||
public RedirectLocations getRedirectLocations() {
|
||||
return getAttribute(REDIRECT_LOCATIONS, RedirectLocations.class);
|
||||
}
|
||||
|
||||
public CookieStore getCookieStore() {
|
||||
|
|
|
@ -28,10 +28,8 @@
|
|||
package org.apache.hc.client5.http.protocol;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -41,7 +39,7 @@ import java.util.Set;
|
|||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class RedirectLocations extends AbstractList<Object> {
|
||||
public final class RedirectLocations {
|
||||
|
||||
private final Set<URI> unique;
|
||||
private final List<URI> all;
|
||||
|
@ -67,23 +65,6 @@ public class RedirectLocations extends AbstractList<Object> {
|
|||
this.all.add(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a URI from the collection.
|
||||
*/
|
||||
public boolean remove(final URI uri) {
|
||||
final boolean removed = this.unique.remove(uri);
|
||||
if (removed) {
|
||||
final Iterator<URI> it = this.all.iterator();
|
||||
while (it.hasNext()) {
|
||||
final URI current = it.next();
|
||||
if (current.equals(uri)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all redirect {@link URI}s in the order they were added to the collection.
|
||||
*
|
||||
|
@ -106,7 +87,6 @@ public class RedirectLocations extends AbstractList<Object> {
|
|||
* {@code index < 0 || index >= size()})
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public URI get(final int index) {
|
||||
return this.all.get(index);
|
||||
}
|
||||
|
@ -119,106 +99,13 @@ public class RedirectLocations extends AbstractList<Object> {
|
|||
* @return the number of elements in this list
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return this.all.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the URI at the specified position in this list with the
|
||||
* specified element (must be a URI).
|
||||
*
|
||||
* @param index
|
||||
* index of the element to replace
|
||||
* @param element
|
||||
* URI to be stored at the specified position
|
||||
* @return the URI previously at the specified position
|
||||
* @throws UnsupportedOperationException
|
||||
* if the {@code set} operation is not supported by this list
|
||||
* @throws ClassCastException
|
||||
* if the element is not a {@link URI}
|
||||
* @throws NullPointerException
|
||||
* if the specified element is null and this list does not
|
||||
* permit null elements
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the index is out of range (
|
||||
* {@code index < 0 || index >= size()})
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public Object set(final int index, final Object element) {
|
||||
final URI removed = this.all.set(index, (URI) element);
|
||||
this.unique.remove(removed);
|
||||
this.unique.add((URI) element);
|
||||
if (this.all.size() != this.unique.size()) {
|
||||
this.unique.addAll(this.all);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the specified position in this list
|
||||
* (must be a URI). Shifts the URI currently at that position (if any) and
|
||||
* any subsequent URIs to the right (adds one to their indices).
|
||||
*
|
||||
* @param index
|
||||
* index at which the specified element is to be inserted
|
||||
* @param element
|
||||
* URI to be inserted
|
||||
* @throws UnsupportedOperationException
|
||||
* if the {@code add} operation is not supported by this list
|
||||
* @throws ClassCastException
|
||||
* if the element is not a {@link URI}
|
||||
* @throws NullPointerException
|
||||
* if the specified element is null and this list does not
|
||||
* permit null elements
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the index is out of range (
|
||||
* {@code index < 0 || index > size()})
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public void add(final int index, final Object element) {
|
||||
this.all.add(index, (URI) element);
|
||||
this.unique.add((URI) element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the URI at the specified position in this list. Shifts any
|
||||
* subsequent URIs to the left (subtracts one from their indices). Returns
|
||||
* the URI that was removed from the list.
|
||||
*
|
||||
* @param index
|
||||
* the index of the URI to be removed
|
||||
* @return the URI previously at the specified position
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the index is out of range (
|
||||
* {@code index < 0 || index >= size()})
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public URI remove(final int index) {
|
||||
final URI removed = this.all.remove(index);
|
||||
this.unique.remove(removed);
|
||||
if (this.all.size() != this.unique.size()) {
|
||||
this.unique.addAll(this.all);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this collection contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this collection
|
||||
* contains at least one element {@code e} such that
|
||||
* {@code (o==null ? e==null : o.equals(e))}.
|
||||
*
|
||||
* @param o element whose presence in this collection is to be tested
|
||||
* @return {@code true} if this collection contains the specified
|
||||
* element
|
||||
*/
|
||||
@Override
|
||||
public boolean contains(final Object o) {
|
||||
return this.unique.contains(o);
|
||||
public void clear() {
|
||||
unique.clear();
|
||||
all.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@
|
|||
package org.apache.hc.client5.http.impl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
|
@ -200,53 +198,6 @@ public class TestDefaultRedirectStrategy {
|
|||
Assert.assertEquals(URI.create("http://localhost/morestuff"), uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLocationUriAllowCircularRedirects() throws Exception {
|
||||
final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final RequestConfig config = RequestConfig.custom().setCircularRedirectsAllowed(true).build();
|
||||
context.setRequestConfig(config);
|
||||
final URI uri1 = URI.create("http://localhost/stuff1");
|
||||
final URI uri2 = URI.create("http://localhost/stuff2");
|
||||
final URI uri3 = URI.create("http://localhost/stuff3");
|
||||
final HttpGet httpget1 = new HttpGet("http://localhost/");
|
||||
final HttpResponse response1 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
|
||||
response1.addHeader("Location", uri1.toASCIIString());
|
||||
final HttpGet httpget2 = new HttpGet(uri1.toASCIIString());
|
||||
final HttpResponse response2 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
|
||||
response2.addHeader("Location", uri2.toASCIIString());
|
||||
final HttpGet httpget3 = new HttpGet(uri2.toASCIIString());
|
||||
final HttpResponse response3 = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
|
||||
response3.addHeader("Location", uri3.toASCIIString());
|
||||
Assert.assertEquals(uri1, redirectStrategy.getLocationURI(httpget1, response1, context));
|
||||
Assert.assertEquals(uri2, redirectStrategy.getLocationURI(httpget2, response2, context));
|
||||
Assert.assertEquals(uri3, redirectStrategy.getLocationURI(httpget3, response3, context));
|
||||
|
||||
final List<URI> uris = context.getRedirectLocations();
|
||||
Assert.assertNotNull(uris);
|
||||
Assert.assertTrue(uris.contains(uri1));
|
||||
Assert.assertTrue(uris.contains(uri2));
|
||||
Assert.assertTrue(uris.contains(uri3));
|
||||
Assert.assertEquals(3, uris.size());
|
||||
Assert.assertEquals(uri1, uris.get(0));
|
||||
Assert.assertEquals(uri2, uris.get(1));
|
||||
Assert.assertEquals(uri3, uris.get(2));
|
||||
}
|
||||
|
||||
@Test(expected=ProtocolException.class)
|
||||
public void testGetLocationUriDisallowCircularRedirects() throws Exception {
|
||||
final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final HttpGet httpget = new HttpGet("http://localhost/stuff");
|
||||
final RequestConfig config = RequestConfig.custom().setCircularRedirectsAllowed(false).build();
|
||||
context.setRequestConfig(config);
|
||||
final HttpResponse response = new BasicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY, "Redirect");
|
||||
response.addHeader("Location", "http://localhost/stuff");
|
||||
final URI uri = URI.create("http://localhost/stuff");
|
||||
Assert.assertEquals(uri, redirectStrategy.getLocationURI(httpget, response, context));
|
||||
redirectStrategy.getLocationURI(httpget, response, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLocationUriInvalidInput() throws Exception {
|
||||
final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
|
|
@ -30,8 +30,10 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.hc.client5.http.CircularRedirectException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.RedirectException;
|
||||
import org.apache.hc.client5.http.auth.AuthExchange;
|
||||
|
@ -40,48 +42,52 @@ import org.apache.hc.client5.http.classic.ExecRuntime;
|
|||
import org.apache.hc.client5.http.classic.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
|
||||
import org.apache.hc.client5.http.impl.auth.BasicScheme;
|
||||
import org.apache.hc.client5.http.impl.auth.NTLMScheme;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||
import org.apache.hc.client5.http.protocol.RedirectStrategy;
|
||||
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHeaders;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.ProtocolException;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@SuppressWarnings({"boxing","static-access"}) // test code
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TestRedirectExec {
|
||||
|
||||
@Mock
|
||||
private HttpRoutePlanner httpRoutePlanner;
|
||||
@Mock
|
||||
private RedirectStrategy redirectStrategy;
|
||||
@Mock
|
||||
private ExecChain chain;
|
||||
@Mock
|
||||
private ExecRuntime endpoint;
|
||||
|
||||
private RedirectStrategy redirectStrategy;
|
||||
private RedirectExec redirectExec;
|
||||
private HttpHost target;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
redirectExec = new RedirectExec(httpRoutePlanner, redirectStrategy);
|
||||
target = new HttpHost("localhost", 80);
|
||||
redirectStrategy = Mockito.spy(new DefaultRedirectStrategy());
|
||||
redirectExec = new RedirectExec(httpRoutePlanner, redirectStrategy);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -90,19 +96,20 @@ public class TestRedirectExec {
|
|||
final HttpGet request = new HttpGet("/test");
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("http://localhost:80/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
|
||||
final HttpEntity entity1 = EntityBuilder.create()
|
||||
.setStream(instream1)
|
||||
.build();
|
||||
Mockito.when(response1.getEntity()).thenReturn(entity1);
|
||||
final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
|
||||
response1.setEntity(entity1);
|
||||
final ClassicHttpResponse response2 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_OK));
|
||||
final InputStream instream2 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
|
||||
final HttpEntity entity2 = EntityBuilder.create()
|
||||
.setStream(instream2)
|
||||
.build();
|
||||
Mockito.when(response2.getEntity()).thenReturn(entity2);
|
||||
final URI redirect = new URI("http://localhost:80/redirect");
|
||||
response2.setEntity(entity2);
|
||||
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.same(request),
|
||||
|
@ -110,26 +117,12 @@ public class TestRedirectExec {
|
|||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(redirect),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(redirectStrategy.getLocationURI(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
redirectExec.execute(request, scope, chain);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(
|
||||
ClassicHttpRequest.class);
|
||||
Mockito.verify(chain, Mockito.times(2)).proceed(
|
||||
reqCaptor.capture(),
|
||||
Mockito.same(scope));
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(chain, Mockito.times(2)).proceed(reqCaptor.capture(), Mockito.same(scope));
|
||||
|
||||
final List<ClassicHttpRequest> allValues = reqCaptor.getAllValues();
|
||||
Assert.assertNotNull(allValues);
|
||||
|
@ -137,7 +130,7 @@ public class TestRedirectExec {
|
|||
Assert.assertSame(request, allValues.get(0));
|
||||
|
||||
Mockito.verify(response1, Mockito.times(1)).close();
|
||||
Mockito.verify(instream1, Mockito.times(1)).close();
|
||||
Mockito.verify(instream1, Mockito.times(2)).close();
|
||||
Mockito.verify(response2, Mockito.never()).close();
|
||||
Mockito.verify(instream2, Mockito.never()).close();
|
||||
}
|
||||
|
@ -153,23 +146,11 @@ public class TestRedirectExec {
|
|||
.build();
|
||||
context.setRequestConfig(config);
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("http://localhost:80/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(redirectStrategy.getLocationURI(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
Mockito.when(chain.proceed(Mockito.<ClassicHttpRequest>any(), Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
redirectExec.execute(request, scope, chain);
|
||||
|
@ -181,26 +162,12 @@ public class TestRedirectExec {
|
|||
final HttpGet request = new HttpGet("/test");
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.same(request),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(redirect),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(redirectStrategy.getLocationURI(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
redirectExec.execute(request, scope, chain);
|
||||
|
@ -223,27 +190,17 @@ public class TestRedirectExec {
|
|||
context.setAuthExchange(target, targetAuthExchange);
|
||||
context.setAuthExchange(proxy, proxyAuthExchange);
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response2 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final HttpHost otherHost = new HttpHost("otherhost", 8888);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("http://otherhost:8888/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
final ClassicHttpResponse response2 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_OK));
|
||||
final HttpHost otherHost = new HttpHost("otherhost", 8888);
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.same(request),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(redirect),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(redirectStrategy.getLocationURI(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(target));
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(otherHost),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(otherHost));
|
||||
|
@ -261,24 +218,101 @@ public class TestRedirectExec {
|
|||
Assert.assertEquals(null, authExchange2.getAuthScheme());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowCircularRedirects() throws Exception {
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
context.setRequestConfig(RequestConfig.custom()
|
||||
.setCircularRedirectsAllowed(true)
|
||||
.build());
|
||||
|
||||
final URI uri = URI.create("http://localhost/");
|
||||
final HttpGet request = new HttpGet(uri);
|
||||
|
||||
final URI uri1 = URI.create("http://localhost/stuff1");
|
||||
final URI uri2 = URI.create("http://localhost/stuff2");
|
||||
final ClassicHttpResponse response1 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response1.addHeader("Location", uri1.toASCIIString());
|
||||
final ClassicHttpResponse response2 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response2.addHeader("Location", uri2.toASCIIString());
|
||||
final ClassicHttpResponse response3 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response3.addHeader("Location", uri1.toASCIIString());
|
||||
final ClassicHttpResponse response4 = new BasicClassicHttpResponse(HttpStatus.SC_OK);
|
||||
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri1),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response2, response4);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri2),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response3);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("localhost")),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
redirectExec.execute(request, scope, chain);
|
||||
|
||||
final RedirectLocations uris = context.getRedirectLocations();
|
||||
Assert.assertNotNull(uris);
|
||||
Assert.assertEquals(Arrays.asList(uri1, uri2, uri1), uris.getAll());
|
||||
}
|
||||
|
||||
@Test(expected=CircularRedirectException.class)
|
||||
public void testGetLocationUriDisallowCircularRedirects() throws Exception {
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
context.setRequestConfig(RequestConfig.custom()
|
||||
.setCircularRedirectsAllowed(false)
|
||||
.build());
|
||||
|
||||
final URI uri = URI.create("http://localhost/");
|
||||
final HttpGet request = new HttpGet(uri);
|
||||
|
||||
final URI uri1 = URI.create("http://localhost/stuff1");
|
||||
final URI uri2 = URI.create("http://localhost/stuff2");
|
||||
final ClassicHttpResponse response1 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response1.addHeader("Location", uri1.toASCIIString());
|
||||
final ClassicHttpResponse response2 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response2.addHeader("Location", uri2.toASCIIString());
|
||||
final ClassicHttpResponse response3 = new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY);
|
||||
response3.addHeader("Location", uri1.toASCIIString());
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("localhost")),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri1),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response2);
|
||||
Mockito.when(chain.proceed(
|
||||
HttpRequestMatcher.matchesRequestUri(uri2),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response3);
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
redirectExec.execute(request, scope, chain);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testRedirectRuntimeException() throws Exception {
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
final HttpGet request = new HttpGet("/test");
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("http://localhost:80/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.same(request),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.doThrow(new RuntimeException("Oppsie")).when(redirectStrategy.getLocationURI(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any()));
|
||||
Mockito.doThrow(new RuntimeException("Oppsie")).when(redirectStrategy).getLocationURI(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<ClassicHttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any());
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
try {
|
||||
|
@ -295,29 +329,27 @@ public class TestRedirectExec {
|
|||
final HttpGet request = new HttpGet("/test");
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
||||
final ClassicHttpResponse response1 = Mockito.mock(ClassicHttpResponse.class);
|
||||
final ClassicHttpResponse response1 = Mockito.spy(new BasicClassicHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY));
|
||||
final URI redirect = new URI("http://localhost:80/redirect");
|
||||
response1.setHeader(HttpHeaders.LOCATION, redirect.toASCIIString());
|
||||
final InputStream instream1 = Mockito.spy(new ByteArrayInputStream(new byte[] {1, 2, 3}));
|
||||
final HttpEntity entity1 = EntityBuilder.create()
|
||||
.setStream(instream1)
|
||||
.build();
|
||||
Mockito.when(response1.getEntity()).thenReturn(entity1);
|
||||
response1.setEntity(entity1);
|
||||
Mockito.when(chain.proceed(
|
||||
Mockito.same(request),
|
||||
Mockito.<ExecChain.Scope>any())).thenReturn(response1);
|
||||
Mockito.when(redirectStrategy.isRedirected(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.doThrow(new ProtocolException("Oppsie")).when(redirectStrategy).getLocationURI(
|
||||
Mockito.same(request),
|
||||
Mockito.same(response1),
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<ClassicHttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any());
|
||||
|
||||
final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
|
||||
try {
|
||||
redirectExec.execute(request, scope, chain);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(instream1).close();
|
||||
Mockito.verify(instream1, Mockito.times(2)).close();
|
||||
Mockito.verify(response1).close();
|
||||
throw ex;
|
||||
}
|
||||
|
@ -325,17 +357,21 @@ public class TestRedirectExec {
|
|||
|
||||
private static class HttpRequestMatcher implements ArgumentMatcher<ClassicHttpRequest> {
|
||||
|
||||
private final URI requestUri;
|
||||
private final URI expectedRequestUri;
|
||||
|
||||
HttpRequestMatcher(final URI requestUri) {
|
||||
super();
|
||||
this.requestUri = requestUri;
|
||||
this.expectedRequestUri = requestUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(final ClassicHttpRequest argument) {
|
||||
if (argument == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return requestUri.equals(argument.getUri());
|
||||
final URI requestUri = argument.getUri();
|
||||
return this.expectedRequestUri.equals(requestUri);
|
||||
} catch (final URISyntaxException ex) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public class TestRedirectLocation {
|
|||
Assert.assertTrue(locations.contains(uri3));
|
||||
Assert.assertFalse(locations.contains(new URI("/")));
|
||||
|
||||
List<URI> list = locations.getAll();
|
||||
final List<URI> list = locations.getAll();
|
||||
Assert.assertNotNull(list);
|
||||
Assert.assertEquals(5, list.size());
|
||||
Assert.assertEquals(uri1, list.get(0));
|
||||
|
@ -64,16 +64,6 @@ public class TestRedirectLocation {
|
|||
Assert.assertEquals(uri2, list.get(2));
|
||||
Assert.assertEquals(uri3, list.get(3));
|
||||
Assert.assertEquals(uri3, list.get(4));
|
||||
|
||||
Assert.assertTrue(locations.remove(uri3));
|
||||
Assert.assertTrue(locations.remove(uri1));
|
||||
Assert.assertFalse(locations.remove(new URI("/")));
|
||||
|
||||
list = locations.getAll();
|
||||
Assert.assertNotNull(list);
|
||||
Assert.assertEquals(2, list.size());
|
||||
Assert.assertEquals(uri2, list.get(0));
|
||||
Assert.assertEquals(uri2, list.get(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue