From eccb08dc1ba0c455b46308053de1b50d32cf7531 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Fri, 21 Feb 2025 11:33:36 +0200 Subject: [PATCH] Allow more fine-grained control of compression setting for REST Client Closes: #46415 --- docs/src/main/asciidoc/rest-client.adoc | 15 +++++++++++- .../restclient/config/RestClientsConfig.java | 20 ++++++++++++++++ ...singGzipCompressionGlobalSettingTest.java} | 5 ++-- .../client-using-gzip-application.properties | 3 --- .../reactive/QuarkusRestClientBuilder.java | 7 ++++++ .../runtime/QuarkusRestClientBuilderImpl.java | 6 +++++ .../runtime/RestClientBuilderImpl.java | 24 +++++++++++++++---- .../runtime/RestClientCDIDelegateBuilder.java | 5 ++++ .../client/impl/ClientBuilderImpl.java | 8 +++---- 9 files changed, 79 insertions(+), 14 deletions(-) rename extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/{ClientUsingGzipCompressionTest.java => ClientUsingGzipCompressionGlobalSettingTest.java} (88%) delete mode 100644 extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/resources/client-using-gzip-application.properties diff --git a/docs/src/main/asciidoc/rest-client.adoc b/docs/src/main/asciidoc/rest-client.adoc index 1b717a9ab9478..0c87dcfc3c032 100644 --- a/docs/src/main/asciidoc/rest-client.adoc +++ b/docs/src/main/asciidoc/rest-client.adoc @@ -1755,9 +1755,22 @@ The code uses the following pieces: As previously mentioned, the body parameter needs to be properly crafted by the application code to conform to the service's requirements. === Receiving compressed messages -REST Client also supports receiving compressed messages using GZIP. You can enable the HTTP compression support by adding the property `quarkus.http.enable-compression=true`. +REST Client also supports receiving compressed messages using GZIP and can be enabled via configuration. When this feature is enabled and a server returns a response that includes the header `Content-Encoding: gzip`, REST Client will automatically decode the content and proceed with the message handling. +An example configuration could be: + +[source,properties] +---- +# global configuration is used for all clients +quarkus.rest-client.enable-compression=true + +# per-client configuration overrides the global settings for a specific client +quarkus.rest-client.my-client.enable-compression=true +---- + +The REST Client falls back onto the Quarkus wide `quarkus.http.enable-compression` configuration property (which defaults to `false`) if no REST Client specific property is set. + == Proxy support REST Client supports sending requests through a proxy. It honors the JVM settings for it but also allows to specify both: 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 cc1b122067830..0a70cf7750628 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 @@ -281,6 +281,17 @@ public interface RestClientsConfig { @ConfigDocDefault("8k") Optional maxChunkSize(); + /** + * Supports receiving compressed messages using GZIP. + * When this feature is enabled and a server returns a response that includes the header {@code Content-Encoding: gzip}, + * REST Client will automatically decode the content and proceed with the message handling. + *

+ * This property is not applicable to the RESTEasy Client. + *

+ * Can be overwritten by client-specific settings. + */ + Optional enableCompression(); + /** * If the Application-Layer Protocol Negotiation is enabled, the client will negotiate which protocol to use over the * protocols exposed by the server. By default, it will try to use HTTP/2 first and if it's not enabled, it will @@ -600,6 +611,15 @@ default Optional uriReload() { @ConfigDocDefault("8K") Optional maxChunkSize(); + /** + * Supports receiving compressed messages using GZIP. + * When this feature is enabled and a server returns a response that includes the header {@code Content-Encoding: gzip}, + * REST Client will automatically decode the content and proceed with the message handling. + *

+ * This property is not applicable to the RESTEasy Client. + */ + Optional enableCompression(); + /** * If the Application-Layer Protocol Negotiation is enabled, the client will negotiate which protocol to use over the * protocols exposed by the server. By default, it will try to use HTTP/2 first and if it's not enabled, it will diff --git a/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionTest.java b/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionGlobalSettingTest.java similarity index 88% rename from extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionTest.java rename to extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionGlobalSettingTest.java index e40abad557070..c3e32300dc674 100644 --- a/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionTest.java +++ b/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/java/io/quarkus/rest/client/reactive/jackson/test/ClientUsingGzipCompressionGlobalSettingTest.java @@ -15,12 +15,13 @@ import io.quarkus.test.QuarkusUnitTest; import io.quarkus.vertx.http.Compressed; -public class ClientUsingGzipCompressionTest { +public class ClientUsingGzipCompressionGlobalSettingTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClasses(MyResource.class, Message.class, MyClient.class)) - .withConfigurationResource("client-using-gzip-application.properties"); + .overrideConfigKey("quarkus.http.enable-compression", "true") + .overrideRuntimeConfigKey("quarkus.rest-client.my-client.url", "http://localhost:${quarkus.http.test-port:8081}"); @RestClient MyClient client; diff --git a/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/resources/client-using-gzip-application.properties b/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/resources/client-using-gzip-application.properties deleted file mode 100644 index 98de043b07b81..0000000000000 --- a/extensions/resteasy-reactive/rest-client-jackson/deployment/src/test/resources/client-using-gzip-application.properties +++ /dev/null @@ -1,3 +0,0 @@ -quarkus.http.enable-compression=true - -quarkus.rest-client.my-client.url=http://localhost:${quarkus.http.test-port:8081} \ No newline at end of file diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java index 6ed77f572ee65..bf3667af5dd50 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java @@ -304,6 +304,13 @@ static QuarkusRestClientBuilder newBuilder() { */ QuarkusRestClientBuilder disableDefaultMapper(Boolean disable); + /** + * Supports receiving compressed messages using GZIP. + * When this feature is enabled and a server returns a response that includes the header {@code Content-Encoding: gzip}, + * REST Client will automatically decode the content and proceed with the message handling. + */ + QuarkusRestClientBuilder enableCompression(boolean enableCompression); + /** * Based on the configured QuarkusRestClientBuilder, creates a new instance of the given REST interface to invoke API calls * against. diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java index f05460ea975d9..54c30ab0b9b5b 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java @@ -268,6 +268,12 @@ public QuarkusRestClientBuilder disableDefaultMapper(Boolean disable) { return this; } + @Override + public QuarkusRestClientBuilder enableCompression(boolean enableCompression) { + proxy.enableCompression(enableCompression); + return this; + } + @Override public T build(Class clazz) throws IllegalStateException, RestClientDefinitionException { return proxy.build(clazz); diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java index cf3f7623d7109..b6b1938611342 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java @@ -89,6 +89,7 @@ public class RestClientBuilderImpl implements RestClientBuilder { private Boolean trustAll; private String userAgent; private Boolean disableDefaultMapper; + private Boolean enableCompression; @Override public RestClientBuilderImpl baseUrl(URL url) { @@ -266,6 +267,11 @@ public RestClientBuilderImpl disableDefaultMapper(Boolean disableDefaultMapper) return this; } + public RestClientBuilderImpl enableCompression(boolean enableCompression) { + this.enableCompression = enableCompression; + return this; + } + @Override public RestClientBuilderImpl executorService(ExecutorService executor) { throw new IllegalArgumentException("Specifying executor service is not supported. " + @@ -533,10 +539,20 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi clientBuilder.alpn(restClients.alpn().get()); } - Boolean enableCompression = ConfigProvider.getConfig() - .getOptionalValue(ENABLE_COMPRESSION, Boolean.class).orElse(false); - if (enableCompression) { - clientBuilder.enableCompression(); + Boolean effectiveEnableCompression = enableCompression; + if (effectiveEnableCompression == null) { + if (restClients.enableCompression().isPresent()) { + effectiveEnableCompression = restClients.enableCompression().get(); + } + } + if (effectiveEnableCompression == null) { + var maybeGlobalEnableCompression = ConfigProvider.getConfig().getOptionalValue(ENABLE_COMPRESSION, Boolean.class); + if (maybeGlobalEnableCompression.isPresent()) { + effectiveEnableCompression = maybeGlobalEnableCompression.get(); + } + } + if (effectiveEnableCompression != null) { + clientBuilder.enableCompression(effectiveEnableCompression); } if (proxyHost != null) { diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java index 76da3d6cf3ab0..bd933b7219118 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilder.java @@ -143,6 +143,11 @@ private void configureCustomProperties(QuarkusRestClientBuilder builder) { configRoot.multipart().maxChunkSize()); builder.property(QuarkusRestClientProperties.MAX_CHUNK_SIZE, maxChunkSize.orElse(DEFAULT_MAX_CHUNK_SIZE)); + Optional enableCompressions = oneOf(restClientConfig.enableCompression(), configRoot.enableCompression()); + if (enableCompressions.isPresent()) { + builder.enableCompression(enableCompressions.get()); + } + Boolean http2 = oneOf(restClientConfig.http2()).orElse(configRoot.http2()); builder.property(QuarkusRestClientProperties.HTTP2, http2); 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 290134c5a752b..a9b35a4753f02 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 @@ -82,7 +82,7 @@ public class ClientBuilderImpl extends ClientBuilder { private ClientLogger clientLogger = new DefaultClientLogger(); private String userAgent = RestClientRequestContext.DEFAULT_USER_AGENT_VALUE; - private boolean enableCompression; + private Boolean enableCompression; public ClientBuilderImpl() { configuration = new ConfigurationImpl(RuntimeType.CLIENT); @@ -202,8 +202,8 @@ public ClientBuilder clientLogger(ClientLogger clientLogger) { return this; } - public ClientBuilder enableCompression() { - this.enableCompression = true; + public ClientBuilder enableCompression(boolean enableCompression) { + this.enableCompression = enableCompression; return this; } @@ -278,7 +278,7 @@ public ClientImpl build() { } } - if (enableCompression) { + if (Boolean.TRUE.equals(enableCompression)) { configuration.register(ClientGZIPDecodingInterceptor.class); }