Skip to content

Commit 92d2d12

Browse files
committed
TIKA-4809: reconcile server/pipes docs and CHANGES with 4.0.0 behavior
1 parent 9946cc7 commit 92d2d12

7 files changed

Lines changed: 136 additions & 37 deletions

File tree

CHANGES.txt

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,51 @@ Release 4.0.0 - ???
1717
completing the Markdown default (TIKA-4663); use /tika/xml for XHTML (TIKA-4809).
1818

1919
* tika-server: request bodies are now capped by maxRequestSizeBytes,
20-
defaulting to 1 GiB; larger requests are rejected with 413 (TIKA-4809).
20+
defaulting to 1 GiB; larger requests are rejected with 413, including
21+
over-limit chunked uploads, which previously surfaced as an empty 500
22+
(TIKA-4809).
23+
24+
* tika-server: a /meta request with no Accept header now returns JSON;
25+
3.x returned CSV. CSV is still available via Accept: text/csv (TIKA-4809).
26+
27+
* tika-server: the raw /tika family's 422 responses carry the extracted
28+
content only; the exception is no longer appended to the body -- use
29+
/rmeta for the structured exception (TIKA-4809).
30+
31+
* tika-server: /async validates fetcher/emitter ids at POST time (400),
32+
rejects a batch larger than the queue's total capacity with 400 instead
33+
of throttling it, and one bad tuple no longer stops the async workers
34+
(TIKA-4809).
35+
36+
* tika-server: /pipes returns 400 with the reason for a malformed request
37+
body and rejects emit strategies other than EMIT_ALL, whose passed-back
38+
data the /pipes response cannot carry (TIKA-4809).
39+
40+
* tika-server: the 'endpoints' allowlist now also gates SPI-provided
41+
resources; a discovered resource binds only when its root endpoint is
42+
enabled (TIKA-4809).
43+
44+
* FetchEmitTuple JSON now names the per-tuple parse context "parse-context"
45+
(was "parseContext") and rejects unknown tuple fields with an error naming
46+
the field (TIKA-4809).
47+
48+
* The pipes config keys staleFetcherTimeoutSeconds and
49+
staleFetcherDelaySeconds have been removed; a config still carrying them
50+
fails startup (TIKA-4809).
51+
52+
* ExceptionUtils.trimMessage has been removed from tika-core; it moved into
53+
tika-eval-core (TIKA-4809).
54+
55+
* BasicContentHandlerFactory.parseHandlerType now throws
56+
IllegalArgumentException for an unrecognized handler name instead of
57+
silently returning the supplied default (TIKA-4809).
58+
59+
* HttpClientFactory's inert redirect-host allowlist accessors
60+
(get/setAllowedHostsForRedirect) have been removed (TIKA-4809).
61+
62+
* TimeoutLimits: progressTimeoutMillis of 0 combined with a positive
63+
totalTaskTimeoutMillis is now rejected at config load; it would kill
64+
every task immediately (TIKA-4809).
2165

2266
* The http-fetcher now verifies TLS certificates and hostnames by default;
2367
set verifySsl:false to opt out (TIKA-4809).

docs/modules/ROOT/pages/advanced/integration-testing/tika-server.adoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ curl -s -X PUT -H "Accept: application/json" -T testPDF.pdf http://localhost:999
118118
curl -s -X PUT -T testPDF.pdf http://localhost:9998/meta/Content-Type
119119
----
120120

121-
*Expected:* `Content-Type,application/pdf`
121+
*Expected:* JSON containing only the requested field: `{"Content-Type":"application/pdf"}`
122+
(the header-less default is JSON; add `-H "Accept: text/csv"` for `Content-Type,application/pdf`)
122123

123124
=== Test 9: PUT /rmeta
124125

@@ -155,7 +156,8 @@ curl -s -X PUT -T test_recursive_embedded.docx http://localhost:9998/unpack/all
155156
unzip -l /tmp/unpack.zip
156157
----
157158

158-
*Expected:* ZIP file containing extracted embedded files plus `__TEXT__` and `__METADATA__` files.
159+
*Expected:* ZIP file containing the extracted embedded files, a `*.metadata.json` entry
160+
per file, and the original container document.
159161

160162
=== Test 13: GET /parsers
161163

docs/modules/ROOT/pages/migration-to-4x/migrating-tika-server-4x.adoc

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,14 @@ The `/stream` and `/string` suffixes never described anything a caller could cho
110110
111111
Collapsing them also removes the `/detect/stream` vs `/detectors` near-collision. `/detectors` is unchanged -- it lists the server's configured detectors and does not detect anything.
112112
113-
**Migration:** drop the suffix. `PUT /detect/stream` becomes `PUT /detect`; `PUT /language/stream` and `PUT /language/string` both become `PUT /language`. Request bodies, headers, and responses are unchanged.
113+
**Migration:** drop the suffix. `PUT /detect/stream` becomes `PUT /detect`; `PUT /language/stream` and `PUT /language/string` both become `PUT /language`. Request bodies and headers are unchanged, but behavior is not:
114+
115+
* `/detect` now runs in the forked worker pool (detection opens containers over
116+
caller-supplied bytes), so it can return `429` or `503` with `Retry-After`, and `413`,
117+
like the parsing endpoints. A failure reading the body is now a `500`; 3.x returned
118+
`200` with `application/octet-stream` as if detection had succeeded.
119+
* `/language` caps detection input at the first 100,000 characters and uses the default
120+
`LanguageDetector` on the classpath; 3.x pinned it to Optimaize.
114121
115122
=== Handler-Type Changes on `/tika`
116123
@@ -158,7 +165,12 @@ The HTTP status codes are also more precise:
158165
header, not `503` or `200`.
159166
* An unknown or reserved fetcher/emitter (`FETCHER_NOT_FOUND`, `EMITTER_NOT_FOUND`)
160167
returns `400`, not `500` — the request is permanently malformed, so retrying will not help.
161-
* A body over `maxRequestSizeBytes` (`PAYLOAD_LIMIT_EXCEEDED`) returns `413`.
168+
* Two distinct limits return `413`. A request body over `maxRequestSizeBytes` is
169+
rejected by a request filter with a plain-text `413` -- both a declared
170+
`Content-Length` over the limit and a chunked body that turns out to be too large.
171+
Separately, a parse *result* too large for the pipes IPC channel
172+
(`pipes.maxIpcPayloadBytes`) returns `413` with the JSON status body
173+
`{"status":"PAYLOAD_LIMIT_EXCEEDED"}`.
162174
* `/pipes` and `/async` now signal the outcome through the HTTP status (the same
163175
`429`/`503`/`400`/`413` mappings, plus `Retry-After`) instead of always returning `200`
164176
with the failure only in the body.
@@ -183,9 +195,22 @@ the exception when there is one. It previously used a `/pipes`-only shape
183195
and a stringified `emitted`). A parse that threw is now reported by its status enum, not as
184196
`"ok"`.
185197
198+
`/pipes` also rejects with `400`: a malformed request body (the reason is in the response),
199+
and any emit strategy other than `EMIT_ALL` -- the `/pipes` response carries only
200+
status and message, so a passback strategy would silently discard the parsed data. Use
201+
`/rmeta` if you want the data passed back.
202+
186203
**`/async` request body.** `POST /async` now requires an object envelope,
187204
`{"tuples":[ ... ]}`, instead of a bare JSON array; the envelope leaves room for future
188-
batch-level fields. A bare array (or any body without a `tuples` array) is rejected with `400`.
205+
batch-level fields. A bare array (or any body without a `tuples` array) is rejected with `400`,
206+
as is a tuple naming a fetcher or emitter the server does not have -- validated at POST time,
207+
before anything is queued. A batch larger than the queue's *total* capacity is also a `400`
208+
telling the caller to split it: retrying cannot help. `429` with `Retry-After` is reserved
209+
for transient fullness, where the same batch can succeed later.
210+
211+
**`FetchEmitTuple` wire format.** The per-tuple parse-context key is `parse-context`;
212+
3.x used `parseContext`. An unknown field anywhere in a tuple is rejected with a `400`
213+
naming the field and listing the known ones, instead of being silently ignored.
189214
190215
=== `/meta` Is Now Pipes-Backed
191216
@@ -209,6 +234,10 @@ should check the new status codes above. Clients that inspected the response bod
209234
for error text should check `tk:exception:container-exception` (full-object
210235
endpoints) or the `422` body (`/meta/\{field}`).
211236
237+
**The default representation is now JSON, not CSV.** A `/meta` request without an
238+
`Accept` header returned CSV in 3.x; it now returns JSON. CSV is still available with
239+
`Accept: text/csv`.
240+
212241
Two changes to the returned metadata come with this, neither of which produces an
213242
error:
214243
@@ -219,7 +248,8 @@ error:
219248
content handler, so there is no text for a language detector to work from.
220249
+
221250
**Migration:** configure a language-detection metadata filter
222-
(`charsoup-metadata-filter`, `optimaize`, or `opennlp`) and use `/rmeta` or
251+
(`charsoup-metadata-filter`, `optimaize-metadata-filter`, or
252+
`open-nlp-metadata-filter`) and use `/rmeta` or
223253
`/tika/json`, which capture content. The detected value arrives as
224254
`tk:detected-language`, with `tk:detected-language-confidence`. Note that these
225255
filters read `tk:content`, so they are no-ops on `/meta` and on any endpoint
@@ -269,9 +299,12 @@ The following `TikaServerConfig` options have been removed:
269299
digests there instead of in the `server` section.
270300
* `idBase` - Renamed to `id`.
271301
* `preventStopMethod`, `maxFiles`, `javaPath`, `maxRestarts`, `numRestarts`,
272-
`forkedStatusFile`, `maxForkedStartupMillis`, `tmpFilePrefix` - Vestigial options from the
273-
pre-4.0 spawn-child server model, which no longer exists. Delete them from your config;
274-
leaving any in place now fails startup, because unrecognized config keys are rejected.
302+
`forkedStatusFile`, `maxForkedStartupMillis`, `tempFilePrefix`, `noFork` - Vestigial
303+
options from the pre-4.0 spawn-child server model, which no longer exists (the `-noFork`
304+
CLI flag is gone too). Delete them from your config; leaving any in place now fails
305+
startup, because unrecognized config keys are rejected.
306+
* `port` is now a single integer. The 3.x multi-instance port ranges and lists
307+
(`-p 9995-9998`, `-p 9995,9997`) are no longer supported; run one server per port.
275308
276309
=== Configuration via HTTP Headers Removed
277310
@@ -377,6 +410,12 @@ The capabilities are two default-`false` flags in the `server` section:
377410
378411
`/status` is no longer gated: it exposes only aggregate counters, so it is enabled simply by listing `status` under `endpoints`.
379412
413+
The `endpoints` allowlist now also gates SPI-provided resources: a discovered resource
414+
whose root path matches a named endpoint binds only when that endpoint is enabled (e.g.
415+
the `application/rdf+xml` XMP resource serves `/meta`, so omitting `meta` removes it too).
416+
An SPI resource with a custom root path still loads unconditionally -- installing the jar
417+
is the opt-in.
418+
380419
**Migration:** if your config selects `pipes` or `async`, add `"allowPipes": true`; if you rely on per-request config, add `"allowPerRequestConfig": true`:
381420
382421
[source,json]
@@ -422,6 +461,10 @@ and want `/pipes`/`/async` to fetch documents from a directory you control:
422461
}
423462
----
424463
464+
The 3.x `pipes` keys `staleFetcherTimeoutSeconds` and `staleFetcherDelaySeconds` are gone.
465+
A pipes config still carrying either fails startup: unknown pipes keys are rejected, not
466+
ignored.
467+
425468
[IMPORTANT]
426469
====
427470
Set `basePath` to a directory that contains only the documents you intend the

docs/modules/ROOT/pages/migration-to-4x/migrating-to-4x.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ If you have build scripts or container images that drop in just the jar, update
4545
In 3.x the default content handler produced XHTML/XML. In 4.x the default is **Markdown** everywhere:
4646

4747
* `tika-app` outputs Markdown by default (was XHTML). Pass `-x`/`--xml`, `-h`/`--html`, or `-t`/`--text` to choose another format.
48-
* `tika-server` the `/tika` and `/rmeta` endpoints return Markdown content by default (was XHTML/XML). Use an explicit handler path (`/tika/xml`, `/rmeta/xml`, ...) to choose another format.
48+
* `tika-server` -- the `/tika` and `/rmeta` endpoints return Markdown content by default. In 3.x, `/rmeta` returned XML content, and a bare `/tika` PUT routed among plain text, HTML, and XHTML by `Accept` header -- nondeterministically for `*/*`. Use an explicit handler path (`/tika/xml`, `/rmeta/xml`, ...) to choose another format.
4949
* The async/pipes CLI emits Markdown by default (was plain text). Use `--handler x` (etc.) to choose another format.
5050

5151
If you parse the extracted content programmatically and expect XHTML/XML, request it explicitly as shown above (TIKA-4663).

docs/modules/ROOT/pages/pipes/timeouts.adoc

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,11 @@ the rest are safe by construction.
271271
*Rejected at config load or startup:*
272272

273273
* Negative values for `totalTaskTimeoutMillis` or `progressTimeoutMillis` (zero is
274-
accepted -- see below).
274+
accepted in some combinations -- see below).
275+
* `progressTimeoutMillis: 0` with a *positive* `totalTaskTimeoutMillis` -- the stall
276+
detector would fire at the first check, killing every task immediately despite the
277+
remaining total budget. Rejected at config load, and again at task start for
278+
programmatically-built limits.
275279
* `pipes.socketTimeoutMillis` less than or equal to `pipes.heartbeatIntervalMillis` -- the client
276280
would kill a healthy server between heartbeats.
277281
* Unknown or renamed configuration fields (including pre-4.0 `timeoutSeconds` names) --
@@ -300,11 +304,11 @@ the rest are safe by construction.
300304

301305
*Accepted without warning (a coherent edge case, not a misconfiguration):*
302306

303-
* Zero for `totalTaskTimeoutMillis` or `progressTimeoutMillis` -- legal, and useful
304-
mainly in tests: it means the budget is already exhausted, so the task fails at the
305-
next operation or embedded-document boundary. It does *not* disable the timeout. A
306-
zero `progressTimeoutMillis` is in fact the *strictest* possible stall detector (any
307-
silence at all trips it) -- the opposite of disabling it. To make stall detection
307+
* Zero for *both* timeouts -- legal, and useful mainly in tests: it means the budget is
308+
already exhausted, so the task fails at the next operation or embedded-document
309+
boundary. A zero `totalTaskTimeoutMillis` alone is likewise legal (the total budget is
310+
spent). Zero does *not* disable a timeout -- and a zero `progressTimeoutMillis` next
311+
to a positive total is rejected outright (see above). To make stall detection
308312
effectively inert, set `progressTimeoutMillis` at or above `totalTaskTimeoutMillis`
309313
(see above).
310314
* `Long.MAX_VALUE` (`9223372036854775807`) for `totalTaskTimeoutMillis` or
@@ -371,9 +375,8 @@ rename with the existing value is correct for all of them: `PipesConfig`'s
371375
flag (now `--timeoutMillis`), the DWG parser's `dwgReadTimeout` (now `timeoutMillis`,
372376
default unchanged at 300000), and `ExternalParser`'s `timeoutMs` (now `timeoutMillis`, a
373377
rename that landed in 4.0 itself so this doc previously lagged the code). Fields that are
374-
genuinely seconds-based and stayed that way (e.g. `staleFetcherTimeoutSeconds`, JDBC's
375-
`queryTimeoutSeconds`, which feeds `java.sql.Statement.setQueryTimeout(int seconds)`
376-
directly) were deliberately left alone.
378+
genuinely seconds-based and stayed that way (e.g. JDBC's `queryTimeoutSeconds`, which feeds
379+
`java.sql.Statement.setQueryTimeout(int seconds)` directly) were deliberately left alone.
377380

378381
`ProcessUtils.checkCommand()` -- used by several detectors and parsers
379382
(`FileCommandDetector`, `GDALParser`, etc.) to probe whether an external binary is

docs/modules/ROOT/pages/using-tika/server/index.adoc

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,12 @@ It is therefore outside the process isolation that protects `/tika`, `/rmeta`, `
191191
one worker.
192192

193193
`/language` caps detection at the first 100,000 characters, since accuracy saturates well
194-
before that. That bounds the CPU per request, but *not* the memory: the request body is read
195-
into the server's heap before the cap applies. Bounding the body itself is what
196-
`maxRequestSizeBytes` is for; it defaults to 1 GiB, so one request cannot fill the temp
197-
directory or the heap with a small body, though enough concurrent large ones still can. Raise
198-
it for larger documents, or set a negative value to remove the limit. Treat the server as
199-
available only to trusted callers, the same as the rest of the server — see
200-
xref:security.adoc[the security model]. If you do not need `/language`, omit it from `endpoints`.
194+
before that. It reads at most that much from the body without materializing the rest, so the
195+
cap bounds both the CPU and the heap used per request. `maxRequestSizeBytes` (default 1 GiB)
196+
still bounds what a request may send at all; raise it for larger documents, or set a negative
197+
value to remove the limit. Treat the server as available only to trusted callers, the same as
198+
the rest of the server — see xref:security.adoc[the security model]. If you do not need
199+
`/language`, omit it from `endpoints`.
201200

202201
NOTE: `/detect` runs in a forked pipes worker like the parsing endpoints. Detection opens
203202
containers — zip, OPC, POIFS — over caller-supplied bytes, so it gets the same isolation,
@@ -249,7 +248,10 @@ not help; fix the fetcher/emitter id.
249248

250249
|`413 Payload Too Large`
251250
|`PAYLOAD_LIMIT_EXCEEDED`
252-
|The request body exceeded `maxRequestSizeBytes`.
251+
|The parse *result* was too large for the pipes IPC channel (`pipes.maxIpcPayloadBytes`).
252+
Distinct from a request *body* over `maxRequestSizeBytes`, which a request filter rejects
253+
with a plain-text `413` (declared `Content-Length` and chunked bodies alike) before any
254+
parsing starts.
253255

254256
|`500 Internal Server Error`
255257
|`FAILED_TO_INITIALIZE`, `FETCH_EXCEPTION`, `EMIT_EXCEPTION`,
@@ -364,7 +366,7 @@ Server behavior beyond host/port is controlled by a JSON config file passed via
364366

365367
|`maxQueuePauseMillis`
366368
|`60000`
367-
|How long a POST to `/async` blocks when the queue is full before it is rejected with `429` (`Retry-After`).
369+
|How long a POST to `/async` blocks when the queue is full before it is rejected with `429` (`Retry-After`). A batch larger than the queue's total capacity is rejected immediately with `400` -- retrying cannot help; split the batch.
368370

369371
|`requestLogLevel`
370372
|_empty (off)_
@@ -448,10 +450,12 @@ mitigation (scope `endpoints` to what you actually use, or set
448450

449451
=== Config Endpoint Protection
450452

451-
By default, the `/config` family of endpoints that expose server configuration are
452-
disabled. These endpoints can reveal sensitive information about your server,
453-
including parser settings and system properties (see
454-
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3271[CVE-2015-3271]).
453+
By default, the `/config` family of endpoints is disabled. These endpoints *accept*
454+
per-request configuration -- they do not reveal the server's own config -- and a
455+
caller-supplied config can enable dangerous operations, such as pointing parsers at
456+
attacker-chosen resources (see
457+
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3271[CVE-2015-3271] for the
458+
class of risk).
455459

456460
Protected endpoints include:
457461

@@ -476,9 +480,9 @@ your config file's `server` section:
476480
WARNING: Only enable `allowPerRequestConfig` if you have secured access to Tika
477481
Server through network controls (firewalls, private subnets), a reverse proxy
478482
(nginx, Apache httpd), or
479-
xref:using-tika/server/tls.adoc[2-way TLS authentication]. Exposing config endpoints
480-
to untrusted networks can help attackers identify vulnerabilities and craft
481-
targeted attacks.
483+
xref:using-tika/server/tls.adoc[2-way TLS authentication]. Per-request configuration
484+
lets callers change how documents are parsed, widening what anyone with access to the
485+
server can do.
482486

483487
=== Pipes and Async Endpoints
484488

tika-server/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,12 @@ Usage examples from command line with `curl` utility:
8585
* Get all document attachments as ZIP-file:
8686
`curl -v -T Doc1_ole.doc http://localhost:9998/unpack > /var/tmp/x.zip`
8787

88-
* Extract metadata to CSV format:
88+
* Extract metadata as JSON (the default):
8989
`curl -T price.xls http://localhost:9998/meta`
9090

91+
* Extract metadata as CSV:
92+
`curl -T price.xls -H "Accept: text/csv" http://localhost:9998/meta`
93+
9194
* Detect media type from CSV format using file extension hint:
9295
`curl -X PUT -H "Content-Disposition: attachment; filename=foo.csv" --upload-file foo.csv http://localhost:9998/detect`
9396

0 commit comments

Comments
 (0)