This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-connection-timeout-agent.git
The following commit(s) were added to refs/heads/master by this push:
new d6afeaa SLING-12948 - Add JDK HttpClient support (#14)
d6afeaa is described below
commit d6afeaa281a55ebbcfadf1eb0368635a90df1410
Author: Michał Szczęśniak <[email protected]>
AuthorDate: Wed Sep 24 14:33:46 2025 +0200
SLING-12948 - Add JDK HttpClient support (#14)
Co-authored-by: Robert Munteanu <[email protected]>
---
pom.xml | 2 +-
src/main/java/org/apache/sling/cta/impl/Agent.java | 4 +-
.../JdkHttpClientBuilderTimeoutTransformer.java | 55 ++++++++++++++++++++++
.../JdkHttpRequestBuilderTimeoutTransformer.java | 55 ++++++++++++++++++++++
.../java/org/apache/sling/cta/impl/AgentIT.java | 6 ++-
.../org/apache/sling/cta/impl/AgentLauncher.java | 2 +-
.../org/apache/sling/cta/impl/ErrorDescriptor.java | 11 ++++-
.../apache/sling/cta/impl/HttpClientLauncher.java | 35 +++++++++++++-
.../java/org/apache/sling/cta/impl/OsgiIT.java | 2 +-
9 files changed, 163 insertions(+), 9 deletions(-)
diff --git a/pom.xml b/pom.xml
index d6109ae..d1e882f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -188,6 +188,6 @@
</dependencies>
<properties>
<pax-exam.version>4.14.0</pax-exam.version>
- <sling.java.version>8</sling.java.version>
+ <sling.java.version>11</sling.java.version>
</properties>
</project>
diff --git a/src/main/java/org/apache/sling/cta/impl/Agent.java
b/src/main/java/org/apache/sling/cta/impl/Agent.java
index 45ef00a..296448a 100644
--- a/src/main/java/org/apache/sling/cta/impl/Agent.java
+++ b/src/main/java/org/apache/sling/cta/impl/Agent.java
@@ -52,7 +52,9 @@ public class Agent {
new JavaNetTimeoutTransformer(connectTimeout, readTimeout,
agentInfoMBean),
new HttpClient3TimeoutTransformer(connectTimeout, readTimeout,
agentInfoMBean),
new HttpClient4TimeoutTransformer(connectTimeout, readTimeout,
agentInfoMBean),
- new OkHttpTimeoutTransformer(connectTimeout, readTimeout,
agentInfoMBean)
+ new OkHttpTimeoutTransformer(connectTimeout, readTimeout,
agentInfoMBean),
+ new JdkHttpClientBuilderTimeoutTransformer(connectTimeout,
agentInfoMBean),
+ new JdkHttpRequestBuilderTimeoutTransformer(readTimeout,
agentInfoMBean)
};
try {
diff --git
a/src/main/java/org/apache/sling/cta/impl/JdkHttpClientBuilderTimeoutTransformer.java
b/src/main/java/org/apache/sling/cta/impl/JdkHttpClientBuilderTimeoutTransformer.java
new file mode 100644
index 0000000..d23052d
--- /dev/null
+++
b/src/main/java/org/apache/sling/cta/impl/JdkHttpClientBuilderTimeoutTransformer.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.cta.impl;
+
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.bytecode.Descriptor;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Sets timeouts for HTTP calls done using
<code>java.net.http</code>/<code>java.net.http.HttpClient</code>.
+ */
+class JdkHttpClientBuilderTimeoutTransformer extends
MBeanAwareTimeoutTransformer {
+
+ static final Set<String> CLASSES_TO_TRANSFORM = new HashSet<>();
+
+ static {
+
CLASSES_TO_TRANSFORM.add(Descriptor.toJvmName("jdk.internal.net.http.HttpClientBuilderImpl"));
+ }
+
+ private final long connectTimeoutMillis;
+
+ public JdkHttpClientBuilderTimeoutTransformer(long connectTimeout,
AgentInfo agentInfo) {
+
+ super(agentInfo, CLASSES_TO_TRANSFORM);
+
+ this.connectTimeoutMillis = connectTimeout;
+ }
+
+ protected byte[] doTransformClass(CtClass cc) throws Exception {
+
+ CtMethod buildMethod = cc.getDeclaredMethod("build");
+ buildMethod.insertBefore("if ( this.connectTimeout == null ) {
connectTimeout(java.time.Duration.ofMillis(" + connectTimeoutMillis + "L)); }");
+ byte[] classfileBuffer = buildMethod.getDeclaringClass().toBytecode();
+ buildMethod.getDeclaringClass().detach();
+ return classfileBuffer;
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/cta/impl/JdkHttpRequestBuilderTimeoutTransformer.java
b/src/main/java/org/apache/sling/cta/impl/JdkHttpRequestBuilderTimeoutTransformer.java
new file mode 100644
index 0000000..1aad78a
--- /dev/null
+++
b/src/main/java/org/apache/sling/cta/impl/JdkHttpRequestBuilderTimeoutTransformer.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.cta.impl;
+
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.bytecode.Descriptor;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Sets timeouts for HTTP calls done using
<code>java.net.http</code>/<code>java.net.http.HttpClient</code>.
+ */
+class JdkHttpRequestBuilderTimeoutTransformer extends
MBeanAwareTimeoutTransformer {
+
+ static final Set<String> CLASSES_TO_TRANSFORM = new HashSet<>();
+
+ static {
+
CLASSES_TO_TRANSFORM.add(Descriptor.toJvmName("jdk.internal.net.http.HttpRequestBuilderImpl"));
+ }
+
+ private final long readTimeoutMillis;
+
+ public JdkHttpRequestBuilderTimeoutTransformer(long readTimeout, AgentInfo
agentInfo) {
+
+ super(agentInfo, CLASSES_TO_TRANSFORM);
+
+ this.readTimeoutMillis = readTimeout;
+ }
+
+ protected byte[] doTransformClass(CtClass cc) throws Exception {
+
+ CtMethod buildMethod = cc.getDeclaredMethod("build");
+ buildMethod.insertBefore("if ( this.duration == null ) {
timeout(java.time.Duration.ofMillis(" + readTimeoutMillis + "L)); }");
+ byte[] classfileBuffer = buildMethod.getDeclaringClass().toBytecode();
+ buildMethod.getDeclaringClass().detach();
+ return classfileBuffer;
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/cta/impl/AgentIT.java
b/src/test/java/org/apache/sling/cta/impl/AgentIT.java
index cac5b8b..bfbe690 100644
--- a/src/test/java/org/apache/sling/cta/impl/AgentIT.java
+++ b/src/test/java/org/apache/sling/cta/impl/AgentIT.java
@@ -21,6 +21,7 @@ import static java.util.Objects.requireNonNull;
import static org.apache.sling.cta.impl.HttpClientLauncher.ClientType.HC3;
import static org.apache.sling.cta.impl.HttpClientLauncher.ClientType.HC4;
import static org.apache.sling.cta.impl.HttpClientLauncher.ClientType.JavaNet;
+import static
org.apache.sling.cta.impl.HttpClientLauncher.ClientType.JdkHttpClient;
import static org.apache.sling.cta.impl.HttpClientLauncher.ClientType.OkHttp;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTimeout;
@@ -29,6 +30,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URL;
+import java.net.http.HttpConnectTimeoutException;
+import java.net.http.HttpTimeoutException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -80,6 +83,7 @@ public class AgentIT {
errorDescriptors.put(HC4, new
ErrorDescriptor(org.apache.http.conn.ConnectTimeoutException.class,
"Connect to 127\\.0\\.0\\.1:[0-9]+ \\[.*\\] failed:
[C|c]onnect timed out", "Read timed out"));
errorDescriptors.put(OkHttp, new
ErrorDescriptor(SocketTimeoutException.class, "[C|c]onnect timed out",
"(timeout|Read timed out)"));
+ errorDescriptors.put(JdkHttpClient, new
ErrorDescriptor(HttpConnectTimeoutException.class, "HTTP connect timed out",
HttpTimeoutException.class, "request timed out"));
}
/**
@@ -151,7 +155,7 @@ public class AgentIT {
RecordedThrowable error =
assertTimeout(ofSeconds(EXECUTION_TIMEOUT_SECONDS),
() -> runTest("http://127.0.0.1:" + server.getLocalPort(),
clientType, timeouts, false));
- assertEquals(SocketTimeoutException.class.getName(), error.className);
+ assertEquals(ed.readTimeoutClass.getName(), error.className);
assertTrue(error.message.matches(ed.readTimeoutRegex),
"Actual message " + error.message + " did not match regex " +
ed.readTimeoutRegex);
}
diff --git a/src/test/java/org/apache/sling/cta/impl/AgentLauncher.java
b/src/test/java/org/apache/sling/cta/impl/AgentLauncher.java
index 1b4d16d..8eaf0d5 100644
--- a/src/test/java/org/apache/sling/cta/impl/AgentLauncher.java
+++ b/src/test/java/org/apache/sling/cta/impl/AgentLauncher.java
@@ -106,4 +106,4 @@ class AgentLauncher {
return String.join(File.pathSeparator, elements);
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
b/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
index 0a1865e..9abe58f 100644
--- a/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
+++ b/src/test/java/org/apache/sling/cta/impl/ErrorDescriptor.java
@@ -17,6 +17,7 @@
package org.apache.sling.cta.impl;
import java.io.IOException;
+import java.net.SocketTimeoutException;
import org.apache.sling.cta.impl.HttpClientLauncher.ClientType;
@@ -26,12 +27,18 @@ import
org.apache.sling.cta.impl.HttpClientLauncher.ClientType;
class ErrorDescriptor {
Class<? extends IOException> connectTimeoutClass;
String connectTimeoutMessageRegex;
+ Class<? extends IOException> readTimeoutClass;
String readTimeoutRegex;
+ public ErrorDescriptor(Class<? extends IOException> connectTimeoutClass,
String connectTimeoutMessageRegex, String readTimeoutRegex) {
+ this(connectTimeoutClass, connectTimeoutMessageRegex,
SocketTimeoutException.class, readTimeoutRegex);
+ }
+
public ErrorDescriptor(Class<? extends IOException> connectTimeoutClass,
String connectTimeoutMessageRegex,
- String readTimeoutRegex) {
+ Class<? extends IOException> readTimeoutClass,
String readTimeoutRegex) {
this.connectTimeoutClass = connectTimeoutClass;
this.connectTimeoutMessageRegex = connectTimeoutMessageRegex;
+ this.readTimeoutClass = readTimeoutClass;
this.readTimeoutRegex = readTimeoutRegex;
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/apache/sling/cta/impl/HttpClientLauncher.java
b/src/test/java/org/apache/sling/cta/impl/HttpClientLauncher.java
index b7e731d..b072d3f 100644
--- a/src/test/java/org/apache/sling/cta/impl/HttpClientLauncher.java
+++ b/src/test/java/org/apache/sling/cta/impl/HttpClientLauncher.java
@@ -21,7 +21,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.EnumSet;
import java.util.stream.Collectors;
@@ -52,10 +56,11 @@ import okhttp3.Response;
public class HttpClientLauncher {
public enum ClientType {
- JavaNet(HttpClientLauncher::runUsingJavaNet),
+ JavaNet(HttpClientLauncher::runUsingJavaNet),
HC3(HttpClientLauncher::runUsingHttpClient3),
HC4(HttpClientLauncher::runUsingHttpClient4),
- OkHttp(HttpClientLauncher::runUsingOkHttp);
+ OkHttp(HttpClientLauncher::runUsingOkHttp),
+ JdkHttpClient(HttpClientLauncher::runUsingJdkHttpClient);
private final HttpConsumer consumer;
@@ -136,6 +141,32 @@ public class HttpClientLauncher {
}
}
+ private static void runUsingJdkHttpClient(String targetUrl, int
connectTimeoutMillis, int readTimeoutMillis) throws IOException,
URISyntaxException, InterruptedException {
+
+ java.net.http.HttpClient.Builder clientBuilder =
java.net.http.HttpClient.newBuilder();
+ HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
+
+ if (connectTimeoutMillis > 0) {
+
clientBuilder.connectTimeout(Duration.ofMillis(connectTimeoutMillis));
+ }
+ if (readTimeoutMillis > 0) {
+ requestBuilder.timeout(Duration.ofMillis(readTimeoutMillis));
+ }
+
+ requestBuilder.uri(new URI(targetUrl));
+
+ java.net.http.HttpClient client = clientBuilder.build();
+ HttpRequest request = requestBuilder.build();
+
+ log("HttpClient timeouts: connection: %d, request: %d",
+ client.connectTimeout().orElse(Duration.ZERO).toMillis(),
+ request.timeout().orElse(Duration.ZERO).toMillis());
+
+ HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
+
+ log("HttpClient response status: %s", response.statusCode());
+ }
+
private static void runUsingHttpClient3(String targetUrl, int
connectTimeoutMillis, int readTimeoutMillis) throws IOException {
HttpClient client = new HttpClient();
diff --git a/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
b/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
index 17b2752..37cef91 100644
--- a/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
+++ b/src/test/java/org/apache/sling/cta/impl/OsgiIT.java
@@ -78,7 +78,7 @@ public class OsgiIT {
mavenBundle("org.apache.httpcomponents", "httpcore-osgi",
"4.4.12"),
mavenBundle("org.apache.httpcomponents", "httpclient-osgi",
"4.5.10"),
mavenBundle("org.apache.felix",
"org.apache.felix.http.servlet-api", "3.0.0"),
-
mavenBundle("org.apache.felix","org.apache.felix.http.jetty","5.1.26"),
+
mavenBundle("org.apache.felix","org.apache.felix.http.jetty","4.2.32"),
vmOption("-javaagent:" + agentCandidates.get(0) +"=10000,1,v") //
large connect timeout, very small read timeout
);
}