diff --git a/vertx-core/src/main/java/io/vertx/core/http/DefaultRedirectHandler.java b/vertx-core/src/main/java/io/vertx/core/http/DefaultRedirectHandler.java new file mode 100644 index 00000000000..24b2d892a36 --- /dev/null +++ b/vertx-core/src/main/java/io/vertx/core/http/DefaultRedirectHandler.java @@ -0,0 +1,71 @@ +package io.vertx.core.http; + +import static io.vertx.core.http.HttpHeaders.CONTENT_LENGTH; +import io.vertx.core.Future; +import io.vertx.core.http.impl.HttpUtils; +import java.net.URI; +import java.util.function.Function; + + +class DefaultRedirectHandler implements Function> { + + public static final DefaultRedirectHandler INSTANCE = new DefaultRedirectHandler(); + + private DefaultRedirectHandler() { + } + + @Override + public Future apply(HttpClientResponse resp) { + try { + int statusCode = resp.statusCode(); + String location = resp.getHeader(HttpHeaders.LOCATION); + if (location != null && (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307 + || statusCode == 308)) { + HttpMethod m = resp.request().getMethod(); + if (statusCode == 303) { + m = HttpMethod.GET; + } else if (m != HttpMethod.GET && m != HttpMethod.HEAD) { + return null; + } + URI uri = HttpUtils.resolveURIReference(resp.request().absoluteURI(), location); + boolean ssl; + int port = uri.getPort(); + String protocol = uri.getScheme(); + char chend = protocol.charAt(protocol.length() - 1); + if (chend == 'p') { + ssl = false; + if (port == -1) { + port = 80; + } + } else if (chend == 's') { + ssl = true; + if (port == -1) { + port = 443; + } + } else { + return null; + } + String requestURI = uri.getPath(); + if (requestURI == null || requestURI.isEmpty()) { + requestURI = "/"; + } + String query = uri.getQuery(); + if (query != null) { + requestURI += "?" + query; + } + RequestOptions options = new RequestOptions(); + options.setMethod(m); + options.setHost(uri.getHost()); + options.setPort(port); + options.setSsl(ssl); + options.setURI(requestURI); + options.setHeaders(resp.request().headers()); + options.removeHeader(CONTENT_LENGTH); + return Future.succeededFuture(options); + } + return null; + } catch (Exception e) { + return Future.failedFuture(e); + } + } +} diff --git a/vertx-core/src/main/java/io/vertx/core/http/HttpClient.java b/vertx-core/src/main/java/io/vertx/core/http/HttpClient.java index a16c1cc0e23..cc2eb3ab127 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/HttpClient.java +++ b/vertx-core/src/main/java/io/vertx/core/http/HttpClient.java @@ -11,10 +11,15 @@ package io.vertx.core.http; +import static io.vertx.core.http.HttpHeaders.CONTENT_LENGTH; +import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.Future; +import io.vertx.core.http.impl.HttpUtils; +import java.net.URI; import java.util.concurrent.TimeUnit; +import java.util.function.Function; /** * The API to interacts with an HTTP server. @@ -113,4 +118,12 @@ default Future close() { */ Future shutdown(long timeout, TimeUnit unit); + /** + * Provides a way for users of the client to get access to the default redirect handler. + * This is useful for building redirect handlers that need to delegate to the default behavior. + */ + @GenIgnore + default Function> defaultRedirectHandler() { + return DefaultRedirectHandler.INSTANCE; + } } diff --git a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java index 66291c811f8..7e6fc0ccd13 100644 --- a/vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java +++ b/vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java @@ -34,14 +34,11 @@ import io.vertx.core.spi.metrics.PoolMetrics; import java.lang.ref.WeakReference; -import java.net.URI; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.regex.Pattern; -import static io.vertx.core.http.HttpHeaders.*; - /** * This class is thread-safe. * @@ -52,63 +49,10 @@ public class HttpClientImpl extends HttpClientBase implements HttpClientInternal // Pattern to check we are not dealing with an absoluate URI static final Pattern ABS_URI_START_PATTERN = Pattern.compile("^\\p{Alpha}[\\p{Alpha}\\p{Digit}+.\\-]*:"); - private static final Function> DEFAULT_HANDLER = resp -> { - try { - int statusCode = resp.statusCode(); - String location = resp.getHeader(HttpHeaders.LOCATION); - if (location != null && (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307 || statusCode == 308)) { - HttpMethod m = resp.request().getMethod(); - if (statusCode == 303) { - m = HttpMethod.GET; - } else if (m != HttpMethod.GET && m != HttpMethod.HEAD) { - return null; - } - URI uri = HttpUtils.resolveURIReference(resp.request().absoluteURI(), location); - boolean ssl; - int port = uri.getPort(); - String protocol = uri.getScheme(); - char chend = protocol.charAt(protocol.length() - 1); - if (chend == 'p') { - ssl = false; - if (port == -1) { - port = 80; - } - } else if (chend == 's') { - ssl = true; - if (port == -1) { - port = 443; - } - } else { - return null; - } - String requestURI = uri.getPath(); - if (requestURI == null || requestURI.isEmpty()) { - requestURI = "/"; - } - String query = uri.getQuery(); - if (query != null) { - requestURI += "?" + query; - } - RequestOptions options = new RequestOptions(); - options.setMethod(m); - options.setHost(uri.getHost()); - options.setPort(port); - options.setSsl(ssl); - options.setURI(requestURI); - options.setHeaders(resp.request().headers()); - options.removeHeader(CONTENT_LENGTH); - return Future.succeededFuture(options); - } - return null; - } catch (Exception e) { - return Future.failedFuture(e); - } - }; - private final PoolOptions poolOptions; private final ResourceManager httpCM; private final EndpointResolverInternal endpointResolver; - private volatile Function> redirectHandler = DEFAULT_HANDLER; + private volatile Function> redirectHandler = defaultRedirectHandler(); private long timerID; private volatile Handler connectionHandler; private final Function contextProvider; @@ -223,7 +167,7 @@ protected void doClose(Promise p) { public void redirectHandler(Function> handler) { if (handler == null) { - handler = DEFAULT_HANDLER; + handler = defaultRedirectHandler(); } redirectHandler = handler; } @@ -487,4 +431,5 @@ HttpClientRequest createRequest(HttpConnection connection, HttpClientStream stre } return request; } + }