Add server.request.body.filenames support for Jetty#10988
Add server.request.body.filenames support for Jetty#10988
Conversation
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 57 metrics, 14 unstable metrics. Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.056 s) : 0, 1056249
Total [baseline] (8.827 s) : 0, 8826556
Agent [candidate] (1.054 s) : 0, 1054469
Total [candidate] (8.845 s) : 0, 8844511
section iast
Agent [baseline] (1.228 s) : 0, 1227866
Total [baseline] (9.578 s) : 0, 9577849
Agent [candidate] (1.229 s) : 0, 1228766
Total [candidate] (9.571 s) : 0, 9571078
gantt
title insecure-bank - break down per module: candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.237 ms) : 0, 1237
crashtracking [candidate] (1.233 ms) : 0, 1233
BytebuddyAgent [baseline] (632.192 ms) : 0, 632192
BytebuddyAgent [candidate] (634.08 ms) : 0, 634080
AgentMeter [baseline] (29.386 ms) : 0, 29386
AgentMeter [candidate] (29.351 ms) : 0, 29351
GlobalTracer [baseline] (248.438 ms) : 0, 248438
GlobalTracer [candidate] (248.43 ms) : 0, 248430
AppSec [baseline] (32.031 ms) : 0, 32031
AppSec [candidate] (31.954 ms) : 0, 31954
Debugger [baseline] (59.055 ms) : 0, 59055
Debugger [candidate] (58.92 ms) : 0, 58920
Remote Config [baseline] (592.423 µs) : 0, 592
Remote Config [candidate] (583.77 µs) : 0, 584
Telemetry [baseline] (8.09 ms) : 0, 8090
Telemetry [candidate] (8.041 ms) : 0, 8041
Flare Poller [baseline] (9.131 ms) : 0, 9131
Flare Poller [candidate] (5.805 ms) : 0, 5805
section iast
crashtracking [baseline] (1.228 ms) : 0, 1228
crashtracking [candidate] (1.222 ms) : 0, 1222
BytebuddyAgent [baseline] (804.439 ms) : 0, 804439
BytebuddyAgent [candidate] (805.14 ms) : 0, 805140
AgentMeter [baseline] (11.442 ms) : 0, 11442
AgentMeter [candidate] (11.479 ms) : 0, 11479
GlobalTracer [baseline] (239.759 ms) : 0, 239759
GlobalTracer [candidate] (238.948 ms) : 0, 238948
AppSec [baseline] (30.354 ms) : 0, 30354
AppSec [candidate] (31.134 ms) : 0, 31134
Debugger [baseline] (61.456 ms) : 0, 61456
Debugger [candidate] (64.683 ms) : 0, 64683
Remote Config [baseline] (530.623 µs) : 0, 531
Remote Config [candidate] (557.205 µs) : 0, 557
Telemetry [baseline] (11.999 ms) : 0, 11999
Telemetry [candidate] (10.111 ms) : 0, 10111
Flare Poller [baseline] (3.81 ms) : 0, 3810
Flare Poller [candidate] (3.502 ms) : 0, 3502
IAST [baseline] (26.577 ms) : 0, 26577
IAST [candidate] (25.781 ms) : 0, 25781
Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.061 s) : 0, 1061137
Total [baseline] (11.104 s) : 0, 11103947
Agent [candidate] (1.062 s) : 0, 1061536
Total [candidate] (11.041 s) : 0, 11041488
section appsec
Agent [baseline] (1.248 s) : 0, 1247769
Total [baseline] (11.132 s) : 0, 11132443
Agent [candidate] (1.249 s) : 0, 1249499
Total [candidate] (11.123 s) : 0, 11122887
section iast
Agent [baseline] (1.224 s) : 0, 1223611
Total [baseline] (11.258 s) : 0, 11257761
Agent [candidate] (1.23 s) : 0, 1230251
Total [candidate] (11.284 s) : 0, 11283532
section profiling
Agent [baseline] (1.187 s) : 0, 1186511
Total [baseline] (11.144 s) : 0, 11143516
Agent [candidate] (1.183 s) : 0, 1182710
Total [candidate] (11.024 s) : 0, 11024256
gantt
title petclinic - break down per module: candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.232 ms) : 0, 1232
crashtracking [candidate] (1.222 ms) : 0, 1222
BytebuddyAgent [baseline] (633.247 ms) : 0, 633247
BytebuddyAgent [candidate] (633.779 ms) : 0, 633779
AgentMeter [baseline] (29.422 ms) : 0, 29422
AgentMeter [candidate] (29.321 ms) : 0, 29321
GlobalTracer [baseline] (249.131 ms) : 0, 249131
GlobalTracer [candidate] (249.62 ms) : 0, 249620
AppSec [baseline] (32.089 ms) : 0, 32089
AppSec [candidate] (32.3 ms) : 0, 32300
Debugger [baseline] (60.249 ms) : 0, 60249
Debugger [candidate] (60.43 ms) : 0, 60430
Remote Config [baseline] (595.124 µs) : 0, 595
Remote Config [candidate] (599.51 µs) : 0, 600
Telemetry [baseline] (8.176 ms) : 0, 8176
Telemetry [candidate] (9.006 ms) : 0, 9006
Flare Poller [baseline] (10.753 ms) : 0, 10753
Flare Poller [candidate] (9.123 ms) : 0, 9123
section appsec
crashtracking [baseline] (1.22 ms) : 0, 1220
crashtracking [candidate] (1.215 ms) : 0, 1215
BytebuddyAgent [baseline] (661.841 ms) : 0, 661841
BytebuddyAgent [candidate] (663.652 ms) : 0, 663652
AgentMeter [baseline] (12.076 ms) : 0, 12076
AgentMeter [candidate] (12.073 ms) : 0, 12073
GlobalTracer [baseline] (249.099 ms) : 0, 249099
GlobalTracer [candidate] (249.289 ms) : 0, 249289
AppSec [baseline] (184.061 ms) : 0, 184061
AppSec [candidate] (184.044 ms) : 0, 184044
Debugger [baseline] (65.76 ms) : 0, 65760
Debugger [candidate] (65.674 ms) : 0, 65674
Remote Config [baseline] (608.541 µs) : 0, 609
Remote Config [candidate] (603.549 µs) : 0, 604
Telemetry [baseline] (8.69 ms) : 0, 8690
Telemetry [candidate] (8.491 ms) : 0, 8491
Flare Poller [baseline] (3.556 ms) : 0, 3556
Flare Poller [candidate] (3.556 ms) : 0, 3556
IAST [baseline] (24.514 ms) : 0, 24514
IAST [candidate] (24.529 ms) : 0, 24529
section iast
crashtracking [baseline] (1.211 ms) : 0, 1211
crashtracking [candidate] (1.223 ms) : 0, 1223
BytebuddyAgent [baseline] (801.072 ms) : 0, 801072
BytebuddyAgent [candidate] (807.255 ms) : 0, 807255
AgentMeter [baseline] (11.358 ms) : 0, 11358
AgentMeter [candidate] (11.613 ms) : 0, 11613
GlobalTracer [baseline] (239.103 ms) : 0, 239103
GlobalTracer [candidate] (239.121 ms) : 0, 239121
AppSec [baseline] (29.395 ms) : 0, 29395
AppSec [candidate] (32.353 ms) : 0, 32353
Debugger [baseline] (61.645 ms) : 0, 61645
Debugger [candidate] (62.693 ms) : 0, 62693
Remote Config [baseline] (1.726 ms) : 0, 1726
Remote Config [candidate] (551.719 µs) : 0, 552
Telemetry [baseline] (12.768 ms) : 0, 12768
Telemetry [candidate] (9.926 ms) : 0, 9926
Flare Poller [baseline] (3.581 ms) : 0, 3581
Flare Poller [candidate] (3.461 ms) : 0, 3461
IAST [baseline] (25.71 ms) : 0, 25710
IAST [candidate] (25.769 ms) : 0, 25769
section profiling
crashtracking [baseline] (1.178 ms) : 0, 1178
crashtracking [candidate] (1.195 ms) : 0, 1195
BytebuddyAgent [baseline] (692.519 ms) : 0, 692519
BytebuddyAgent [candidate] (690.867 ms) : 0, 690867
AgentMeter [baseline] (9.15 ms) : 0, 9150
AgentMeter [candidate] (9.067 ms) : 0, 9067
GlobalTracer [baseline] (207.324 ms) : 0, 207324
GlobalTracer [candidate] (206.831 ms) : 0, 206831
AppSec [baseline] (32.596 ms) : 0, 32596
AppSec [candidate] (32.462 ms) : 0, 32462
Debugger [baseline] (65.024 ms) : 0, 65024
Debugger [candidate] (65.434 ms) : 0, 65434
Remote Config [baseline] (578.309 µs) : 0, 578
Remote Config [candidate] (572.838 µs) : 0, 573
Telemetry [baseline] (8.709 ms) : 0, 8709
Telemetry [candidate] (7.835 ms) : 0, 7835
Flare Poller [baseline] (3.639 ms) : 0, 3639
Flare Poller [candidate] (3.546 ms) : 0, 3546
ProfilingAgent [baseline] (94.432 ms) : 0, 94432
ProfilingAgent [candidate] (93.772 ms) : 0, 93772
Profiling [baseline] (95.018 ms) : 0, 95018
Profiling [candidate] (94.354 ms) : 0, 94354
LoadParameters
See matching parameters
SummaryFound 2 performance improvements and 0 performance regressions! Performance is the same for 18 metrics, 16 unstable metrics.
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section baseline
no_agent (18.378 ms) : 18189, 18567
. : milestone, 18378,
appsec (19.363 ms) : 19168, 19558
. : milestone, 19363,
code_origins (17.803 ms) : 17628, 17979
. : milestone, 17803,
iast (17.85 ms) : 17675, 18025
. : milestone, 17850,
profiling (18.24 ms) : 18060, 18421
. : milestone, 18240,
tracing (18.782 ms) : 18595, 18968
. : milestone, 18782,
section candidate
no_agent (19.319 ms) : 19125, 19514
. : milestone, 19319,
appsec (18.717 ms) : 18525, 18909
. : milestone, 18717,
code_origins (18.031 ms) : 17854, 18207
. : milestone, 18031,
iast (17.793 ms) : 17618, 17967
. : milestone, 17793,
profiling (18.312 ms) : 18131, 18493
. : milestone, 18312,
tracing (17.736 ms) : 17560, 17912
. : milestone, 17736,
Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section baseline
no_agent (1.244 ms) : 1232, 1256
. : milestone, 1244,
iast (3.427 ms) : 3386, 3468
. : milestone, 3427,
iast_FULL (5.957 ms) : 5897, 6017
. : milestone, 5957,
iast_GLOBAL (3.744 ms) : 3676, 3812
. : milestone, 3744,
profiling (2.214 ms) : 2194, 2234
. : milestone, 2214,
tracing (1.911 ms) : 1895, 1927
. : milestone, 1911,
section candidate
no_agent (1.253 ms) : 1241, 1265
. : milestone, 1253,
iast (3.382 ms) : 3339, 3425
. : milestone, 3382,
iast_FULL (6.088 ms) : 6025, 6151
. : milestone, 6088,
iast_GLOBAL (3.58 ms) : 3527, 3633
. : milestone, 3580,
profiling (2.309 ms) : 2287, 2331
. : milestone, 2309,
tracing (1.923 ms) : 1907, 1939
. : milestone, 1923,
DacapoParameters
See matching parameters
SummaryFound 1 performance improvements and 0 performance regressions! Performance is the same for 10 metrics, 1 unstable metrics.
Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section baseline
no_agent (15.593 s) : 15593000, 15593000
. : milestone, 15593000,
appsec (14.86 s) : 14860000, 14860000
. : milestone, 14860000,
iast (18.378 s) : 18378000, 18378000
. : milestone, 18378000,
iast_GLOBAL (18.297 s) : 18297000, 18297000
. : milestone, 18297000,
profiling (14.617 s) : 14617000, 14617000
. : milestone, 14617000,
tracing (14.79 s) : 14790000, 14790000
. : milestone, 14790000,
section candidate
no_agent (14.83 s) : 14830000, 14830000
. : milestone, 14830000,
appsec (15.28 s) : 15280000, 15280000
. : milestone, 15280000,
iast (18.49 s) : 18490000, 18490000
. : milestone, 18490000,
iast_GLOBAL (17.859 s) : 17859000, 17859000
. : milestone, 17859000,
profiling (14.958 s) : 14958000, 14958000
. : milestone, 14958000,
tracing (14.936 s) : 14936000, 14936000
. : milestone, 14936000,
Execution time for tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.61.0-SNAPSHOT~b9f5a74c5a, baseline=1.62.0-SNAPSHOT~067d0d2c4b
dateFormat X
axisFormat %s
section baseline
no_agent (1.489 ms) : 1477, 1500
. : milestone, 1489,
appsec (3.851 ms) : 3629, 4073
. : milestone, 3851,
iast (2.28 ms) : 2210, 2350
. : milestone, 2280,
iast_GLOBAL (2.322 ms) : 2252, 2392
. : milestone, 2322,
profiling (2.529 ms) : 2362, 2695
. : milestone, 2529,
tracing (2.088 ms) : 2034, 2142
. : milestone, 2088,
section candidate
no_agent (1.487 ms) : 1475, 1499
. : milestone, 1487,
appsec (2.535 ms) : 2479, 2590
. : milestone, 2535,
iast (2.286 ms) : 2216, 2356
. : milestone, 2286,
iast_GLOBAL (2.317 ms) : 2247, 2388
. : milestone, 2317,
profiling (2.1 ms) : 2045, 2155
. : milestone, 2100,
tracing (2.094 ms) : 2040, 2149
. : milestone, 2094,
|
e3d4073 to
e2d5ed0
Compare
Add GetFilenamesAdvice to all three Jetty AppSec modules to collect uploaded file names from multipart requests and fire the requestFilesFilenames() IG callback: - jetty-appsec-8.1.3: intercepts getParts() return value; includes Content-Disposition header fallback for Servlet 3.0 (Jetty 9.0) where getSubmittedFileName() is not available - jetty-appsec-9.2: intercepts no-arg getParts() for Servlet 3.1+ - jetty-appsec-9.3: same, applies to Jetty 9.3, 10, 11 Enable testBodyFilenames() in Jetty 9.x, 10 and 11 server tests.
f2998c3 to
629f074
Compare
| } | ||
| } | ||
| // Fallback: parse filename from Content-Disposition header (Servlet 3.0) | ||
| if (name == null) { |
There was a problem hiding this comment.
Shouldn't this be outside of the main parts loop?
There was a problem hiding this comment.
Fixed. Restructured into two separate loops chosen once before iteration: if getSubmittedFileName != null (Servlet 3.1+) iterate using that method; otherwise iterate parsing the Content-Disposition header (Servlet 3.0 fallback). No per-part branching inside the loop.
| transformer.applyAdvice( | ||
| named("extractContentParameters").and(takesArguments(0)).or(named("getParts")), | ||
| getClass().getName() + "$ExtractContentParametersAdvice"); | ||
| transformer.applyAdvice(named("getParts"), getClass().getName() + "$GetFilenamesAdvice"); |
There was a problem hiding this comment.
Fixed. GetFilenamesAdvice now has a call-depth guard (CallDepthThreadLocalMap with Collection.class) to avoid double-firing when getParts() internally calls getParts(MultiMap)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c732823549
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
...va/datadog/trace/instrumentation/jetty92/RequestExtractContentParametersInstrumentation.java
Outdated
Show resolved
Hide resolved
...va/datadog/trace/instrumentation/jetty93/RequestExtractContentParametersInstrumentation.java
Outdated
Show resolved
Hide resolved
ecf65c5 to
eae08aa
Compare
…MultiMap) path - jetty-appsec-9.3: add call-depth guard (Collection.class) to GetFilenamesAdvice to prevent double callback invocation when getParts() calls getParts(MultiMap) internally - jetty-appsec-9.2: extend GetFilenamesAdvice matcher to all getParts overloads (not just no-arg) to cover getParameter*()/getParameterMap() code paths, guarded with same call-depth mechanism to avoid double-firing
3ab9ff7 to
77ec572
Compare
2e72584 to
d37e03e
Compare
d37e03e to
d8a92f8
Compare
- Add BODY_MULTIPART_REPEATED case to TestServlet3 (javax) so Jetty 9.x/10.x test modules can exercise the repeated getParts() scenario - Enable testBodyFilenamesCalledOnce() for Jetty 9.0, 9.0.4, 9.3, 9.4.21, and 10.0
…vice path - New BODY_MULTIPART_COMBINED endpoint: calls getParameterMap() first (triggers GetFilenamesFromMultiPartAdvice via extractContentParameters -> getParts(MultiMap)), then getParts() explicitly (GetFilenamesAdvice must not double-fire since _contentParameters is already set) - New test 'file upload filenames called once via parameter map' verifies the callback fires exactly once across both advice paths - Enabled in Jetty 9.0, 9.0.4, 9.3, 9.4.21, 10.0 and 11.0
…eplaces _contentParameters as the getParts() cache In Jetty 9.3, getParts(MultiMap) sets _contentParameters, so the map==null guard prevents re-firing on repeated getParts() calls. In Jetty 9.4+, getParts() delegates to getParts(null) and caches the result in _multiParts instead, leaving _contentParameters null on every call. Add _multiParts==null as an additional guard (optional=true handles Jetty 9.3 where the field does not exist).
In Jetty 8.x/9.0, _multiPartInputStream is null only on the first getParts() call. Add OnMethodEnter guard to skip the WAF callback on subsequent calls which return the cached multipart result.
@advice.FieldValue(optional=true) is not supported in ByteBuddy 1.11.22. Replace it with @Advice.This + inline reflection to detect whether getParts() has already been called on this request: - Jetty 9.4+: checks _multiParts (set after first getParts() call) - Jetty 9.3.x: falls back to _multiPartInputStream (the cache field in 9.3.x, where _multiParts does not exist and _contentParameters is only set by the getParameterMap() → extractContentParameters() path, not by getParts()) Covers all forkedTest and latestDepForkedTest suites for Jetty 9.0–11.
Jetty multipart file upload instrumentation fixed in DataDog/dd-trace-java#10988 (Jetty 8.1.3, 9.3–11).
…t 3.1+ branch
Jetty 8 implements only Servlet 3.0, so getSubmittedFileName() is never
present on the Part objects. The reflection probe (try { getMethod("getSubmittedFileName") })
and the Servlet 3.1+ code path were dead code. Remove them and always
parse filenames from the Content-Disposition header directly.
Type @Advice.Return as Collection<Part> so the loop variable can be Part directly, eliminating the (Part) cast on each iteration.
Move the filename extraction logic from GetFilenamesAdvice into a new MultipartHelper helper class so it can be unit tested in isolation. Add 12 Spock test cases covering quoted/unquoted filenames, empty values, whitespace, null input, and edge cases.
…unit tests Move the getSubmittedFileName() loop from GetFilenamesAdvice into a new MultipartHelper helper class (injected via helperClassNames) so it can be unit tested in isolation. Add 8 Spock test cases covering null/empty collections, null/empty filenames, multiple parts, and special characters.
Eliminates all reflection from the multipart filename instrumentation by creating version-specific modules with compile-time type safety: - jetty-appsec-9.3 [9.3,9.4): javax.servlet, uses _multiPartInputStream field - jetty-appsec-9.4 [9.4,11.0): javax.servlet, uses _multiParts field - jetty-appsec-11.0 [11.0,12.0): jakarta.servlet, uses _multiParts field Each module uses muzzle references as version discriminators instead of runtime reflection, and delegates filename extraction to a testable MultipartHelper class with 8 Spock unit tests each. Server test modules updated to reference the correct appsec module per Jetty version range.
- Add Jetty8LatestDepForkedTest: runs against Jetty 8.x (latestDepForkedTest task) and enables testBodyMultipart/testBodyFilenames coverage. Gated by 'test.dd.filenames' system property so it is skipped when running against Jetty 7.6. - Add testCompileOnly dep on org.eclipse.jetty.orbit:javax.servlet so MultipartConfigElement compiles without pulling in the excluded javax.servlet:javax.servlet-api artifact. - Fix ParameterCollector.put to accept (Object, Object) and cast internally: Jetty 8.x MultiMap.add uses (Object, Object) descriptor while Jetty 9.x uses (String, Object), so the ASM bytecode visitor was silently skipping all form field captures on Jetty 8. - Update GetPartsMethodVisitor to match both (String,Object) and (Object,Object) MultiMap.add descriptors and emit the INVOKEINTERFACE with (Object, Object).
_multiPartInputStream was replaced by _multiParts in Jetty 9.4.10.v20180503. Early 9.4.x versions (9.4.0–9.4.9) still use _multiPartInputStream like 9.3.x, so extend jetty-appsec-9.3 to cover [9.3, 9.4.10) and narrow jetty-appsec-9.4 to [9.4.10, 11.0). The classLoaderMatcher in jetty-appsec-9.4 (checking for _multiParts) now correctly matches only versions >= 9.4.10.
What Does This Do
Jetty parses multipart bodies through two code paths depending on how the application accesses the request:
getParameterMap()→extractContentParameters()→ internalgetParts(MultiMap)getParts()call from user codeBoth paths are instrumented to fire
requestFilesFilenames. Guards on internal state fields (_contentParameters,_multiParts,_multiPartInputStream) prevent double-firing.jetty-appsec-7.0GetFilenamesAdviceforgetParts(). NoextractContentParametersin 7.x so only one path exists.jetty-appsec-8.1.3getSubmittedFileName()so filenames are parsed from theContent-Dispositionheader. Logic extracted toMultipartHelperwith unit tests.jetty-appsec-9.2Part.getSubmittedFileName()(Servlet 3.1). Logic extracted toMultipartHelperwith unit tests.jetty-appsec-9.3[9.3, 12)to[9.3, 9.4). Removed reflection (getDeclaredField/Method.invoke) by restricting scope to only 9.3.x, where_multiPartInputStreamis the correct field.MultipartHelperadded with unit tests.jetty-appsec-9.4(new)[9.4, 11.0)— javax.servlet, uses_multiPartsfield (introduced in 9.4). Previously handled by 9.3 via reflection.MultipartHelperwith unit tests.jetty-appsec-11.0(new)[11.0, 12.0)— jakarta.servlet (first Jetty version to drop javax). Previously handled by 9.3 via reflection.MultipartHelperwith unit tests.jetty-server-9.3/9.4.21/10.0/11.0/12.0) updated to reference the correct appsec module per Jetty version range.Motivation
Additional Notes
Depends on #10973 (merged).
Part of Jira ticket: APPSEC-61873 —
server.request.body.filenamesimplementation across server frameworks.Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issue