[
https://issues.apache.org/jira/browse/TIKA-4857?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18109711#comment-18109711
]
ASF GitHub Bot commented on TIKA-4857:
--------------------------------------
dschmidt commented on code in PR #3098:
URL: https://github.com/apache/tika/pull/3098#discussion_r3890247202
##########
tika-core/src/test/java/org/apache/tika/extractor/EmbeddedDepthLimitTest.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.extractor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import org.apache.tika.config.EmbeddedLimits;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.io.TikaInputStream;
+import org.apache.tika.metadata.HttpHeaders;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.TikaCoreProperties;
+import org.apache.tika.mime.MediaType;
+import org.apache.tika.parser.CompositeParser;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.parser.Parser;
+import org.apache.tika.parser.RecursiveParserWrapper;
+import org.apache.tika.sax.BasicContentHandlerFactory;
+import org.apache.tika.sax.RecursiveParserWrapperHandler;
+
+/**
+ * {@code maxDepth} of {@link EmbeddedLimits} counts embedding levels, not the
+ * parsers a parse passes through (TIKA-4857): with two composite layers per
+ * document, as {@code AutoDetectParser} over {@code DefaultParser} has, the
+ * limit used to stop one level early for every value above 1.
+ */
+public class EmbeddedDepthLimitTest {
+
+ private static final MediaType NESTED = MediaType.application("x-nested");
+
+ /**
+ * Every document of this type contains one document of the same type,
+ * five levels deep.
+ */
+ private static class NestingParser implements Parser {
+ @Override
+ public Set<MediaType> getSupportedTypes(ParseContext context) {
+ return Collections.singleton(NESTED);
+ }
+
+ @Override
+ public void parse(TikaInputStream stream, ContentHandler handler,
Metadata metadata,
+ ParseContext context) throws IOException,
SAXException, TikaException {
+ int level = Integer.parseInt(new String(stream.readAllBytes(),
StandardCharsets.UTF_8));
+ if (level >= 5) {
+ return;
+ }
+ Metadata child = new Metadata();
+ child.set(HttpHeaders.CONTENT_TYPE, NESTED.toString());
+ EmbeddedDocumentExtractor extractor =
+ EmbeddedDocumentUtil.getEmbeddedDocumentExtractor(context);
+ if (extractor.shouldParseEmbedded(child, context)) {
+ try (TikaInputStream tis = TikaInputStream.get(
+ String.valueOf(level +
1).getBytes(StandardCharsets.UTF_8))) {
+ extractor.parseEmbedded(tis, handler, child, context,
false);
+ }
+ }
+ }
+ }
+
+ @ParameterizedTest
+ @CsvSource({"-1, 6, false", "0, 1, true", "1, 2, true", "2, 3, true", "3,
4, true",
+ "5, 6, false"})
+ public void testMaxDepthCountsEmbeddingLevels(int maxDepth, int
expectedDocuments,
+ boolean limitReached) throws
Exception {
+ //two composite layers, as AutoDetectParser over DefaultParser
+ Parser parser = new CompositeParser(new
org.apache.tika.mime.MediaTypeRegistry(),
+ new CompositeParser(new
org.apache.tika.mime.MediaTypeRegistry(),
+ new NestingParser()));
+ RecursiveParserWrapper wrapper = new RecursiveParserWrapper(parser);
+ RecursiveParserWrapperHandler handler = new
RecursiveParserWrapperHandler(
+ new
BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.IGNORE,
+ -1));
+ ParseContext context = new ParseContext();
+ EmbeddedLimits limits = new EmbeddedLimits();
+ limits.setMaxDepth(maxDepth);
+ context.set(EmbeddedLimits.class, limits);
+ Metadata metadata = new Metadata();
+ metadata.set(HttpHeaders.CONTENT_TYPE, NESTED.toString());
+
+ try (TikaInputStream tis =
TikaInputStream.get("0".getBytes(StandardCharsets.UTF_8))) {
+ wrapper.parse(tis, handler, metadata, context);
+ }
+ List<Metadata> documents = handler.getMetadataList();
+ assertEquals(expectedDocuments, documents.size(),
documents.toString());
+ //the wrapper lists a document once it is finished, so the deepest
comes first
Review Comment:
Reworded.
##########
tika-core/src/main/java/org/apache/tika/parser/ParseRecord.java:
##########
@@ -193,6 +194,33 @@ public void incrementEmbeddedCount() {
embeddedCount++;
}
+ /**
+ * Marks the start of an embedded document's parse: the documents parsed
+ * until {@link #exitEmbedded()} are one level deeper than the current one.
+ * Unlike {@link #getDepth()}, which counts the parsers a parse passes
+ * through, this counts embedding levels only.
+ */
+ public void enterEmbedded() {
+ embeddedDepth++;
+ }
+
+ /**
+ * Marks the end of an embedded document's parse.
+ */
+ public void exitEmbedded() {
+ embeddedDepth--;
+ }
Review Comment:
Guarded: exitEmbedded() without a matching enterEmbedded() throws
IllegalStateException.
> embedded-limits.maxDepth counts parser layers, not embedding levels
> -------------------------------------------------------------------
>
> Key: TIKA-4857
> URL: https://issues.apache.org/jira/browse/TIKA-4857
> Project: Tika
> Issue Type: Bug
> Reporter: Dominik Schmidt
> Priority: Major
>
> The javadoc of EmbeddedLimits says maxDepth is the maximum nesting depth of
> embedded documents that are still parsed (maxDepth=1: depth 1 parsed, depth 2
> not). In practice maxDepth=2 parses depth 1 only; depth 2 needs maxDepth=3.
> Reproduced with RecursiveParserWrapper on a DOCX whose EMF thumbnail is
> rendered (the rendering is a depth-2 embedded document):
> - maxDepth 1: depth 1 only, tk:exception:embedded-depth-limit-reached set
> - maxDepth 2: depth 1 only, limit reached set
> - maxDepth 3: depth 1 and 2
> - maxDepth -1: everything
> ParseRecord.depth is incremented in CompositeParser.parse for every composite
> layer a parse passes through; with AutoDetectParser wrapping DefaultParser
> that is two increments per document level, and
> ParsingEmbeddedDocumentExtractor compares that counter with maxDepth + 1. The
> limit should be checked against the embedding depth (tk:embedded-depth of the
> child), independent of how parsers are composed. The same off-by-one applies
> to /unpack with embedded-limits in tika-server.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)