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

chibenwa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-mime4j.git

commit c9847207a5aa3ce2526bfee78edf3dbae9c22e35
Author: Rene Cordier <[email protected]>
AuthorDate: Tue Nov 3 14:31:45 2026 +0700

    fix: ignore a malformed leading duplicate Content-Type / 
Content-Transfer-Encoding header so core and DOM agree (PR #137)
---
 .../james/mime4j/message/AbstractEntity.java       | 20 +++++++++++++++
 .../message/DefaultBodyDescriptorBuilder.java      | 30 ++++++++++++++++++++--
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git 
a/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntity.java 
b/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntity.java
index 1875ada7..3c688905 100644
--- a/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntity.java
+++ b/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntity.java
@@ -28,6 +28,7 @@ import 
org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
 import org.apache.james.mime4j.dom.field.ContentTypeField;
 import org.apache.james.mime4j.dom.field.FieldName;
 import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.stream.Field;
 
 /**
  * Abstract MIME entity.
@@ -135,6 +136,15 @@ public abstract class AbstractEntity implements Entity {
     }
 
     private ContentTypeField getContentTypeField() {
+        // a first Content-Type header that yields no mime type (empty, 
invalid,
+        // or multipart without boundary) does not describe the body: use the 
next
+        // usable one, like the core FallbackBodyDescriptorBuilder does
+        for (Field field : 
getHeader().getFields(FieldName.CONTENT_TYPE_LOWERCASE)) {
+            ContentTypeField f = (ContentTypeField) field;
+            if (f.getMimeType() != null && !(f.isMultipart() && 
f.getBoundary() == null)) {
+                return f;
+            }
+        }
         return (ContentTypeField) 
getHeader().getField(FieldName.CONTENT_TYPE_LOWERCASE);
     }
 
@@ -153,6 +163,16 @@ public abstract class AbstractEntity implements Entity {
      * @return the transfer encoding.
      */
     public String getContentTransferEncoding() {
+        // a first Content-Transfer-Encoding header with an empty value does 
not
+        // describe the body: use the next usable one, like the core
+        // FallbackBodyDescriptorBuilder does
+        for (Field field : 
getHeader().getFields(FieldName.CONTENT_TRANSFER_ENCODING)) {
+            ContentTransferEncodingField f = (ContentTransferEncodingField) 
field;
+            String encoding = f.getEncoding();
+            if (encoding != null && encoding.trim().length() > 0) {
+                return calcTransferEncoding(f);
+            }
+        }
         ContentTransferEncodingField f = (ContentTransferEncodingField)
                         
getHeader().getField(FieldName.CONTENT_TRANSFER_ENCODING);
 
diff --git 
a/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
 
b/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
index af3a6b2e..c4b3f84b 100644
--- 
a/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
+++ 
b/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
@@ -28,6 +28,7 @@ import java.util.Map;
 import org.apache.james.mime4j.MimeException;
 import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.dom.FieldParser;
+import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
 import org.apache.james.mime4j.dom.field.ContentTypeField;
 import org.apache.james.mime4j.dom.field.FieldName;
 import org.apache.james.mime4j.dom.field.ParsedField;
@@ -38,6 +39,8 @@ import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.RawField;
 import org.apache.james.mime4j.util.MimeUtil;
 
+import static 
org.apache.james.mime4j.dom.field.ContentTypeField.TYPE_MULTIPART_PREFIX;
+
 /**
  * Default {@link BodyDescriptorBuilder} implementation.
  */
@@ -96,12 +99,35 @@ public class DefaultBodyDescriptorBuilder implements 
BodyDescriptorBuilder {
     public Field addField(final RawField rawfield) throws MimeException {
         ParsedField field = fieldParser.parse(rawfield, monitor);
         String name = field.getNameLowerCase();
-        if (field.bodyDescriptionField() && !fields.containsKey(name)) {
-            fields.put(name, field);
+        if (field.bodyDescriptionField()) {
+            ParsedField previous = fields.get(name);
+            if (previous == null || !describesBody(previous) && 
describesBody(field)) {
+                fields.put(name, field);
+            }
         }
         return field;
     }
 
+    /**
+     * Whether the field actually describes the body: a Content-Type with no
+     * mime type (empty or invalid, or a multipart type without boundary) or a
+     * Content-Transfer-Encoding with an empty value does not, and a later
+     * field may then be used instead.
+     */
+    private static boolean describesBody(ParsedField field) {
+        if (field instanceof ContentTypeField) {
+            ContentTypeField contentType = (ContentTypeField) field;
+            return contentType.getMimeType() != null
+                    && 
!(contentType.getMimeType().startsWith(TYPE_MULTIPART_PREFIX)
+                        && contentType.getBoundary() == null);
+        }
+        if (field instanceof ContentTransferEncodingField) {
+            String encoding = ((ContentTransferEncodingField) 
field).getEncoding();
+            return encoding != null && encoding.trim().length() > 0;
+        }
+        return true;
+    }
+
     public BodyDescriptor build() {
         String actualMimeType = null;
         String actualMediaType = null;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to