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 f28c1e7d25 TIKA-4977: detect *.rs as text/x-rust; RLS services XML by 
root element (#3365)
f28c1e7d25 is described below

commit f28c1e7d25fe7d6f41ea2db65974bc8b41c96521
Author: Tim Allison <[email protected]>
AuthorDate: Mon Oct 19 14:30:35 2026 +0100

    TIKA-4977: detect *.rs as text/x-rust; RLS services XML by root element 
(#3365)
---
 CHANGES.txt                                        |  4 ++++
 .../org/apache/tika/mime/tika-mimetypes.xml        |  9 ++++++-
 .../java/org/apache/tika/TikaDetectionTest.java    |  3 ++-
 .../org/apache/tika/mime/MimeDetectionTest.java    | 28 ++++++++++++++++++++++
 4 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 1c02d2fd92..4b04bc03bc 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,9 @@
 Release 4.2.0 - unreleased
 
+   * Files named *.rs are now detected as text/x-rust (Rust source) instead of
+     application/rls-services+xml. RLS services XML is still detected from its
+     root element, whatever the file name (TIKA-4977).
+     
    * Opt-in "metadata-list": {"typedValues": true} writes INTEGER, REAL and
      BOOLEAN metadata as JSON numbers and booleans, and tk:chunks as nested
      JSON rather than an escaped string, in -J, /rmeta and the JSON emitters.
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 88387956e5..7fa05d2920 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
@@ -1040,7 +1040,8 @@
   <mime-type type="application/riscos"/>
   <mime-type type="application/rlmi+xml"/>
   <mime-type type="application/rls-services+xml">
-    <glob pattern="*.rs"/>
+    <root-XML namespaceURI="urn:ietf:params:xml:ns:rls-services" 
localName="rls-services"/>
+    <!-- <glob pattern="*.rs"/> - conflicts with text/x-rust -->
   </mime-type>
   <mime-type type="application/rsd+xml">
     <glob pattern="*.rsd"/>
@@ -8578,6 +8579,12 @@
     <sub-class-of type="text/plain"/>
   </mime-type>
 
+  <mime-type type="text/x-rust">
+    <_comment>Rust source code</_comment>
+    <glob pattern="*.rs"/>
+    <sub-class-of type="text/plain"/>
+  </mime-type>
+
   <mime-type type="text/x-scala">
     <_comment>Scala source code</_comment>
     <glob pattern="*.scala"/>
diff --git a/tika-core/src/test/java/org/apache/tika/TikaDetectionTest.java 
b/tika-core/src/test/java/org/apache/tika/TikaDetectionTest.java
index 8dead957bf..77fe46899a 100644
--- a/tika-core/src/test/java/org/apache/tika/TikaDetectionTest.java
+++ b/tika-core/src/test/java/org/apache/tika/TikaDetectionTest.java
@@ -121,7 +121,8 @@ public class TikaDetectionTest {
         assertEquals("application/relax-ng-compact-syntax", 
tika.detect("x.rnc"));
         assertEquals("application/resource-lists+xml", tika.detect("x.rl"));
         assertEquals("application/resource-lists-diff+xml", 
tika.detect("x.rld"));
-        assertEquals("application/rls-services+xml", tika.detect("x.rs"));
+        // httpd maps .rs to application/rls-services+xml; Rust source wins 
(TIKA-4977)
+        assertEquals("text/x-rust", tika.detect("x.rs"));
         assertEquals("application/rsd+xml", tika.detect("x.rsd"));
         assertEquals("application/rss+xml", tika.detect("x.rss"));
         assertEquals("application/rtf", tika.detect("x.rtf"));
diff --git 
a/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java 
b/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
index 01dab1f671..3d7f214169 100644
--- a/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
+++ b/tika-core/src/test/java/org/apache/tika/mime/MimeDetectionTest.java
@@ -214,6 +214,34 @@ public class MimeDetectionTest {
         }
     }
 
+    private static MediaType detect(byte[] bytes, String name) throws 
IOException {
+        Metadata metadata = new Metadata();
+        if (name != null) {
+            metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, name);
+        }
+        try (TikaInputStream tis = TikaInputStream.get(bytes)) {
+            return MIME_TYPES.detect(tis, metadata, new ParseContext());
+        }
+    }
+
+    @Test
+    public void testRustVersusRlsServices() throws IOException {
+        MediaType rust = MediaType.text("x-rust");
+        MediaType rls = MediaType.application("rls-services+xml");
+        assertEquals(rust, detect("fn main() {}\n".getBytes(UTF_8), 
"main.rs"));
+        assertEquals(rust, detect("// Licensed to the ASF\nfn main() 
{}\n".getBytes(UTF_8),
+                "main.rs"));
+
+        byte[] rlsXml = ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                + "<rls-services 
xmlns=\"urn:ietf:params:xml:ns:rls-services\">"
+                + "<service 
uri=\"sip:[email protected]\"/></rls-services>").getBytes(UTF_8);
+        assertEquals(rls, detect(rlsXml, "services.rs"));
+        assertEquals(rls, detect(rlsXml, null));
+
+        byte[] png = {(byte) 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 0, 
0, 0, 0};
+        assertEquals(MediaType.image("png"), detect(png, "main.rs"));
+    }
+
     @Test
     public void testDetectionWithoutContent() throws IOException {
         testUrlWithoutContent("text/html", "test.html");

Reply via email to