This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-mime4j.git
The following commit(s) were added to refs/heads/master by this push: new 3d1f2cf3 MIME4J-330 Fix MimeStreamParser bug: part body stream ends with CR 3d1f2cf3 is described below commit 3d1f2cf35501ac457ef2e6b71306be5f1295df55 Author: hung phan <hp...@linagora.com> AuthorDate: Fri Jan 10 15:24:14 2025 +0700 MIME4J-330 Fix MimeStreamParser bug: part body stream ends with CR --- .../james/mime4j/io/MimeBoundaryInputStream.java | 14 +++-- .../ExtractPartWithDifferentLengthsTest.java | 73 ++++++++++++++++++++++ 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java b/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java index 140f6b65..53ab013c 100644 --- a/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java +++ b/core/src/main/java/org/apache/james/mime4j/io/MimeBoundaryInputStream.java @@ -245,14 +245,14 @@ public class MimeBoundaryInputStream extends LineReaderInputStream { // Make sure the boundary is terminated with EOS break; } else { - // or with a whitespace or '--' + // or with a whitespace or '--' char ch = (char)(buffer.byteAt(pos)); if (CharsetUtil.isWhitespace(ch)) { break; } if (ch == '-' && remaining > 1 && (char)(buffer.byteAt(pos+1)) == '-') { break; - } + } } } off = i + boundary.length; @@ -265,8 +265,14 @@ public class MimeBoundaryInputStream extends LineReaderInputStream { if (eof) { limit = buffer.limit(); } else { - limit = buffer.limit() - (boundary.length + 2); - // [LF] [boundary] [CR][LF] minus one char + int position = buffer.limit() - (boundary.length + 3); // 2nd position before boundary + if (position >= 0 && (char) buffer.byteAt(position) == '\r') { + limit = buffer.limit() - (boundary.length + 3); + // boundary [CR][LF] minus two chars + } else { + limit = buffer.limit() - (boundary.length + 2); + // boundary [LF] minus one char + } } } return bytesRead; diff --git a/core/src/test/java/org/apache/james/mime4j/parser/ExtractPartWithDifferentLengthsTest.java b/core/src/test/java/org/apache/james/mime4j/parser/ExtractPartWithDifferentLengthsTest.java new file mode 100644 index 00000000..ec8eb4fa --- /dev/null +++ b/core/src/test/java/org/apache/james/mime4j/parser/ExtractPartWithDifferentLengthsTest.java @@ -0,0 +1,73 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.mime4j.parser; + +import org.apache.commons.io.IOUtils; +import org.apache.james.mime4j.MimeException; +import org.apache.james.mime4j.stream.BodyDescriptor; +import org.junit.Assert; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public class ExtractPartWithDifferentLengthsTest { + @Test + public void testExtractPartWithDifferentLengths() throws Exception { + StringBuilder partBuilder = new StringBuilder(); + for (int i = 1; i <= 5000; i++) { + partBuilder.append(i % 80 == 0 ? "\n" : "A"); + String part = partBuilder.toString(); + String mimeMessage = createMimeMultipart(part); + + String extracted = extractPart(mimeMessage); + Assert.assertEquals(part, extracted); + } + } + + private String createMimeMultipart(String part) { + return "Content-type: multipart/mixed; boundary=QvEgqhjEnYxz\n" + + "\n" + + "--QvEgqhjEnYxz\n" + + "Content-Type: text/plain\n" + + "\n" + + part + + "\r\n" + + "--QvEgqhjEnYxz--\n"; + } + + private String extractPart(String mimeMessage) throws + MimeException, IOException { + String[] resultWrapper = new String[1]; + + MimeStreamParser parser = new MimeStreamParser(); + parser.setContentHandler(new AbstractContentHandler() { + @Override + public void body(BodyDescriptor bd, InputStream is) throws IOException { + resultWrapper[0] = new String(IOUtils.toString(is, + StandardCharsets.UTF_8).getBytes()); + } + }); + parser.parse(new ByteArrayInputStream(mimeMessage.getBytes())); + return resultWrapper[0]; + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org