From 356509ba8a8c03c38ed3b011b3c7844108d11c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vandon?= Date: Thu, 2 Jul 2026 16:14:19 +0200 Subject: [PATCH 1/3] bump undertow lockfile --- .../instrumentation/undertow/undertow-2.0/gradle.lockfile | 6 +++--- .../instrumentation/undertow/undertow-2.2/gradle.lockfile | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.0/gradle.lockfile b/dd-java-agent/instrumentation/undertow/undertow-2.0/gradle.lockfile index 028afaea1e5..89a960c33f4 100644 --- a/dd-java-agent/instrumentation/undertow/undertow-2.0/gradle.lockfile +++ b/dd-java-agent/instrumentation/undertow/undertow-2.0/gradle.lockfile @@ -53,11 +53,11 @@ de.thetaphi:forbiddenapis:3.10=compileClasspath,latestDepForkedTestCompileClassp io.leangen.geantyref:geantyref:1.3.16=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath io.sqreen:libsqreen:17.3.0=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath io.undertow:undertow-core:2.0.0.Final=compileClasspath,testCompileClasspath,testRuntimeClasspath -io.undertow:undertow-core:2.2.39.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-core:2.2.40.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath io.undertow:undertow-servlet:2.0.0.Final=compileClasspath,testCompileClasspath,testRuntimeClasspath -io.undertow:undertow-servlet:2.2.39.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-servlet:2.2.40.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath io.undertow:undertow-websockets-jsr:2.0.0.Final=testCompileClasspath,testRuntimeClasspath -io.undertow:undertow-websockets-jsr:2.2.39.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-websockets-jsr:2.2.40.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath javax.servlet:javax.servlet-api:3.1.0=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath jaxen:jaxen:2.0.0=spotbugs junit:junit:4.13.2=latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.2/gradle.lockfile b/dd-java-agent/instrumentation/undertow/undertow-2.2/gradle.lockfile index 1e9207ba64d..c398135a2e3 100644 --- a/dd-java-agent/instrumentation/undertow/undertow-2.2/gradle.lockfile +++ b/dd-java-agent/instrumentation/undertow/undertow-2.2/gradle.lockfile @@ -62,13 +62,13 @@ io.smallrye.common:smallrye-common-ref:2.4.0=latestDepForkedTestRuntimeClasspath io.sqreen:libsqreen:17.3.0=latest22ForkedTestRuntimeClasspath,latest22TestRuntimeClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath io.undertow:undertow-core:2.2.14.Final=compileClasspath,testCompileClasspath,testRuntimeClasspath io.undertow:undertow-core:2.2.20.Final=latest22ForkedTestCompileClasspath,latest22ForkedTestRuntimeClasspath,latest22TestCompileClasspath,latest22TestRuntimeClasspath -io.undertow:undertow-core:2.3.24.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-core:2.3.25.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath io.undertow:undertow-servlet-jakarta:2.2.14.Final=compileClasspath,latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath io.undertow:undertow-servlet-jakarta:2.2.20.Final=latest22ForkedTestCompileClasspath,latest22ForkedTestRuntimeClasspath,latest22TestCompileClasspath,latest22TestRuntimeClasspath -io.undertow:undertow-servlet:2.3.24.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-servlet:2.3.25.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath io.undertow:undertow-websockets-jsr-jakarta:2.2.14.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath io.undertow:undertow-websockets-jsr-jakarta:2.2.20.Final=latest22ForkedTestCompileClasspath,latest22ForkedTestRuntimeClasspath,latest22TestCompileClasspath,latest22TestRuntimeClasspath -io.undertow:undertow-websockets-jsr:2.3.24.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.undertow:undertow-websockets-jsr:2.3.25.Final=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath jakarta.annotation:jakarta.annotation-api:2.0.0=compileClasspath,latest22ForkedTestCompileClasspath,latest22ForkedTestRuntimeClasspath,latest22TestCompileClasspath,latest22TestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath jakarta.annotation:jakarta.annotation-api:2.1.1=latestDepForkedTestCompileClasspath,latestDepForkedTestRuntimeClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath jakarta.servlet:jakarta.servlet-api:5.0.0=compileClasspath,latest22ForkedTestCompileClasspath,latest22ForkedTestRuntimeClasspath,latest22TestCompileClasspath,latest22TestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath From b2d0fb6c0263c78875d699a0a3589df67b7aa2ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vandon?= Date: Thu, 2 Jul 2026 17:46:46 +0200 Subject: [PATCH 2/3] instrument new parser class for undertow --- .../HttpRequestParserInstrumentation.java | 2 + .../RequestParserInstrumentation.java | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/RequestParserInstrumentation.java diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/HttpRequestParserInstrumentation.java b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/HttpRequestParserInstrumentation.java index 119cbf2538a..d32e9c2f111 100644 --- a/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/HttpRequestParserInstrumentation.java +++ b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/HttpRequestParserInstrumentation.java @@ -28,6 +28,8 @@ public HttpRequestParserInstrumentation() { @Override public String hierarchyMarkerType() { + // removed in https://github.com/undertow-io/undertow/pull/1949/changes + // see RequestParserInstrumentation for the new type return "io.undertow.server.protocol.http.HttpRequestParser"; } diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/RequestParserInstrumentation.java b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/RequestParserInstrumentation.java new file mode 100644 index 00000000000..a70080f997e --- /dev/null +++ b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/main/java/datadog/trace/instrumentation/undertow/RequestParserInstrumentation.java @@ -0,0 +1,50 @@ +package datadog.trace.instrumentation.undertow; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; + +@AutoService(InstrumenterModule.class) +public class RequestParserInstrumentation extends InstrumenterModule.Tracing + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + public RequestParserInstrumentation() { + super("undertow", "undertow-2.2", "undertow-request-parse"); + } + + @Override + public String instrumentedType() { + // new class added in new minor versions in + // https://github.com/undertow-io/undertow/pull/1949/changes + // from 2.2.40, 2.3.25 and 2.4.0 + // not instrumenting the hierarchy like in its predecessor HttpRequestParserInstrumentation + // because RequestParser is marked final. + return "io.undertow.server.protocol.http.RequestParser"; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + isMethod() + .and(named("handle")) + .and(takesArgument(2, named("io.undertow.server.HttpServerExchange"))), + HttpRequestParserInstrumentation.class.getName() + "$RequestParseFailureAdvice"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".HttpServerExchangeURIDataAdapter", + packageName + ".UndertowDecorator", + packageName + ".UndertowBlockingHandler", + packageName + ".IgnoreSendAttribute", + packageName + ".UndertowBlockResponseFunction", + packageName + ".UndertowExtractAdapter", + packageName + ".UndertowExtractAdapter$Request", + packageName + ".UndertowExtractAdapter$Response" + }; + } +} From 81d352e8abb4c2c8a31d9ea0ab91bde193b4ac69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vandon?= Date: Wed, 8 Jul 2026 11:14:29 +0200 Subject: [PATCH 3/3] adapt test setup to parser used --- .../groovy/UndertowServletAsyncTest.groovy | 69 +++++++++++-------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.0/src/test/groovy/UndertowServletAsyncTest.groovy b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/test/groovy/UndertowServletAsyncTest.groovy index 1866b24d7cb..3c086ff39a6 100644 --- a/dd-java-agent/instrumentation/undertow/undertow-2.0/src/test/groovy/UndertowServletAsyncTest.groovy +++ b/dd-java-agent/instrumentation/undertow/undertow-2.0/src/test/groovy/UndertowServletAsyncTest.groovy @@ -1,3 +1,24 @@ +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_URLENCODED +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED_IS +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.FORWARDED +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.LOGIN +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_HERE +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.PATH_PARAM +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ENCODED_BOTH +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ENCODED_QUERY +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR +import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.USER_BLOCK +import static datadog.trace.agent.test.base.HttpServerTest.controller + import datadog.trace.agent.test.asserts.TraceAssert import datadog.trace.agent.test.base.HttpServer import datadog.trace.agent.test.base.HttpServerTest @@ -14,8 +35,8 @@ import io.undertow.servlet.api.InstanceHandle import io.undertow.servlet.api.ServletContainer import io.undertow.servlet.api.ServletInfo import io.undertow.servlet.util.ImmediateInstanceHandle -import org.slf4j.LoggerFactory - +import java.nio.charset.StandardCharsets +import java.util.concurrent.atomic.AtomicReference import javax.servlet.AsyncContext import javax.servlet.AsyncEvent import javax.servlet.AsyncListener @@ -26,29 +47,7 @@ import javax.servlet.WriteListener import javax.servlet.http.HttpServlet import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse -import java.nio.charset.StandardCharsets -import java.util.concurrent.atomic.AtomicReference - -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_URLENCODED -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED_IS -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.FORWARDED -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.LOGIN -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_HERE -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.PATH_PARAM -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ENCODED_BOTH -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_ENCODED_QUERY -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.QUERY_PARAM -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.REDIRECT -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.SUCCESS -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.TIMEOUT_ERROR -import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.USER_BLOCK -import static datadog.trace.agent.test.base.HttpServerTest.controller +import org.slf4j.LoggerFactory class UndertowServletAsyncTest extends HttpServerTest { private static final CONTEXT = "ctx" @@ -119,9 +118,10 @@ class UndertowServletAsyncTest extends HttpServerTest { dispatch = false req.setAttribute('ddog.dispatched', 1) if (req.servletPath.contains(' ')) { - // bug in undertow when dispatching from /foo%20bar - // (matches mapping "/foo bar" 1st and "/foo%20bar" after dispatch) - asyncContext.dispatch(req.servletPath) + // Older versions match the decoded servlet path on redispatch, + // while the newer RequestParser expects the raw encoded path; + // using the other form either misses the servlet mapping or hangs. + asyncContext.dispatch(hasNewRequestParser() ? ep.rawPath : req.servletPath) } else { asyncContext.dispatch() } @@ -260,6 +260,16 @@ class UndertowServletAsyncTest extends HttpServerTest { operation() } + private static boolean hasNewRequestParser() { + // returns true for versions that include the bugfix pushed in https://github.com/undertow-io/undertow/pull/1949 + try { + Class.forName('io.undertow.server.protocol.http.RequestParser') + return true + } catch (ClassNotFoundException ignored) { + return false + } + } + @Override boolean testTimeout() { true @@ -408,7 +418,8 @@ class UndertowServletAsyncTest extends HttpServerTest { trace.span { serviceName expectedServiceName() operationName 'servlet.dispatch' - String resName = endpoint.path == endpoint.rawPath ? 'servlet.dispatch' : endpoint.path + String resName = + endpoint.path == endpoint.rawPath ? 'servlet.dispatch' : hasNewRequestParser() ? endpoint.rawPath : endpoint.path resourceName resName errored(endpoint.throwsException || endpoint == TIMEOUT_ERROR) childOfPrevious()