From 2a5317158f2b3129461dfe394249b6935db96a41 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 11 May 2022 15:37:26 +0300 Subject: [PATCH] Allow setting user-agent via configuration for the Reactive REST Client Closes: #25445 --- .../restclient/config/RestClientConfig.java | 11 +++ .../restclient/config/RestClientsConfig.java | 8 ++ .../headers/UserAgentFromConfigTest.java | 83 +++++++++++++++++++ .../runtime/RestClientBuilderImpl.java | 8 ++ .../runtime/RestClientCDIDelegateBuilder.java | 6 ++ .../RestClientCDIDelegateBuilderTest.java | 2 + .../api/QuarkusRestClientProperties.java | 2 + 7 files changed, 120 insertions(+) create mode 100644 extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UserAgentFromConfigTest.java 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 f0f87c0be37f8..4d833152a4c9f 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 @@ -44,6 +44,7 @@ public class RestClientConfig { EMPTY.headers = Collections.emptyMap(); EMPTY.shared = Optional.empty(); EMPTY.name = Optional.empty(); + EMPTY.userAgent = Optional.empty(); } /** @@ -220,6 +221,14 @@ public class RestClientConfig { @ConfigItem public Optional name; + /** + * Configure the HTTP user-agent header to use. + * + * This property is applicable to reactive REST clients only. + */ + @ConfigItem + public Optional userAgent; + public static RestClientConfig load(String configKey) { final RestClientConfig instance = new RestClientConfig(); @@ -248,6 +257,7 @@ public static RestClientConfig load(String configKey) { instance.headers = getConfigValues(configKey, "headers", String.class, String.class); instance.shared = getConfigValue(configKey, "shared", Boolean.class); instance.name = getConfigValue(configKey, "name", String.class); + instance.userAgent = getConfigValue(configKey, "user-agent", String.class); return instance; } @@ -280,6 +290,7 @@ public static RestClientConfig load(Class interfaceClass) { instance.headers = getConfigValues(interfaceClass, "headers", String.class, String.class); instance.shared = getConfigValue(interfaceClass, "shared", Boolean.class); instance.name = getConfigValue(interfaceClass, "name", String.class); + instance.userAgent = getConfigValue(interfaceClass, "user-agent", String.class); return instance; } 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 69919795a33a0..1e4a88c51db38 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 @@ -116,6 +116,14 @@ public class RestClientsConfig { @ConfigItem(defaultValue = "false") public boolean disableContextualErrorMessages; + /** + * Configure the HTTP user-agent header to use. + * + * This property is applicable to reactive REST clients only. + */ + @ConfigItem + public Optional userAgent; + public RestClientConfig getClientConfig(String configKey) { if (configKey == null) { return RestClientConfig.EMPTY; diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UserAgentFromConfigTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UserAgentFromConfigTest.java new file mode 100644 index 0000000000000..2fef92992e0d9 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/headers/UserAgentFromConfigTest.java @@ -0,0 +1,83 @@ +package io.quarkus.rest.client.reactive.headers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; + +import javax.enterprise.context.ApplicationScoped; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; + +public class UserAgentFromConfigTest { + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar.addClasses(Resource.class, Client.class) + .addAsResource(new StringAsset( + "quarkus.rest-client.user-agent=base\n" + + "quarkus.rest-client.client1.url=http://localhost:${quarkus.http.test-port:8081}\n" + + "quarkus.rest-client.client2.url=http://localhost:${quarkus.http.test-port:8081}\n" + + "quarkus.rest-client.client2.user-agent=specific"), + "application.properties")); + + @TestHTTPResource + URI baseUri; + + @RestClient + Client client; + + @RestClient + Client2 client2; + + @Test + void testProgrammatic() { + Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class); + assertThat(client.call()).isEqualTo("base"); + } + + @Test + void testBaseUserAgent() { + assertThat(client.call()).isEqualTo("base"); + } + + @Test + void testSpecificUserAgent() { + assertThat(client2.call()).isEqualTo("specific"); + } + + @Path("/") + @ApplicationScoped + public static class Resource { + @GET + public String returnHeaders(@HeaderParam("user-agent") String header) { + return header; + } + } + + @RegisterRestClient(configKey = "client1") + public interface Client { + + @Path("/") + @GET + String call(); + } + + @RegisterRestClient(configKey = "client2") + public interface Client2 { + + @Path("/") + @GET + String call(); + } + +} 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 5c54f60cc8693..12c830977b9c8 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 @@ -25,6 +25,7 @@ import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; import org.jboss.resteasy.reactive.client.api.InvalidRestClientDefinitionException; import org.jboss.resteasy.reactive.client.api.LoggingScope; +import org.jboss.resteasy.reactive.client.api.QuarkusRestClientProperties; import org.jboss.resteasy.reactive.client.impl.ClientBuilderImpl; import org.jboss.resteasy.reactive.client.impl.ClientImpl; import org.jboss.resteasy.reactive.client.impl.WebTargetImpl; @@ -314,6 +315,13 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi clientBuilder.trustAll(trustAll); + String userAgent = (String) getConfiguration().getProperty(QuarkusRestClientProperties.USER_AGENT); + if (userAgent != null) { + clientBuilder.setUserAgent(userAgent); + } else if (restClientsConfig.userAgent.isPresent()) { + clientBuilder.setUserAgent(restClientsConfig.userAgent.get()); + } + if (proxyHost != null) { configureProxy(proxyHost, proxyPort, proxyUser, proxyPassword, nonProxyHosts); } else if (restClientsConfig.proxyAddress.isPresent()) { 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 9e791616ec5da..22d3941be8489 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 @@ -107,6 +107,12 @@ private void configureCustomProperties(RestClientBuilder builder) { builder.property(QuarkusRestClientProperties.DISABLE_CONTEXTUAL_ERROR_MESSAGES, configRoot.disableContextualErrorMessages); + + Optional userAgent = oneOf(clientConfigByClassName().userAgent, + clientConfigByConfigKey().userAgent, configRoot.userAgent); + if (userAgent.isPresent()) { + builder.property(QuarkusRestClientProperties.USER_AGENT, userAgent.get()); + } } private void configureProxy(RestClientBuilderImpl 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 c43bb7d913dc5..f378ea58bf377 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 @@ -103,6 +103,7 @@ public void testGlobalTimeouts() { configRoot.connectTimeout = 5000L; configRoot.readTimeout = 10000L; configRoot.multipartPostEncoderMode = Optional.empty(); + configRoot.userAgent = Optional.empty(); RestClientBuilderImpl restClientBuilderMock = Mockito.mock(RestClientBuilderImpl.class); new RestClientCDIDelegateBuilder<>(TestClient.class, "http://localhost:8080", @@ -142,6 +143,7 @@ private static RestClientsConfig createSampleConfiguration() { clientConfig.headers = Collections.emptyMap(); clientConfig.shared = Optional.of(true); clientConfig.name = Optional.of("my-client"); + clientConfig.userAgent = Optional.of("rest-client"); RestClientsConfig configRoot = new RestClientsConfig(); configRoot.multipartPostEncoderMode = Optional.of("HTML5"); diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/api/QuarkusRestClientProperties.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/api/QuarkusRestClientProperties.java index 2511d4c10b2c5..a009850bddefb 100644 --- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/api/QuarkusRestClientProperties.java +++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/api/QuarkusRestClientProperties.java @@ -48,4 +48,6 @@ public class QuarkusRestClientProperties { */ public static final String DISABLE_CONTEXTUAL_ERROR_MESSAGES = "io.quarkus.rest.client.disable-contextual-error-messages"; + public static final String USER_AGENT = "io.quarkus.rest.client.user-agent"; + }