Skip to content

Commit 6c78186

Browse files
authored
1 parent aeea39e commit 6c78186

29 files changed

Lines changed: 365 additions & 178 deletions

File tree

tika-core/src/main/java/org/apache/tika/detect/AutoDetectReader.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.InputStream;
2222
import java.io.InputStreamReader;
2323
import java.nio.charset.Charset;
24+
import java.nio.charset.StandardCharsets;
2425
import java.util.List;
2526

2627
import org.xml.sax.InputSource;
@@ -30,9 +31,7 @@
3031
import org.apache.tika.io.TikaInputStream;
3132
import org.apache.tika.metadata.Metadata;
3233
import org.apache.tika.metadata.TikaCoreProperties;
33-
import org.apache.tika.mime.MediaType;
3434
import org.apache.tika.parser.ParseContext;
35-
import org.apache.tika.utils.CharsetUtils;
3635

3736
/**
3837
* An input stream reader that automatically detects the character encoding
@@ -108,24 +107,35 @@ private static Charset detect(TikaInputStream tis, Metadata metadata,
108107
return detected;
109108
}
110109

111-
// Try determining the encoding based on hints in document metadata
112-
MediaType type = MediaType.parse(metadata.get(Metadata.CONTENT_TYPE));
113-
if (type != null) {
114-
String charsetParam = type.getParameters().get("charset");
115-
if (charsetParam != null) {
116-
try {
117-
Charset cs = CharsetUtils.forName(charsetParam);
118-
metadata.set(TikaCoreProperties.DETECTED_ENCODING, cs.name());
119-
metadata.set(TikaCoreProperties.ENCODING_DETECTOR,
120-
"AutoDetectReader-charset-metadata-fallback");
121-
return cs;
122-
} catch (IllegalArgumentException e) {
123-
// ignore
124-
}
125-
}
110+
// Try determining the encoding based on hints in document metadata.
111+
// Two metadata keys are honoured (TIKA-4683 — restoring 3.x parser-layer
112+
// behaviour that consulted both): the charset parameter of CONTENT_TYPE
113+
// (e.g. "text/html; charset=UTF-8") and a bare charset label in
114+
// CONTENT_ENCODING (set by parsers such as RFC822Parser).
115+
Charset metaCharset = MetadataCharsetDetector.charsetFromContentType(metadata);
116+
if (metaCharset == null) {
117+
metaCharset = MetadataCharsetDetector.charsetFromContentEncoding(metadata);
118+
}
119+
if (metaCharset != null) {
120+
metadata.set(TikaCoreProperties.DETECTED_ENCODING, metaCharset.name());
121+
metadata.set(TikaCoreProperties.ENCODING_DETECTOR,
122+
"AutoDetectReader-charset-metadata-fallback");
123+
return metaCharset;
126124
}
127125

128-
throw new TikaException("Failed to detect the character encoding of a document");
126+
// Final fallback (TIKA-4683): when the rolled-back 3.x-style chain
127+
// (Html, Universal, Icu4j) abstains on short/pure-ASCII inputs and
128+
// metadata carries no charset hint, default to ISO-8859-1 rather
129+
// than throwing. This matches 3.x's default-charset behaviour:
130+
// pre-TIKA-4685 the chain effectively returned ISO-8859-1 for
131+
// ASCII-only content, and tests assert that. 4.x's TIKA-4685
132+
// refactor moved to windows-1252 via WHATWG normalisation; we
133+
// explicitly opt out of that here.
134+
Charset fallback = StandardCharsets.ISO_8859_1;
135+
metadata.set(TikaCoreProperties.DETECTED_ENCODING, fallback.name());
136+
metadata.set(TikaCoreProperties.ENCODING_DETECTOR,
137+
"AutoDetectReader-default-fallback");
138+
return fallback;
129139
}
130140

131141
private static TikaInputStream getTikaInputStream(InputStream stream) {

tika-core/src/main/java/org/apache/tika/detect/BOMDetector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
*
4545
* @since Apache Tika 0.x (moved to org.apache.tika.detect in 4.0)
4646
*/
47-
@TikaComponent
47+
@TikaComponent(spi = false)
4848
public class BOMDetector implements EncodingDetector {
4949

5050
private static final ByteOrderMark[] BOMS =

tika-core/src/main/java/org/apache/tika/detect/DefaultEncodingDetector.java

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
import java.util.Collection;
2020
import java.util.Comparator;
21+
import java.util.HashMap;
2122
import java.util.List;
23+
import java.util.Map;
2224
import javax.imageio.spi.ServiceRegistry;
2325

2426
import org.apache.tika.config.ServiceLoader;
@@ -28,29 +30,37 @@
2830
* implementations available through the
2931
* {@link ServiceRegistry service provider mechanism}.
3032
*
31-
* <p>Loaded detectors are sorted in two tiers:
33+
* <p>The default chain (Tika 3.x style) runs three detectors in order, with
34+
* the first non-empty result winning:
3235
* <ol>
33-
* <li>Base detectors (non-{@link MetaEncodingDetector}) sorted by full
34-
* class name (non-Tika before Tika, then ascending alphabetically).
35-
* The package ordering guarantees:
36-
* {@code org.apache.tika.ml.*} (Mojibuster) →
37-
* {@code org.apache.tika.parser.*} (HTML).</li>
38-
* <li>{@link MetaEncodingDetector} instances always run last, after all
39-
* base detectors have collected their candidates into
40-
* {@link EncodingDetectorContext}.</li>
41-
* </ol></p>
36+
* <li>{@code org.apache.tika.parser.html.HtmlEncodingDetector}</li>
37+
* <li>{@code org.apache.tika.parser.txt.UniversalEncodingDetector}</li>
38+
* <li>{@code org.apache.tika.parser.txt.Icu4jEncodingDetector}</li>
39+
* </ol>
40+
* Any other {@link EncodingDetector} discovered via SPI (e.g.,
41+
* user-supplied detectors) runs after the three blessed detectors,
42+
* preserving back-compat for callers who add their own.</p>
4243
*
4344
* <p>If you need to control the order of the Detectors explicitly, construct
4445
* your own {@link CompositeEncodingDetector} and pass in the list in the
4546
* required order.</p>
4647
*
47-
* <p>{@link MetaEncodingDetector} handling (collect-all-then-arbitrate)
48-
* is provided by {@link CompositeEncodingDetector}.</p>
49-
*
5048
* @since Apache Tika 1.15
5149
*/
5250
public class DefaultEncodingDetector extends CompositeEncodingDetector {
5351

52+
/** Pinned ordering for the 3.x-style default chain. Detectors not on this
53+
* map keep their natural SPI load order behind the three blessed ones. */
54+
private static final Map<String, Integer> PRIORITY = buildPriority();
55+
56+
private static Map<String, Integer> buildPriority() {
57+
Map<String, Integer> p = new HashMap<>();
58+
p.put("org.apache.tika.parser.html.HtmlEncodingDetector", 0);
59+
p.put("org.apache.tika.parser.txt.UniversalEncodingDetector", 1);
60+
p.put("org.apache.tika.parser.txt.Icu4jEncodingDetector", 2);
61+
return p;
62+
}
63+
5464
public DefaultEncodingDetector() {
5565
this(new ServiceLoader(DefaultEncodingDetector.class.getClassLoader()));
5666
}
@@ -67,11 +77,13 @@ public DefaultEncodingDetector(ServiceLoader loader,
6777
}
6878

6979
private static List<EncodingDetector> sorted(List<EncodingDetector> detectors) {
70-
// Two-key sort: base detectors first (meta=0) then MetaEncodingDetectors (meta=1),
71-
// within each tier sorted by full class name for stability across JARs.
80+
// Pin the 3.x default chain (html, universal, icu4j) to fixed
81+
// positions; other detectors fall to the end with stable secondary
82+
// ordering by class name.
7283
detectors.sort(Comparator
7384
.<EncodingDetector, Integer>comparing(
74-
d -> (d instanceof MetaEncodingDetector) ? 1 : 0)
85+
d -> PRIORITY.getOrDefault(
86+
d.getClass().getName(), Integer.MAX_VALUE))
7587
.thenComparing(d -> d.getClass().getName()));
7688
return detectors;
7789
}

tika-core/src/main/java/org/apache/tika/detect/MetadataCharsetDetector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
*
5050
* @since Apache Tika 4.0
5151
*/
52-
@TikaComponent(name = "metadata-charset-detector")
52+
@TikaComponent(spi = false, name = "metadata-charset-detector")
5353
public class MetadataCharsetDetector implements EncodingDetector {
5454

5555
@Override

tika-core/src/main/resources/META-INF/services/org.apache.tika.detect.EncodingDetector

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
# org.apache.tika.detect.* sorts before other detector namespaces so BOM and
17-
# HTTP/MIME DECLARATIVE evidence reaches JunkFilterEncodingDetector before any
18-
# statistical detector runs. Class-name order: BOMDetector first, then
19-
# MetadataCharsetDetector.
20-
org.apache.tika.detect.BOMDetector
21-
org.apache.tika.detect.MetadataCharsetDetector
16+
# Intentionally empty: tika-core itself does not register any default
17+
# EncodingDetector implementations. The default chain is provided by the
18+
# tika-encoding-detector-html, tika-encoding-detector-universal, and
19+
# tika-encoding-detector-icu4j modules and is sequenced by
20+
# DefaultEncodingDetector.
2221

tika-encoding-detectors/tika-encoding-detector-html/src/main/resources/META-INF/services/org.apache.tika.detect.EncodingDetector

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15-
org.apache.tika.parser.html.charsetdetector.StandardHtmlEncodingDetector
15+
org.apache.tika.parser.html.HtmlEncodingDetector
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
org.apache.tika.parser.txt.Icu4jEncodingDetector

tika-encoding-detectors/tika-encoding-detector-mojibuster/src/main/java/org/apache/tika/ml/chardetect/MojibusterEncodingDetector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
* candidate. Conservative: only return at a layer when that layer's
6767
* structural check is clean.</p>
6868
*/
69-
@TikaComponent(name = "mojibuster-encoding-detector")
69+
@TikaComponent(spi = false, name = "mojibuster-encoding-detector")
7070
public class MojibusterEncodingDetector implements EncodingDetector {
7171

7272
private static final Logger LOG =

tika-encoding-detectors/tika-encoding-detector-mojibuster/src/main/resources/META-INF/services/org.apache.tika.detect.EncodingDetector

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16-
org.apache.tika.ml.chardetect.MojibusterEncodingDetector
16+
# Intentionally empty: MojibusterEncodingDetector is no longer part of the
17+
# default Tika encoding-detection chain. Users who want it must register it
18+
# explicitly via tika-config.

tika-encoding-detectors/tika-encoding-detector-mojibuster/src/test/java/org/apache/tika/ml/chardetect/SparseLatinVcardRegressionTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.nio.charset.StandardCharsets;
2323
import java.util.List;
2424

25+
import org.junit.jupiter.api.Disabled;
2526
import org.junit.jupiter.api.Test;
2627

2728
import org.apache.tika.detect.DefaultEncodingDetector;
@@ -53,6 +54,7 @@ public class SparseLatinVcardRegressionTest {
5354
* (windows-1257, IBM852, etc.) is a documented sibling-arbitration
5455
* limitation; only the catastrophic case is asserted here.
5556
*/
57+
@Disabled("TIKA-4683: rolled-back chain (Html, Universal, Icu4j); Mojibuster no longer in default chain.")
5658
@Test
5759
public void sparseLatinVcardDoesNotDetectAsIbm424() throws Exception {
5860
byte[] probe = buildSparseLatinVcard();

0 commit comments

Comments
 (0)