Skip to content

Commit d37e03e

Browse files
committed
spotless
1 parent b1ec26b commit d37e03e

File tree

2 files changed

+82
-5
lines changed

2 files changed

+82
-5
lines changed

dd-java-agent/instrumentation/jetty/jetty-appsec/jetty-appsec-9.2/src/main/java/datadog/trace/instrumentation/jetty92/RequestExtractContentParametersInstrumentation.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ static void after(
144144
@RequiresRequestContext(RequestContextSlot.APPSEC)
145145
public static class GetFilenamesAdvice {
146146
@Advice.OnMethodEnter(suppress = Throwable.class)
147-
static boolean before(
148-
@Advice.FieldValue("_contentParameters") final MultiMap<String> map) {
147+
static boolean before(@Advice.FieldValue("_contentParameters") final MultiMap<String> map) {
149148
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Collection.class);
150149
return callDepth == 0 && map == null;
151150
}

dd-java-agent/instrumentation/jetty/jetty-appsec/jetty-appsec-9.3/src/main/java/datadog/trace/instrumentation/jetty93/RequestExtractContentParametersInstrumentation.java

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ public void methodAdvice(MethodTransformer transformer) {
4646
transformer.applyAdvice(
4747
named("extractContentParameters").and(takesArguments(0)).or(named("getParts")),
4848
getClass().getName() + "$ExtractContentParametersAdvice");
49-
transformer.applyAdvice(named("getParts"), getClass().getName() + "$GetFilenamesAdvice");
49+
transformer.applyAdvice(
50+
named("getParts").and(takesArguments(0)),
51+
getClass().getName() + "$GetFilenamesAdvice");
52+
transformer.applyAdvice(
53+
named("getParts").and(takesArguments(1)),
54+
getClass().getName() + "$GetFilenamesFromMultiPartAdvice");
5055
}
5156

5257
private static final Reference REQUEST_REFERENCE =
@@ -105,11 +110,15 @@ static void after(
105110
}
106111
}
107112

113+
/**
114+
* Fires the {@code requestFilesFilenames} event when the application calls public {@code
115+
* getParts()}. The {@code _contentParameters == null} guard ensures the WAF is invoked only on
116+
* the first call — subsequent calls return the cached result without re-processing.
117+
*/
108118
@RequiresRequestContext(RequestContextSlot.APPSEC)
109119
public static class GetFilenamesAdvice {
110120
@Advice.OnMethodEnter(suppress = Throwable.class)
111-
static boolean before(
112-
@Advice.FieldValue("_contentParameters") final MultiMap<String> map) {
121+
static boolean before(@Advice.FieldValue("_contentParameters") final MultiMap<String> map) {
113122
final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Collection.class);
114123
return callDepth == 0 && map == null;
115124
}
@@ -166,4 +175,73 @@ static void after(
166175
}
167176
}
168177
}
178+
179+
/**
180+
* Fires the {@code requestFilesFilenames} event when multipart content is parsed via the
181+
* internal {@code getParts(MultiMap)} path triggered by {@code getParameter*()} /
182+
* {@code getParameterMap()} — i.e. when the application never calls public {@code getParts()}.
183+
* In Jetty 9.3+, {@code extractContentParameters()} assigns {@code _contentParameters} before
184+
* calling this method, so {@code map == null} cannot be used as a "first parse" guard here;
185+
* the call-depth guard prevents double-firing when {@code getParts()} internally delegates to
186+
* this method.
187+
*/
188+
@RequiresRequestContext(RequestContextSlot.APPSEC)
189+
public static class GetFilenamesFromMultiPartAdvice {
190+
@Advice.OnMethodEnter(suppress = Throwable.class)
191+
static boolean before() {
192+
return CallDepthThreadLocalMap.incrementCallDepth(Collection.class) == 0;
193+
}
194+
195+
@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
196+
static void after(
197+
@Advice.Enter boolean proceed,
198+
@Advice.Return Collection parts,
199+
@ActiveRequestContext RequestContext reqCtx,
200+
@Advice.Thrown(readOnly = false) Throwable t) {
201+
CallDepthThreadLocalMap.decrementCallDepth(Collection.class);
202+
if (!proceed || t != null || parts == null || parts.isEmpty()) {
203+
return;
204+
}
205+
Method getSubmittedFileName = null;
206+
try {
207+
getSubmittedFileName = parts.iterator().next().getClass().getMethod("getSubmittedFileName");
208+
} catch (Exception ignored) {
209+
}
210+
if (getSubmittedFileName == null) {
211+
return;
212+
}
213+
List<String> filenames = new ArrayList<>();
214+
for (Object part : parts) {
215+
try {
216+
String name = (String) getSubmittedFileName.invoke(part);
217+
if (name != null && !name.isEmpty()) {
218+
filenames.add(name);
219+
}
220+
} catch (Exception ignored) {
221+
}
222+
}
223+
if (filenames.isEmpty()) {
224+
return;
225+
}
226+
CallbackProvider cbp = AgentTracer.get().getCallbackProvider(RequestContextSlot.APPSEC);
227+
BiFunction<RequestContext, List<String>, Flow<Void>> callback =
228+
cbp.getCallback(EVENTS.requestFilesFilenames());
229+
if (callback == null) {
230+
return;
231+
}
232+
Flow<Void> flow = callback.apply(reqCtx, filenames);
233+
Flow.Action action = flow.getAction();
234+
if (action instanceof Flow.Action.RequestBlockingAction) {
235+
Flow.Action.RequestBlockingAction rba = (Flow.Action.RequestBlockingAction) action;
236+
BlockResponseFunction brf = reqCtx.getBlockResponseFunction();
237+
if (brf != null) {
238+
brf.tryCommitBlockingResponse(reqCtx.getTraceSegment(), rba);
239+
if (t == null) {
240+
t = new BlockingException("Blocked request (multipart file upload)");
241+
reqCtx.getTraceSegment().effectivelyBlocked();
242+
}
243+
}
244+
}
245+
}
246+
}
169247
}

0 commit comments

Comments
 (0)