You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ta...@apache.org on 2026/08/12 16:03:09 UTC
(tika) 07/07: TIKA-4809 fix EMBEDDED_EXCEPTION erasure under active metadata limiter
This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch TIKA-4809-metadata-key-api
in repository https://gitbox.apache.org/repos/asf/tika.git
commit 68744105caf64d6f862b7d6f88da89c2f908b033
Author: tallison <ta...@apache.org>
AuthorDate: Wed Aug 12 11:41:30 2026 -0400
TIKA-4809 fix EMBEDDED_EXCEPTION erasure under active metadata limiter
---
.../writefilter/StandardMetadataLimiter.java | 3 +-
.../writefilter/StandardMetadataLimiterTest.java | 75 ++++++++++++++++++++++
2 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiter.java b/tika-core/src/main/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiter.java
index 913057a8f0..4acd9db81a 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiter.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiter.java
@@ -82,12 +82,13 @@ public class StandardMetadataLimiter implements MetadataWriteLimiter, Serializab
ALWAYS_SET_FIELDS.add(AccessPermissions.EXTRACT_FOR_ACCESSIBILITY.getName());
ALWAYS_SET_FIELDS.add(Metadata.CONTENT_DISPOSITION.getName());
ALWAYS_SET_FIELDS.add(TikaCoreProperties.CONTAINER_EXCEPTION.getName());
- ALWAYS_SET_FIELDS.add(TikaCoreProperties.EMBEDDED_EXCEPTION.getName());
//Metadata.CONTENT_LOCATION? used by the html parser
}
static {
ALWAYS_ADD_FIELDS.add(TikaCoreProperties.TIKA_PARSED_BY.getName());
+ //bag-typed: one embedded-file failure per add() call must not clobber prior ones
+ ALWAYS_ADD_FIELDS.add(TikaCoreProperties.EMBEDDED_EXCEPTION.getName());
}
private static final String METADATA_TRUNCATED_KEY =
diff --git a/tika-serialization/src/test/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiterTest.java b/tika-serialization/src/test/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiterTest.java
index 989d1cdf11..9ad85c5fb2 100644
--- a/tika-serialization/src/test/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiterTest.java
+++ b/tika-serialization/src/test/java/org/apache/tika/metadata/writefilter/StandardMetadataLimiterTest.java
@@ -286,6 +286,81 @@ public class StandardMetadataLimiterTest extends TikaTest {
}
+ @Test
+ public void testEmbeddedExceptionAddRetainsAllValues() throws Exception {
+ //EMBEDDED_EXCEPTION is bag-typed and in ALWAYS_ADD_FIELDS: N adds must retain
+ //N values, in order, even under an active limiter
+ Metadata metadata = filter(100, 10000, 10000, 100,
+ Collections.EMPTY_SET, Collections.EMPTY_SET, true);
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "exception 1");
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "exception 2");
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "exception 3");
+
+ assertArrayEquals(new String[]{"exception 1", "exception 2", "exception 3"},
+ metadata.getValues(TikaCoreProperties.EMBEDDED_EXCEPTION));
+ }
+
+ @Test
+ public void testEmbeddedExceptionSetStillReplaces() throws Exception {
+ //set() must still replace, even though add() now appends
+ Metadata metadata = filter(100, 10000, 10000, 100,
+ Collections.EMPTY_SET, Collections.EMPTY_SET, true);
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "exception 1");
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "exception 2");
+ metadata.set(TikaCoreProperties.EMBEDDED_EXCEPTION, "replacement");
+
+ assertArrayEquals(new String[]{"replacement"},
+ metadata.getValues(TikaCoreProperties.EMBEDDED_EXCEPTION));
+ }
+
+ @Test
+ public void testEmbeddedExceptionPerValueTruncation() throws Exception {
+ //per-value truncation and the truncated-metadata marker must still apply,
+ //without erasing values already added
+ Metadata metadata = filter(100, 10, 100000, 100,
+ Collections.EMPTY_SET, Collections.EMPTY_SET, true);
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "short");
+ //800 utf-16 bytes, over the 300-byte always-field floor
+ String longValue = "x".repeat(400);
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, longValue);
+
+ String[] values = metadata.getValues(TikaCoreProperties.EMBEDDED_EXCEPTION);
+ assertEquals(2, values.length);
+ assertEquals("short", values[0]);
+ //truncated to the 300-byte (utf-16) always-field floor = 150 chars
+ assertEquals(150, values[1].length());
+ assertTruncated(metadata);
+ }
+
+ @Test
+ public void testEmbeddedExceptionSurvivesOverBudget() throws Exception {
+ //always-add fields must not be dropped even once the overall budget is exhausted
+ Metadata metadata = filter(100, 1, 1, 100,
+ Collections.EMPTY_SET, Collections.EMPTY_SET, true);
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "e1");
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "e2");
+ metadata.add(TikaCoreProperties.EMBEDDED_EXCEPTION, "e3");
+
+ assertArrayEquals(new String[]{"e1", "e2", "e3"},
+ metadata.getValues(TikaCoreProperties.EMBEDDED_EXCEPTION));
+ }
+
+ @Test
+ public void testSimpleAlwaysSetFieldStillReplacesOnAdd() throws Exception {
+ //CONTAINER_EXCEPTION is SIMPLE (not bag) and stays in ALWAYS_SET_FIELDS:
+ //the limiter's add() dispatch must keep replacing, as before this fix.
+ //Use addTrusted() to reach the limiter directly: Metadata.add(Property,..) itself
+ //already throws PropertyTypeException on a 2nd add to a SIMPLE property, so that
+ //typed path can't otherwise exercise the limiter's repeated-add behavior.
+ Metadata metadata = filter(100, 10000, 10000, 100,
+ Collections.EMPTY_SET, Collections.EMPTY_SET, true);
+ metadata.addTrusted(TikaCoreProperties.CONTAINER_EXCEPTION.getName(), "container exception 1");
+ metadata.addTrusted(TikaCoreProperties.CONTAINER_EXCEPTION.getName(), "container exception 2");
+
+ assertArrayEquals(new String[]{"container exception 2"},
+ metadata.getValues(TikaCoreProperties.CONTAINER_EXCEPTION));
+ }
+
@Test
public void testExclude() throws Exception {
TikaLoader loader = TikaLoader.load(getConfigPath(getClass(), "TIKA-3695-exclude.json"));