Skip to content
Open
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 @@ -38,12 +38,17 @@ public class AttachmentBoundaryDeserializer {
private static final int PUSHBACK_AMOUNT = 2048;

private final int maxHeaderLength;
private final int maxHeadersCount;
private final Message message;

public AttachmentBoundaryDeserializer(Message message) {
this.message = message;
this.maxHeaderLength = MessageUtils.getContextualInteger(message,
AttachmentDeserializer.ATTACHMENT_MAX_HEADER_SIZE, AttachmentDeserializer.DEFAULT_MAX_HEADER_SIZE);
// Get the maximum headers count
this.maxHeadersCount = MessageUtils.getContextualInteger(message,
AttachmentDeserializer.ATTACHMENT_HEADERS_MAX_COUNT,
AttachmentDeserializer.DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT);
}

public Attachment read(InputStream body) throws IOException {
Expand All @@ -60,7 +65,8 @@ public Attachment read(InputStream body) throws IOException {
throw new IOException("Couldn't find MIME boundary: " + boundaryString);
}

Map<String, List<String>> ih = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
final Map<String, List<String>> ih = AttachmentDeserializerUtil
.loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
String val = AttachmentUtil.getHeader(ih, "Content-Transfer-Encoding");

MimeBodyPartInputStream mmps = new MimeBodyPartInputStream(stream, boundary, PUSHBACK_AMOUNT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public class AttachmentDeserializer {
*/
public static final String ATTACHMENT_MAX_COUNT = "attachment-max-count";

/**
* The maximum number of attachment headers permitted in a message. The default is 500.
*/
public static final String ATTACHMENT_HEADERS_MAX_COUNT = "attachment-headers-max-count";
public static final int DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT =
SystemPropertyAction.getInteger("org.apache.cxf.attachment-max-headers-count", 500);

/**
* The maximum MIME Header Length. The default is 300.
*/
Expand Down Expand Up @@ -102,6 +109,7 @@ public class AttachmentDeserializer {
private List<String> supportedTypes;

private int maxHeaderLength = DEFAULT_MAX_HEADER_SIZE;
private int maxHeadersCount = DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT;

public AttachmentDeserializer(Message message) {
this(message, Collections.singletonList("multipart/related"));
Expand All @@ -114,6 +122,9 @@ public AttachmentDeserializer(Message message, List<String> supportedTypes) {
// Get the maximum Header length from configuration
maxHeaderLength = MessageUtils.getContextualInteger(message, ATTACHMENT_MAX_HEADER_SIZE,
DEFAULT_MAX_HEADER_SIZE);
// Get the maximum headers count
maxHeadersCount = MessageUtils.getContextualInteger(message, ATTACHMENT_HEADERS_MAX_COUNT,
DEFAULT_ATTACHMENT_HEADERS_MAX_COUNT);
}

public void initializeAttachments() throws IOException {
Expand Down Expand Up @@ -160,7 +171,8 @@ protected void initializeRootMessage() throws IOException {
throw new IOException("Couldn't find MIME boundary: " + boundaryString);
}

Map<String, List<String>> ih = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
final Map<String, List<String>> ih = AttachmentDeserializerUtil
.loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
message.put(ATTACHMENT_PART_HEADERS, ih);
String val = AttachmentUtil.getHeader(ih, "Content-Type", "; ");
if (!StringUtils.isEmpty(val)) {
Expand Down Expand Up @@ -225,7 +237,8 @@ public AttachmentImpl readNext() throws IOException {
}
stream.unread(v);

Map<String, List<String>> headers = AttachmentDeserializerUtil.loadPartHeaders(stream, maxHeaderLength);
final Map<String, List<String>> headers = AttachmentDeserializerUtil
.loadPartHeaders(stream, maxHeaderLength, maxHeadersCount);
return (AttachmentImpl)createAttachment(headers);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ static boolean readTillFirstBoundary(PushbackInputStream pushbackInStream,
}


static Map<String, List<String>> loadPartHeaders(InputStream in, int maxHeaderLength) throws IOException {
static Map<String, List<String>> loadPartHeaders(InputStream in, int maxHeaderLength,
int maxHeadersCount) throws IOException {
StringBuilder buffer = new StringBuilder(128);
StringBuilder b = new StringBuilder(128);
Map<String, List<String>> heads = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Expand All @@ -98,7 +99,7 @@ static Map<String, List<String>> loadPartHeaders(InputStream in, int maxHeaderLe
} else {
// if we have a line pending in the buffer, flush it
if (buffer.length() > 0) {
addHeaderLine(heads, buffer);
addHeaderLine(heads, buffer, maxHeadersCount);
buffer.setLength(0);
}
// add this to the accumulator
Expand All @@ -108,7 +109,7 @@ static Map<String, List<String>> loadPartHeaders(InputStream in, int maxHeaderLe

// if we have a line pending in the buffer, flush it
if (buffer.length() > 0) {
addHeaderLine(heads, buffer);
addHeaderLine(heads, buffer, maxHeadersCount);
}
return heads;
}
Expand Down Expand Up @@ -142,7 +143,8 @@ private static boolean readLine(InputStream in, StringBuilder buffer, int maxHea
return buffer.length() != 0;
}

private static void addHeaderLine(Map<String, List<String>> heads, StringBuilder line) {
private static void addHeaderLine(Map<String, List<String>> heads, StringBuilder line,
int maxHeadersCount) throws IOException {
// null lines are a nop
final int size = line.length();
if (size == 0) {
Expand All @@ -167,6 +169,10 @@ private static void addHeaderLine(Map<String, List<String>> heads, StringBuilder
}
value = line.substring(separator);
}

if (heads.size() >= maxHeadersCount) {
throw new IOException("The attachment contains more headers than are permitted");
}
List<String> v = heads.computeIfAbsent(name, k -> new ArrayList<>(1));
v.add(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -667,6 +668,28 @@ public void testCXF3582c() throws Exception {
ins.close();
}

@Test
public void testManyAttachmentHeaders() throws Exception {
StringBuilder sb = new StringBuilder(10000);
// Add many attachment headers
sb.append("------=_Part_34950_1098328613.1263781527359\n");
IntStream.range(0, 1000).forEach(i -> sb.append("Header-").append(i).append(": foo").append(i).append('\n'));
sb.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");

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

assertThrows("Failure expected on too many attachment headers", IOException.class,
() -> ad.initializeAttachments());
}


@Test
public void testManyAttachments() throws Exception {
StringBuilder sb = new StringBuilder(1000);
Expand Down
Loading