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 787d9ffe4e TIKA-4809: Fix /meta's spurious depth-limit flag and
envelope Content-Type (#3007)
787d9ffe4e is described below
commit 787d9ffe4e3b31fa715eea4690ee6b1febfaee0c
Author: Tim Allison <[email protected]>
AuthorDate: Tue Aug 11 14:25:32 2026 -0400
TIKA-4809: Fix /meta's spurious depth-limit flag and envelope Content-Type
(#3007)
---
.../server/core/resource/MetadataResource.java | 19 +++++---
.../tika/server/standard/MetadataResourceTest.java | 50 +++++++++++++++++++++-
2 files changed, 63 insertions(+), 6 deletions(-)
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
index 1fbc0bffdb..3e0b3625ca 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java
@@ -36,8 +36,9 @@ import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.tika.config.EmbeddedLimits;
import org.apache.tika.exception.TikaException;
+import org.apache.tika.extractor.DocumentSelector;
+import org.apache.tika.extractor.SkipEmbeddedDocumentSelector;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
@@ -89,7 +90,11 @@ public class MetadataResource {
Metadata metadata = Metadata.newInstance(context);
try (TikaInputStream tis =
tikaResource.setupMultipartConfig(attachments, metadata, context)) {
TikaResource.logRequest(LOG, "/meta/config", metadata);
- return Response.ok(parseMetadata(tis, metadata,
httpHeaders.getRequestHeaders(), context)).build();
+ // No request headers: on a multipart request those describe the
envelope
+ // ("multipart/form-data; boundary=..." and its total length), and
would
+ // overwrite the Content-Type/Content-Length setupMultipartConfig
derived
+ // from the file part.
+ return Response.ok(parseMetadata(tis, metadata, null,
context)).build();
}
}
@@ -163,7 +168,7 @@ public class MetadataResource {
/**
* Parses via the shared pipes-backed PipesParser, stopping at the
container document
- * (EmbeddedLimits maxDepth=0) with content capture off ("ignore" handler)
-- metadata
+ * (SkipEmbeddedDocumentSelector) with content capture off ("ignore"
handler) -- metadata
* only, matching /meta's contract. Set unconditionally so per-request
config can't
* turn content capture back on. A container-level exception is embedded in
* CONTAINER_EXCEPTION here, not thrown; getMetadataField throws instead
since it
@@ -171,8 +176,12 @@ public class MetadataResource {
*/
protected Metadata parseMetadata(TikaInputStream tis, Metadata metadata,
MultivaluedMap<String, String> httpHeaders, ParseContext context)
throws Exception {
- fillMetadata(null, metadata, httpHeaders);
- context.set(EmbeddedLimits.class, new EmbeddedLimits(0, false,
EmbeddedLimits.UNLIMITED, false));
+ if (httpHeaders != null) {
+ fillMetadata(null, metadata, httpHeaders);
+ }
+ // Selector, not EmbeddedLimits(maxDepth=0): reaching a limit is
recorded, so a depth
+ // limit would stamp tk:exception:embedded-depth-limit-reached on
every container.
+ context.set(DocumentSelector.class, new
SkipEmbeddedDocumentSelector());
context.set(ContentHandlerFactory.class,
new
BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.IGNORE, -1));
diff --git
a/tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/MetadataResourceTest.java
b/tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/MetadataResourceTest.java
index e548f9d5c6..75b2b36509 100644
---
a/tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/MetadataResourceTest.java
+++
b/tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/MetadataResourceTest.java
@@ -19,6 +19,7 @@ package org.apache.tika.server.standard;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -46,11 +47,14 @@ import org.junit.jupiter.api.Test;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.metadata.TikaCoreProperties;
import org.apache.tika.serialization.JsonMetadata;
+import org.apache.tika.serialization.JsonMetadataList;
import org.apache.tika.server.core.CXFTestBase;
import org.apache.tika.server.core.TikaServerParseExceptionMapper;
import org.apache.tika.server.core.resource.MetadataResource;
+import org.apache.tika.server.core.resource.RecursiveMetadataResource;
import org.apache.tika.server.core.writer.CSVMessageBodyWriter;
import org.apache.tika.server.core.writer.JSONMessageBodyWriter;
+import org.apache.tika.server.core.writer.MetadataListMessageBodyWriter;
import org.apache.tika.server.core.writer.TextMessageBodyWriter;
import org.apache.tika.server.standard.resource.XMPMetadataResource;
import org.apache.tika.server.standard.writer.XMPMessageBodyWriter;
@@ -58,6 +62,7 @@ import
org.apache.tika.server.standard.writer.XMPMessageBodyWriter;
public class MetadataResourceTest extends CXFTestBase {
private static final String META_PATH = "/meta";
+ private static final String TEST_RECURSIVE_DOC =
"test-documents/test_recursive_embedded.docx";
@Override
protected boolean isAllowPerRequestConfig() {
@@ -66,9 +71,12 @@ public class MetadataResourceTest extends CXFTestBase {
@Override
protected void setUpResources(JAXRSServerFactoryBean sf) {
- sf.setResourceClasses(MetadataResource.class,
XMPMetadataResource.class);
+ sf.setResourceClasses(MetadataResource.class,
XMPMetadataResource.class,
+ RecursiveMetadataResource.class);
sf.setResourceProvider(MetadataResource.class, new
SingletonResourceProvider(new MetadataResource(tikaResource)));
sf.setResourceProvider(XMPMetadataResource.class, new
SingletonResourceProvider(new XMPMetadataResource(tikaResource)));
+ sf.setResourceProvider(RecursiveMetadataResource.class,
+ new SingletonResourceProvider(new
RecursiveMetadataResource(tikaResource)));
}
@Override
@@ -78,6 +86,7 @@ public class MetadataResourceTest extends CXFTestBase {
providers.add(new TikaServerParseExceptionMapper(false));
providers.add(new JSONMessageBodyWriter());
providers.add(new CSVMessageBodyWriter());
+ providers.add(new MetadataListMessageBodyWriter());
providers.add(new XMPMessageBodyWriter());
providers.add(new TextMessageBodyWriter());
sf.setProviders(providers);
@@ -282,4 +291,43 @@ public class MetadataResourceTest extends CXFTestBase {
}
+ /**
+ * /meta and /rmeta[0] describe the same container document, so their
metadata must
+ * agree. /meta reaches it by a different route (embedded parsing
suppressed, content
+ * capture off), and every /meta defect this release -- a dropped field, a
spurious
+ * exception flag, a Content-Type taken from the multipart envelope -- was
a silent
+ * divergence between the two that no test compared.
+ */
+ @Test
+ public void testMetaAgreesWithRmeta() throws Exception {
+ Metadata meta = JsonMetadata.fromJson(new InputStreamReader(
+ (InputStream) WebClient.create(endPoint +
META_PATH).accept("application/json")
+
.put(ClassLoader.getSystemResourceAsStream(TEST_RECURSIVE_DOC))
+ .getEntity(), UTF_8));
+
+ List<Metadata> rmeta = JsonMetadataList.fromJson(new InputStreamReader(
+ (InputStream) WebClient.create(endPoint +
"/rmeta/ignore").accept("application/json")
+
.put(ClassLoader.getSystemResourceAsStream(TEST_RECURSIVE_DOC))
+ .getEntity(), UTF_8));
+ Metadata container = rmeta.get(0);
+
+ for (String name : container.names()) {
+ // tk:content is absent from both (ignore handler); embedded-only
bookkeeping
+ // legitimately differs because /meta stops at the container.
+ // tk:content is absent from both (ignore handler).
tk:resource-name and
+ // tk:source-path currently carry the server's per-request spool
filename, so
+ // they differ by construction until that is fixed.
+ if (name.startsWith("X-TIKA:EXCEPTION") ||
name.equals("tk:content")
+ || name.startsWith("tk:parsed-by-full-set")
+ || name.equals("tk:resource-name") ||
name.equals("tk:source-path")
+ || name.equals("tk:parse-time-millis")) {
+ continue;
+ }
+ assertEquals(container.get(name), meta.get(name),
+ "/meta and /rmeta[0] disagree on '" + name + "'");
+ }
+ assertNull(meta.get("tk:exception:embedded-depth-limit-reached"),
+ "/meta suppresses embedded docs; that is not a limit the
caller hit");
+ }
+
}