From 6de74acdb0e0a7707b0d51c2430512293401c8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Szynkiewicz?= Date: Wed, 5 Jan 2022 13:36:16 +0100 Subject: [PATCH] Support non-proxy hosts in REST Client Reactive --- .../main/asciidoc/rest-client-reactive.adoc | 11 ++++- .../restclient/config/RestClientConfig.java | 13 ++++++ .../restclient/config/RestClientsConfig.java | 13 +++++- .../rest/client/reactive/proxy/Client5.java | 14 ++++++ .../rest/client/reactive/proxy/Client6.java | 14 ++++++ .../reactive/proxy/GlobalNonProxyTest.java | 37 +++++++++++++++ .../rest/client/reactive/proxy/ProxyTest.java | 34 ++++++++++---- .../client/reactive/proxy/ProxyTestBase.java | 2 + .../proxy/SystemPropertyProxyTest.java | 15 ++++++- .../SystemPropertyProxyWithAuthTest.java | 1 + ...obal-non-proxy-test-application.properties | 4 ++ .../proxy-test-application.properties | 9 ++++ .../runtime/RestClientBuilderImpl.java | 19 ++++++-- .../runtime/RestClientCDIDelegateBuilder.java | 20 ++++++--- .../RestClientCDIDelegateBuilderTest.java | 1 + .../client/impl/ClientBuilderImpl.java | 45 +++++++++++++++---- 16 files changed, 219 insertions(+), 33 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client5.java create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client6.java create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/global-non-proxy-test-application.properties diff --git a/docs/src/main/asciidoc/rest-client-reactive.adoc b/docs/src/main/asciidoc/rest-client-reactive.adoc index 32ffec31efeae..1e67b5df361eb 100644 --- a/docs/src/main/asciidoc/rest-client-reactive.adoc +++ b/docs/src/main/asciidoc/rest-client-reactive.adoc @@ -702,9 +702,15 @@ All the available modes are described in the link:https://netty.io/4.1/api/io/ne REST Client Reactive supports sending requests through a proxy. It honors the JVM settings for it but also allows to specify both: -* global client proxy settings, with `quarkus.rest-client.proxy-address`, `quarkus.rest-client.proxy-user`, `quarkus.rest-client.proxy-password` +* global client proxy settings, with `quarkus.rest-client.proxy-address`, `quarkus.rest-client.proxy-user`, `quarkus.rest-client.proxy-password`, `quarkus.rest-client.non-proxy-hosts` + +* per-client proxy settings, with `quarkus.rest-client..proxy-address`, etc. These are applied only to clients injected with CDI, that is the ones created with `@RegisterRestClient` + +If `proxy-address` is set on the client level, the client uses its specific proxy settings. No proxy settings are propagated from the global configuration or JVM properties. + +If `proxy-address` is not set for the client but is set on the global level, the client uses the global settings. +Otherwise, the client uses the JVM settings. -* per-client proxy settings, with `quarkus.rest-client..proxy-address`, etc An example configuration for setting proxy: @@ -714,6 +720,7 @@ An example configuration for setting proxy: quarkus.rest-client.proxy-address=localhost:8182 quarkus.rest-client.proxy-user= quarkus.rest-client.proxy-password= +quarkus.rest-client.non-proxy-hosts=example.com # per-client configuration overrides the global settings for a specific client quarkus.rest-client.my-client.proxy-address=localhost:8183 diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientConfig.java b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientConfig.java index a90150473e64f..db678c7bb877e 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientConfig.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientConfig.java @@ -29,6 +29,7 @@ public class RestClientConfig { EMPTY.proxyAddress = Optional.empty(); EMPTY.proxyUser = Optional.empty(); EMPTY.proxyPassword = Optional.empty(); + EMPTY.nonProxyHosts = Optional.empty(); EMPTY.queryParamStyle = Optional.empty(); EMPTY.trustStore = Optional.empty(); EMPTY.trustStorePassword = Optional.empty(); @@ -93,6 +94,8 @@ public class RestClientConfig { /** * A string value in the form of `:` that specifies the HTTP proxy server hostname * (or IP address) and port for requests of this client to use. + * + * Use `none` to disable proxy */ @ConfigItem public Optional proxyAddress; @@ -113,6 +116,14 @@ public class RestClientConfig { @ConfigItem public Optional proxyPassword; + /** + * Hosts to access without proxy + * + * This property is applicable to reactive REST clients only. + */ + @ConfigItem + public Optional nonProxyHosts; + /** * An enumerated type string value with possible values of "MULTI_PAIRS" (default), "COMMA_SEPARATED", * or "ARRAY_PAIRS" that specifies the format in which multiple values for the same query parameter is used. @@ -202,6 +213,7 @@ public static RestClientConfig load(String configKey) { instance.proxyAddress = getConfigValue(configKey, "proxy-address", String.class); instance.proxyUser = getConfigValue(configKey, "proxy-user", String.class); instance.proxyPassword = getConfigValue(configKey, "proxy-password", String.class); + instance.nonProxyHosts = getConfigValue(configKey, "non-proxy-hosts", String.class); instance.queryParamStyle = getConfigValue(configKey, "query-param-style", QueryParamStyle.class); instance.trustStore = getConfigValue(configKey, "trust-store", String.class); instance.trustStorePassword = getConfigValue(configKey, "trust-store-password", String.class); @@ -231,6 +243,7 @@ public static RestClientConfig load(Class interfaceClass) { instance.proxyAddress = getConfigValue(interfaceClass, "proxy-address", String.class); instance.proxyUser = getConfigValue(interfaceClass, "proxy-user", String.class); instance.proxyPassword = getConfigValue(interfaceClass, "proxy-password", String.class); + instance.nonProxyHosts = getConfigValue(interfaceClass, "non-proxy-hosts", String.class); instance.queryParamStyle = getConfigValue(interfaceClass, "query-param-style", QueryParamStyle.class); instance.trustStore = getConfigValue(interfaceClass, "trust-store", String.class); instance.trustStorePassword = getConfigValue(interfaceClass, "trust-store-password", String.class); diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java index 5386012582ba5..eae41728e869f 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/main/java/io/quarkus/restclient/config/RestClientsConfig.java @@ -65,7 +65,7 @@ public class RestClientsConfig { public Optional proxyAddress; /** - * Proxy username, equivalent to the http.proxy or https.proxy system property + * Proxy username, equivalent to the http.proxy or https.proxy JVM settings. * * This property is applicable to reactive REST clients only. */ @@ -73,13 +73,22 @@ public class RestClientsConfig { public Optional proxyUser; /** - * Proxy password, equivalent to the http.proxyPassword or https.proxyPassword system property + * Proxy password, equivalent to the http.proxyPassword or https.proxyPassword JVM settings. * * This property is applicable to reactive REST clients only. */ @ConfigItem public Optional proxyPassword; + /** + * Hosts to access without proxy, similar to the http.nonProxyHosts or https.nonProxyHosts JVM settings. + * Please note that unlike the JVM settings, this property is empty by default + * + * This property is applicable to reactive REST clients only. + */ + @ConfigItem + public Optional nonProxyHosts; + public RestClientLoggingConfig logging; public RestClientConfig getClientConfig(String configKey) { diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client5.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client5.java new file mode 100644 index 0000000000000..35d7181208745 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client5.java @@ -0,0 +1,14 @@ +package io.quarkus.rest.client.reactive.proxy; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "client5") +@Path("/resource") +public interface Client5 { + @GET + Response get(); +} diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client6.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client6.java new file mode 100644 index 0000000000000..2eb7cb7c6d3a8 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/Client6.java @@ -0,0 +1,14 @@ +package io.quarkus.rest.client.reactive.proxy; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Response; + +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@RegisterRestClient(configKey = "client6") +@Path("/resource") +public interface Client6 { + @GET + Response get(); +} diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java new file mode 100644 index 0000000000000..4dd2dcdb66146 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/GlobalNonProxyTest.java @@ -0,0 +1,37 @@ +package io.quarkus.rest.client.reactive.proxy; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.ws.rs.core.Response; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class GlobalNonProxyTest extends ProxyTestBase { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot( + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, + Client6.class, ViaHeaderReturningResource.class)) + .withConfigurationResource("global-non-proxy-test-application.properties"); + + @RestClient + Client1 client1; + + @Test + void shouldNotApplyProxyIfNonProxyMatches() { + assertThat(client1.get().readEntity(String.class)).isEqualTo(NO_PROXY); + } + + @Test + void shouldProxyBuilderWithPerClientSettings() { + Response response = RestClientBuilder.newBuilder().baseUri(appUri) + .build(Client1.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(NO_PROXY); + } +} diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java index 74b130861e792..8e3f10109129a 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTest.java @@ -20,8 +20,8 @@ public class ProxyTest extends ProxyTestBase { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot( - jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, - ViaHeaderReturningResource.class)) + jar -> jar.addClasses(Client1.class, Client2.class, Client3.class, Client4.class, Client5.class, + Client6.class, ViaHeaderReturningResource.class)) .withConfigurationResource("proxy-test-application.properties"); @RestClient @@ -32,6 +32,10 @@ public class ProxyTest extends ProxyTestBase { Client3 client3; @RestClient Client4 client4; + @RestClient + Client5 clientWithNonProxyHost; + @RestClient + Client6 clientWithProxyHostNone; @Test void shouldProxyCDIWithPerClientSettings() { @@ -39,20 +43,34 @@ void shouldProxyCDIWithPerClientSettings() { assertThat(client2.get().readEntity(String.class)).isEqualTo(PROXY_8181); assertThat(client3.get().readEntity(String.class)).isEqualTo(PROXY_8182); assertThat(client4.get().readEntity(String.class)).isEqualTo(AUTHENTICATED_PROXY); + assertThat(clientWithNonProxyHost.get().readEntity(String.class)).isEqualTo(NO_PROXY); + assertThat(clientWithProxyHostNone.get().readEntity(String.class)).isEqualTo(NO_PROXY); } @Test void shouldProxyBuilderWithPerClientSettings() { - Response response1 = RestClientBuilder.newBuilder().baseUri(appUri).proxyAddress("localhost", 8181) + Response response = RestClientBuilder.newBuilder().baseUri(appUri).proxyAddress("localhost", 8181) .build(Client1.class).get(); - assertThat(response1.readEntity(String.class)).isEqualTo(PROXY_8181); - Response response2 = RestClientBuilder.newBuilder().baseUri(appUri).build(Client2.class).get(); - assertThat(response2.readEntity(String.class)).isEqualTo(PROXY_8182); + assertThat(response.readEntity(String.class)).isEqualTo(PROXY_8181); + + response = RestClientBuilder.newBuilder().baseUri(appUri).build(Client2.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(PROXY_8182); RestClientBuilderImpl restClientBuilder = (RestClientBuilderImpl) RestClientBuilder.newBuilder(); - Response response3 = restClientBuilder.baseUri(appUri).proxyAddress("localhost", 8183) + response = restClientBuilder.baseUri(appUri).proxyAddress("localhost", 8183) .proxyUser("admin").proxyPassword("r00t") .build(Client1.class).get(); - assertThat(response3.readEntity(String.class)).isEqualTo(AUTHENTICATED_PROXY); + assertThat(response.readEntity(String.class)).isEqualTo(AUTHENTICATED_PROXY); + + restClientBuilder = (RestClientBuilderImpl) RestClientBuilder.newBuilder(); + response = restClientBuilder.baseUri(appUri).proxyAddress("localhost", 8183) + .proxyUser("admin").proxyPassword("r00t").nonProxyHosts("example.com|localhost") + .build(Client1.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(NO_PROXY); + + restClientBuilder = (RestClientBuilderImpl) RestClientBuilder.newBuilder(); + response = restClientBuilder.baseUri(appUri).proxyAddress("none", -1) + .build(Client1.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(NO_PROXY); } } diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTestBase.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTestBase.java index 09e4c02612780..69340cfe407dd 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTestBase.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/ProxyTestBase.java @@ -16,6 +16,8 @@ public abstract class ProxyTestBase { + public static final String NO_PROXY = "noProxy"; + public static final String PROXY_8181 = "proxyServer1"; public static final String PROXY_8182 = "proxyServer2"; public static final String AUTHENTICATED_PROXY = "authenticatedProxy"; diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java index a54ffb08a87f7..6cd30d2b8d37f 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.extension.RegisterExtension; import org.junitpioneer.jupiter.SetSystemProperty; +import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl; import io.quarkus.test.QuarkusUnitTest; public class SystemPropertyProxyTest extends ProxyTestBase { @@ -32,11 +33,21 @@ public class SystemPropertyProxyTest extends ProxyTestBase { @Test @SetSystemProperty(key = "http.proxyHost", value = "localhost") @SetSystemProperty(key = "http.proxyPort", value = "8182") + // the default nonProxyHosts skip proxying localhost + @SetSystemProperty(key = "http.nonProxyHosts", value = "example.com") void shouldProxyWithSystemProperties() { assertThat(client1.get().readEntity(String.class)).isEqualTo(PROXY_8182); assertThat(client2.get().readEntity(String.class)).isEqualTo(PROXY_8181); - Response response2 = RestClientBuilder.newBuilder().baseUri(appUri).build(Client2.class).get(); - assertThat(response2.readEntity(String.class)).isEqualTo(PROXY_8182); + Response response = RestClientBuilder.newBuilder().baseUri(appUri).build(Client2.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(PROXY_8182); + + response = RestClientBuilder.newBuilder().baseUri(appUri).build(Client2.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(PROXY_8182); + + RestClientBuilderImpl restClientBuilder = (RestClientBuilderImpl) RestClientBuilder.newBuilder(); + response = restClientBuilder.baseUri(appUri).proxyAddress("none", -1) + .build(Client2.class).get(); + assertThat(response.readEntity(String.class)).isEqualTo(NO_PROXY); } } diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java index c6dce4216ae4a..abd2f27960ce5 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/proxy/SystemPropertyProxyWithAuthTest.java @@ -34,6 +34,7 @@ public class SystemPropertyProxyWithAuthTest extends ProxyTestBase { @SetSystemProperty(key = "http.proxyPort", value = "8183") @SetSystemProperty(key = "http.proxyUser", value = "admin") @SetSystemProperty(key = "http.proxyPassword", value = "r00t") + @SetSystemProperty(key = "http.nonProxyHosts", value = "example.com") void shouldProxyWithCredentialsFromProperties() { assertThat(client1.get().readEntity(String.class)).isEqualTo(AUTHENTICATED_PROXY); assertThat(client2.get().readEntity(String.class)).isEqualTo(PROXY_8181); diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/global-non-proxy-test-application.properties b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/global-non-proxy-test-application.properties new file mode 100644 index 0000000000000..e58239792976c --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/global-non-proxy-test-application.properties @@ -0,0 +1,4 @@ +quarkus.rest-client.proxy-address=localhost:8182 +quarkus.rest-client.non-proxy-hosts=localhost + +quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}/ diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/proxy-test-application.properties b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/proxy-test-application.properties index 26dc817b5798f..1ca955b99cc2a 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/proxy-test-application.properties +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/resources/proxy-test-application.properties @@ -11,4 +11,13 @@ quarkus.rest-client.client4.proxy-user=admin quarkus.rest-client.client4.proxy-password=r00t quarkus.rest-client.client4.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client5.proxy-address=localhost:8183 +quarkus.rest-client.client5.proxy-user=admin +quarkus.rest-client.client5.proxy-password=r00t +quarkus.rest-client.client5.url=http://localhost:${quarkus.http.test-port:8081}/ +quarkus.rest-client.client5.non-proxy-hosts=localhost + +quarkus.rest-client.client6.proxy-address=none +quarkus.rest-client.client6.url=http://localhost:${quarkus.http.test-port:8081}/ + quarkus.rest-client.proxy-address=localhost:8182 diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java index 057320db5f169..75ccc5a9df55d 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java @@ -58,6 +58,7 @@ public class RestClientBuilderImpl implements RestClientBuilder { private Integer proxyPort; private String proxyUser; private String proxyPassword; + private String nonProxyHosts; @Override public RestClientBuilderImpl baseUrl(URL url) { @@ -116,7 +117,7 @@ public RestClientBuilderImpl proxyAddress(final String proxyHost, final int prox if (proxyHost == null) { throw new IllegalArgumentException("proxyHost must not be null"); } - if (proxyPort <= 0 || proxyPort > 65535) { + if ((proxyPort <= 0 || proxyPort > 65535) && !proxyHost.equals("none")) { throw new IllegalArgumentException("Invalid port number"); } this.proxyHost = proxyHost; @@ -135,6 +136,11 @@ public RestClientBuilderImpl proxyUser(String proxyUser) { return this; } + public RestClientBuilderImpl nonProxyHosts(String nonProxyHosts) { + this.nonProxyHosts = nonProxyHosts; + return this; + } + @Override public RestClientBuilderImpl executorService(ExecutorService executor) { throw new IllegalArgumentException("Specifying executor service is not supported. " + @@ -309,11 +315,11 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi clientBuilder.trustAll(trustAll); if (proxyHost != null) { - configureProxy(proxyHost, proxyPort, proxyUser, proxyPassword); + configureProxy(proxyHost, proxyPort, proxyUser, proxyPassword, nonProxyHosts); } else if (restClientsConfig.proxyAddress.isPresent()) { HostAndPort globalProxy = ProxyAddressUtil.parseAddress(restClientsConfig.proxyAddress.get()); configureProxy(globalProxy.host, globalProxy.port, restClientsConfig.proxyUser.orElse(null), - restClientsConfig.proxyPassword.orElse(null)); + restClientsConfig.proxyPassword.orElse(null), restClientsConfig.nonProxyHosts.orElse(null)); } ClientImpl client = clientBuilder.build(); WebTargetImpl target = (WebTargetImpl) client.target(uri); @@ -325,13 +331,18 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi } } - private void configureProxy(String proxyHost, Integer proxyPort, String proxyUser, String proxyPassword) { + private void configureProxy(String proxyHost, Integer proxyPort, String proxyUser, String proxyPassword, + String nonProxyHosts) { if (proxyHost != null) { clientBuilder.proxy(proxyHost, proxyPort); if (proxyUser != null && proxyPassword != null) { clientBuilder.proxyUser(proxyUser); clientBuilder.proxyPassword(proxyPassword); } + + if (nonProxyHosts != null) { + clientBuilder.nonProxyHosts(nonProxyHosts); + } } } diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java index 6c6a827dc6996..0c9ec25ba7941 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java @@ -113,13 +113,21 @@ private void configureProxy(RestClientBuilderImpl builder) { if (maybeProxy.isEmpty()) { return; } - ProxyAddressUtil.HostAndPort hostAndPort = ProxyAddressUtil.parseAddress(maybeProxy.get()); - builder.proxyAddress(hostAndPort.host, hostAndPort.port); - oneOf(clientConfigByClassName().proxyUser, clientConfigByConfigKey().proxyUser) - .ifPresent(builder::proxyUser); - oneOf(clientConfigByClassName().proxyPassword, clientConfigByConfigKey().proxyPassword) - .ifPresent(builder::proxyPassword); + String proxyAddress = maybeProxy.get(); + if (proxyAddress.equals("none")) { + builder.proxyAddress("none", 0); + } else { + ProxyAddressUtil.HostAndPort hostAndPort = ProxyAddressUtil.parseAddress(proxyAddress); + builder.proxyAddress(hostAndPort.host, hostAndPort.port); + + oneOf(clientConfigByClassName().proxyUser, clientConfigByConfigKey().proxyUser) + .ifPresent(builder::proxyUser); + oneOf(clientConfigByClassName().proxyPassword, clientConfigByConfigKey().proxyPassword) + .ifPresent(builder::proxyPassword); + oneOf(clientConfigByClassName().nonProxyHosts, clientConfigByConfigKey().nonProxyHosts) + .ifPresent(builder::nonProxyHosts); + } } private void configureQueryParamStyle(RestClientBuilder builder) { diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java index ff15f6e5dd38b..dda9ddf57eeb0 100644 --- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java +++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java @@ -108,6 +108,7 @@ private static RestClientsConfig createSampleConfiguration() { clientConfig.proxyAddress = Optional.of("localhost:1234"); clientConfig.proxyUser = Optional.of("admin"); clientConfig.proxyPassword = Optional.of("adm1n"); + clientConfig.nonProxyHosts = Optional.empty(); clientConfig.queryParamStyle = Optional.of(QueryParamStyle.COMMA_SEPARATED); clientConfig.trustStore = Optional.of(truststoreFile.getAbsolutePath()); clientConfig.trustStorePassword = Optional.of("truststorePassword"); diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java index ea1dec606107c..6ca8e156ec75f 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/ClientBuilderImpl.java @@ -17,6 +17,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.ws.rs.client.ClientBuilder; @@ -35,6 +36,7 @@ public class ClientBuilderImpl extends ClientBuilder { private static final ClientContextResolver CLIENT_CONTEXT_RESOLVER = ClientContextResolver.getInstance(); private static final char[] EMPTY_CHAR_ARARAY = new char[0]; + public static final String PIPE = Pattern.quote("|"); private ConfigurationImpl configuration; private HostnameVerifier hostnameVerifier; @@ -47,6 +49,7 @@ public class ClientBuilderImpl extends ClientBuilder { private int proxyPort; private String proxyPassword; private String proxyUser; + private String nonProxyHosts; private boolean followRedirects; private boolean trustAll; @@ -187,16 +190,19 @@ public ClientImpl build() { } if (proxyHost != null) { - ProxyOptions proxyOptions = new ProxyOptions() - .setHost(proxyHost) - .setPort(proxyPort); - if (proxyPassword != null && !proxyPassword.isBlank()) { - proxyOptions.setPassword(proxyPassword); - } - if (proxyUser != null && !proxyUser.isBlank()) { - proxyOptions.setUsername(proxyUser); + if (!"none".equals(proxyHost)) { + ProxyOptions proxyOptions = new ProxyOptions() + .setHost(proxyHost) + .setPort(proxyPort); + if (proxyPassword != null && !proxyPassword.isBlank()) { + proxyOptions.setPassword(proxyPassword); + } + if (proxyUser != null && !proxyUser.isBlank()) { + proxyOptions.setUsername(proxyUser); + } + options.setProxyOptions(proxyOptions); + configureNonProxyHosts(options, nonProxyHosts); } - options.setProxyOptions(proxyOptions); } else { String proxyHost = options.isSsl() ? System.getProperty("https.proxyHost", "none") @@ -204,6 +210,9 @@ public ClientImpl build() { String proxyPortAsString = options.isSsl() ? System.getProperty("https.proxyPort", "443") : System.getProperty("http.proxyPort", "80"); + String nonProxyHosts = options.isSsl() + ? System.getProperty("https.nonProxyHosts", "localhost|127.*|[::1]") + : System.getProperty("http.nonProxyHosts", "localhost|127.*|[::1]"); int proxyPort = Integer.parseInt(proxyPortAsString); if (!"none".equals(proxyHost)) { @@ -221,6 +230,9 @@ public ClientImpl build() { proxyOptions.setPassword(proxyPassword); } options.setProxyOptions(proxyOptions); + if (nonProxyHosts != null) { + configureNonProxyHosts(options, nonProxyHosts); + } } } @@ -238,6 +250,16 @@ public ClientImpl build() { } + private void configureNonProxyHosts(HttpClientOptions options, String nonProxyHosts) { + if (nonProxyHosts != null) { + for (String host : nonProxyHosts.split(PIPE)) { + if (!host.isBlank()) { + options.addNonProxyHost(host); + } + } + } + } + private Buffer asBuffer(KeyStore keyStore, char[] password) { if (keyStore != null) { ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -319,4 +341,9 @@ public ClientBuilderImpl setUserAgent(String userAgent) { this.userAgent = userAgent; return this; } + + public ClientBuilderImpl nonProxyHosts(String nonProxyHosts) { + this.nonProxyHosts = nonProxyHosts; + return this; + } }