This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch TIKA-4856-presets
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/TIKA-4856-presets by this push:
new 38887515ca improve documentation
38887515ca is described below
commit 38887515cac15d7e7836b593aa400bb01b2185e8
Author: tallison <[email protected]>
AuthorDate: Wed Sep 2 16:03:49 2026 -0400
improve documentation
---
CHANGES.txt | 24 +++----
docs/modules/ROOT/pages/pipes/configuration.adoc | 2 +-
docs/modules/ROOT/pages/pipes/plugins/json.adoc | 2 +-
.../ROOT/pages/using-tika/server/index.adoc | 42 ++++++------
.../org/apache/tika/pipes/api/FetchEmitTuple.java | 10 ++-
.../serialization/FetchEmitTupleDeserializer.java | 5 +-
.../apache/tika/pipes/core/server/PipesServer.java | 4 +-
.../pipes/core/server/PresetNotFoundException.java | 7 +-
.../apache/tika/config/loader/PresetRegistry.java | 74 ++++++++--------------
.../server/core/resource/PipesParsingHelper.java | 6 +-
.../tika/server/core/resource/PresetSelection.java | 12 ++--
.../core/resource/RecursiveMetadataResource.java | 5 +-
.../tika/server/core/resource/TikaResource.java | 23 +++----
.../server/core/resource/UnpackerResource.java | 7 +-
14 files changed, 93 insertions(+), 130 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index d18d621da8..01c9f054c3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,21 +3,17 @@ Release 4.1.0 - unreleased
* tika-server: named configuration presets (TIKA-4856). A preset is a
vetted parse-context fragment activated in the server config (top-level
"presets" key: an object defines one in place, true activates a
- definition from the classpath catalog so its content tracks the Tika
- version) and selected whole by inserting preset/{name} after the
- resource root: /tika/preset/{name}[/text|...],
+ classpath-catalog definition) and selected whole via preset/{name}
+ after the resource root: /tika/preset/{name}[/text|...],
/rmeta/preset/{name}[/{handlerType}], /unpack/preset/{name}[/all].
- Exactly one preset per request, never combined with a config part, and
- usable without allowPerRequestConfig -- the preset routes are network-
- addressable separately from the /config endpoints, and nothing on the
- classpath can activate a preset by itself. Only the preset's name
- travels: the forked worker resolves the content from its own config at
- config-tier trust, so presets may bind wire-blocked components and
- raise timeout limits above the per-request clamp, and every active
- preset resolves at startup or fails it. FetchEmitTuples submitted to
- /pipes and /async may carry a "preset" field, resolved the same way
- (unknown names answer the new PRESET_NOT_FOUND task status / HTTP 400;
- the REST preset routes 404 before submission).
+ One preset per request, never combined with a config part, usable
+ without allowPerRequestConfig, and network-addressable separately from
+ /config. Only the name travels: the forked worker resolves the content
+ from its own config at config-tier trust, so presets may bind
+ wire-blocked components and raise timeout limits above the per-request
+ clamp; every active preset resolves at startup or fails it.
+ FetchEmitTuples on /pipes and /async may carry a "preset" field
+ (unknown names: new PRESET_NOT_FOUND status / HTTP 400).
* Raster previews for the vector thumbnails of Office documents: the new
poi-metafile-renderer draws EMF and WMF images through POI (a PNG of
diff --git a/docs/modules/ROOT/pages/pipes/configuration.adoc
b/docs/modules/ROOT/pages/pipes/configuration.adoc
index fb1c205117..b88756be5d 100644
--- a/docs/modules/ROOT/pages/pipes/configuration.adoc
+++ b/docs/modules/ROOT/pages/pipes/configuration.adoc
@@ -113,7 +113,7 @@ See also xref:pipes/timeouts.adoc[Timeouts] for the full
timeout model.
|`maxTotalTaskTimeoutMillis`
|`3600000`
-|Ceiling for *request-supplied* timeout limits: a per-request `timeout-limits`
override may lower its timeouts freely but can never raise
`totalTaskTimeoutMillis` or `progressTimeoutMillis` above this value (values
over the cap are clamped with a warning). Limits set in the server's own
`parse-context` are trusted and not subject to this cap.
+|Ceiling for *request-supplied* timeout limits: a per-request `timeout-limits`
override may lower its timeouts freely but can never raise
`totalTaskTimeoutMillis` or `progressTimeoutMillis` above this value (values
over the cap are clamped with a warning). Limits set in the server's own
`parse-context` — or in a preset a request selects — are trusted and not
subject to this cap.
|`maxWaitForClientMillis`
|`60000`
diff --git a/docs/modules/ROOT/pages/pipes/plugins/json.adoc
b/docs/modules/ROOT/pages/pipes/plugins/json.adoc
index 62301adc8f..52b1ebba9d 100644
--- a/docs/modules/ROOT/pages/pipes/plugins/json.adoc
+++ b/docs/modules/ROOT/pages/pipes/plugins/json.adoc
@@ -57,6 +57,6 @@ Unlike the other iterators, this one takes no `fetcherId` /
`emitterId`: each li
== Notes
* The file format is JSON-lines (also called NDJSON) — one valid JSON object
per line, no surrounding array brackets.
-* Each line must be a serialized `FetchEmitTuple`: `id`, `fetcher`,
`fetchKey`, `emitter`, `emitKey`, and optionally `fetchRangeStart`,
`fetchRangeEnd`, `metadata`, `parse-context`, `onParseException`. Any other
+* Each line must be a serialized `FetchEmitTuple`: `id`, `fetcher`,
`fetchKey`, `emitter`, `emitKey`, and optionally `fetchRangeStart`,
`fetchRangeEnd`, `metadata`, `parse-context`, `onParseException`, `preset`. Any
other
field is rejected — the deserializer does not tolerate unknown keys.
* For columnar work items in a CSV, use the xref:pipes/plugins/csv.adoc[CSV
iterator] instead.
diff --git a/docs/modules/ROOT/pages/using-tika/server/index.adoc
b/docs/modules/ROOT/pages/using-tika/server/index.adoc
index 80a4a3e234..3ad3f58cc1 100644
--- a/docs/modules/ROOT/pages/using-tika/server/index.adoc
+++ b/docs/modules/ROOT/pages/using-tika/server/index.adoc
@@ -110,6 +110,8 @@ callers change how documents are parsed, widening what
anyone who can reach the
A *preset* is a named, vetted parse-context fragment: parser and component
configurations keyed
by friendly name, defined once in the server config (or shipped with Tika) and
selected whole by
name. Callers apply one by inserting `preset/{name}` directly after the
resource root:
+`/tika/preset/{name}[/text|/html|/xml|/md|/json[/{handlerType}]]`,
+`/rmeta/preset/{name}[/{handlerType}]`, `/unpack/preset/{name}[/all]`.
[source,bash]
----
@@ -136,30 +138,28 @@ the catalog fails startup:
----
Presets are deliberately narrow: a request selects exactly one, the preset
routes take no
-`config` part, and a preset never combines with request-supplied configuration
— a caller who
-needs a variant asks the operator to define it as another preset. Because the
content of a
-preset is operator- or Tika-vetted, the preset routes do *not* require
`allowPerRequestConfig`:
-they are the safe public knob, while free-form `/config` stays the privileged
one. The
-`preset/{name}` path segment also gives network controls an addressable
surface — a reverse
-proxy can allow `/rmeta/preset/render-thumbnails` (or all of `/rmeta/preset/`)
while blocking
-`/rmeta/config` entirely. An unknown preset name answers `404`. Preset names
may not start
-with `config` (that path fragment gates the `/config` endpoints).
+`config` part, and a preset never combines with request-supplied configuration
— a variant is
+another preset. Because preset content is operator- or Tika-vetted, the preset
routes do *not*
+require `allowPerRequestConfig`, and the `preset/{name}` path segment gives
network controls an
+addressable surface — a reverse proxy can allow `/rmeta/preset/` while
blocking `/rmeta/config`
+entirely. An unknown preset name answers `404`. Names are letters, digits,
`.`, `_`, `-`
+(max 100 chars) and may not start with `config` (that path fragment gates the
`/config`
+endpoints).
Only the preset's *name* travels with a request: the forked parse worker
resolves the content
from its own copy of the server config, with the same trust as the config's own
-`parse-context` block. A preset can therefore configure components that
per-request `/config`
-input may not (detectors, embedded-document extraction, exception reporting,
...) and raise
-timeout limits above the per-request clamp. Every active preset is fully
resolved at startup,
-so a preset that cannot resolve fails the server rather than its first request.
-
-Output format on the preset routes: an explicit format segment in the URL
-(`/tika/preset/{name}/text`, `/rmeta/preset/{name}/xml`) always wins. Without
one, a
-`ContentHandlerFactory` the preset itself binds decides the format; otherwise
the config's
-factory, and finally the endpoint's usual default (Markdown).
-
-Presets also work on the batch surfaces: a `FetchEmitTuple` submitted to
`/pipes` or `/async`
-may carry a top-level `"preset": "name"` field, resolved the same way and
overlaid beneath
-whatever `parseContext` the tuple itself supplies.
+`parse-context` block. A preset can therefore bind components per-request
`/config` input may
+not (detectors, embedded-document extraction, exception reporting, ...) and
raise timeout
+limits above the per-request clamp. Every active preset resolves at startup,
so a bad preset
+fails the server, not its first request.
+
+Output format on the preset routes: an explicit format segment
(`/tika/preset/{name}/text`)
+always wins; without one, a `ContentHandlerFactory` the preset binds decides,
then the
+config's, then the endpoint default (Markdown).
+
+On the batch surfaces, a `FetchEmitTuple` submitted to `/pipes` or `/async`
may carry a
+top-level `"preset": "name"` field, resolved the same way beneath the tuple's
own
+`parseContext`; an unknown name there answers the `PRESET_NOT_FOUND` status
(HTTP `400`).
=== `allowPipes` — the `/pipes` and `/async` endpoints
diff --git
a/tika-pipes/tika-pipes-api/src/main/java/org/apache/tika/pipes/api/FetchEmitTuple.java
b/tika-pipes/tika-pipes-api/src/main/java/org/apache/tika/pipes/api/FetchEmitTuple.java
index 16ac3023ae..2e9440112f 100644
---
a/tika-pipes/tika-pipes-api/src/main/java/org/apache/tika/pipes/api/FetchEmitTuple.java
+++
b/tika-pipes/tika-pipes-api/src/main/java/org/apache/tika/pipes/api/FetchEmitTuple.java
@@ -38,8 +38,7 @@ public class FetchEmitTuple implements Serializable {
private final Metadata metadata;
private final ParseContext parseContext;
private final ON_PARSE_EXCEPTION onParseException;
- // Name of an operator-defined preset the server resolves from its own
config
- // at config-tier trust; only the name travels, never the preset's content.
+ // Preset selector only: the server resolves the content from its own
config
private final String presetName;
public FetchEmitTuple(String id, FetchKey fetchKey, EmitKey emitKey) {
@@ -58,6 +57,7 @@ public class FetchEmitTuple implements Serializable {
this(id, fetchKey, emitKey, metadata, parseContext, onParseException,
null);
}
+ /** @since Apache Tika 4.1.0 */
public FetchEmitTuple(String id, FetchKey fetchKey, EmitKey emitKey,
Metadata metadata, ParseContext parseContext,
ON_PARSE_EXCEPTION onParseException, String
presetName) {
this.id = id;
@@ -95,7 +95,11 @@ public class FetchEmitTuple implements Serializable {
return onParseException;
}
- /** The selected preset's name, or null for none. */
+ /**
+ * The selected preset's name, or null for none.
+ *
+ * @since Apache Tika 4.1.0
+ */
public String getPresetName() {
return presetName;
}
diff --git
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/serialization/FetchEmitTupleDeserializer.java
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/serialization/FetchEmitTupleDeserializer.java
index 3baf55647f..90df40149f 100644
---
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/serialization/FetchEmitTupleDeserializer.java
+++
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/serialization/FetchEmitTupleDeserializer.java
@@ -150,10 +150,7 @@ public class FetchEmitTupleDeserializer extends
JsonDeserializer<FetchEmitTuple>
}
}
- /**
- * A preset name is only a selector: the server resolves it against its
own config,
- * so the sole check here is the shared name syntax (which also bounds its
length).
- */
+ // A preset name is only a selector; the shared syntax rule also bounds
its length.
private static String readPresetName(JsonNode root) throws IOException {
String presetName = readVal(PRESET, root, null, false);
if (presetName != null && !PresetRegistry.isValidName(presetName)) {
diff --git
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PipesServer.java
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PipesServer.java
index e496ca7f8f..f19ac05064 100644
---
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PipesServer.java
+++
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PipesServer.java
@@ -761,8 +761,8 @@ public class PipesServer implements AutoCloseable {
/**
* Overlays the named preset, resolved from this server's own config at
config-tier
- * trust. Only the name arrived on the wire; the caller's untrusted delta
is copied
- * on top afterwards and remains subject to the wire screens and timeout
clamping.
+ * trust; only the name arrived on the wire. The caller's untrusted delta
is copied
+ * on top afterwards and stays subject to wire screening and timeout
clamping.
*/
static void mergePreset(PresetRegistry registry, String presetName,
ParseContext merged)
throws TikaConfigException {
diff --git
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PresetNotFoundException.java
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PresetNotFoundException.java
index b3198b223f..6d03da7b0f 100644
---
a/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PresetNotFoundException.java
+++
b/tika-pipes/tika-pipes-core/src/main/java/org/apache/tika/pipes/core/server/PresetNotFoundException.java
@@ -19,9 +19,10 @@ package org.apache.tika.pipes.core.server;
import org.apache.tika.exception.TikaConfigException;
/**
- * A request selected a preset name this server's config does not activate. A
caller
- * error, not a server fault: answered with a {@code PRESET_NOT_FOUND} result
rather
- * than the crash path other pre-parse failures take.
+ * A request named a preset this server's config does not activate: a caller
error,
+ * answered with a {@code PRESET_NOT_FOUND} result rather than the crash path.
+ *
+ * @since Apache Tika 4.1.0
*/
public class PresetNotFoundException extends TikaConfigException {
diff --git
a/tika-serialization/src/main/java/org/apache/tika/config/loader/PresetRegistry.java
b/tika-serialization/src/main/java/org/apache/tika/config/loader/PresetRegistry.java
index c4892392f6..13ee3e629e 100644
---
a/tika-serialization/src/main/java/org/apache/tika/config/loader/PresetRegistry.java
+++
b/tika-serialization/src/main/java/org/apache/tika/config/loader/PresetRegistry.java
@@ -39,35 +39,27 @@ import org.apache.tika.serialization.ParseContextUtils;
import org.apache.tika.serialization.serdes.ParseContextDeserializer;
/**
- * Named, vetted parse-context fragments a caller can select whole ("presets").
- * A preset's content has the shape of a {@code parse-context} block: parser
and
- * component configurations keyed by friendly name. A caller references a
preset
- * by name only, so the configuration itself stays in Tika and in the server's
- * config rather than in consuming applications.
+ * Named, vetted parse-context fragments a caller selects whole, by name only
("presets").
+ * A preset is operator config, not caller input: resolved with the same trust
as the
+ * config's own {@code parse-context} block, and fully resolved at load so a
bad preset
+ * fails startup, not its first request.
* <p>
- * A preset is operator-authored config, not caller input: it is resolved with
- * the same trust as the config's own {@code parse-context} block (no
wire-block
- * screening), and only its <em>name</em> ever travels on a request. Every
- * active preset is fully resolved at load time, so a preset that cannot
- * resolve fails startup rather than its first request.
+ * Nothing is active unless the config's {@code presets} block names it:
{@code true}
+ * activates the classpath-catalog definition of that name (error if absent),
an object
+ * defines the preset in place (replacing any catalog definition wholesale),
+ * {@code false}/{@code null} is an explicit no-op. Catalog jars can never
activate
+ * themselves. Presets do not compose.
* <p>
- * Nothing is active unless the config's {@code presets} block names it: an
- * entry with value {@code true} activates the catalog definition of that name
- * (content shipped on the classpath, so it tracks the Tika version); an object
- * value defines the preset in place (replacing any catalog definition
- * wholesale); {@code false} or {@code null} is an explicit no-op. Catalog jars
- * can never activate themselves -- every active preset is a visible line in
- * the operator's config. Presets do not compose.
- * <p>
- * The catalog is discovered from {@code META-INF/tika/presets.idx} resources,
- * each line {@code name=/classpath/resource.json}. Blank lines and {@code #}
- * comments are ignored.
+ * The catalog is discovered from {@code META-INF/tika/presets.idx} resources,
each line
+ * {@code name=/classpath/resource.json}; blank lines and {@code #} comments
ignored.
* <pre>
* "presets": {
* "some-catalog-preset": true,
* "ocr-heavy": { "pdf-parser": { "ocr": { "strategy":
"OCR_AND_TEXT_EXTRACTION" } } }
* }
* </pre>
+ *
+ * @since Apache Tika 4.1.0
*/
public final class PresetRegistry {
@@ -90,16 +82,12 @@ public final class PresetRegistry {
}
/**
- * Builds the active roster from the config's {@code presets} block: only
- * names it lists are active. {@code true} activates a catalog definition
- * (startup error if the catalog has no such name); an object defines the
- * preset in place; {@code false}/{@code null} deactivates explicitly.
- * Every active preset is resolved here, so a preset whose content cannot
- * bind is a startup error.
+ * Builds the active roster from the config's {@code presets} block (see
the class
+ * javadoc for the value semantics), resolving every active preset.
*
* @param config the loaded config, may be null (empty roster)
- * @param classLoader loader to scan for catalog preset indexes and resolve
- * preset components, may be null for the thread
context loader
+ * @param classLoader for catalog scanning and component resolution; null
for the
+ * thread context loader
*/
public static PresetRegistry load(TikaJsonConfig config, ClassLoader
classLoader)
throws TikaConfigException {
@@ -147,10 +135,7 @@ public final class PresetRegistry {
return new PresetRegistry(presets, withContentHandlerFactory, loader);
}
- /**
- * Trusted-tier resolution: presets are operator config, so no wire-block
screening
- * -- identical treatment to the config's own {@code parse-context} block.
- */
+ // Trusted-tier resolution: operator config, so no wire-block screening.
private static ParseContext resolve(String name, JsonNode content,
ClassLoader loader)
throws TikaConfigException {
try {
@@ -232,10 +217,9 @@ public final class PresetRegistry {
}
/**
- * True if {@code name} is a legal preset name: the character/length rule
above, and
- * not starting with "config" (tika-server gates {@code /config} endpoints
on that
- * path fragment, so such a name would be unreachable there). Public so
wire
- * deserializers can bound a preset-name field with the same rule.
+ * Legal preset name: the NAME rule, and not "config"-prefixed
(tika-server gates
+ * {@code /config} endpoints on that path fragment). Public so wire
deserializers
+ * can bound a preset-name field with the same rule.
*/
public static boolean isValidName(String name) {
return name != null && NAME.matcher(name).matches()
@@ -250,29 +234,23 @@ public final class PresetRegistry {
return name != null && presets.containsKey(name);
}
- /**
- * The preset's content -- a {@code parse-context}-shaped JSON object of
- * component configurations -- or null if no preset has this name.
- */
+ /** The preset's {@code parse-context}-shaped JSON, or null for an unknown
name. */
public String parseContextJson(String name) {
JsonNode node = name == null ? null : presets.get(name);
return node == null ? null : node.toString();
}
/**
- * A fresh, fully resolved ParseContext for the named preset, or null if
no preset
- * has this name. Fresh per call: callers mutate the result per request.
+ * A fully resolved ParseContext for the preset, or null for an unknown
name.
+ * Fresh per call: callers mutate the result per request.
*/
public ParseContext newParseContext(String name) throws
TikaConfigException {
JsonNode content = name == null ? null : presets.get(name);
return content == null ? null : resolve(name, content, classLoader);
}
- /**
- * True if the named preset binds a {@link ContentHandlerFactory}: a route
with no
- * explicit format segment should then leave the choice to the preset
rather than
- * forcing its own default.
- */
+ /** True if the preset binds a {@link ContentHandlerFactory} (it then owns
the
+ * output format on routes with no explicit format segment). */
public boolean suppliesContentHandlerFactory(String name) {
return name != null && withContentHandlerFactory.contains(name);
}
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PipesParsingHelper.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PipesParsingHelper.java
index 5732661194..37ad1ffa23 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PipesParsingHelper.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PipesParsingHelper.java
@@ -245,11 +245,7 @@ public class PipesParsingHelper {
}
}
- /**
- * Lifts the in-process {@link PresetSelection} carrier out of the context
and onto the
- * tuple's own preset field: only the name travels; the forked worker
resolves the
- * preset's content from its own config at config-tier trust.
- */
+ // Only the name travels: the worker resolves the preset from its own
config.
private static String liftPresetSelection(ParseContext parseContext) {
PresetSelection preset = parseContext.get(PresetSelection.class);
if (preset == null) {
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PresetSelection.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PresetSelection.java
index 264c1bc262..f1360a73ad 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PresetSelection.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/PresetSelection.java
@@ -17,12 +17,12 @@
package org.apache.tika.server.core.resource;
/**
- * In-process carrier for a request's selected preset name, riding the request
- * ParseContext between the resource and {@link PipesParsingHelper}, which
lifts it
- * onto the tuple's own preset field before serialization. Never travels on
the wire
- * itself (the wire serializer refuses unregistered context entries, so a leak
fails
- * loudly). The preset's content is resolved by the forked worker from its own
config
- * at config-tier trust.
+ * In-process carrier for a request's selected preset name: rides the request
+ * ParseContext until {@link PipesParsingHelper} lifts it onto the tuple's
preset
+ * field. Never serialized (the wire serializer refuses unregistered entries,
so a
+ * leak fails loudly).
+ *
+ * @since Apache Tika 4.1.0
*/
public record PresetSelection(String name) {
}
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
index b3126b4f7d..4d8091d85e 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/RecursiveMetadataResource.java
@@ -161,9 +161,8 @@ public class RecursiveMetadataResource {
@PathParam(HANDLER_TYPE_PARAM)
String handlerTypeName)
throws Exception {
ParseContext context = tikaResource.createPresetContext(presetName);
- // An explicit format segment wins over a factory the preset itself
binds; with no
- // segment, parseMetadataWithContext defers to the preset's factory,
then the
- // config's, then the endpoint default.
+ // Explicit format segment wins over the preset's own factory; without
one,
+ // parseMetadataWithContext defers preset -> config -> default.
if (handlerTypeName != null && !handlerTypeName.isBlank()) {
tikaResource.setupContentHandlerFactory(context, handlerTypeName);
}
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
index 1033d1324c..f85fbaa603 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/TikaResource.java
@@ -131,12 +131,10 @@ public class TikaResource {
}
/**
- * A request context carrying the named preset selection. Only the name is
recorded
- * here: the forked worker resolves the preset from its own copy of this
config at
- * config-tier trust, so preset content is never treated as
caller-supplied wire
- * data (which would screen out wire-blocked components and clamp its
timeouts).
- * A preset is selected whole and exclusively -- the {@code preset} routes
take
- * no config part, so it never combines with request-supplied
configuration.
+ * A request context carrying only the preset selection: the forked worker
resolves
+ * the content from its own copy of this config at config-tier trust, so a
preset is
+ * never treated as caller-supplied wire data (which would screen out
wire-blocked
+ * components and clamp its timeouts).
*
* @throws NotFoundException if no preset has this name
*/
@@ -622,15 +620,12 @@ public class TikaResource {
// ==================== PUT preset endpoints ====================
- // Mirrors of the PUT endpoints above with a vetted, named parse-context
fragment
- // applied:
/tika/preset/{name}[/text|/html|/xml|/md|/json[/{handlerType}]]. The
- // preset segment sits directly after the resource root so network-layer
rules can
- // address /tika/preset/* -- or a single preset -- independently of
/tika/config*.
+ // Mirrors of the PUT endpoints above:
/tika/preset/{name}[/text|/html|/xml|/md|
+ // /json[/{handlerType}]]. The preset segment sits directly after the
resource root
+ // so network-layer rules can address /tika/preset/* independently of
/tika/config*.
// These routes take no config part; a preset never combines with request
config.
-
- // explicitHandlerType semantics: non-null (an explicit format segment in
the URL) wins
- // over everything, including a factory the preset itself binds; null
defers to the
- // preset's factory, then the config's, then the endpoint default.
+ // explicitHandlerType: non-null (an explicit format segment) wins over
everything,
+ // including the preset's own factory; null defers preset -> config ->
default.
private Response putRawPreset(InputStream is, HttpHeaders httpHeaders,
String presetName,
String explicitHandlerType) throws
IOException {
diff --git
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
index 4acaa959d5..f47243795e 100644
---
a/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
+++
b/tika-server/tika-server-core/src/main/java/org/apache/tika/server/core/resource/UnpackerResource.java
@@ -145,11 +145,8 @@ public class UnpackerResource {
* @param info URI info
* @return streaming zip response
*/
- /**
- * The wildcard {@code id} on the pre-existing routes would otherwise
silently absorb a
- * transposed preset URL ({@code /unpack/all/preset/x}, {@code
/unpack/preset} with no
- * name) and run with no preset applied -- a silent wrong-config success.
- */
+ // The wildcard id would otherwise absorb a transposed preset URL
(/unpack/all/preset/x)
+ // and silently run with no preset applied.
private static void rejectPresetInWildcard(UriInfo info) {
String id = info.getPathParameters().getFirst("id");
if (id != null && (id.equals("/preset") || id.startsWith("/preset/")))
{