diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java b/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java index e433b1cea3e..aeb31cf5072 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java +++ b/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java @@ -1005,7 +1005,7 @@ private HttpClientRequest createRequest(HttpMethod method, String protocol, Stri } checkClosed(); HttpClientRequest req; - boolean useProxy = !useSSL && proxyType == ProxyType.HTTP; + boolean useProxy = userProxy(useSSL, options.getProxyOptions(), host); if (useProxy) { final int defaultPort = protocol.equals("ftp") ? 21 : 80; final String addPort = (port != -1 && port != defaultPort) ? (":" + port) : ""; @@ -1030,6 +1030,17 @@ private HttpClientRequest createRequest(HttpMethod method, String protocol, Stri return req; } + private boolean userProxy(boolean isSsl, ProxyOptions proxyOptions, String targetHost) { + if(!isSsl && proxyType == ProxyType.HTTP) { + if(proxyOptions.getExcludedHosts().isEmpty()) { + return true; + } else { + return !proxyOptions.getExcludedHosts().contains(targetHost); + } + } + return false; + } + private synchronized void checkClosed() { if (closed) { throw new IllegalStateException("Client is closed"); diff --git a/src/main/java/io/vertx/core/net/ProxyOptions.java b/src/main/java/io/vertx/core/net/ProxyOptions.java index f246dc0bff6..876455efd25 100644 --- a/src/main/java/io/vertx/core/net/ProxyOptions.java +++ b/src/main/java/io/vertx/core/net/ProxyOptions.java @@ -11,7 +11,7 @@ package io.vertx.core.net; -import java.util.Objects; +import java.util.*; import io.vertx.codegen.annotations.DataObject; import io.vertx.core.json.JsonObject; @@ -46,6 +46,7 @@ public class ProxyOptions { private String username; private String password; private ProxyType type; + private Set exludedHosts; /** * Default constructor. @@ -54,6 +55,7 @@ public ProxyOptions() { host = DEFAULT_HOST; port = DEFAULT_PORT; type = DEFAULT_TYPE; + exludedHosts = new HashSet<>(0); } /** @@ -67,6 +69,7 @@ public ProxyOptions(ProxyOptions other) { username = other.getUsername(); password = other.getPassword(); type = other.getType(); + exludedHosts = other.getExcludedHosts(); } /** @@ -199,6 +202,39 @@ public ProxyOptions setType(ProxyType type) { return this; } + /** + * Set list of excluded hosts. + * + * @param excludedHosts list of hosts to exclude from proxy logic + * @return a reference to this, so the API can be used fluently + */ + public ProxyOptions setExcludedHosts(final Set excludedHosts) { + Objects.requireNonNull(excludedHosts, "Excluded host cannot be null"); + this.exludedHosts = excludedHosts; + return this; + } + + /** + * Add host to existing excludedHost list. + * + * @param excludedHost host excluded from proxy logic + * @return a reference to this, so the API can be used fluently + */ + public ProxyOptions addExcludedHost(final String excludedHost) { + Objects.requireNonNull(excludedHost, "Excluded host cannot be null"); + this.exludedHosts.add(excludedHost); + return this; + } + + /** + * Get excluded hosts. + * + * @return list of hosts that should not be proxied. + */ + public Set getExcludedHosts() { + return exludedHosts; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -212,6 +248,7 @@ public boolean equals(Object o) { if (port != that.port) return false; if (!Objects.equals(password, that.password)) return false; if (!Objects.equals(username, that.username)) return false; + if (!Objects.equals(exludedHosts, that.exludedHosts)) return false; return true; } @@ -224,6 +261,7 @@ public int hashCode() { result = 31 * result + port; result = 31 * result + (password != null ? password.hashCode() : 0); result = 31 * result + (username != null ? username.hashCode() : 0); + result = 31 * result + exludedHosts.hashCode(); return result; } } diff --git a/src/test/java/io/vertx/test/core/Http1xTest.java b/src/test/java/io/vertx/test/core/Http1xTest.java index eec90a1ba6b..e05981c2b23 100644 --- a/src/test/java/io/vertx/test/core/Http1xTest.java +++ b/src/test/java/io/vertx/test/core/Http1xTest.java @@ -2955,6 +2955,32 @@ public void testHttpProxyRequest() throws Exception { testHttpProxyRequest2(client.get(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/")); } + @Test + public void testHttpHostExclusionOfProxyRequest() throws Exception { + startProxy(null, ProxyType.HTTP); + client.close(); + client = vertx.createHttpClient(new HttpClientOptions() + .setProxyOptions(new ProxyOptions().setType(ProxyType.HTTP).addExcludedHost("localhost").setHost("google.com").setPort(proxy.getPort()))); + + HttpClientRequest clientReq = client.get(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/"); + + server.requestHandler(req -> { + req.response().end(); + }); + + //because we excluded localhost from proxying logic, it will not reach google.com but localhost. + server.listen(onSuccess(s -> { + clientReq.handler(resp -> { + assertEquals(200, resp.statusCode()); + testComplete(); + }); + clientReq.exceptionHandler(this::fail); + clientReq.end(); + })); + + await(); + } + @Test public void testHttpProxyRequestOverrideClientSsl() throws Exception { startProxy(null, ProxyType.HTTP);