Skip to content

Commit c4da39c

Browse files
committed
Cache MultipartFormData.files() Method to avoid per-request reflection lookup
1 parent b3a4e2a commit c4da39c

2 files changed

Lines changed: 42 additions & 12 deletions

File tree

  • dd-java-agent/instrumentation/play

dd-java-agent/instrumentation/play/play-appsec-2.5/src/main/java/datadog/trace/instrumentation/play25/appsec/BodyParserHelpers.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import datadog.trace.api.gateway.RequestContextSlot;
2020
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
2121
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
22+
import java.lang.reflect.Method;
2223
import java.util.ArrayList;
2324
import java.util.HashMap;
2425
import java.util.List;
@@ -47,6 +48,21 @@ public class BodyParserHelpers {
4748
private static final Logger log = LoggerFactory.getLogger(BodyParserHelpers.class);
4849
public static final int MAX_RECURSION = 15;
4950

51+
// Cached via reflection to avoid embedding a hard binary reference to
52+
// files():Lscala/collection/Seq; — the return type changed to
53+
// Lscala/collection/immutable/Seq; in Scala 2.13 (Play 2.7+), which would
54+
// cause muzzle to disable the instrumentation for Play 2.7.
55+
private static final Method MULTIPART_FILES_METHOD;
56+
57+
static {
58+
Method m = null;
59+
try {
60+
m = MultipartFormData.class.getMethod("files");
61+
} catch (Exception ignored) {
62+
}
63+
MULTIPART_FILES_METHOD = m;
64+
}
65+
5066
private static JFunction1<
5167
scala.collection.immutable.Map<String, Seq<String>>,
5268
scala.collection.immutable.Map<String, Seq<String>>>
@@ -116,12 +132,11 @@ private static MultipartFormData<?> handleMultipartFormData(MultipartFormData<?>
116132
}
117133

118134
try {
119-
// Use reflection to avoid a hard binary reference to files():Lscala/collection/Seq; —
120-
// in Scala 2.13 (Play 2.7+) the return type became scala.collection.immutable.Seq,
121-
// which would cause muzzle to disable the whole instrumentation for Play 2.7.
122-
Object files = data.getClass().getMethod("files").invoke(data);
123-
if (files instanceof scala.collection.Iterable) {
124-
handleMultipartFilenames(((scala.collection.Iterable<?>) files).iterator());
135+
if (MULTIPART_FILES_METHOD != null) {
136+
Object files = MULTIPART_FILES_METHOD.invoke(data);
137+
if (files instanceof scala.collection.Iterable) {
138+
handleMultipartFilenames(((scala.collection.Iterable<?>) files).iterator());
139+
}
125140
}
126141
} catch (Exception e) {
127142
handleException(e, "Error handling multipartFormData filenames");

dd-java-agent/instrumentation/play/play-appsec-2.6/src/main/java/datadog/trace/instrumentation/play26/appsec/BodyParserHelpers.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import datadog.trace.api.gateway.RequestContextSlot;
2020
import datadog.trace.bootstrap.instrumentation.api.AgentSpan;
2121
import datadog.trace.bootstrap.instrumentation.api.AgentTracer;
22+
import java.lang.reflect.Method;
2223
import java.util.ArrayList;
2324
import java.util.Collections;
2425
import java.util.HashMap;
@@ -57,6 +58,21 @@ public class BodyParserHelpers {
5758
private static final Logger log = LoggerFactory.getLogger(BodyParserHelpers.class);
5859
public static final int MAX_RECURSION = 15;
5960

61+
// Cached via reflection to avoid embedding a hard binary reference to
62+
// files():Lscala/collection/Seq; — the return type changed to
63+
// Lscala/collection/immutable/Seq; in Scala 2.13 (Play 2.7+), which would
64+
// cause muzzle to disable the instrumentation for Play 2.7.
65+
private static final Method MULTIPART_FILES_METHOD;
66+
67+
static {
68+
Method m = null;
69+
try {
70+
m = MultipartFormData.class.getMethod("files");
71+
} catch (Exception ignored) {
72+
}
73+
MULTIPART_FILES_METHOD = m;
74+
}
75+
6076
private static JFunction1<
6177
scala.collection.immutable.Map<String, Seq<String>>,
6278
scala.collection.immutable.Map<String, Seq<String>>>
@@ -127,12 +143,11 @@ private static MultipartFormData<?> handleMultipartFormData(MultipartFormData<?>
127143
}
128144

129145
try {
130-
// Use reflection to avoid a hard binary reference to files():Lscala/collection/Seq; —
131-
// in Scala 2.13 (Play 2.7+) the return type became scala.collection.immutable.Seq,
132-
// which would cause muzzle to disable the whole instrumentation for Play 2.7.
133-
Object files = data.getClass().getMethod("files").invoke(data);
134-
if (files instanceof scala.collection.Iterable) {
135-
handleMultipartFilenames(((scala.collection.Iterable<?>) files).iterator());
146+
if (MULTIPART_FILES_METHOD != null) {
147+
Object files = MULTIPART_FILES_METHOD.invoke(data);
148+
if (files instanceof scala.collection.Iterable) {
149+
handleMultipartFilenames(((scala.collection.Iterable<?>) files).iterator());
150+
}
136151
}
137152
} catch (Exception e) {
138153
handleException(e, "Error handling multipartFormData filenames");

0 commit comments

Comments
 (0)