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 7326f2195ab15..e7ca4f72868dc 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 @@ -365,6 +365,19 @@ interface RestClientMultipartConfig { */ @Deprecated OptionalInt maxChunkSize(); + + /** + * The threshold to use for the amount of data to store in memory for entities, up to {@code Long.MAX_VALUE}. See + * {@code dev.resteasy.entity.memory.threshold} in RESTEasy documentation. + */ + Optional memoryThreshold(); + + /** + * The threshold to use for the amount of data that can be stored in a file for entities. If the threshold is reached an + * IllegalStateException will be thrown. A value of -1 means no limit, up to {@code Long.MAX_VALUE}. See + * {@code dev.resteasy.entity.file.threshold } in RESTEasy documentation. + */ + Optional fileThreshold(); } interface RestClientConfig { diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java index f14db6f12e04d..fa70cde6a10ee 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/java/io/quarkus/restclient/config/RestClientConfigTest.java @@ -17,6 +17,7 @@ import io.quarkus.restclient.config.key.SharedThreeConfigKeyRestClient; import io.quarkus.restclient.config.key.SharedTwoConfigKeyRestClient; import io.quarkus.runtime.configuration.ConfigUtils; +import io.quarkus.runtime.configuration.MemorySizeConverter; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SmallRyeConfigBuilderCustomizer; @@ -371,5 +372,9 @@ private void verifyConfig(RestClientConfig config) { assertThat(config.connectionPoolSize().getAsInt()).isEqualTo(10); assertTrue(config.maxChunkSize().isPresent()); assertThat(config.maxChunkSize().get().asBigInteger()).isEqualTo(BigInteger.valueOf(1024)); + assertThat(config.multipart().fileThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("5M").asBigInteger()); + assertThat(config.multipart().memoryThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("10M").asBigInteger()); } } diff --git a/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties b/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties index 8e4560a7ddb65..3db996720b49a 100644 --- a/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties +++ b/extensions/resteasy-classic/rest-client-config/runtime/src/test/resources/application.properties @@ -14,6 +14,8 @@ quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".hostname-v quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".connection-ttl=30000 quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".connection-pool-size=10 quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".max-chunk-size=1024 +quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".multipart.file-threshold=5M +quarkus.rest-client."io.quarkus.restclient.config.FullNameRestClient".multipart.memory-threshold=10M quarkus.rest-client.key.removes-trailing-slash=false quarkus.rest-client.key.url=http://localhost:8080 @@ -29,6 +31,8 @@ quarkus.rest-client.key.hostname-verifier=io.quarkus.restclient.configuration.My quarkus.rest-client.key.connection-ttl=30000 quarkus.rest-client.key.connection-pool-size=10 quarkus.rest-client.key.max-chunk-size=1024 +quarkus.rest-client.key.multipart.file-threshold=5M +quarkus.rest-client.key.multipart.memory-threshold=10M quarkus.rest-client."io.quarkus.restclient.config.MPRestClient".url=http://localhost:8080 io.quarkus.restclient.config.MPRestClient/mp-rest/url=http://localhost:8081 diff --git a/extensions/resteasy-classic/resteasy-client/deployment/src/test/java/io/quarkus/restclient/configuration/GlobalConfigurationTest.java b/extensions/resteasy-classic/resteasy-client/deployment/src/test/java/io/quarkus/restclient/configuration/GlobalConfigurationTest.java index be3f925d41818..9aa134df3561f 100644 --- a/extensions/resteasy-classic/resteasy-client/deployment/src/test/java/io/quarkus/restclient/configuration/GlobalConfigurationTest.java +++ b/extensions/resteasy-classic/resteasy-client/deployment/src/test/java/io/quarkus/restclient/configuration/GlobalConfigurationTest.java @@ -17,6 +17,7 @@ import io.quarkus.arc.Arc; import io.quarkus.restclient.config.RestClientsConfig; +import io.quarkus.runtime.configuration.MemorySizeConverter; import io.quarkus.test.QuarkusUnitTest; public class GlobalConfigurationTest { @@ -79,5 +80,9 @@ void checkGlobalConfigValues() { assertThat(configRoot.keyStore().get()).isEqualTo("/path"); assertThat(configRoot.keyStorePassword().get()).isEqualTo("password"); assertThat(configRoot.keyStoreType().get()).isEqualTo("JKS"); + assertThat(configRoot.multipart().fileThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("5M").asBigInteger()); + assertThat(configRoot.multipart().memoryThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("10M").asBigInteger()); } } diff --git a/extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java b/extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java index be8578fb19378..f2b8cf1e26f6f 100644 --- a/extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java +++ b/extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java @@ -29,6 +29,7 @@ import io.quarkus.restclient.NoopHostnameVerifier; import io.quarkus.restclient.config.RestClientsConfig; import io.quarkus.restclient.config.RestClientsConfig.RestClientConfig; +import io.quarkus.runtime.configuration.MemorySize; import io.smallrye.config.SmallRyeConfig; public class RestClientBase { @@ -93,6 +94,20 @@ protected void configureCustomProperties(RestClientBuilder builder) { builder.property("resteasy.connectionTTL", Arrays.asList(connectionTTL.getAsInt(), TimeUnit.MILLISECONDS)); } + + Optional fileThreshold = oneOf(restClientConfig.multipart().fileThreshold(), + configRoot.multipart().fileThreshold()); + if (fileThreshold.isPresent()) { + builder.property("dev.resteasy.entity.file.threshold", + fileThreshold.get().asLongValue()); + } + + Optional memoryThreshold = oneOf(restClientConfig.multipart().memoryThreshold(), + configRoot.multipart().memoryThreshold()); + if (memoryThreshold.isPresent()) { + builder.property("dev.resteasy.entity.memory.threshold", + memoryThreshold.get().asLongValue()); + } } protected void configureProxy(RestClientBuilder builder) { diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/ConfigurationTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/ConfigurationTest.java index c511ce2b5d08f..d42dd9949fc15 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/ConfigurationTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/ConfigurationTest.java @@ -22,6 +22,7 @@ import io.quarkus.arc.Arc; import io.quarkus.rest.client.reactive.configuration.EchoResource; import io.quarkus.restclient.config.RestClientsConfig; +import io.quarkus.runtime.configuration.MemorySizeConverter; import io.quarkus.test.QuarkusUnitTest; class ConfigurationTest { @@ -91,6 +92,10 @@ private void verifyClientConfig(RestClientsConfig.RestClientConfig clientConfig, assertThat(clientConfig.followRedirects().get()).isEqualTo(true); assertTrue(clientConfig.queryParamStyle().isPresent()); assertThat(clientConfig.queryParamStyle().get()).isEqualTo(QueryParamStyle.COMMA_SEPARATED); + assertThat(clientConfig.multipart().fileThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("5M").asBigInteger()); + assertThat(clientConfig.multipart().memoryThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("10M").asBigInteger()); if (checkExtraProperties) { assertTrue(clientConfig.connectionTTL().isPresent()); diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/GlobalConfigurationTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/GlobalConfigurationTest.java index 7f20bad31caaa..efb230be3f72d 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/GlobalConfigurationTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/GlobalConfigurationTest.java @@ -18,6 +18,7 @@ import io.quarkus.arc.Arc; import io.quarkus.rest.client.reactive.configuration.EchoResource; import io.quarkus.restclient.config.RestClientsConfig; +import io.quarkus.runtime.configuration.MemorySizeConverter; import io.quarkus.test.QuarkusUnitTest; public class GlobalConfigurationTest { @@ -78,5 +79,9 @@ void checkGlobalConfigValues() { assertThat(configRoot.keyStore().get()).isEqualTo("/path"); assertThat(configRoot.keyStorePassword().get()).isEqualTo("password"); assertThat(configRoot.keyStoreType().get()).isEqualTo("JKS"); + assertThat(configRoot.multipart().fileThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("5M").asBigInteger()); + assertThat(configRoot.multipart().memoryThreshold().get().asBigInteger()) + .isEqualTo(new MemorySizeConverter().convert("10M").asBigInteger()); } } 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 ffccf1c9e9701..b7cbd852c5c70 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 @@ -49,6 +49,7 @@ import io.quarkus.arc.InstanceHandle; import io.quarkus.rest.client.reactive.runtime.ProxyAddressUtil.HostAndPort; import io.quarkus.restclient.config.RestClientsConfig; +import io.quarkus.runtime.configuration.MemorySize; import io.quarkus.tls.TlsConfiguration; import io.smallrye.config.SmallRyeConfig; import io.vertx.core.net.KeyCertOptions; @@ -527,6 +528,24 @@ public T build(Class aClass) throws IllegalStateException, RestClientDefi clientBuilder.maxChunkSize(DEFAULT_MAX_CHUNK_SIZE); } + MemorySize fileThreshold = (MemorySize) getConfiguration() + .getProperty(QuarkusRestClientProperties.MULTIPART_FILE_THRESHOLD); + if (fileThreshold != null) { + property("dev.resteasy.entity.file.threshold", fileThreshold.asLongValue()); + } else if (restClients.multipart().fileThreshold().isPresent()) { + property("dev.resteasy.entity.file.threshold", + restClients.multipart().fileThreshold().get().asLongValue()); + } + + MemorySize memoryThreshold = (MemorySize) getConfiguration() + .getProperty(QuarkusRestClientProperties.MULTIPART_MEMORY_THRESHOLD); + if (memoryThreshold != null) { + property("dev.resteasy.entity.memory.threshold", memoryThreshold.asLongValue()); + } else if (restClients.multipart().memoryThreshold().isPresent()) { + property("dev.resteasy.entity.memory.threshold", + restClients.multipart().memoryThreshold().get().asLongValue()); + } + if (getConfiguration().hasProperty(QuarkusRestClientProperties.HTTP2)) { clientBuilder.http2((Boolean) getConfiguration().getProperty(QuarkusRestClientProperties.HTTP2)); } else if (restClients.http2()) { 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 123166db0d107..c3afed282567f 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 @@ -148,6 +148,20 @@ private void configureCustomProperties(QuarkusRestClientBuilder builder) { : Optional.empty()); builder.property(QuarkusRestClientProperties.MAX_CHUNK_SIZE, maxChunkSize.orElse(DEFAULT_MAX_CHUNK_SIZE)); + Optional fileThreshold = oneOf(restClientConfig.multipart().fileThreshold(), + configRoot.multipart().fileThreshold()); + if (fileThreshold.isPresent()) { + builder.property("dev.resteasy.entity.file.threshold", + fileThreshold.get().asLongValue()); + } + + Optional memoryThreshold = oneOf(restClientConfig.multipart().memoryThreshold(), + configRoot.multipart().memoryThreshold()); + if (memoryThreshold.isPresent()) { + builder.property("dev.resteasy.entity.memory.threshold", + memoryThreshold.get().asLongValue()); + } + Optional enableCompressions = oneOf(restClientConfig.enableCompression(), configRoot.enableCompression()); if (enableCompressions.isPresent()) { builder.enableCompression(enableCompressions.get()); diff --git a/extensions/resteasy-reactive/rest-client/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java b/extensions/resteasy-reactive/rest-client/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java index 1c622fe39aeb7..3de8ed0173d31 100644 --- a/extensions/resteasy-reactive/rest-client/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java +++ b/extensions/resteasy-reactive/rest-client/runtime/src/test/java/io/quarkus/rest/client/reactive/runtime/RestClientCDIDelegateBuilderTest.java @@ -44,6 +44,7 @@ import io.quarkus.restclient.config.RegisteredRestClient; import io.quarkus.restclient.config.RestClientsConfig; import io.quarkus.runtime.configuration.ConfigUtils; +import io.quarkus.runtime.configuration.MemorySizeConverter; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SmallRyeConfigBuilderCustomizer; @@ -143,6 +144,10 @@ public List getRestClients() { verify(restClientBuilderMock).property(KEEP_ALIVE_ENABLED, false); verify(restClientBuilderMock).property(MAX_REDIRECTS, 104); verify(restClientBuilderMock).property(MAX_CHUNK_SIZE, 1024); + verify(restClientBuilderMock).property("dev.resteasy.entity.file.threshold", + new MemorySizeConverter().convert("50M").asLongValue()); + verify(restClientBuilderMock).property("dev.resteasy.entity.memory.threshold", + new MemorySizeConverter().convert("100M").asLongValue()); verify(restClientBuilderMock).followRedirects(true); verify(restClientBuilderMock).register(MyResponseFilter1.class); verify(restClientBuilderMock).queryParamStyle(COMMA_SEPARATED); @@ -197,6 +202,10 @@ public List getRestClients() { verify(restClientBuilderMock).property(KEEP_ALIVE_ENABLED, true); verify(restClientBuilderMock).property(MAX_REDIRECTS, 204); verify(restClientBuilderMock).property(MAX_CHUNK_SIZE, 1024); + verify(restClientBuilderMock).property("dev.resteasy.entity.file.threshold", + new MemorySizeConverter().convert("5M").asLongValue()); + verify(restClientBuilderMock).property("dev.resteasy.entity.memory.threshold", + new MemorySizeConverter().convert("10M").asLongValue()); verify(restClientBuilderMock).followRedirects(true); verify(restClientBuilderMock).register(MyResponseFilter2.class); verify(restClientBuilderMock).queryParamStyle(MULTI_PAIRS); @@ -224,6 +233,8 @@ private static Map createSampleConfigRoot() { rootConfig.put("quarkus.rest-client.keep-alive-enabled", "true"); rootConfig.put("quarkus.rest-client.max-redirects", "204"); rootConfig.put("quarkus.rest-client.multipart-max-chunk-size", "1024"); + rootConfig.put("quarkus.rest-client.multipart.file-threshold", "5M"); + rootConfig.put("quarkus.rest-client.multipart.memory-threshold", "10M"); rootConfig.put("quarkus.rest-client.follow-redirects", "true"); rootConfig.put("quarkus.rest-client.max-chunk-size", "1024"); rootConfig.put("quarkus.rest-client.providers", @@ -260,6 +271,8 @@ private static Map createSampleClientConfig(final String restCli clientConfig.put("quarkus.rest-client." + restClientName + ".max-redirects", "104"); clientConfig.put("quarkus.rest-client." + restClientName + ".follow-redirects", "true"); clientConfig.put("quarkus.rest-client." + restClientName + ".max-chunk-size", "1024"); + clientConfig.put("quarkus.rest-client." + restClientName + ".multipart.file-threshold", "50M"); + clientConfig.put("quarkus.rest-client." + restClientName + ".multipart.memory-threshold", "100M"); clientConfig.put("quarkus.rest-client." + restClientName + ".providers", "io.quarkus.rest.client.reactive.runtime.RestClientCDIDelegateBuilderTest$MyResponseFilter1"); clientConfig.put("quarkus.rest-client." + restClientName + ".query-param-style", "comma-separated"); 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 345f32aa66a96..3b90e0bb0e491 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 @@ -9,6 +9,15 @@ public class QuarkusRestClientProperties { */ public static final String MAX_CHUNK_SIZE = "io.quarkus.rest.client.max-chunk-size"; + /** + * Configure the threshold to use for the amount of data to store in memory for entities. + */ + public static final String MULTIPART_FILE_THRESHOLD = "io.quarkus.rest.client.multipart.file-threshold"; + /** + * Configure the threshold to use for the amount of data that can be stored in a file for entities. + */ + public static final String MULTIPART_MEMORY_THRESHOLD = "io.quarkus.rest.client.multipart.memory-threshold"; + /** * Configure the connect timeout in ms. */ diff --git a/integration-tests/rest-client-reactive-multipart/src/main/resources/application.properties b/integration-tests/rest-client-reactive-multipart/src/main/resources/application.properties index ee23fa191a064..e986a95e03679 100644 --- a/integration-tests/rest-client-reactive-multipart/src/main/resources/application.properties +++ b/integration-tests/rest-client-reactive-multipart/src/main/resources/application.properties @@ -2,5 +2,7 @@ multipart-client/mp-rest/url=${test.url} multipart-chunks-client/mp-rest/url=${test.url} quarkus.rest-client.multipart-chunks-client.max-chunk-size=1000 +quarkus.rest-client.multipart-chunks-client.multipart.file-threshold=5M +quarkus.rest-client.multipart-chunks-client.multipart.memory-threshold=10M -quarkus.rest.jackson.optimization.enable-reflection-free-serializers=true \ No newline at end of file +quarkus.rest.jackson.optimization.enable-reflection-free-serializers=true