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

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


The following commit(s) were added to refs/heads/branch_3x by this push:
     new d1c05ec206 TIKA-4985: keep parsing a RAR past an entry junrar fails to 
extract (backport of #3377) (#3398)
d1c05ec206 is described below

commit d1c05ec2060bce07eb9763c18af3bffe2a0a24a2
Author: Tim Allison <[email protected]>
AuthorDate: Thu Oct 22 16:12:07 2026 -0400

    TIKA-4985: keep parsing a RAR past an entry junrar fails to extract 
(backport of #3377) (#3398)
    
    Co-authored-by: Tilman Hausherr <[email protected]>
---
 CHANGES.txt                                        |  5 ++++
 .../java/org/apache/tika/parser/pkg/RarParser.java | 28 +++++++++++++++++++++-
 .../org/apache/tika/parser/pkg/RarParserTest.java  | 25 +++++++++++++++++++
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 4a2e918629..99832430e3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,10 @@
 Release 3.4.0 - ???
 
+  * A RAR entry junrar fails to extract is recorded as
+    X-TIKA:EXCEPTION:embedded_stream_exception on the container; what was 
extracted
+    before the failure is kept and the rest of the archive is parsed (junrar 
8.1.2,
+    TIKA-4985).
+
   * ISArchiveParser resolves the ISA-Tab directory on each parse instead of 
reading every
     later document's investigation and assay files from the first document's 
directory,
     and concurrent parses no longer share the study file name (TIKA-4986).
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/RarParser.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/RarParser.java
index 871f293881..8b77d36cc6 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/RarParser.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/main/java/org/apache/tika/parser/pkg/RarParser.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import com.github.junrar.Archive;
 import com.github.junrar.exception.RarException;
 import com.github.junrar.rarfile.FileHeader;
+import org.apache.commons.io.input.ProxyInputStream;
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 
@@ -86,11 +87,16 @@ public class RarParser implements Parser {
                     Metadata entrydata = 
PackageParser.handleEntryMetadata(header.getFileName(),
                             header.getCTime(), header.getMTime(), 
header.getFullUnpackSize(),
                             xhtml);
-                    try (InputStream subFile = rar.getInputStream(header)) {
+                    EntryStream entryStream = new 
EntryStream(rar.getInputStream(header));
+                    try (InputStream subFile = entryStream) {
                         if (extractor.shouldParseEmbedded(entrydata)) {
                             extractor.parseEmbedded(subFile, handler, 
entrydata, true);
                         }
                     }
+                    if (entryStream.failure != null) {
+                        EmbeddedDocumentUtil.recordEmbeddedStreamException(
+                                entryStream.failure, metadata);
+                    }
                 }
 
                 header = rar.nextFileHeader();
@@ -107,4 +113,24 @@ public class RarParser implements Parser {
 
         xhtml.endDocument();
     }
+
+    /**
+     * junrar 8.1.2+ reports a failed entry (truncated archive, bad CRC, 
missing password) as an
+     * IOException on the entry's stream. End the entry there instead, as 
junrar 8.1.1 did, so
+     * the bytes it delivered are still parsed and the rest of the archive is 
reached.
+     */
+    private static class EntryStream extends ProxyInputStream {
+        private IOException failure;
+
+        EntryStream(InputStream in) {
+            super(in);
+        }
+
+        @Override
+        protected void handleIOException(IOException e) {
+            if (failure == null) {
+                failure = e;
+            }
+        }
+    }
 }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/RarParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/RarParserTest.java
index e76c90f48c..899f6f52e3 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/RarParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-pkg-module/src/test/java/org/apache/tika/parser/pkg/RarParserTest.java
@@ -23,12 +23,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
 
+import org.apache.commons.io.IOUtils;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
 import org.xml.sax.ContentHandler;
 
 import org.apache.tika.exception.EncryptedDocumentException;
 import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
 import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
 import org.apache.tika.parser.PasswordProvider;
@@ -93,6 +99,25 @@ public class RarParserTest extends AbstractPkgTest {
         assertContains("test-documents/testXML.xml", content);
     }
 
+    @Test
+    public void testCorruptEntryKeepsLaterEntries(@TempDir Path tmp) throws 
Exception {
+        byte[] rar;
+        try (InputStream is = 
getResourceAsStream("/test-documents/test-documents.rar")) {
+            rar = IOUtils.toByteArray(is);
+        }
+        // testEXCEL.xls, the first entry, has its packed data at 80..2885
+        rar[1500] ^= 0x5A;
+        Path corrupt = tmp.resolve("corrupt.rar");
+        Files.write(corrupt, rar);
+
+        List<Metadata> metadataList = getRecursiveMetadata(corrupt, new 
ParseContext(), false);
+        
assertNotNull(metadataList.get(0).get(TikaCoreProperties.TIKA_META_EXCEPTION_EMBEDDED_STREAM));
+        assertContains("test-documents/testXML.xml",
+                metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT));
+        assertEquals("/testXML.xml",
+                metadataList.get(metadataList.size() - 
1).get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH));
+    }
+
     /**
      * Note - we don't currently support Encrypted RAR files,
      * so all we can do is throw a helpful exception

Reply via email to