Skip to content

Commit 86c4da5

Browse files
committed
Add server.request.body.filenames support for Jersey and RESTEasy
1 parent 081af53 commit 86c4da5

5 files changed

Lines changed: 125 additions & 0 deletions

File tree

dd-java-agent/instrumentation/jersey/jersey-2.0/src/jersey2JettyTest/groovy/datadog/trace/instrumentation/jersey2/Jersey2JettyTest.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ class Jersey2JettyTest extends HttpServerTest<JettyServer> {
5454
true
5555
}
5656

57+
@Override
58+
boolean testBodyFilenames() {
59+
true
60+
}
61+
5762
@Override
5863
boolean testBodyJson() {
5964
true

dd-java-agent/instrumentation/jersey/jersey-2.0/src/jersey3JettyTest/groovy/datadog/trace/instrumentation/jersey3/Jersey3JettyTest.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ class Jersey3JettyTest extends HttpServerTest<JettyServer> {
5353
true
5454
}
5555

56+
@Override
57+
boolean testBodyFilenames() {
58+
true
59+
}
60+
5661
@Override
5762
boolean testBodyJson() {
5863
true

dd-java-agent/instrumentation/jersey/jersey-appsec/jersey-appsec-2.0/src/main/java/datadog/trace/instrumentation/jersey2/MultiPartReaderServerSideInstrumentation.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import net.bytebuddy.asm.Advice;
2828
import org.glassfish.jersey.media.multipart.BodyPart;
2929
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
30+
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
3031
import org.glassfish.jersey.media.multipart.MultiPart;
3132
import org.glassfish.jersey.message.internal.MediaTypes;
3233

@@ -110,6 +111,41 @@ static void after(
110111
reqCtx.getTraceSegment().effectivelyBlocked();
111112
}
112113
}
114+
115+
BiFunction<RequestContext, List<String>, Flow<Void>> filenamesCallback =
116+
cbp.getCallback(EVENTS.requestFilesFilenames());
117+
if (filenamesCallback == null) {
118+
return;
119+
}
120+
List<String> filenames = new ArrayList<>();
121+
for (BodyPart bodyPart : ret.getBodyParts()) {
122+
if (!(bodyPart instanceof FormDataBodyPart)) {
123+
continue;
124+
}
125+
FormDataBodyPart dataBodyPart = (FormDataBodyPart) bodyPart;
126+
FormDataContentDisposition cd = dataBodyPart.getFormDataContentDisposition();
127+
if (cd == null) {
128+
continue;
129+
}
130+
String filename = cd.getFileName();
131+
if (filename != null && !filename.isEmpty()) {
132+
filenames.add(filename);
133+
}
134+
}
135+
if (filenames.isEmpty()) {
136+
return;
137+
}
138+
Flow<Void> filenamesFlow = filenamesCallback.apply(reqCtx, filenames);
139+
Flow.Action filenamesAction = filenamesFlow.getAction();
140+
if (t == null && filenamesAction instanceof Flow.Action.RequestBlockingAction) {
141+
Flow.Action.RequestBlockingAction rba = (Flow.Action.RequestBlockingAction) filenamesAction;
142+
BlockResponseFunction blockResponseFunction = reqCtx.getBlockResponseFunction();
143+
if (blockResponseFunction != null) {
144+
blockResponseFunction.tryCommitBlockingResponse(reqCtx.getTraceSegment(), rba);
145+
t = new BlockingException("Blocked request (multipart file upload)");
146+
reqCtx.getTraceSegment().effectivelyBlocked();
147+
}
148+
}
113149
}
114150
}
115151
}

dd-java-agent/instrumentation/jersey/jersey-appsec/jersey-appsec-3.0/src/main/java/datadog/trace/instrumentation/jersey3/MultiPartReaderServerSideInstrumentation.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import net.bytebuddy.asm.Advice;
2828
import org.glassfish.jersey.media.multipart.BodyPart;
2929
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
30+
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
3031
import org.glassfish.jersey.media.multipart.MultiPart;
3132
import org.glassfish.jersey.message.internal.MediaTypes;
3233

@@ -110,6 +111,41 @@ static void after(
110111
reqCtx.getTraceSegment().effectivelyBlocked();
111112
}
112113
}
114+
115+
BiFunction<RequestContext, List<String>, Flow<Void>> filenamesCallback =
116+
cbp.getCallback(EVENTS.requestFilesFilenames());
117+
if (filenamesCallback == null) {
118+
return;
119+
}
120+
List<String> filenames = new ArrayList<>();
121+
for (BodyPart bodyPart : ret.getBodyParts()) {
122+
if (!(bodyPart instanceof FormDataBodyPart)) {
123+
continue;
124+
}
125+
FormDataBodyPart dataBodyPart = (FormDataBodyPart) bodyPart;
126+
FormDataContentDisposition cd = dataBodyPart.getFormDataContentDisposition();
127+
if (cd == null) {
128+
continue;
129+
}
130+
String filename = cd.getFileName();
131+
if (filename != null && !filename.isEmpty()) {
132+
filenames.add(filename);
133+
}
134+
}
135+
if (filenames.isEmpty()) {
136+
return;
137+
}
138+
Flow<Void> filenamesFlow = filenamesCallback.apply(reqCtx, filenames);
139+
Flow.Action filenamesAction = filenamesFlow.getAction();
140+
if (t == null && filenamesAction instanceof Flow.Action.RequestBlockingAction) {
141+
Flow.Action.RequestBlockingAction rba = (Flow.Action.RequestBlockingAction) filenamesAction;
142+
BlockResponseFunction blockResponseFunction = reqCtx.getBlockResponseFunction();
143+
if (blockResponseFunction != null) {
144+
blockResponseFunction.tryCommitBlockingResponse(reqCtx.getTraceSegment(), rba);
145+
t = new BlockingException("Blocked request (multipart file upload)");
146+
reqCtx.getTraceSegment().effectivelyBlocked();
147+
}
148+
}
113149
}
114150
}
115151
}

dd-java-agent/instrumentation/resteasy/resteasy-appsec-3.0/src/main/java/datadog/trace/instrumentation/resteasy/MultipartFormDataReaderInstrumentation.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,49 @@ static void after(
9696
reqCtx.getTraceSegment().effectivelyBlocked();
9797
}
9898
}
99+
100+
BiFunction<RequestContext, List<String>, Flow<Void>> filenamesCallback =
101+
cbp.getCallback(EVENTS.requestFilesFilenames());
102+
if (filenamesCallback == null) {
103+
return;
104+
}
105+
List<String> filenames = new ArrayList<>();
106+
for (Map.Entry<String, List<InputPart>> e : ret.getFormDataMap().entrySet()) {
107+
for (InputPart inputPart : e.getValue()) {
108+
List<String> cdHeaders = inputPart.getHeaders().get("Content-Disposition");
109+
if (cdHeaders == null || cdHeaders.isEmpty()) {
110+
continue;
111+
}
112+
String cd = cdHeaders.get(0);
113+
for (String token : cd.split(";")) {
114+
token = token.trim();
115+
if (token.startsWith("filename=")) {
116+
String filename = token.substring(9).trim();
117+
if (filename.startsWith("\"") && filename.endsWith("\"")) {
118+
filename = filename.substring(1, filename.length() - 1);
119+
}
120+
if (!filename.isEmpty()) {
121+
filenames.add(filename);
122+
}
123+
break;
124+
}
125+
}
126+
}
127+
}
128+
if (filenames.isEmpty()) {
129+
return;
130+
}
131+
Flow<Void> filenamesFlow = filenamesCallback.apply(reqCtx, filenames);
132+
Flow.Action filenamesAction = filenamesFlow.getAction();
133+
if (t == null && filenamesAction instanceof Flow.Action.RequestBlockingAction) {
134+
Flow.Action.RequestBlockingAction rba = (Flow.Action.RequestBlockingAction) filenamesAction;
135+
BlockResponseFunction brf = reqCtx.getBlockResponseFunction();
136+
if (brf != null) {
137+
brf.tryCommitBlockingResponse(reqCtx.getTraceSegment(), rba);
138+
t = new BlockingException("Blocked request (multipart file upload)");
139+
reqCtx.getTraceSegment().effectivelyBlocked();
140+
}
141+
}
99142
}
100143
}
101144
}

0 commit comments

Comments
 (0)