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

tballison pushed a commit to branch TIKA-4809-stage-7
in repository https://gitbox.apache.org/repos/asf/tika.git

commit 8cf724e51c396e671cf90296776d0ce75bc9c848
Author: tallison <[email protected]>
AuthorDate: Mon Aug 10 13:01:53 2026 -0400

    TIKA-4809: Fix /meta's spurious depth-limit flag and envelope Content-Type
---
 .../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");
+    }
+
 }

Reply via email to