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

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new afcd8621ae TIKA-4890: fix extension overrules failed mime; fix 
httpcapture (#3213)
afcd8621ae is described below

commit afcd8621aeab75d381bbbfc3235ec8246b29bb9f
Author: Tim Allison <[email protected]>
AuthorDate: Sun Sep 20 08:52:11 2026 -0400

    TIKA-4890: fix extension overrules failed mime; fix httpcapture (#3213)
---
 CHANGES.txt                                        |  6 ++++
 .../main/java/org/apache/tika/mime/MimeTypes.java  | 13 ++++++--
 .../org/apache/tika/mime/tika-mimetypes.xml        |  4 ++-
 .../org/apache/tika/mime/EMLXDetectionTest.java    | 37 ++++++++++++++++++++++
 4 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 38f867a215..41a40a0203 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,11 @@
 Release 4.1.0 - unreleased
 
+   * A file name no longer turns plain text into a message type (emlx, mbox,
+     rfc822, news, HTTP capture) when the type's magic has already rejected
+     the bytes: prose named .emlx is text/plain. An HTTP response captured
+     without its version line ("200 OK", then headers) is detected as
+     application/x-httpresponse (TIKA-4890).
+
    * Apple Mail emlx files are detected as message/x-emlx (real files pad the
      byte-count line to 10 columns and were falling through to text/html or
      message/rfc822), and RFC822Parser now parses them, dropping the byte-count
diff --git a/tika-core/src/main/java/org/apache/tika/mime/MimeTypes.java 
b/tika-core/src/main/java/org/apache/tika/mime/MimeTypes.java
index d2e9f082ff..e16eba987b 100644
--- a/tika-core/src/main/java/org/apache/tika/mime/MimeTypes.java
+++ b/tika-core/src/main/java/org/apache/tika/mime/MimeTypes.java
@@ -65,6 +65,8 @@ public final class MimeTypes implements Detector, 
Serializable {
      * Name of the {@link #rootMimeType root} type, application/octet-stream.
      */
     public static final String OCTET_STREAM = "application/octet-stream";
+    private static final MediaType TEXT_BASED_MESSAGE =
+            MediaType.parse("text/x-tika-text-based-message");
     /**
      * Name of the {@link #textMimeType text} type, text/plain.
      */
@@ -630,9 +632,14 @@ public final class MimeTypes implements Detector, 
Serializable {
             return Collections.singletonList(hint);
         } else {
             for (final MimeType type : possibleTypes) {
-                if (hint.equals(type) ||
-                        registry.isSpecializationOf(hint.getType(), 
type.getType())) {
-                    // Use just this type
+                if (hint.equals(type)) {
+                    return Collections.singletonList(hint);
+                }
+                // a message type's magic is the verdict: prose named .emlx is 
not mail, though
+                // prose named .java is still java source (no magic can tell)
+                if (registry.isSpecializationOf(hint.getType(), type.getType())
+                        && !(MediaType.TEXT_PLAIN.equals(type.getType())
+                        && registry.isSpecializationOf(hint.getType(), 
TEXT_BASED_MESSAGE))) {
                     return Collections.singletonList(hint);
                 }
             }
diff --git 
a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml 
b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
index e88e55adf0..0ccf499954 100644
--- a/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
+++ b/tika-core/src/main/resources/org/apache/tika/mime/tika-mimetypes.xml
@@ -7542,8 +7542,10 @@
         <match value="\nDate:" type="string" offset="0:1000"/>
         <match value="\nServer:" type="string" offset="0:1000"/>
       </match>
-      <sub-class-of type="text/x-tika-text-based-message"/>
+      <!-- a capture without the version: "200 OK" then headers (LWP, curl -i 
on some proxies) -->
+      <match value="[1-5][0-9]{2} [A-Za-z][A-Za-z 
-]{0,40}\r?\n(Cache-Control|Content-Type|Content-Length|Content-Disposition|Date|Server|Set-Cookie|Client-Date|Last-Modified|Connection):"
 type="regex" offset="0"/>
     </magic>
+    <sub-class-of type="text/x-tika-text-based-message"/>
   </mime-type>
   <!-- TODO See TIKA-2723 for discussions on the mime type hierarchy -->
   <!--  and best parser structure for these email-like formats -->
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/EMLXDetectionTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/EMLXDetectionTest.java
index caa909558e..98653f3071 100644
--- a/tika-core/src/test/java/org/apache/tika/mime/EMLXDetectionTest.java
+++ b/tika-core/src/test/java/org/apache/tika/mime/EMLXDetectionTest.java
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
 
 import org.apache.tika.io.TikaInputStream;
 import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.parser.ParseContext;
 
 public class EMLXDetectionTest {
@@ -79,6 +80,42 @@ public class EMLXDetectionTest {
         assertMime("message/x-emlx", sb.toString());
     }
 
+    @Test
+    public void testHttpCaptureIsNotEmlx() throws Exception {
+        // an LWP-style capture: a status line without the version, then HTTP 
headers
+        String capture = "200 OK\nDate: Thu, 08 Aug 2002 10:44:35 GMT\n"
+                + "Server: Apache Tomcat/4.0.1 (HTTP/1.1 
Connector)\nContent-Type: image/svg+xml\n"
+                + "Client-Date: Thu, 08 Aug 2002 10:39:29 GMT\n\n<svg/>\n";
+        assertMime("application/x-httpresponse", capture);
+        // the .emlx name must not turn it into mail either
+        Metadata named = new Metadata();
+        named.set(TikaCoreProperties.RESOURCE_NAME_KEY, "capture.emlx");
+        try (TikaInputStream tis = 
TikaInputStream.get(capture.getBytes(StandardCharsets.UTF_8))) {
+            assertEquals("application/x-httpresponse",
+                    MIME_TYPES.detect(tis, named, new 
ParseContext()).toString());
+        }
+        assertMime("application/x-httpresponse", "HTTP/1.1 404 Not 
Found\r\nServer: nginx\r\n\r\n");
+    }
+
+    @Test
+    public void testNameDoesNotMakeProseAMessage() throws Exception {
+        // the magic looked and said no; the extension cannot overrule it for 
a message type
+        String prose = "The quick brown fox jumps over the lazy dog.\n";
+        for (String name : new String[]{"fox.emlx", "fox.mbox", "fox.eml"}) {
+            Metadata named = new Metadata();
+            named.set(TikaCoreProperties.RESOURCE_NAME_KEY, name);
+            try (TikaInputStream tis = 
TikaInputStream.get(prose.getBytes(StandardCharsets.UTF_8))) {
+                assertEquals("text/plain", MIME_TYPES.detect(tis, named, new 
ParseContext()).toString(), name);
+            }
+        }
+        // a type without magic still takes its name
+        Metadata java = new Metadata();
+        java.set(TikaCoreProperties.RESOURCE_NAME_KEY, "Fox.java");
+        try (TikaInputStream tis = 
TikaInputStream.get(prose.getBytes(StandardCharsets.UTF_8))) {
+            assertEquals("text/x-java-source", MIME_TYPES.detect(tis, java, 
new ParseContext()).toString());
+        }
+    }
+
     private void assertMime(String expected, String txt) throws IOException {
         try (TikaInputStream tis = 
TikaInputStream.get(txt.getBytes(StandardCharsets.UTF_8))) {
             MediaType mediaType = MIME_TYPES.detect(tis, new Metadata(), new 
ParseContext());

Reply via email to