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 e18116b9458 Make sure LazyAttachmentCollection respects max attachment
count in all cases (#3344)
e18116b9458 is described below
commit e18116b94588013b236791abfadd995122fb42c8
Author: Andriy Redko <[email protected]>
AuthorDate: Tue Jul 28 15:54:59 2026 -0400
Make sure LazyAttachmentCollection respects max attachment count in all
cases (#3344)
---
.../cxf/attachment/LazyAttachmentCollection.java | 16 ++-
.../cxf/attachment/AttachmentDeserializerTest.java | 124 +++++++++++++++++----
.../apache/cxf/systest/jaxb/MTOMBase64Test.java | 2 +
3 files changed, 118 insertions(+), 24 deletions(-)
diff --git
a/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
b/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
index 8fdbba76604..e8cfe40d4c2 100644
--- a/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
+++ b/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java
@@ -73,6 +73,10 @@ public class LazyAttachmentCollection
*/
public boolean hasNext(boolean shouldLoadNew) throws IOException {
if (shouldLoadNew) {
+ if (attachments.size() > maxAttachmentCount) {
+ throw new IOException("The message contains more attachments
than are permitted");
+ }
+
Attachment a = deserializer.readNext();
if (a != null) {
attachments.add(a);
@@ -87,6 +91,7 @@ public class LazyAttachmentCollection
return hasNext(true);
}
public Iterator<Attachment> iterator() {
+ // CHECKSTYLE:OFF
return new Iterator<Attachment>() {
int current;
boolean removed;
@@ -98,6 +103,9 @@ public class LazyAttachmentCollection
// check if there is another attachment
try {
+ if (attachments.size() > maxAttachmentCount) {
+ throw new IOException("The message contains more
attachments than are permitted");
+ }
Attachment a = deserializer.readNext();
if (a == null) {
return false;
@@ -125,8 +133,8 @@ public class LazyAttachmentCollection
attachments.remove(--current);
removed = true;
}
-
};
+ // CHECKSTYLE:ON
}
public int size() {
@@ -136,10 +144,16 @@ public class LazyAttachmentCollection
}
public boolean add(Attachment arg0) {
+ if (attachments.size() > maxAttachmentCount) {
+ throw new RuntimeException(new IOException("The message contains
more attachments than are permitted"));
+ }
return attachments.add(arg0);
}
public boolean addAll(Collection<? extends Attachment> arg0) {
+ if (attachments.size() + arg0.size() > maxAttachmentCount) {
+ throw new RuntimeException(new IOException("The message contains
more attachments than are permitted"));
+ }
return attachments.addAll(arg0);
}
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 857704c7878..9c106da1800 100644
---
a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
+++
b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java
@@ -29,6 +29,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -40,6 +41,7 @@ import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.helpers.DefaultHandler;
+import jakarta.activation.DataHandler;
import jakarta.activation.DataSource;
import jakarta.activation.URLDataSource;
import org.apache.cxf.helpers.IOUtils;
@@ -711,33 +713,29 @@ public class AttachmentDeserializerTest {
assertThrows("Failure expected on too many attachment headers",
IOException.class,
() -> ad.initializeAttachments());
}
-
@Test
- public void testManyAttachments() throws Exception {
- StringBuilder sb = new StringBuilder(1000);
- sb.append("SomeHeader: foo\n")
- .append("------=_Part_34950_1098328613.1263781527359\n")
- .append("Content-Type: text/xml; charset=UTF-8\n")
- .append("Content-Transfer-Encoding: binary\n")
- .append("Content-Id:
<318731183421.1263781527359.IBM.WEBSERVICES@auhpap02>\n")
- .append('\n')
- .append("<envelope/>\n");
+ public void testManyAttachmentsDataHandlerIterator() throws Exception {
+ prepareAttachments();
- // Add many attachments
- IntStream.range(0, 100000).forEach(i -> {
- sb.append("------=_Part_34950_1098328613.1263781527359\n")
- .append("Content-Type: text/xml\n")
- .append("Content-Transfer-Encoding: binary\n")
- .append("Content-Id: <b86a5f2d-e7af-4e5e-b71a-9f6f2307cab0>\n")
- .append('\n')
- .append("<message>\n")
- .append("------=_Part_34950_1098328613.1263781527359--\n");
- });
+ AttachmentDeserializer ad = new AttachmentDeserializer(msg);
+ ad.initializeAttachments();
+
+ // Force it to load the attachments
+ final LazyAttachmentCollection attachments =
(LazyAttachmentCollection) msg.getAttachments();
+ assertThrows("Failure expected on too many attachments",
RuntimeException.class,
+ () -> {
+ // Exercise iterator() path
+ for (Map.Entry<String, DataHandler> entry :
attachments.createDataHandlerMap().entrySet()) {
+ // Do nothing, just force loading
+ }
+ });
+ }
+
+ @Test
+ public void testManyAttachmentsLoadAll() throws Exception {
+ prepareAttachments();
- msg = new MessageImpl();
- msg.setContent(InputStream.class, new
ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)));
- msg.put(Message.CONTENT_TYPE, "multipart/related");
AttachmentDeserializer ad = new AttachmentDeserializer(msg);
ad.initializeAttachments();
@@ -746,6 +744,60 @@ public class AttachmentDeserializerTest {
() -> msg.getAttachments().size());
}
+ @Test
+ public void testManyAttachmentsIterator() throws Exception {
+ prepareAttachments();
+
+ AttachmentDeserializer ad = new AttachmentDeserializer(msg);
+ ad.initializeAttachments();
+
+ // Iterate over attachments
+ assertThrows("Failure expected on too many attachments",
RuntimeException.class,
+ () -> {
+ // Exercise iterator() path
+ for (Attachment attachment : msg.getAttachments()) {
+ // Do nothing, just force loading
+ }
+ }
+ );
+
+ // Iterate over attachments
+ final LazyAttachmentCollection attachments =
(LazyAttachmentCollection) msg.getAttachments();
+ assertThrows("Failure expected on too many attachments",
IOException.class,
+ () -> {
+ // Exercise iterator() path
+ while (attachments.hasNext()) {
+ // Do nothing, just force loading
+ }
+ }
+ );
+
+ assertThrows("Failure expected on too many attachments",
RuntimeException.class,
+ () -> attachments.add(new AttachmentImpl("contentId")));
+
+ assertThrows("Failure expected on too many attachments",
RuntimeException.class,
+ () -> attachments.addAll(List.of(new
AttachmentImpl("contentId"))));
+ }
+
+ @Test
+ public void testManyAttachmentsHasNext() throws Exception {
+ prepareAttachments();
+
+ AttachmentDeserializer ad = new AttachmentDeserializer(msg);
+ ad.initializeAttachments();
+
+ // Iterate over attachments
+ final LazyAttachmentCollection attachments =
(LazyAttachmentCollection) msg.getAttachments();
+ assertThrows("Failure expected on too many attachments",
IOException.class,
+ () -> {
+ // Exercise iterator() path
+ while (attachments.hasNext()) {
+ // Do nothing, just force loading
+ }
+ }
+ );
+ }
+
@Test
public void testChangingMaxAttachmentCount() throws Exception {
StringBuilder sb = new StringBuilder(1000);
@@ -954,4 +1006,30 @@ public class AttachmentDeserializerTest {
System.clearProperty(AttachmentUtil.ATTACHMENT_XOP_FOLLOW_URLS_PROPERTY);
}
}
+
+ private void prepareAttachments() {
+ StringBuilder sb = new StringBuilder(1000);
+ sb.append("SomeHeader: foo\n")
+ .append("------=_Part_34950_1098328613.1263781527359\n")
+ .append("Content-Type: text/xml; charset=UTF-8\n")
+ .append("Content-Transfer-Encoding: binary\n")
+ .append("Content-Id:
<318731183421.1263781527359.IBM.WEBSERVICES@auhpap02>\n")
+ .append('\n')
+ .append("<envelope/>\n");
+
+ // Add many attachments
+ IntStream.range(0, 100000).forEach(i -> {
+ sb.append("------=_Part_34950_1098328613.1263781527359\n")
+ .append("Content-Type: text/xml\n")
+ .append("Content-Transfer-Encoding: binary\n")
+ .append("Content-Id: <b86a5f2d-e7af-4e5e-b71a-9f6f2307cab0>\n")
+ .append('\n')
+ .append("<message>\n")
+ .append("------=_Part_34950_1098328613.1263781527359--\n");
+ });
+
+ msg = new MessageImpl();
+ msg.setContent(InputStream.class, new
ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8)));
+ msg.put(Message.CONTENT_TYPE, "multipart/related");
+ }
}
diff --git
a/systests/databinding/src/test/java/org/apache/cxf/systest/jaxb/MTOMBase64Test.java
b/systests/databinding/src/test/java/org/apache/cxf/systest/jaxb/MTOMBase64Test.java
index 278be3b3741..242da079836 100644
---
a/systests/databinding/src/test/java/org/apache/cxf/systest/jaxb/MTOMBase64Test.java
+++
b/systests/databinding/src/test/java/org/apache/cxf/systest/jaxb/MTOMBase64Test.java
@@ -30,6 +30,7 @@ import jakarta.xml.ws.Endpoint;
import jakarta.xml.ws.Service;
import jakarta.xml.ws.soap.MTOM;
import jakarta.xml.ws.soap.SOAPBinding;
+import org.apache.cxf.attachment.AttachmentDeserializer;
import org.apache.cxf.ext.logging.Logging;
import org.apache.cxf.ext.logging.LoggingInInterceptor;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
@@ -111,6 +112,7 @@ public class MTOMBase64Test extends
AbstractBusClientServerTestBase {
protected void run() {
EndpointImpl endpointImpl =
(EndpointImpl)Endpoint.publish(ADDRESS, new MTOMServer());
endpointImpl.getProperties().put(Message.CONTENT_TRANSFER_ENCODING, "base64");
+
endpointImpl.getBus().getProperties().put(AttachmentDeserializer.ATTACHMENT_MAX_COUNT,
"100");
}
public static void main(String[] args) {
try {