Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
33 changes: 17 additions & 16 deletions core/src/main/java/org/apache/cxf/attachment/AttachmentUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,24 +214,25 @@ public static void setStreamedAttachmentProperties(Message message, CachedOutput
}

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");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
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;
Expand All @@ -41,6 +43,7 @@
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;
Expand Down Expand Up @@ -377,6 +380,25 @@ public void testSmallStream() throws Exception {
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,34 @@
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;

Expand Down Expand Up @@ -141,6 +156,40 @@ public void testMultiLines() throws Exception {
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -132,6 +133,28 @@ public void testBookJaxbForm() throws Exception {
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 {

Expand Down