This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 34158809481d48be173f15885f861b963957eed3
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
    
    (cherry picked from commit cdd8cb07a684708e570abec806dbf85c5055c238)
---
 .../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 96fe01855dd..b870c447143 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 {
 

Reply via email to