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