diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/RedirectingAsyncDecorator.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/RedirectingAsyncDecorator.java new file mode 100644 index 000000000..9fe15b506 --- /dev/null +++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/async/RedirectingAsyncDecorator.java @@ -0,0 +1,158 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.client5.testing.redirect.RedirectResolver; +import org.apache.hc.core5.http.EntityDetails; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HeaderElements; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.HttpResponse; +import org.apache.hc.core5.http.ProtocolException; +import org.apache.hc.core5.http.message.BasicHeader; +import org.apache.hc.core5.http.message.BasicHttpResponse; +import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; +import org.apache.hc.core5.http.nio.CapacityChannel; +import org.apache.hc.core5.http.nio.DataStreamChannel; +import org.apache.hc.core5.http.nio.ResponseChannel; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.Args; + +public class RedirectingAsyncDecorator implements AsyncServerExchangeHandler { + + private final AsyncServerExchangeHandler exchangeHandler; + private final RedirectResolver redirectResolver; + private final AtomicBoolean redirecting; + + public RedirectingAsyncDecorator(final AsyncServerExchangeHandler exchangeHandler, + final RedirectResolver redirectResolver) { + this.exchangeHandler = Args.notNull(exchangeHandler, "Exchange handler"); + this.redirectResolver = redirectResolver; + this.redirecting = new AtomicBoolean(); + } + + private Redirect resolveRedirect(final HttpRequest request) throws HttpException { + try { + final URI requestURI = request.getUri(); + return redirectResolver != null ? redirectResolver.resolve(requestURI) : null; + } catch (final URISyntaxException ex) { + throw new ProtocolException(ex.getMessage(), ex); + } + } + + private HttpResponse createRedirectResponse(final Redirect redirect) { + final HttpResponse response = new BasicHttpResponse(redirect.status); + if (redirect.location != null) { + response.addHeader(new BasicHeader(HttpHeaders.LOCATION, redirect.location)); + } + switch (redirect.connControl) { + case KEEP_ALIVE: + response.addHeader(new BasicHeader(HttpHeaders.CONNECTION, HeaderElements.KEEP_ALIVE)); + break; + case CLOSE: + response.addHeader(new BasicHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE)); + } + return response; + } + + @Override + public void handleRequest(final HttpRequest request, + final EntityDetails entityDetails, + final ResponseChannel responseChannel, + final HttpContext context) throws HttpException, IOException { + final Redirect redirect = resolveRedirect(request); + if (redirect != null) { + responseChannel.sendResponse(createRedirectResponse(redirect), null, context); + redirecting.set(true); + } else { + exchangeHandler.handleRequest(request, entityDetails, responseChannel, context); + } + } + + @Override + public final void updateCapacity(final CapacityChannel capacityChannel) throws IOException { + if (!redirecting.get()) { + exchangeHandler.updateCapacity(capacityChannel); + } else { + capacityChannel.update(Integer.MAX_VALUE); + } + } + + @Override + public final void consume(final ByteBuffer src) throws IOException { + if (!redirecting.get()) { + exchangeHandler.consume(src); + } + } + + @Override + public final void streamEnd(final List trailers) throws HttpException, IOException { + if (!redirecting.get()) { + exchangeHandler.streamEnd(trailers); + } + } + + @Override + public int available() { + if (!redirecting.get()) { + return exchangeHandler.available(); + } else { + return 0; + } + } + + @Override + public void produce(final DataStreamChannel channel) throws IOException { + if (!redirecting.get()) { + exchangeHandler.produce(channel); + } + } + + @Override + public void failed(final Exception cause) { + if (!redirecting.get()) { + exchangeHandler.failed(cause); + } + } + + @Override + public void releaseResources() { + exchangeHandler.releaseResources(); + } + +} diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/RedirectingDecorator.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/RedirectingDecorator.java new file mode 100644 index 000000000..37160a752 --- /dev/null +++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/classic/RedirectingDecorator.java @@ -0,0 +1,86 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.classic; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.client5.testing.redirect.RedirectResolver; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HeaderElements; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.ProtocolException; +import org.apache.hc.core5.http.io.HttpServerRequestHandler; +import org.apache.hc.core5.http.message.BasicClassicHttpResponse; +import org.apache.hc.core5.http.message.BasicHeader; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.util.Args; + +public class RedirectingDecorator implements HttpServerRequestHandler { + + private final HttpServerRequestHandler requestHandler; + private final RedirectResolver redirectResolver; + + public RedirectingDecorator(final HttpServerRequestHandler requestHandler, + final RedirectResolver redirectResolver) { + this.requestHandler = Args.notNull(requestHandler, "Request handler"); + this.redirectResolver = redirectResolver; + } + + @Override + public void handle(final ClassicHttpRequest request, + final ResponseTrigger responseTrigger, + final HttpContext context) throws HttpException, IOException { + try { + final URI requestURI = request.getUri(); + final Redirect redirect = redirectResolver != null ? redirectResolver.resolve(requestURI) : null; + if (redirect != null) { + final ClassicHttpResponse response = new BasicClassicHttpResponse(redirect.status); + if (redirect.location != null) { + response.addHeader(new BasicHeader(HttpHeaders.LOCATION, redirect.location)); + } + switch (redirect.connControl) { + case KEEP_ALIVE: + response.addHeader(new BasicHeader(HttpHeaders.CONNECTION, HeaderElements.KEEP_ALIVE)); + break; + case CLOSE: + response.addHeader(new BasicHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE)); + } + responseTrigger.submitResponse(response); + } else { + requestHandler.handle(request, responseTrigger, context); + } + } catch (final URISyntaxException ex) { + throw new ProtocolException(ex.getMessage(), ex); + } + } +} diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/Redirect.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/Redirect.java new file mode 100644 index 000000000..b52fb35a9 --- /dev/null +++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/Redirect.java @@ -0,0 +1,48 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.redirect; + +public class Redirect { + + public enum ConnControl { PROTOCOL_DEFAULT, KEEP_ALIVE, CLOSE } + + public final int status; + public final String location; + public final ConnControl connControl; + + public Redirect(final int status, final String location, final ConnControl connControl) { + this.status = status; + this.location = location; + this.connControl = connControl; + } + + public Redirect(final int status, final String location) { + this(status , location, ConnControl.PROTOCOL_DEFAULT); + } + +} diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/RedirectResolver.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/RedirectResolver.java new file mode 100644 index 000000000..2ffa2dbdf --- /dev/null +++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/redirect/RedirectResolver.java @@ -0,0 +1,37 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.redirect; + +import java.net.URI; +import java.net.URISyntaxException; + +public interface RedirectResolver { + + Redirect resolve(URI requestUri) throws URISyntaxException; + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/OldPathRedirectResolver.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/OldPathRedirectResolver.java new file mode 100644 index 000000000..84aaf0979 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/OldPathRedirectResolver.java @@ -0,0 +1,68 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.client5.testing.redirect.RedirectResolver; +import org.apache.hc.core5.net.URIBuilder; + +public class OldPathRedirectResolver implements RedirectResolver { + + private final String oldPath; + private final String newPath; + private final int status; + private final Redirect.ConnControl connControl; + + public OldPathRedirectResolver( + final String oldPath, final String newPath, final int status, final Redirect.ConnControl connControl) { + this.oldPath = oldPath; + this.newPath = newPath; + this.status = status; + this.connControl = connControl; + } + + public OldPathRedirectResolver(final String oldPath, final String newPath, final int status) { + this(oldPath, newPath, status, Redirect.ConnControl.PROTOCOL_DEFAULT); + } + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.startsWith(oldPath)) { + final URI location = new URIBuilder(requestUri) + .setPath(newPath + path.substring(oldPath.length())) + .build(); + return new Redirect(status, location.toString(), connControl); + + } + return null; + } +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java index e92af3a1a..185722973 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java @@ -29,8 +29,6 @@ package org.apache.hc.client5.testing.async; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -45,7 +43,11 @@ import org.apache.hc.client5.http.cookie.CookieStore; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.OldPathRedirectResolver; import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.client5.testing.redirect.RedirectResolver; +import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.function.Supplier; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; @@ -58,14 +60,14 @@ import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; import org.apache.hc.core5.http.protocol.HttpCoreContext; import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.net.URIBuilder; +import org.apache.hc.core5.reactive.ReactiveServerExchangeHandler; import org.apache.hc.core5.reactor.IOReactorConfig; -import org.apache.hc.core5.reactor.ListenerEndpoint; import org.apache.hc.core5.testing.nio.H2TestServer; +import org.apache.hc.core5.testing.reactive.ReactiveRandomProcessor; import org.apache.hc.core5.util.TimeValue; import org.junit.Assert; import org.junit.Test; @@ -88,132 +90,26 @@ public abstract class AbstractHttpAsyncRedirectsTest exchangeHandlerDecorator) throws Exception { + if (version.greaterEquals(HttpVersion.HTTP_2)) { + return super.start(null, exchangeHandlerDecorator, H2Config.DEFAULT); + } else { + return super.start(null, exchangeHandlerDecorator, Http1Config.DEFAULT); } - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(statuscode); - response.addHeader(new BasicHeader("Location", - new URIBuilder(requestURI).setPath("/newlocation/").build())); - return response; - } else if (path.equals("/newlocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK); - response.setBody("Successful redirect", ContentType.TEXT_PLAIN); - return response; - } else { - return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - - } - - static class CircularRedirectService extends AbstractSimpleServerExchangeHandler { - - public CircularRedirectService() { - super(); - } - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.startsWith("/circular-oldlocation")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/circular-location2")); - return response; - } else if (path.startsWith("/circular-location2")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/circular-oldlocation")); - return response; - } else { - return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - - } - - static class RelativeRedirectService extends AbstractSimpleServerExchangeHandler { - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/relativelocation/")); - return response; - } else if (path.equals("/relativelocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK); - response.setBody("Successful redirect", ContentType.TEXT_PLAIN); - return response; - } else { - return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } - - static class RelativeRedirectService2 extends AbstractSimpleServerExchangeHandler { - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/test/oldlocation")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "relativelocation")); - return response; - } else if (path.equals("/test/relativelocation")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK); - response.setBody("Successful redirect", ContentType.TEXT_PLAIN); - return response; - } else { - return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } @Test public void testBasicRedirect300() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_MULTIPLE_CHOICES); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES)); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( @@ -229,117 +125,131 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_MOVED_PERMANENTLY); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY)); } }); - - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/100"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/100", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testBasicRedirect302() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_MOVED_TEMPORARILY); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/123"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/123", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testBasicRedirect302NoLocation() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new AbstractSimpleServerExchangeHandler() { + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - return new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - } + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); + } + return null; + } - }; + }); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/100"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getCode()); - Assert.assertEquals("/oldlocation/", request.getRequestUri()); + Assert.assertEquals("/oldlocation/100", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testBasicRedirect303() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_SEE_OTHER); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER)); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/123"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/123", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testBasicRedirect304() throws Exception { - server.register("*", new Supplier() { + server.register("/oldlocation/*", new Supplier() { @Override public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_NOT_MODIFIED); - } + return new AbstractSimpleServerExchangeHandler() { + + @Override + protected SimpleHttpResponse handle(final SimpleHttpRequest request, + final HttpCoreContext context) throws HttpException { + return SimpleHttpResponse.create(HttpStatus.SC_NOT_MODIFIED, (String) null); + } + }; + + } }); final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); @@ -356,13 +266,21 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + server.register("/oldlocation/*", new Supplier() { @Override public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_USE_PROXY); - } + return new AbstractSimpleServerExchangeHandler() { + + @Override + protected SimpleHttpResponse handle(final SimpleHttpRequest request, + final HttpCoreContext context) throws HttpException { + return SimpleHttpResponse.create(HttpStatus.SC_USE_PROXY, (String) null); + } + }; + + } }); final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); @@ -379,39 +297,42 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_TEMPORARY_REDIRECT); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT)); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/123"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/123", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test(expected=ExecutionException.class) public void testMaxRedirectCheck() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new CircularRedirectService(); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)); } }); - final HttpHost target = start(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(true) @@ -429,15 +350,17 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new CircularRedirectService(); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)); } }); - final HttpHost target = start(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(false) @@ -455,19 +378,20 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_SEE_OTHER); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER)); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); - final SimpleHttpRequest post = SimpleHttpRequests.post(target, "/oldlocation/"); + final SimpleHttpRequest post = SimpleHttpRequests.post(target, "/oldlocation/stuff"); post.setBody("stuff", ContentType.TEXT_PLAIN); final Future future = httpclient.execute(post, context, null); final HttpResponse response = future.get(); @@ -476,106 +400,112 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new RelativeRedirectService(); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); + + } + return null; + } + + }); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/stuff"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/relativelocation/", request.getRequestUri()); + Assert.assertEquals("/random/100", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testRelativeRedirect2() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new RelativeRedirectService2(); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/random/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); + + } + return null; + } + + }); } }); - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/test/oldlocation"), context, null); + SimpleHttpRequests.get(target, "/random/oldlocation"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/test/relativelocation", request.getRequestUri()); + Assert.assertEquals("/random/100", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } - static class BogusRedirectService extends AbstractSimpleServerExchangeHandler { - - private final String url; - - public BogusRedirectService(final String url) { - super(); - this.url = url; - } - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", url)); - return response; - } else if (path.equals("/relativelocation/")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK); - response.setBody("Successful redirect", ContentType.TEXT_PLAIN); - return response; - } else { - return new SimpleHttpResponse(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - - } - @Test(expected=ExecutionException.class) public void testRejectBogusRedirectLocation() throws Exception { - server.register("*", new Supplier() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BogusRedirectService("xxx://bogus"); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation/")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); + + } + return null; + } + + }); } }); - final HttpHost target = start(); try { final Future future = httpclient.execute( @@ -589,15 +519,28 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BogusRedirectService("/newlocation/?p=I have spaces"); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation/")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); + + } + return null; + } + + }); } }); - final HttpHost target = start(); try { final Future future = httpclient.execute( @@ -611,15 +554,16 @@ public abstract class AbstractHttpAsyncRedirectsTest () { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new BasicRedirectService(HttpStatus.SC_MOVED_TEMPORARILY); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)); } }); - final HttpHost target = start(); final CookieStore cookieStore = new BasicCookieStore(); final HttpClientContext context = HttpClientContext.create(); @@ -632,214 +576,84 @@ public abstract class AbstractHttpAsyncRedirectsTest future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/100"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/100", request.getRequestUri()); final Header[] headers = request.getHeaders("Cookie"); Assert.assertEquals("There can only be one (cookie)", 1, headers.length); } - static class CrossSiteRedirectService extends AbstractSimpleServerExchangeHandler { - - private final HttpHost host; - - public CrossSiteRedirectService(final HttpHost host) { - super(); - this.host = host; - } - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - final String location; - try { - final URIBuilder uribuilder = new URIBuilder(request.getUri()); - uribuilder.setScheme(host.getSchemeName()); - uribuilder.setHost(host.getHostName()); - uribuilder.setPort(host.getPort()); - uribuilder.setPath("/random/1024"); - location = uribuilder.build().toASCIIString(); - } catch (final URISyntaxException ex) { - throw new ProtocolException("Invalid request URI", ex); - } - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_TEMPORARY_REDIRECT); - response.addHeader(new BasicHeader("Location", location)); - return response; - } - } - @Test public void testCrossSiteRedirect() throws Exception { - server.register("/random/*", new Supplier() { - - @Override - public AsyncServerExchangeHandler get() { - return new AsyncRandomHandler(); - } - - }); - final HttpHost redirectTarget = start(); - final H2TestServer secondServer = new H2TestServer(IOReactorConfig.DEFAULT, scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, null, null); try { - secondServer.register("/redirect/*", new Supplier() { + secondServer.register("/random/*", new Supplier() { @Override public AsyncServerExchangeHandler get() { - return new CrossSiteRedirectService(redirectTarget); + if (isReactive()) { + return new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()); + } else { + return new AsyncRandomHandler(); + } + } + + }); + final InetSocketAddress address2; + if (version.greaterEquals(HttpVersion.HTTP_2)) { + address2 = secondServer.start(H2Config.DEFAULT); + } else { + address2 = secondServer.start(Http1Config.DEFAULT); + } + final HttpHost redirectTarget = new HttpHost(scheme.name(), "localhost", address2.getPort()); + + final HttpHost target = start(new Decorator() { + + @Override + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + final URI location = new URIBuilder(requestUri) + .setHttpHost(redirectTarget) + .setPath("/random/100") + .build(); + return new Redirect(HttpStatus.SC_MOVED_PERMANENTLY, location.toString()); + } + return null; + } + + }); } }); - if (version.greaterEquals(HttpVersion.HTTP_2)) { - secondServer.start(H2Config.DEFAULT); - } else { - secondServer.start(Http1Config.DEFAULT); - } - final Future endpointFuture = secondServer.listen(new InetSocketAddress(0)); - final ListenerEndpoint endpoint2 = endpointFuture.get(); + final HttpClientContext context = HttpClientContext.create(); + final Future future = httpclient.execute( + SimpleHttpRequests.get(target, "/oldlocation"), context, null); + final HttpResponse response = future.get(); + Assert.assertNotNull(response); - final InetSocketAddress address2 = (InetSocketAddress) endpoint2.getAddress(); - final HttpHost initialTarget = new HttpHost(scheme.name(), "localhost", address2.getPort()); + final HttpRequest request = context.getRequest(); - final Queue> queue = new ConcurrentLinkedQueue<>(); - for (int i = 0; i < 1; i++) { - queue.add(httpclient.execute(SimpleHttpRequests.get(initialTarget, "/redirect/anywhere"), null)); - } - while (!queue.isEmpty()) { - final Future future = queue.remove(); - final HttpResponse response = future.get(); - Assert.assertNotNull(response); - Assert.assertEquals(200, response.getCode()); - } + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals("/random/100", request.getRequestUri()); + Assert.assertEquals(redirectTarget, new HttpHost(request.getScheme(), request.getAuthority())); } finally { server.shutdown(TimeValue.ofSeconds(5)); } } - private static class RomeRedirectService extends AbstractSimpleServerExchangeHandler { - - @Override - protected SimpleHttpResponse handle( - final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/rome")) { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_OK); - response.setBody("Successful redirect", ContentType.TEXT_PLAIN); - return response; - } else { - final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/rome")); - return response; - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - - } - - @Test - public void testRepeatRequest() throws Exception { - server.register("*", new Supplier() { - - @Override - public AsyncServerExchangeHandler get() { - return new RomeRedirectService(); - } - - }); - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final Future future1 = httpclient.execute( - SimpleHttpRequests.get(target, "/rome"), context, null); - final HttpResponse response1 = future1.get(); - Assert.assertNotNull(response1); - - final Future future2 = httpclient.execute( - SimpleHttpRequests.get(target, "/rome"), context, null); - final HttpResponse response2 = future2.get(); - Assert.assertNotNull(response2); - - final HttpRequest request = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); - Assert.assertEquals("/rome", request.getRequestUri()); - Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); - } - - @Test - public void testRepeatRequestRedirect() throws Exception { - server.register("*", new Supplier() { - - @Override - public AsyncServerExchangeHandler get() { - return new RomeRedirectService(); - } - - }); - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final Future future1 = httpclient.execute( - SimpleHttpRequests.get(target, "/lille"), context, null); - final HttpResponse response1 = future1.get(); - Assert.assertNotNull(response1); - - final Future future2 = httpclient.execute( - SimpleHttpRequests.get(target, "/lille"), context, null); - final HttpResponse response2 = future2.get(); - Assert.assertNotNull(response2); - - final HttpRequest request = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); - Assert.assertEquals("/rome", request.getRequestUri()); - Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); - } - - @Test - public void testDifferentRequestSameRedirect() throws Exception { - server.register("*", new Supplier() { - - @Override - public AsyncServerExchangeHandler get() { - return new RomeRedirectService(); - } - - }); - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final Future future1 = httpclient.execute( - SimpleHttpRequests.get(target, "/alian"), context, null); - final HttpResponse response1 = future1.get(); - Assert.assertNotNull(response1); - - final Future future2 = httpclient.execute( - SimpleHttpRequests.get(target, "/lille"), context, null); - final HttpResponse response2 = future2.get(); - Assert.assertNotNull(response2); - - - final HttpRequest request = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); - Assert.assertEquals("/rome", request.getRequestUri()); - Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); - } - } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java index 0e2239032..ee72da949 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java @@ -26,15 +26,12 @@ */ package org.apache.hc.client5.testing.async; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.Future; -import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleHttpRequests; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.config.RequestConfig; @@ -44,23 +41,20 @@ import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.OldPathRedirectResolver; import org.apache.hc.client5.testing.SSLTestContexts; -import org.apache.hc.core5.function.Supplier; -import org.apache.hc.core5.http.ContentType; +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.Header; -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.HttpRequest; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.HttpVersion; -import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.http.protocol.HttpCoreContext; -import org.apache.hc.core5.net.URIBuilder; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -129,54 +123,19 @@ public class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest() { + public void testBasicRedirect300NoKeepAlive() throws Exception { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new NoKeepAliveRedirectService(HttpStatus.SC_MULTIPLE_CHOICES); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, + Redirect.ConnControl.CLOSE)); } }); - final HttpHost target = start(); - final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( SimpleHttpRequests.get(target, "/oldlocation/"), context, null); @@ -191,57 +150,59 @@ public class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest() { + final HttpHost target = start(new Decorator() { @Override - public AsyncServerExchangeHandler get() { - return new NoKeepAliveRedirectService(HttpStatus.SC_MOVED_PERMANENTLY); + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, + Redirect.ConnControl.CLOSE)); } }); - - final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/100"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/100", request.getRequestUri()); Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority())); } @Test public void testDefaultHeadersRedirect() throws Exception { - server.register("*", new Supplier() { - - @Override - public AsyncServerExchangeHandler get() { - return new NoKeepAliveRedirectService(HttpStatus.SC_MOVED_TEMPORARILY); - } - - }); - final List
defaultHeaders = new ArrayList<>(1); defaultHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, "my-test-client")); clientBuilder.setDefaultHeaders(defaultHeaders); - final HttpHost target = start(); + final HttpHost target = start(new Decorator() { + + @Override + public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) { + return new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, + Redirect.ConnControl.CLOSE)); + } + + }); final HttpClientContext context = HttpClientContext.create(); final Future future = httpclient.execute( - SimpleHttpRequests.get(target, "/oldlocation/"), context, null); + SimpleHttpRequests.get(target, "/oldlocation/123"), context, null); final HttpResponse response = future.get(); Assert.assertNotNull(response); final HttpRequest request = context.getRequest(); Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals("/newlocation/", request.getRequestUri()); + Assert.assertEquals("/random/123", request.getRequestUri()); final Header header = request.getFirstHeader(HttpHeaders.USER_AGENT); Assert.assertEquals("my-test-client", header.getValue()); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java index aedefd6c4..78b12b1b6 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java @@ -43,6 +43,11 @@ 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.client5.testing.OldPathRedirectResolver; +import org.apache.hc.client5.testing.classic.RedirectingDecorator; +import org.apache.hc.client5.testing.redirect.Redirect; +import org.apache.hc.client5.testing.redirect.RedirectResolver; +import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.Header; @@ -53,11 +58,11 @@ import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.io.HttpRequestHandler; +import org.apache.hc.core5.http.io.HttpServerRequestHandler; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.net.URIBuilder; import org.junit.Assert; import org.junit.Test; @@ -66,282 +71,201 @@ import org.junit.Test; */ public class TestRedirects extends LocalServerTestBase { - private static class BasicRedirectService implements HttpRequestHandler { + @Test + public void testBasicRedirect300() throws Exception { + final HttpHost target = start(null, new Decorator() { - private final int statuscode; - - public BasicRedirectService(final int statuscode) { - super(); - this.statuscode = statuscode > 0 ? statuscode : HttpStatus.SC_MOVED_TEMPORARILY; - } - - public BasicRedirectService() { - this(-1); - } - - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - response.setCode(this.statuscode); - response.addHeader(new BasicHeader("Location", - new URIBuilder(requestURI).setPath("/newlocation/").build())); - response.addHeader(new BasicHeader("Connection", "close")); - } else if (path.equals("/newlocation/")) { - response.setCode(HttpStatus.SC_OK); - final StringEntity entity = new StringEntity("Successful redirect"); - response.setEntity(entity); - } else { - response.setCode(HttpStatus.SC_NOT_FOUND); - } - - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES)); } - } - } + }); - private static class CircularRedirectService implements HttpRequestHandler { + final HttpClientContext context = HttpClientContext.create(); + final HttpGet httpget = new HttpGet("/oldlocation/100"); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - public CircularRedirectService() { - super(); - } + Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/oldlocation/100"), reqWrapper.getUri()); - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.startsWith("/circular-oldlocation")) { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/circular-location2")); - } else if (path.startsWith("/circular-location2")) { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/circular-oldlocation")); - } else { - response.setCode(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } + final RedirectLocations redirects = context.getRedirectLocations(); + Assert.assertNotNull(redirects); + Assert.assertEquals(0, redirects.size()); - private static class RelativeRedirectService implements HttpRequestHandler { - - public RelativeRedirectService() { - super(); - } - - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/relativelocation/")); - } else if (path.equals("/relativelocation/")) { - response.setCode(HttpStatus.SC_OK); - final StringEntity entity = new StringEntity("Successful redirect"); - response.setEntity(entity); - } else { - response.setCode(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } - - private static class RelativeRedirectService2 implements HttpRequestHandler { - - public RelativeRedirectService2() { - super(); - } - - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/test/oldlocation")) { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "relativelocation")); - } else if (path.equals("/test/relativelocation")) { - response.setCode(HttpStatus.SC_OK); - final StringEntity entity = new StringEntity("Successful redirect"); - response.setEntity(entity); - } else { - response.setCode(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } - - private static class RomeRedirectService implements HttpRequestHandler { - - public RomeRedirectService() { - super(); - } - - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/rome")) { - response.setCode(HttpStatus.SC_OK); - final StringEntity entity = new StringEntity("Successful redirect"); - response.setEntity(entity); - } else { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", "/rome")); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } - } - } - - interface UriTransformation { - - String rewrite(URI requestUri); - - } - - private static class TransformingRedirectService implements HttpRequestHandler { - - private final UriTransformation uriTransformation; - - public TransformingRedirectService(final UriTransformation uriTransformation) { - super(); - this.uriTransformation = uriTransformation; - } - - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - try { - final URI requestURI = request.getUri(); - final String path = requestURI.getPath(); - if (path.equals("/oldlocation/")) { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); - response.addHeader(new BasicHeader("Location", uriTransformation.rewrite(requestURI))); - } else if (path.equals("/relativelocation/")) { - response.setCode(HttpStatus.SC_OK); - final StringEntity entity = new StringEntity("Successful redirect"); - response.setEntity(entity); - } else { - response.setCode(HttpStatus.SC_NOT_FOUND); - } - } catch (final URISyntaxException ex) { - throw new ProtocolException(ex.getMessage(), ex); - } + EntityUtils.consume(response.getEntity()); } } @Test - public void testBasicRedirect300() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_MULTIPLE_CHOICES)); + public void testBasicRedirect300NoKeepAlive() throws Exception { + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, + Redirect.ConnControl.CLOSE)); + } + + }); final HttpClientContext context = HttpClientContext.create(); + final HttpGet httpget = new HttpGet("/oldlocation/100"); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/oldlocation/100"), reqWrapper.getUri()); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + final RedirectLocations redirects = context.getRedirectLocations(); + Assert.assertNotNull(redirects); + Assert.assertEquals(0, redirects.size()); - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/oldlocation/"), reqWrapper.getUri()); - - final RedirectLocations redirects = context.getRedirectLocations(); - Assert.assertNotNull(redirects); - Assert.assertEquals(0, redirects.size()); + EntityUtils.consume(response.getEntity()); + } } @Test public void testBasicRedirect301() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_MOVED_PERMANENTLY)); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY)); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/100"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/100"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); + final RedirectLocations redirects = context.getRedirectLocations(); + Assert.assertNotNull(redirects); + Assert.assertEquals(1, redirects.size()); - final RedirectLocations redirects = context.getRedirectLocations(); - Assert.assertNotNull(redirects); - Assert.assertEquals(1, redirects.size()); + final URI redirect = URIUtils.rewriteURI(new URI("/random/100"), target); + Assert.assertTrue(redirects.contains(redirect)); - final URI redirect = URIUtils.rewriteURI(new URI("/newlocation/"), target); - Assert.assertTrue(redirects.contains(redirect)); + EntityUtils.consume(response.getEntity()); + } } @Test public void testBasicRedirect302() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_MOVED_TEMPORARILY)); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/50"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/50"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); + EntityUtils.consume(response.getEntity()); + } } @Test public void testBasicRedirect302NoLocation() throws Exception { - this.server.registerHandler("*", new HttpRequestHandler() { + final HttpHost target = start(null, new Decorator() { @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - response.setCode(HttpStatus.SC_MOVED_TEMPORARILY); + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); + } + return null; + } + + }); + } + + }); + + final HttpClientContext context = HttpClientContext.create(); + + final HttpGet httpget = new HttpGet("/oldlocation/100"); + + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); + + Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getCode()); + Assert.assertEquals("/oldlocation/100", reqWrapper.getRequestUri()); + + EntityUtils.consume(response.getEntity()); + } + } + + @Test + public void testBasicRedirect303() throws Exception { + final HttpHost target = start(null, new Decorator() { + + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER)); + } + + }); + + final HttpClientContext context = HttpClientContext.create(); + + final HttpGet httpget = new HttpGet("/oldlocation/123"); + + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); + + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/123"), reqWrapper.getUri()); + + EntityUtils.consume(response.getEntity()); + } + } + + @Test + public void testBasicRedirect304() throws Exception { + this.server.registerHandler("/oldlocation/*", new HttpRequestHandler() { + + @Override + public void handle(final ClassicHttpRequest request, + final ClassicHttpResponse response, + final HttpContext context) throws HttpException, IOException { + response.setCode(HttpStatus.SC_NOT_MODIFIED); + response.addHeader(HttpHeaders.LOCATION, "/random/100"); } }); @@ -350,104 +274,103 @@ public class TestRedirects extends LocalServerTestBase { final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/stuff"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/oldlocation/stuff"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getCode()); - Assert.assertEquals("/oldlocation/", reqWrapper.getRequestUri()); - } + final RedirectLocations redirects = context.getRedirectLocations(); + Assert.assertNotNull(redirects); + Assert.assertEquals(0, redirects.size()); - @Test - public void testBasicRedirect303() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_SEE_OTHER)); - - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final HttpGet httpget = new HttpGet("/oldlocation/"); - - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); - - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); - } - - @Test - public void testBasicRedirect304() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_NOT_MODIFIED)); - - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final HttpGet httpget = new HttpGet("/oldlocation/"); - - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); - - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/oldlocation/"), reqWrapper.getUri()); + EntityUtils.consume(response.getEntity()); + } } @Test public void testBasicRedirect305() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_USE_PROXY)); + this.server.registerHandler("/oldlocation/*", new HttpRequestHandler() { + + @Override + public void handle(final ClassicHttpRequest request, + final ClassicHttpResponse response, + final HttpContext context) throws HttpException, IOException { + response.setCode(HttpStatus.SC_USE_PROXY); + response.addHeader(HttpHeaders.LOCATION, "/random/100"); + } + + }); + final HttpHost target = start(); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/stuff"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_USE_PROXY, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/oldlocation/stuff"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_USE_PROXY, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/oldlocation/"), reqWrapper.getUri()); + final RedirectLocations redirects = context.getRedirectLocations(); + Assert.assertNotNull(redirects); + Assert.assertEquals(0, redirects.size()); + + EntityUtils.consume(response.getEntity()); + } } @Test public void testBasicRedirect307() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_TEMPORARY_REDIRECT)); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT)); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/123"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/123"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); + EntityUtils.consume(response.getEntity()); + } } - @Test(expected=ClientProtocolException.class) + @Test(expected = ClientProtocolException.class) public void testMaxRedirectCheck() throws Exception { - this.server.registerHandler("*", new CircularRedirectService()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)); + } + + }); final RequestConfig config = RequestConfig.custom() - .setCircularRedirectsAllowed(true) - .setMaxRedirects(5) - .build(); + .setCircularRedirectsAllowed(true) + .setMaxRedirects(5) + .build(); - final HttpGet httpget = new HttpGet("/circular-oldlocation/"); + final HttpGet httpget = new HttpGet("/circular-oldlocation/123"); httpget.setConfig(config); try { this.httpclient.execute(target, httpget); @@ -457,17 +380,25 @@ public class TestRedirects extends LocalServerTestBase { } } - @Test(expected=ClientProtocolException.class) + @Test(expected = ClientProtocolException.class) public void testCircularRedirect() throws Exception { - this.server.registerHandler("*", new CircularRedirectService()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)); + } + + }); final RequestConfig config = RequestConfig.custom() - .setCircularRedirectsAllowed(false) - .build(); + .setCircularRedirectsAllowed(false) + .build(); - final HttpGet httpget = new HttpGet("/circular-oldlocation/"); + final HttpGet httpget = new HttpGet("/circular-oldlocation/123"); httpget.setConfig(config); try { this.httpclient.execute(target, httpget); @@ -477,149 +408,140 @@ public class TestRedirects extends LocalServerTestBase { } } - @Test - public void testRepeatRequest() throws Exception { - this.server.registerHandler("*", new RomeRedirectService()); - - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final HttpGet first = new HttpGet("/rome"); - - EntityUtils.consume(this.httpclient.execute(target, first, context).getEntity()); - - final HttpGet second = new HttpGet("/rome"); - - final ClassicHttpResponse response = this.httpclient.execute(target, second, context); - EntityUtils.consume(response.getEntity()); - - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/rome"), reqWrapper.getUri()); - } - - @Test - public void testRepeatRequestRedirect() throws Exception { - this.server.registerHandler("*", new RomeRedirectService()); - - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final HttpGet first = new HttpGet("/lille"); - final ClassicHttpResponse response1 = this.httpclient.execute(target, first, context); - EntityUtils.consume(response1.getEntity()); - - final HttpGet second = new HttpGet("/lille"); - - final ClassicHttpResponse response2 = this.httpclient.execute(target, second, context); - EntityUtils.consume(response2.getEntity()); - - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); - Assert.assertEquals(URIUtils.create(target, "/rome"), reqWrapper.getUri()); - } - - @Test - public void testDifferentRequestSameRedirect() throws Exception { - this.server.registerHandler("*", new RomeRedirectService()); - - final HttpHost target = start(); - - final HttpClientContext context = HttpClientContext.create(); - - final HttpGet first = new HttpGet("/alian"); - - final ClassicHttpResponse response1 = this.httpclient.execute(target, first, context); - EntityUtils.consume(response1.getEntity()); - - final HttpGet second = new HttpGet("/lille"); - - final ClassicHttpResponse response2 = this.httpclient.execute(target, second, context); - EntityUtils.consume(response2.getEntity()); - - final HttpRequest reqWrapper = context.getRequest(); - - Assert.assertEquals(HttpStatus.SC_OK, response2.getCode()); - Assert.assertEquals(URIUtils.create(target, "/rome"), reqWrapper.getUri()); - } - @Test public void testPostRedirectSeeOther() throws Exception { - this.server.registerHandler("*", new BasicRedirectService(HttpStatus.SC_SEE_OTHER)); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER)); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpPost httppost = new HttpPost("/oldlocation/"); + final HttpPost httppost = new HttpPost("/oldlocation/stuff"); httppost.setEntity(new StringEntity("stuff")); - final ClassicHttpResponse response = this.httpclient.execute(target, httppost, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httppost, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/echo/stuff"), reqWrapper.getUri()); + Assert.assertEquals("GET", reqWrapper.getMethod()); + + EntityUtils.consume(response.getEntity()); + } - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); - Assert.assertEquals("GET", reqWrapper.getMethod()); } @Test public void testRelativeRedirect() throws Exception { - this.server.registerHandler("*", new RelativeRedirectService()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new RedirectResolver() { + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); + + } + return null; + } + + }); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/stuff"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/100"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/relativelocation/"), reqWrapper.getUri()); + EntityUtils.consume(response.getEntity()); + } } @Test public void testRelativeRedirect2() throws Exception { - this.server.registerHandler("*", new RelativeRedirectService2()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/random/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); + + } + return null; + } + + }); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/test/oldlocation"); + final HttpGet httpget = new HttpGet("/random/oldlocation"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/100"), reqWrapper.getUri()); + + EntityUtils.consume(response.getEntity()); + } - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/test/relativelocation"), reqWrapper.getUri()); } - @Test(expected=ClientProtocolException.class) + @Test(expected = ClientProtocolException.class) public void testRejectBogusRedirectLocation() throws Exception { - this.server.registerHandler("*", new TransformingRedirectService(new UriTransformation() { + final HttpHost target = start(null, new Decorator() { @Override - public String rewrite(final URI requestUri) { - return "xxx://bogus"; + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); + + } + return null; + } + + }); } - })); + }); - final HttpHost target = start(); - - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation"); try { this.httpclient.execute(target, httpget); @@ -630,19 +552,32 @@ public class TestRedirects extends LocalServerTestBase { } } - @Test(expected=ClientProtocolException.class) + @Test(expected = ClientProtocolException.class) public void testRejectInvalidRedirectLocation() throws Exception { - this.server.registerHandler("*", new TransformingRedirectService(new UriTransformation() { + final HttpHost target = start(null, new Decorator() { @Override - public String rewrite(final URI requestUri) { - return "/newlocation/?p=I have spaces"; + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new RedirectResolver() { + + @Override + public Redirect resolve(final URI requestUri) throws URISyntaxException { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); + + } + return null; + } + + }); } - })); - final HttpHost target = start(); + }); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation"); try { this.httpclient.execute(target, httpget); @@ -654,9 +589,16 @@ public class TestRedirects extends LocalServerTestBase { @Test public void testRedirectWithCookie() throws Exception { - this.server.registerHandler("*", new BasicRedirectService()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)); + } + + }); final CookieStore cookieStore = new BasicCookieStore(); @@ -668,43 +610,51 @@ public class TestRedirects extends LocalServerTestBase { final HttpClientContext context = HttpClientContext.create(); context.setCookieStore(cookieStore); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/100"); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final HttpRequest reqWrapper = context.getRequest(); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/100"), reqWrapper.getUri()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); + final Header[] headers = reqWrapper.getHeaders("Cookie"); + Assert.assertEquals("There can only be one (cookie)", 1, headers.length); - final Header[] headers = reqWrapper.getHeaders("Cookie"); - Assert.assertEquals("There can only be one (cookie)", 1, headers.length); + EntityUtils.consume(response.getEntity()); + } } @Test public void testDefaultHeadersRedirect() throws Exception { this.clientBuilder.setDefaultHeaders(Arrays.asList(new BasicHeader(HttpHeaders.USER_AGENT, "my-test-client"))); - this.server.registerHandler("*", new BasicRedirectService()); + final HttpHost target = start(null, new Decorator() { - final HttpHost target = start(); + @Override + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)); + } + + }); final HttpClientContext context = HttpClientContext.create(); - final HttpGet httpget = new HttpGet("/oldlocation/"); + final HttpGet httpget = new HttpGet("/oldlocation/100"); + try (final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context)) { + final HttpRequest reqWrapper = context.getRequest(); - final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context); - EntityUtils.consume(response.getEntity()); + Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); + Assert.assertEquals(URIUtils.create(target, "/random/100"), reqWrapper.getUri()); - final HttpRequest reqWrapper = context.getRequest(); + final Header header = reqWrapper.getFirstHeader(HttpHeaders.USER_AGENT); + Assert.assertEquals("my-test-client", header.getValue()); - Assert.assertEquals(HttpStatus.SC_OK, response.getCode()); - Assert.assertEquals(URIUtils.create(target, "/newlocation/"), reqWrapper.getUri()); - - final Header header = reqWrapper.getFirstHeader(HttpHeaders.USER_AGENT); - Assert.assertEquals("my-test-client", header.getValue()); + EntityUtils.consume(response.getEntity()); + } } }