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"); + } + }
