This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new cdd8cb07a68 Add sensible default value to attachment-max-size property
(#3188)
cdd8cb07a68 is described below
commit cdd8cb07a684708e570abec806dbf85c5055c238
Author: Andriy Redko <[email protected]>
AuthorDate: Mon Jun 8 12:05:45 2026 -0400
Add sensible default value to attachment-max-size property (#3188)
* Add sensible default value to attachment-max-size property
* Address code review comments
---
.../cxf/attachment/AttachmentDeserializer.java | 2 +
.../org/apache/cxf/attachment/AttachmentUtil.java | 33 ++++++++-------
.../cxf/attachment/AttachmentDeserializerTest.java | 22 ++++++++++
.../jaxrs/provider/FormEncodingProviderTest.java | 49 ++++++++++++++++++++++
.../cxf/systest/jaxrs/JAXRSEntityPartTest.java | 23 ++++++++++
5 files changed, 113 insertions(+), 16 deletions(-)
diff --git
a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
index d5c6409cb56..dc0e735315a 100644
--- a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
+++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java
@@ -61,6 +61,8 @@ public class AttachmentDeserializer {
* The maximum size of the attachment. Allowed value is any of {@link
Number} or {@link String}.
*/
public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size";
+ public static final long DEFAULT_ATTACHMENT_MAX_SIZE =
+ SystemPropertyAction.getInteger("org.apache.cxf.attachment-max-size",
50 * 1024 * 1024 /* 50 Mb */);
/**
* The maximum number of attachments permitted in a message. The default
is 50.
diff --git a/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
b/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
index 42cffc8c027..79f34d81101 100644
--- a/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
+++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
@@ -214,24 +214,25 @@ public final class AttachmentUtil {
}
Object maxSize =
message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_MAX_SIZE);
- if (maxSize != null) {
- if (maxSize instanceof Number) {
- long size = ((Number) maxSize).longValue();
- if (size >= 0) {
- bos.setMaxSize(size);
- } else {
- LOG.warning("Max size value overflowed long. Do not set
max size!");
- }
- } else if (maxSize instanceof String) {
- try {
- bos.setMaxSize(Long.parseLong((String) maxSize));
- } catch (NumberFormatException e) {
- throw new IOException("Provided threshold String is not a
number", e);
- }
+ if (maxSize == null) {
+ maxSize = AttachmentDeserializer.DEFAULT_ATTACHMENT_MAX_SIZE;
+ }
+ if (maxSize instanceof Number) {
+ long size = ((Number) maxSize).longValue();
+ if (size >= 0) {
+ bos.setMaxSize(size);
} else {
- throw new IOException("The value set as " +
AttachmentDeserializer.ATTACHMENT_MAX_SIZE
- + " should be either an instance of Number or String");
+ LOG.warning("The max size value is set to unlimited.");
}
+ } else if (maxSize instanceof String) {
+ try {
+ bos.setMaxSize(Long.parseLong((String) maxSize));
+ } catch (NumberFormatException e) {
+ throw new IOException("Provided max size String is not a
number", e);
+ }
+ } else {
+ throw new IOException("The value set as " +
AttachmentDeserializer.ATTACHMENT_MAX_SIZE
+ + " should be either an instance of Number or String");
}
}
diff --git
a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
index eec76dbba9c..1d6e2dd756e 100644
---
a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
+++
b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
@@ -31,7 +31,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import java.util.stream.LongStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
@@ -41,6 +43,7 @@ import org.xml.sax.helpers.DefaultHandler;
import jakarta.activation.DataSource;
import jakarta.activation.URLDataSource;
import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.CacheSizeExceededException;
import org.apache.cxf.message.Attachment;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
@@ -377,6 +380,25 @@ public class AttachmentDeserializerTest {
assertEquals(-1, m.read(new byte[1000]));
m.close();
}
+
+ @Test
+ public void testDefaultAttachmentMaxSize() throws Exception {
+ final byte[] messageBytes =
("------=_Part_1\n\nJJJJ\n------=_Part_1\n\n"
+ + "Content-Transfer-Encoding: binary\n\n" + LongStream
+ .range(0,
AttachmentDeserializer.DEFAULT_ATTACHMENT_MAX_SIZE / 3 + 1)
+ .mapToObj(i -> "=3D")
+ .collect(Collectors.joining())
+ + "\n------=_Part_1\n").getBytes();
+
+ msg = new MessageImpl();
+ msg.setContent(InputStream.class, new
ByteArrayInputStream(messageBytes));
+ msg.put(Message.CONTENT_TYPE, "multipart/related");
+ AttachmentDeserializer ad = new AttachmentDeserializer(msg);
+ ad.initializeAttachments();
+
+ // Force it to load the attachments
+ assertThrows(CacheSizeExceededException.class, () ->
msg.getAttachments().size());
+ }
@Test
public void testCXF2542() throws Exception {
diff --git
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java
index ffb489a7d64..c103bf6bd24 100644
---
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java
+++
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/provider/FormEncodingProviderTest.java
@@ -25,19 +25,34 @@ import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.Encoded;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Form;
import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedHashMap;
import jakarta.ws.rs.core.MultivaluedMap;
+import org.apache.cxf.Bus;
+import org.apache.cxf.attachment.AttachmentDeserializer;
+import org.apache.cxf.bus.extension.ExtensionManagerBus;
+import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.model.ProviderInfo;
import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
import org.junit.Test;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -141,6 +156,40 @@ public class FormEncodingProviderTest {
assertEquals("Wrong entry for baz", "4", mvMap.getFirst("baz"));
}
+
+ @Test
+ public void testWriteMultipartTooLarge() throws Exception {
+ final MultivaluedMap<String, String> headers = new
MultivaluedHashMap<>();
+ headers.add("Content-Transfer-Encoding", "binary");
+
+ final Bus bus = new ExtensionManagerBus();
+ final Message m = new MessageImpl();
+ m.put(AttachmentDeserializer.ATTACHMENT_PART_HEADERS, headers);
+ m.put(Message.CONTENT_TYPE, "multipart/related");
+
+ final ExchangeImpl exchange = new ExchangeImpl();
+ m.setExchange(exchange);
+ exchange.setInMessage(m);
+
+ FormEncodingProvider<MultipartBody> ferp = new
FormEncodingProvider<>();
+ InjectionUtils.injectContextFields(ferp, new ProviderInfo<>(ferp, bus,
false), m);
+
+ final byte[] messageBytes =
("------=_Part_1\n\nJJJJ\n------=_Part_1\n\n"
+ + "Content-Transfer-Encoding: binary\n\n" + LongStream
+ .range(0,
AttachmentDeserializer.DEFAULT_ATTACHMENT_MAX_SIZE / 3 + 1)
+ .mapToObj(i -> "=3D")
+ .collect(Collectors.joining())
+ + "\n------=_Part_1\n").getBytes();
+ try (ByteArrayInputStream in = new ByteArrayInputStream(messageBytes))
{
+ m.setContent(InputStream.class, in);
+
+ final WebApplicationException ex =
assertThrows(WebApplicationException.class,
+ () -> ferp.readFrom(MultipartBody.class, null, new
Annotation[]{},
+ MediaType.MULTIPART_FORM_DATA_TYPE, null, in));
+
+ assertThat(ex.getResponse().getStatus(), equalTo(413) /* Request
Entity Too Large */);
+ }
+ }
@Test
public void testWriteMultipleValues() throws Exception {
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSEntityPartTest.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSEntityPartTest.java
index c7ecd4b1a0b..cbd81f2f9fa 100644
---
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSEntityPartTest.java
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSEntityPartTest.java
@@ -19,6 +19,7 @@
package org.apache.cxf.systest.jaxrs;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -132,6 +133,28 @@ public class JAXRSEntityPartTest extends
AbstractBusClientServerTestBase {
doAddFormBook(address, "attachmentFormJaxb", "bookXML",
MediaType.APPLICATION_XML, 200);
}
+ @Test
+ public void testMultipartRequestTooLarge() throws Exception {
+ final String address = "http://localhost:" + PORT +
"/bookstore/books/images";
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ PrintWriter writer = new PrintWriter(output, true);
+ LoggingOutInterceptor out = new LoggingOutInterceptor(writer);
+
+ final WebClient client = WebClient.create(address);
+ client.getConfiguration().getOutInterceptors().add(out);
+
client.type(MediaType.MULTIPART_FORM_DATA).accept(MediaType.MULTIPART_FORM_DATA);
+
+ final EntityPart part = EntityPart
+ .withFileName("testfile.png")
+ .content(new ByteArrayInputStream(new byte[1024 * 11]))
+ .build();
+
+ try (Response response = client.postCollection(List.of(part),
EntityPart.class)) {
+ assertEquals(413, response.getStatus());
+ }
+ }
+
private void doAddFormBook(String address, String resourceName,
String name, String mt, int status) throws Exception {