Skip to content

Commit 787d9ff

Browse files
authored
TIKA-4809: Fix /meta's spurious depth-limit flag and envelope Content-Type (#3007)
1 parent 3d5bd05 commit 787d9ff

2 files changed

Lines changed: 63 additions & 6 deletions

File tree

tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/MetadataResource.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636
import org.slf4j.Logger;
3737
import org.slf4j.LoggerFactory;
3838

39-
import org.apache.tika.config.EmbeddedLimits;
4039
import org.apache.tika.exception.TikaException;
40+
import org.apache.tika.extractor.DocumentSelector;
41+
import org.apache.tika.extractor.SkipEmbeddedDocumentSelector;
4142
import org.apache.tika.io.TikaInputStream;
4243
import org.apache.tika.metadata.Metadata;
4344
import org.apache.tika.metadata.TikaCoreProperties;
@@ -89,7 +90,11 @@ public Response getMetadataWithConfig(
8990
Metadata metadata = Metadata.newInstance(context);
9091
try (TikaInputStream tis = tikaResource.setupMultipartConfig(attachments, metadata, context)) {
9192
TikaResource.logRequest(LOG, "/meta/config", metadata);
92-
return Response.ok(parseMetadata(tis, metadata, httpHeaders.getRequestHeaders(), context)).build();
93+
// No request headers: on a multipart request those describe the envelope
94+
// ("multipart/form-data; boundary=..." and its total length), and would
95+
// overwrite the Content-Type/Content-Length setupMultipartConfig derived
96+
// from the file part.
97+
return Response.ok(parseMetadata(tis, metadata, null, context)).build();
9398
}
9499
}
95100

@@ -163,16 +168,20 @@ public Response getMetadataField(InputStream is, @Context HttpHeaders httpHeader
163168

164169
/**
165170
* Parses via the shared pipes-backed PipesParser, stopping at the container document
166-
* (EmbeddedLimits maxDepth=0) with content capture off ("ignore" handler) -- metadata
171+
* (SkipEmbeddedDocumentSelector) with content capture off ("ignore" handler) -- metadata
167172
* only, matching /meta's contract. Set unconditionally so per-request config can't
168173
* turn content capture back on. A container-level exception is embedded in
169174
* CONTAINER_EXCEPTION here, not thrown; getMetadataField throws instead since it
170175
* returns a bare scalar with nowhere to embed it.
171176
*/
172177
protected Metadata parseMetadata(TikaInputStream tis, Metadata metadata, MultivaluedMap<String, String> httpHeaders, ParseContext context)
173178
throws Exception {
174-
fillMetadata(null, metadata, httpHeaders);
175-
context.set(EmbeddedLimits.class, new EmbeddedLimits(0, false, EmbeddedLimits.UNLIMITED, false));
179+
if (httpHeaders != null) {
180+
fillMetadata(null, metadata, httpHeaders);
181+
}
182+
// Selector, not EmbeddedLimits(maxDepth=0): reaching a limit is recorded, so a depth
183+
// limit would stamp tk:exception:embedded-depth-limit-reached on every container.
184+
context.set(DocumentSelector.class, new SkipEmbeddedDocumentSelector());
176185
context.set(ContentHandlerFactory.class,
177186
new BasicContentHandlerFactory(BasicContentHandlerFactory.HANDLER_TYPE.IGNORE, -1));
178187

tika-server/tika-server-standard/src/test/java/org/apache/tika/server/standard/MetadataResourceTest.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static java.nio.charset.StandardCharsets.UTF_8;
2020
import static org.junit.jupiter.api.Assertions.assertEquals;
2121
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
import static org.junit.jupiter.api.Assertions.assertNull;
2223

2324
import java.io.InputStream;
2425
import java.io.InputStreamReader;
@@ -46,18 +47,22 @@
4647
import org.apache.tika.metadata.Metadata;
4748
import org.apache.tika.metadata.TikaCoreProperties;
4849
import org.apache.tika.serialization.JsonMetadata;
50+
import org.apache.tika.serialization.JsonMetadataList;
4951
import org.apache.tika.server.core.CXFTestBase;
5052
import org.apache.tika.server.core.TikaServerParseExceptionMapper;
5153
import org.apache.tika.server.core.resource.MetadataResource;
54+
import org.apache.tika.server.core.resource.RecursiveMetadataResource;
5255
import org.apache.tika.server.core.writer.CSVMessageBodyWriter;
5356
import org.apache.tika.server.core.writer.JSONMessageBodyWriter;
57+
import org.apache.tika.server.core.writer.MetadataListMessageBodyWriter;
5458
import org.apache.tika.server.core.writer.TextMessageBodyWriter;
5559
import org.apache.tika.server.standard.resource.XMPMetadataResource;
5660
import org.apache.tika.server.standard.writer.XMPMessageBodyWriter;
5761

5862
public class MetadataResourceTest extends CXFTestBase {
5963

6064
private static final String META_PATH = "/meta";
65+
private static final String TEST_RECURSIVE_DOC = "test-documents/test_recursive_embedded.docx";
6166

6267
@Override
6368
protected boolean isAllowPerRequestConfig() {
@@ -66,9 +71,12 @@ protected boolean isAllowPerRequestConfig() {
6671

6772
@Override
6873
protected void setUpResources(JAXRSServerFactoryBean sf) {
69-
sf.setResourceClasses(MetadataResource.class, XMPMetadataResource.class);
74+
sf.setResourceClasses(MetadataResource.class, XMPMetadataResource.class,
75+
RecursiveMetadataResource.class);
7076
sf.setResourceProvider(MetadataResource.class, new SingletonResourceProvider(new MetadataResource(tikaResource)));
7177
sf.setResourceProvider(XMPMetadataResource.class, new SingletonResourceProvider(new XMPMetadataResource(tikaResource)));
78+
sf.setResourceProvider(RecursiveMetadataResource.class,
79+
new SingletonResourceProvider(new RecursiveMetadataResource(tikaResource)));
7280
}
7381

7482
@Override
@@ -78,6 +86,7 @@ protected void setUpProviders(JAXRSServerFactoryBean sf) {
7886
providers.add(new TikaServerParseExceptionMapper(false));
7987
providers.add(new JSONMessageBodyWriter());
8088
providers.add(new CSVMessageBodyWriter());
89+
providers.add(new MetadataListMessageBodyWriter());
8190
providers.add(new XMPMessageBodyWriter());
8291
providers.add(new TextMessageBodyWriter());
8392
sf.setProviders(providers);
@@ -282,4 +291,43 @@ public void testGetField_Author_XMP_Partial_Found() throws Exception {
282291
}
283292

284293

294+
/**
295+
* /meta and /rmeta[0] describe the same container document, so their metadata must
296+
* agree. /meta reaches it by a different route (embedded parsing suppressed, content
297+
* capture off), and every /meta defect this release -- a dropped field, a spurious
298+
* exception flag, a Content-Type taken from the multipart envelope -- was a silent
299+
* divergence between the two that no test compared.
300+
*/
301+
@Test
302+
public void testMetaAgreesWithRmeta() throws Exception {
303+
Metadata meta = JsonMetadata.fromJson(new InputStreamReader(
304+
(InputStream) WebClient.create(endPoint + META_PATH).accept("application/json")
305+
.put(ClassLoader.getSystemResourceAsStream(TEST_RECURSIVE_DOC))
306+
.getEntity(), UTF_8));
307+
308+
List<Metadata> rmeta = JsonMetadataList.fromJson(new InputStreamReader(
309+
(InputStream) WebClient.create(endPoint + "/rmeta/ignore").accept("application/json")
310+
.put(ClassLoader.getSystemResourceAsStream(TEST_RECURSIVE_DOC))
311+
.getEntity(), UTF_8));
312+
Metadata container = rmeta.get(0);
313+
314+
for (String name : container.names()) {
315+
// tk:content is absent from both (ignore handler); embedded-only bookkeeping
316+
// legitimately differs because /meta stops at the container.
317+
// tk:content is absent from both (ignore handler). tk:resource-name and
318+
// tk:source-path currently carry the server's per-request spool filename, so
319+
// they differ by construction until that is fixed.
320+
if (name.startsWith("X-TIKA:EXCEPTION") || name.equals("tk:content")
321+
|| name.startsWith("tk:parsed-by-full-set")
322+
|| name.equals("tk:resource-name") || name.equals("tk:source-path")
323+
|| name.equals("tk:parse-time-millis")) {
324+
continue;
325+
}
326+
assertEquals(container.get(name), meta.get(name),
327+
"/meta and /rmeta[0] disagree on '" + name + "'");
328+
}
329+
assertNull(meta.get("tk:exception:embedded-depth-limit-reached"),
330+
"/meta suppresses embedded docs; that is not a limit the caller hit");
331+
}
332+
285333
}

0 commit comments

Comments
 (0)