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 f52c779fe3 TIKA-4985: keep parsing a RAR past an entry junrar fails to
extract (#3377)
f52c779fe3 is described below
commit f52c779fe3a6511754f36501cef4bc8d81bef094
Author: Tim Allison <[email protected]>
AuthorDate: Wed Oct 21 08:52:56 2026 -0400
TIKA-4985: keep parsing a RAR past an entry junrar fails to extract (#3377)
* TIKA-4985: keep parsing a RAR past an entry junrar fails to extract
junrar 8.1.2 reports a truncated, corrupt or password-protected entry as
an
IOException on the entry's stream, which escaped as a container exception
and
lost the rest of the archive. End the entry at the failure instead, keep
what
was extracted, and record the failure as an embedded-stream exception.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
* TIKA-4985: name the failed RAR entry; assert test entries by path
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Tilman Hausherr <[email protected]>
---
CHANGES.txt | 12 ++++++--
.../java/org/apache/tika/parser/pkg/RarParser.java | 30 +++++++++++++++++++-
.../org/apache/tika/parser/pkg/RarParserTest.java | 32 ++++++++++++++++++++++
3 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index f3df1b316f..ef14a82210 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
Release 4.2.0 - unreleased
+ BREAKING CHANGES AND DEPRECATIONS
* Extract stored line and paragraph counts from legacy Microsoft Word
(.doc) documents. The existing metadata properties are now populated
when these values are available in the document (TIKA-4694).
@@ -12,8 +13,6 @@ Release 4.2.0 - unreleased
parent directory of the study file, so pass a file-backed TikaInputStream
(TikaInputStream.get(Path)) (TIKA-4986).
- BREAKING CHANGES AND DEPRECATIONS
-
* Unpack output is a Frictionless Data Package by default on tika-server
/unpack,
tika-app -z/-Z and pipes UNPACK; unpack-config.outputFormat=REGULAR
(--unpack-format=REGULAR) restores the old layout (TIKA-4681). A document
without
@@ -318,6 +317,15 @@ Release 4.2.0 - unreleased
OTHER CHANGES
+ * A RAR entry junrar fails to extract (truncated archive, bad CRC, missing
password)
+ is now recorded as tk:exception:embedded-stream-exception on the
container; the
+ entry still yields what was extracted before the failure, and the rest of
the
+ archive is still parsed (junrar 8.1.2, TIKA-4985).
+
+ * ISArchiveParser no longer reads every ISA-Tab document's investigation
and assay files
+ from the directory of the first document it parsed; concurrent parses no
longer share
+ the study file name (TIKA-4986).
+
* JSoupParser emits CDATA text again (TIKA-4963).
* OutlookExtractor falls back to the Date: header when a .msg has no MAPI
date
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 667c983612..377667da03 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
@@ -17,12 +17,14 @@
package org.apache.tika.parser.pkg;
import java.io.IOException;
+import java.io.InputStream;
import java.util.Collections;
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;
@@ -91,11 +93,17 @@ public class RarParser implements Parser {
AbstractArchiveParser.setLocalTime(entrydata,
FileSystem.CREATED, header.getCTime());
AbstractArchiveParser.setLocalTime(entrydata,
FileSystem.MODIFIED, header.getMTime());
AbstractArchiveParser.setLocalTime(entrydata,
FileSystem.ACCESSED, header.getATime());
- try (TikaInputStream rarTis =
TikaInputStream.get(rar.getInputStream(header))) {
+ EntryStream entryStream = new
EntryStream(rar.getInputStream(header));
+ try (TikaInputStream rarTis =
TikaInputStream.get(entryStream)) {
if (extractor.shouldParseEmbedded(entrydata, context))
{
extractor.parseEmbedded(rarTis, handler,
entrydata, context, true);
}
}
+ if (entryStream.failure != null) {
+ EmbeddedDocumentUtil.recordEmbeddedStreamException(
+ new IOException("RAR entry " +
header.getFileName(),
+ entryStream.failure), metadata,
context);
+ }
}
header = rar.nextFileHeader();
@@ -112,4 +120,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 89380866b5..fc0e601e52 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
@@ -22,12 +22,19 @@ import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
+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.io.TikaInputStream;
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;
@@ -92,6 +99,31 @@ public class RarParserTest extends AbstractPkgTest {
assertContains("test-documents/testXML.xml", content);
}
+ @Test
+ public void testCorruptEntryKeepsLaterEntries(@TempDir Path tmp) throws
Exception {
+ byte[] rar;
+ try (TikaInputStream tis =
getResourceAsStream("/test-documents/test-documents.rar")) {
+ rar = IOUtils.toByteArray(tis);
+ }
+ // 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);
+ assertContains("testEXCEL.xls",
+
metadataList.get(0).get(TikaCoreProperties.TIKA_META_EXCEPTION_EMBEDDED_STREAM));
+ assertContains("test-documents/testXML.xml",
+ metadataList.get(0).get(TikaCoreProperties.TIKA_CONTENT));
+ assertTrue(hasEmbeddedPath(metadataList, "/testEXCEL.xls"));
+ assertTrue(hasEmbeddedPath(metadataList, "/testXML.xml"));
+ }
+
+ private static boolean hasEmbeddedPath(List<Metadata> metadataList, String
path) {
+ return metadataList.stream()
+ .anyMatch(m ->
path.equals(m.get(TikaCoreProperties.EMBEDDED_RESOURCE_PATH)));
+ }
+
/**
* Note - we don't currently support Encrypted RAR files,
* so all we can do is throw a helpful exception