Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
629f074
Instrument Jetty for server.request.body.filenames
jandro996 Mar 23, 2026
b276e16
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 6, 2026
b1ec26b
Fix GetFilenamesAdvice double-firing and extend coverage to getParts(…
jandro996 Apr 6, 2026
d8a92f8
spotless
jandro996 Apr 7, 2026
4d8ca56
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 8, 2026
30bb769
Extend testBodyFilenamesCalledOnce coverage to Jetty 9.x and 10.x
jandro996 Apr 7, 2026
abddcfa
Add BODY_MULTIPART_COMBINED test to cover GetFilenamesFromMultiPartAd…
jandro996 Apr 8, 2026
eeab933
spotless
jandro996 Apr 8, 2026
0040e75
Fix missing static imports for BODY_MULTIPART_REPEATED and BODY_MULTI…
jandro996 Apr 8, 2026
c5268dd
Fix GetFilenamesAdvice double-fire for Jetty 9.4+ where _multiParts r…
jandro996 Apr 8, 2026
db08e43
Fix GetFilenamesAdvice double-fire in jetty-appsec-8.1.3
jandro996 Apr 8, 2026
30e4b8c
Fix GetFilenamesAdvice double-fire for all Jetty 9.3–11 versions
jandro996 Apr 8, 2026
3fd02e3
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 9, 2026
7f391b4
Simplify GetFilenamesAdvice in jetty-appsec-8.1.3: remove dead Servle…
jandro996 Apr 9, 2026
246f4e3
Remove unnecessary casts in Jetty AppSec GetFilenamesAdvice
jandro996 Apr 9, 2026
20f8bb4
Extract Content-Disposition parsing to MultipartHelper + unit tests
jandro996 Apr 9, 2026
398ea51
Extract filename extraction to MultipartHelper in jetty-appsec-9.2 + …
jandro996 Apr 9, 2026
52c5cb8
Split jetty-appsec-9.3 [9.3,12) into three clean modules: 9.3, 9.4, 11.0
jandro996 Apr 10, 2026
182ce98
Add Jetty 8.x integration tests for multipart body and filenames
jandro996 Apr 10, 2026
b9f5a74
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 10, 2026
d92ff94
Fix muzzle range for jetty-appsec-9.3/9.4: split at 9.4.10
jandro996 Apr 10, 2026
eb6ca70
Replace MultiPartsFieldMatcher with typed module splits for Jetty 9.4…
jandro996 Apr 10, 2026
5a85e01
Fix CI failures and reduce agent JAR size for Jetty filenames PR
jandro996 Apr 13, 2026
2043d77
Remove redundant .or(named("getParts")) from ExtractContentParameters…
jandro996 Apr 13, 2026
befdf9b
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 13, 2026
f180b6a
Disable testBodyFilenames in jetty-server-9.0 and jetty-server-9.0.4
jandro996 Apr 13, 2026
08f15a2
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 14, 2026
8b9a83a
Restore .or(named("getParts")) in ExtractContentParametersAdvice for …
jandro996 Apr 15, 2026
5747f2e
Merge remote-tracking branch 'origin/alejandro.gonzalez/APPSEC-61873-…
jandro996 Apr 15, 2026
69ca568
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 16, 2026
2b2f46d
fix(appsec/jetty): use _dispatcherType bytecode discriminator for jet…
jandro996 Apr 16, 2026
fd725f2
Skip multipart test on Jetty 9.0.x where jetty-appsec-8.1.3 causes HT…
jandro996 Apr 16, 2026
05a5ec4
Use @Ignore to skip multipart test on Jetty 9.0.x where jetty-appsec-…
jandro996 Apr 16, 2026
f8163c2
Add supportsMultipart() hook to skip multipart test on Jetty 9.0.x
jandro996 Apr 16, 2026
3ccb046
fix(appsec/jetty): disable multipart test on Jetty 9.0.x and bump tes…
jandro996 Apr 17, 2026
22596a2
Merge branch 'master' into alejandro.gonzalez/APPSEC-61873-3
jandro996 Apr 17, 2026
3b7c9ff
fix(appsec/jetty): replace bytecode injection in jetty-appsec-8.1.3 w…
jandro996 Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,13 @@ abstract class AppSecInactiveHttpServerTest extends WithHttpServer {
}
}

protected boolean supportsMultipart() {
true
}

void multipart() {
setup:
assumeTrue supportsMultipart()
def body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart('a', 'x')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ import java.util.function.Supplier

import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_JSON
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART_COMBINED
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART_REPEATED
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
Expand Down Expand Up @@ -368,6 +370,14 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
false
}

boolean testBodyFilenamesCalledOnce() {
false
}

boolean testBodyFilenamesCalledOnceCombined() {
false
}

boolean testBodyFilenames() {
false
}
Expand Down Expand Up @@ -476,6 +486,8 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
CREATED_IS("created_input_stream", 201, "created"),
BODY_URLENCODED("body-urlencoded?ignore=pair", 200, '[a:[x]]'),
BODY_MULTIPART("body-multipart?ignore=pair", 200, '[a:[x]]'),
BODY_MULTIPART_REPEATED("body-multipart-repeated", 200, "ok"),
BODY_MULTIPART_COMBINED("body-multipart-combined", 200, "ok"),
BODY_JSON("body-json", 200, '{"a":"x"}'),
BODY_XML("body-xml", 200, '<foo attr="attr_value">mytext<bar/></foo>'),
REDIRECT("redirect", 302, "/redirected"),
Expand Down Expand Up @@ -1646,6 +1658,54 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
response.close()
}

def 'test instrumentation gateway file upload filenames called once'() {
setup:
assumeTrue(testBodyFilenamesCalledOnce())
RequestBody fileBody = RequestBody.create(MediaType.parse('application/octet-stream'), 'file content')
def body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart('file', 'evil.php', fileBody)
.build()
def httpRequest = request(BODY_MULTIPART_REPEATED, 'POST', body).build()
def response = client.newCall(httpRequest).execute()

when:
TEST_WRITER.waitForTraces(1)

then:
TEST_WRITER.get(0).any {
it.getTag('request.body.filenames') == "[evil.php]"
&& it.getTag('_dd.appsec.filenames.cb.calls') == 1
}

cleanup:
response.close()
}

def 'test instrumentation gateway file upload filenames called once via parameter map'() {
setup:
assumeTrue(testBodyFilenamesCalledOnceCombined())
RequestBody fileBody = RequestBody.create(MediaType.parse('application/octet-stream'), 'file content')
def body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart('file', 'evil.php', fileBody)
.build()
def httpRequest = request(BODY_MULTIPART_COMBINED, 'POST', body).build()
def response = client.newCall(httpRequest).execute()

when:
TEST_WRITER.waitForTraces(1)

then:
TEST_WRITER.get(0).any {
it.getTag('request.body.filenames') == "[evil.php]"
&& it.getTag('_dd.appsec.filenames.cb.calls') == 1
}

cleanup:
response.close()
}

def 'test instrumentation gateway json request body'() {
setup:
assumeTrue(testBodyJson())
Expand Down Expand Up @@ -2581,6 +2641,7 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
boolean responseBodyTag
Object responseBody
List<String> uploadedFilenames
int uploadedFilenamesCallCount = 0
}

static final String stringOrEmpty(String string) {
Expand Down Expand Up @@ -2754,6 +2815,8 @@ abstract class HttpServerTest<SERVER> extends WithHttpServer<SERVER> {
rqCtxt.traceSegment.setTagTop('request.body.filenames', filenames as String)
Context context = rqCtxt.getData(RequestContextSlot.APPSEC)
context.uploadedFilenames = filenames
context.uploadedFilenamesCallCount++
rqCtxt.traceSegment.setTagTop('_dd.appsec.filenames.cb.calls', context.uploadedFilenamesCallCount)
Flow.ResultFlow.empty()
} as BiFunction<RequestContext, List<String>, Flow<Void>>)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ dependencies {
testRuntimeOnly project(':dd-java-agent:instrumentation:jetty:jetty-server:jetty-server-9.0')
testRuntimeOnly(project(':dd-java-agent:instrumentation:jetty:jetty-util-9.4.31'))
testRuntimeOnly project(':dd-java-agent:instrumentation:jetty:jetty-appsec:jetty-appsec-9.3')
testRuntimeOnly project(':dd-java-agent:instrumentation:jetty:jetty-appsec:jetty-appsec-9.4')
testRuntimeOnly project(':dd-java-agent:instrumentation:jetty:jetty-appsec:jetty-appsec-11.0')
testRuntimeOnly project(':dd-java-agent:instrumentation:servlet:jakarta-servlet-5.0')
testRuntimeOnly project(':dd-java-agent:instrumentation:servlet:javax-servlet:javax-servlet-3.0')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
muzzle {
pass {
group = 'org.eclipse.jetty'
module = 'jetty-server'
versions = '[11.0,12.0)'
assertInverse = true
javaVersion = 11
}
}

apply from: "$rootDir/gradle/java.gradle"

dependencies {
compileOnly(group: 'org.eclipse.jetty', name: 'jetty-server', version: '11.0.26') {
exclude group: 'org.slf4j', module: 'slf4j-api'
}
testImplementation(group: 'org.eclipse.jetty.toolchain', name: 'jetty-jakarta-servlet-api', version: '5.0.1')
}

tasks.withType(JavaCompile).configureEach {
configureCompiler(it, 11, JavaVersion.VERSION_1_8)
}

tasks.withType(Test).configureEach {
javaLauncher = getJavaLauncherFor(11)
}

// testing happens in the jetty-* modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
cafe.cryptography:curve25519-elisabeth:0.1.0=testRuntimeClasspath
cafe.cryptography:ed25519-elisabeth:0.1.0=testRuntimeClasspath
ch.qos.logback:logback-classic:1.2.13=testCompileClasspath,testRuntimeClasspath
ch.qos.logback:logback-core:1.2.13=testCompileClasspath,testRuntimeClasspath
com.blogspot.mydailyjava:weak-lock-free:0.17=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.datadoghq.okhttp3:okhttp:3.12.15=testCompileClasspath,testRuntimeClasspath
com.datadoghq.okio:okio:1.17.6=testCompileClasspath,testRuntimeClasspath
com.datadoghq:dd-instrument-java:0.0.3=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.datadoghq:dd-javac-plugin-client:0.2.2=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.datadoghq:java-dogstatsd-client:4.4.3=testRuntimeClasspath
com.datadoghq:sketches-java:0.8.3=testRuntimeClasspath
com.github.javaparser:javaparser-core:3.25.6=codenarc
com.github.jnr:jffi:1.3.14=testRuntimeClasspath
com.github.jnr:jnr-a64asm:1.0.0=testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.4=testRuntimeClasspath
com.github.jnr:jnr-enxio:0.32.19=testRuntimeClasspath
com.github.jnr:jnr-ffi:2.2.18=testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.21=testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.24=testRuntimeClasspath
com.github.jnr:jnr-x86asm:1.0.2=testRuntimeClasspath
com.github.spotbugs:spotbugs-annotations:4.9.8=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath
com.github.spotbugs:spotbugs:4.9.8=spotbugs
com.github.stephenc.jcip:jcip-annotations:1.0-1=spotbugs
com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,testAnnotationProcessor,testCompileClasspath
com.google.auto.service:auto-service:1.1.1=annotationProcessor,testAnnotationProcessor
com.google.auto:auto-common:1.2.1=annotationProcessor,testAnnotationProcessor
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.13.2=spotbugs
com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.41.0=spotbugs
com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor
com.google.guava:guava:20.0=testCompileClasspath,testRuntimeClasspath
com.google.guava:guava:32.0.1-jre=annotationProcessor,testAnnotationProcessor
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,testAnnotationProcessor
com.google.j2objc:j2objc-annotations:2.8=annotationProcessor,testAnnotationProcessor
com.google.re2j:re2j:1.7=testRuntimeClasspath
com.squareup.moshi:moshi:1.11.0=testCompileClasspath,testRuntimeClasspath
com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath
com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath
com.squareup.okio:okio:1.17.5=testCompileClasspath,testRuntimeClasspath
com.thoughtworks.qdox:qdox:1.12.1=codenarc
commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath
commons-io:commons-io:2.20.0=spotbugs
de.thetaphi:forbiddenapis:3.10=compileClasspath
io.leangen.geantyref:geantyref:1.3.16=testRuntimeClasspath
io.sqreen:libsqreen:17.3.0=testRuntimeClasspath
javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath
jaxen:jaxen:2.0.0=spotbugs
junit:junit:4.13.2=testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.18.3=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.18.3=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.java.dev.jna:jna-platform:5.8.0=testRuntimeClasspath
net.java.dev.jna:jna:5.8.0=testRuntimeClasspath
net.sf.saxon:Saxon-HE:12.9=spotbugs
org.apache.ant:ant-antlr:1.10.14=codenarc
org.apache.ant:ant-junit:1.10.14=codenarc
org.apache.bcel:bcel:6.11.0=spotbugs
org.apache.commons:commons-lang3:3.19.0=spotbugs
org.apache.commons:commons-text:1.14.0=spotbugs
org.apache.logging.log4j:log4j-api:2.25.2=spotbugs
org.apache.logging.log4j:log4j-core:2.25.2=spotbugs
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
org.checkerframework:checker-qual:3.33.0=annotationProcessor,testAnnotationProcessor
org.codehaus.groovy:groovy-ant:3.0.23=codenarc
org.codehaus.groovy:groovy-docgenerator:3.0.23=codenarc
org.codehaus.groovy:groovy-groovydoc:3.0.23=codenarc
org.codehaus.groovy:groovy-json:3.0.23=codenarc
org.codehaus.groovy:groovy-json:3.0.25=testCompileClasspath,testRuntimeClasspath
org.codehaus.groovy:groovy-templates:3.0.23=codenarc
org.codehaus.groovy:groovy-xml:3.0.23=codenarc
org.codehaus.groovy:groovy:3.0.23=codenarc
org.codehaus.groovy:groovy:3.0.25=testCompileClasspath,testRuntimeClasspath
org.codenarc:CodeNarc:3.7.0=codenarc
org.dom4j:dom4j:2.2.0=spotbugs
org.eclipse.jetty.toolchain:jetty-jakarta-servlet-api:5.0.1=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-http:11.0.0=compileClasspath
org.eclipse.jetty:jetty-io:11.0.0=compileClasspath
org.eclipse.jetty:jetty-server:11.0.0=compileClasspath
org.eclipse.jetty:jetty-util:11.0.0=compileClasspath
org.gmetrics:GMetrics:2.1.0=codenarc
org.hamcrest:hamcrest-core:1.3=testRuntimeClasspath
org.hamcrest:hamcrest:3.0=testCompileClasspath,testRuntimeClasspath
org.jctools:jctools-core-jdk11:4.0.6=testRuntimeClasspath
org.jctools:jctools-core:4.0.6=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.14.1=testRuntimeClasspath
org.junit.jupiter:junit-jupiter-params:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter:5.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-commons:1.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-engine:1.14.1=testCompileClasspath,testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-runner:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-suite-api:1.14.1=testRuntimeClasspath
org.junit.platform:junit-platform-suite-commons:1.14.1=testRuntimeClasspath
org.junit:junit-bom:5.14.0=spotbugs
org.junit:junit-bom:5.14.1=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:4.4.0=testRuntimeClasspath
org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.7.1=testRuntimeClasspath
org.ow2.asm:asm-analysis:9.9=spotbugs
org.ow2.asm:asm-commons:9.9=spotbugs
org.ow2.asm:asm-commons:9.9.1=testRuntimeClasspath
org.ow2.asm:asm-tree:9.9=spotbugs
org.ow2.asm:asm-tree:9.9.1=testRuntimeClasspath
org.ow2.asm:asm-util:9.7.1=testRuntimeClasspath
org.ow2.asm:asm-util:9.9=spotbugs
org.ow2.asm:asm:9.9=spotbugs
org.ow2.asm:asm:9.9.1=buildTimeInstrumentationPlugin,compileClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=buildTimeInstrumentationPlugin,compileClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath
org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.17=spotbugs,spotbugsSlf4j
org.slf4j:slf4j-simple:2.0.17=spotbugsSlf4j
org.snakeyaml:snakeyaml-engine:2.9=buildTimeInstrumentationPlugin,muzzleTooling,runtimeClasspath,testRuntimeClasspath
org.spockframework:spock-bom:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
org.spockframework:spock-core:2.4-groovy-3.0=testCompileClasspath,testRuntimeClasspath
org.tabletest:tabletest-junit:1.2.1=testCompileClasspath,testRuntimeClasspath
org.tabletest:tabletest-parser:1.2.0=testCompileClasspath,testRuntimeClasspath
org.xmlresolver:xmlresolver:5.3.3=spotbugs
empty=spotbugsPlugins
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package datadog.trace.instrumentation.jetty11;

import jakarta.servlet.http.Part;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class MultipartHelper {

private MultipartHelper() {}

/**
* Extracts non-null, non-empty filenames from a collection of multipart {@link Part}s using
* {@link Part#getSubmittedFileName()} (Servlet 5.0+, Jetty 11.x).
*
* @return list of filenames; never {@code null}, may be empty
*/
public static List<String> extractFilenames(Collection<Part> parts) {
if (parts == null || parts.isEmpty()) {
return Collections.emptyList();
}
List<String> filenames = new ArrayList<>();
for (Part part : parts) {
String name = part.getSubmittedFileName();
if (name != null && !name.isEmpty()) {
filenames.add(name);
}
}
return filenames;
}
}
Loading
Loading