This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 08705ef9a0 keep configured timeouts on HttpFetcher requests (#3453)
08705ef9a0 is described below
commit 08705ef9a01d74043f422e88d59483c74b327b40
Author: Naveed <[email protected]>
AuthorDate: Fri Oct 30 21:06:14 2026 +0530
keep configured timeouts on HttpFetcher requests (#3453)
HttpFetcher and AtlassianJwtFetcher set a RequestConfig on every GET to
apply maxRedirects. HttpClient uses a request's own config in place of
the client default rather than merging the two, so the connect, socket
and connection-request timeouts HttpClientFactory installs as the
default never applied to a fetch. Start the per-request config from a
copy of the factory's default.
Generated-by: Claude Code (Claude Opus 5.5)
---
.../org/apache/tika/client/HttpClientFactory.java | 19 +++++++++++++-----
.../fetcher/atlassianjwt/AtlassianJwtFetcher.java | 2 +-
.../atlassianjwt/AtlassianJwtFetcherTest.java | 21 ++++++++++++++++++++
.../tika/pipes/fetcher/http/HttpFetcher.java | 2 +-
.../tika/pipes/fetcher/http/HttpFetcherTest.java | 23 ++++++++++++++++++++++
5 files changed, 60 insertions(+), 7 deletions(-)
diff --git
a/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientFactory.java
b/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientFactory.java
index 6416f99524..292f2ae065 100644
---
a/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientFactory.java
+++
b/tika-pipes/tika-httpclient-commons/src/main/java/org/apache/tika/client/HttpClientFactory.java
@@ -300,11 +300,8 @@ public class HttpClientFactory {
return builder.setConnectionManager(manager)
.evictExpiredConnections()
.setRedirectStrategy(new CustomRedirectStrategy())
-
.setDefaultRequestConfig(RequestConfig.custom().setTargetPreferredAuthSchemes(
- Arrays.asList(AuthSchemes.BASIC, AuthSchemes.NTLM))
- .setConnectionRequestTimeout(requestTimeoutMillis)
-
.setConnectTimeout(connectTimeoutMillis).setSocketTimeout(socketTimeoutMillis)
- .build()).setKeepAliveStrategy(getKeepAliveStrategy())
+ .setDefaultRequestConfig(getDefaultRequestConfig())
+ .setKeepAliveStrategy(getKeepAliveStrategy())
.setSSLSocketFactory(sslsf)
.setSSLHostnameVerifier(verifySsl
?
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
@@ -312,6 +309,18 @@ public class HttpClientFactory {
.build();
}
+ /**
+ * The request config {@link #build()} installs as the client default. A
config set on a
+ * request replaces that default rather than merging with it, so start one
from a copy of this.
+ */
+ public RequestConfig getDefaultRequestConfig() {
+ return RequestConfig.custom().setTargetPreferredAuthSchemes(
+ Arrays.asList(AuthSchemes.BASIC, AuthSchemes.NTLM))
+ .setConnectionRequestTimeout(requestTimeoutMillis)
+
.setConnectTimeout(connectTimeoutMillis).setSocketTimeout(socketTimeoutMillis)
+ .build();
+ }
+
private void addProxy(HttpClientBuilder builder) {
if (!StringUtils.isBlank(proxyHost)) {
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/main/java/org/apache/tika/pipes/fetcher/atlassianjwt/AtlassianJwtFetcher.java
b/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/main/java/org/apache/tika/pipes/fetcher/atlassianjwt/AtlassianJwtFetcher.java
index 721fc1d0d6..4c668d7aaa 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/main/java/org/apache/tika/pipes/fetcher/atlassianjwt/AtlassianJwtFetcher.java
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/main/java/org/apache/tika/pipes/fetcher/atlassianjwt/AtlassianJwtFetcher.java
@@ -148,7 +148,7 @@ public class AtlassianJwtFetcher extends
AbstractTikaExtension implements Fetche
public TikaInputStream fetch(String fetchKey, Metadata metadata,
ParseContext parseContext)
throws IOException, TikaException {
HttpGet get = new HttpGet(fetchKey);
- RequestConfig requestConfig = RequestConfig.custom()
+ RequestConfig requestConfig =
RequestConfig.copy(httpClientFactory.getDefaultRequestConfig())
.setMaxRedirects(config.getMaxRedirects())
.setRedirectsEnabled(config.getMaxRedirects() > 0).build();
get.setConfig(requestConfig);
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/test/java/org/apache/tika/pipes/atlassianjwt/AtlassianJwtFetcherTest.java
b/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/test/java/org/apache/tika/pipes/atlassianjwt/AtlassianJwtFetcherTest.java
index 665beb38bf..675eabc6b2 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/test/java/org/apache/tika/pipes/atlassianjwt/AtlassianJwtFetcherTest.java
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-atlassian-jwt/src/test/java/org/apache/tika/pipes/atlassianjwt/AtlassianJwtFetcherTest.java
@@ -17,10 +17,17 @@
package org.apache.tika.pipes.atlassianjwt;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.SocketTimeoutException;
+
import org.junit.jupiter.api.Test;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.ParseContext;
import org.apache.tika.pipes.fetcher.atlassianjwt.AtlassianJwtFetcher;
import
org.apache.tika.pipes.fetcher.atlassianjwt.config.AtlassianJwtFetcherConfig;
@@ -51,4 +58,18 @@ public class AtlassianJwtFetcherTest {
assertFalse(AtlassianJwtFetcherConfig.load("{\"verifySsl\":false}").isVerifySsl());
assertTrue(AtlassianJwtFetcherConfig.load("{}").isVerifySsl());
}
+
+ @Test
+ public void testSocketTimeoutAppliesToRequests() throws Exception {
+ AtlassianJwtFetcher fetcher = new AtlassianJwtFetcher(null, new
AtlassianJwtFetcherConfig()
+ .setSocketTimeoutMillis(500)
+ .setOverallTimeoutMillis(10_000L));
+ fetcher.initialize();
+ // the backlog completes the handshake; nothing ever answers the
request
+ try (ServerSocket silent = new ServerSocket(0, 50,
InetAddress.getLoopbackAddress())) {
+ String url = "http://127.0.0.1:" + silent.getLocalPort() + "/";
+ assertThrows(SocketTimeoutException.class,
+ () -> fetcher.fetch(url, new Metadata(), new
ParseContext()));
+ }
+ }
}
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/main/java/org/apache/tika/pipes/fetcher/http/HttpFetcher.java
b/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/main/java/org/apache/tika/pipes/fetcher/http/HttpFetcher.java
index efaf6e0106..14e81f0f96 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/main/java/org/apache/tika/pipes/fetcher/http/HttpFetcher.java
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/main/java/org/apache/tika/pipes/fetcher/http/HttpFetcher.java
@@ -173,7 +173,7 @@ public class HttpFetcher extends AbstractTikaExtension
implements Fetcher, Range
private RequestConfig buildRequestConfig() {
return RequestConfig
- .custom()
+ .copy(httpClientFactory.getDefaultRequestConfig())
.setMaxRedirects(httpFetcherConfig.getMaxRedirects())
.setRedirectsEnabled(httpFetcherConfig.getMaxRedirects() > 0)
.build();
diff --git
a/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/test/java/org/apache/tika/pipes/fetcher/http/HttpFetcherTest.java
b/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/test/java/org/apache/tika/pipes/fetcher/http/HttpFetcherTest.java
index 0a6501dd55..b5e0d7d793 100644
---
a/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/test/java/org/apache/tika/pipes/fetcher/http/HttpFetcherTest.java
+++
b/tika-pipes/tika-pipes-plugins/tika-pipes-http/src/test/java/org/apache/tika/pipes/fetcher/http/HttpFetcherTest.java
@@ -24,6 +24,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -48,6 +51,7 @@ import org.apache.http.HttpStatus;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
@@ -327,6 +331,23 @@ class HttpFetcherTest extends TikaTest {
}
}
+ @Test
+ public void testSocketTimeoutAppliesToRequests() throws Exception {
+ HttpFetcherConfig config = new HttpFetcherConfig()
+ .setSocketTimeoutMillis(500)
+ .setOverallTimeoutMillis(10_000L);
+ HttpFetcher fetcher = new HttpFetcher(null, config);
+ fetcher.initialize();
+ // the backlog completes the handshake; nothing ever answers the
request
+ try (ServerSocket silent = new ServerSocket(0, 50,
InetAddress.getLoopbackAddress())) {
+ String url = "http://127.0.0.1:" + silent.getLocalPort() + "/";
+ assertThrows(SocketTimeoutException.class,
+ () -> fetcher.fetch(url, new Metadata(), new
ParseContext()));
+ assertThrows(SocketTimeoutException.class,
+ () -> fetcher.fetch(url, 0, 10, new Metadata(), new
ParseContext()));
+ }
+ }
+
FetcherManager getFetcherManager(String path) throws Exception {
Path configPath =
Paths.get(HttpFetcherTest.class.getResource("/configs/" + path).toURI());
TikaJsonConfig tikaJsonConfig = TikaJsonConfig.load(configPath);
@@ -369,6 +390,8 @@ class HttpFetcherTest extends TikaTest {
.when(clientFactory.build()).thenReturn(httpClient);
Mockito
.when(clientFactory.copy()).thenReturn(clientFactory);
+ Mockito
+
.when(clientFactory.getDefaultRequestConfig()).thenReturn(RequestConfig.DEFAULT);
httpFetcher.setHttpClientFactory(clientFactory);
httpFetcher.setHttpFetcherConfig(httpFetcherConfig);