Skip to content

Add server.request.body.files_content AppSec address support for Jetty - #11706

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 5 commits into
masterfrom
jetty-filecontent
Jul 13, 2026
Merged

Add server.request.body.files_content AppSec address support for Jetty#11706
gh-worker-dd-mergequeue-cf854d[bot] merged 5 commits into
masterfrom
jetty-filecontent

Conversation

@jandro996

@jandro996jandro996 commented Jun 23, 2026

Copy link
Copy Markdown
Member

What Does This Do

  • Adds extractContents() to MultipartHelper (jetty-appsec-9.2/9.3/9.4/11.0) and PartHelper (jetty-appsec-8.1.3) to extract file content from multipart Parts, reading up to dd.appsec.max-file-content-bytes (default 4096) bytes per part, capped at dd.appsec.max-file-content-count (default 25) parts per request
  • Adds fireFilesContentEvent() to each helper, firing the server.request.body.files_content IG event via EVENTS.requestFilesContent()
  • Updates both advice classes in all five AppSec modules to fire the content event sequentially after the filenames event: t = fireFilenamesEvent(...); if (t == null) t = fireFilesContentEvent(...)
  • Form fields (parts with null submitted filename) are excluded; files with empty filename ("") are included for content inspection but excluded from filenames — matches the filter established in Add server.request.body.files_content AppSec address for Tomcat and Netty multipart #11198
  • Content is decoded via MultipartContentDecoder.readInputStream() with charset detection from the part's Content-Type header
  • For Jetty 8.1.3, filenameFromPart() (Content-Disposition header parsing) is used in place of getSubmittedFileName(), which was only added in Servlet 3.1
  • Adds unit tests for extractContents() in all five modules (null/empty, form-field skip, empty-filename include, content read, byte truncation, IOException fallback, count cap)
  • Enables testBodyFilesContent() in integration test classes for Jetty 8.x, 9.2, 9.3, 9.4, 10.0, and 11.0

Motivation

Extends the server.request.body.files_content WAF address to Jetty, following the Tomcat/Netty implementation in #11198 and building on the Jetty filenames support from #10988.

Additional Notes

The content event fires sequentially after the filenames event — only when filenames did not block. This matches the intent from #11137 (commons-fileupload). The MAX_CONTENT_BYTES and MAX_FILES_TO_INSPECT constants are static final fields on the helper classes (not on advice inner classes with @RequiresRequestContext) to avoid muzzle validation failures at CI.

Contributor Checklist

Jira ticket: N/A

Note:Once your PR is ready to merge, add it to the merge queue by commenting /merge./merge -c cancels the queue request. /merge -f --reason "reason" skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.

@jandro996jandro996 added type: feature Enhancements and improvements comp: asm waf Application Security Management (WAF) labels Jun 23, 2026
@jandro996jandro996 changed the title Add server.request.body.files_content WAF address support to JettyAdd server.request.body.files_content AppSec address support for JettyJun 23, 2026
@jandro996

Copy link
Copy Markdown
MemberAuthor

@codex review

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:66fad6bbfd

ℹ️ 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".

@datadog-prod-us1-5

datadog-prod-us1-5Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 69.73% (+12.80%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 3b9ea42 | Docs | Datadog PR Page | Give us feedback!

@dd-octo-sts

dd-octo-stsBot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

SuiteStatus
Startup🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
ScenarioCandidatemasterΔ (95% CI of mean)
startup:insecure-bank:iast:Agent14.74 s14.63 s[-0.1%; +1.5%] (no difference)
startup:insecure-bank:tracing:Agent13.67 s13.63 s[-0.4%; +1.0%] (no difference)
startup:petclinic:appsec:Agent16.94 s16.64 s[+0.9%; +2.7%] (maybe worse)
startup:petclinic:iast:Agent16.83 s16.54 s[-2.5%; +6.0%] (no difference)
startup:petclinic:profiling:Agent16.61 s16.88 s[-3.0%; -0.3%] (maybe better)
startup:petclinic:sca:Agent16.91 s16.48 s[-1.8%; +7.1%] (no difference)
startup:petclinic:tracing:Agent15.61 s16.10 s[-7.1%; +0.9%] (no difference)

Commit:3b9ea428 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@jandro996

Copy link
Copy Markdown
MemberAuthor

Addressed in d605e01:

@jandro996
jandro996 marked this pull request as ready for review June 23, 2026 13:38
@jandro996
jandro996 requested review from a team as code ownersJune 23, 2026 13:38
@jandro996
jandro996 requested review from amarziali, claponcet, manuel-alvarez-alvarez and vandonr and removed request for a teamJune 23, 2026 13:38
@jandro996
jandro996 requested a review from claponcetJune 24, 2026 11:52

@amarzialiamarziali left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok for apm-java (we only own the HttpServerTest) so our review is not blocking. However I left comments (not exhaustive since there are more occurrences) about the fact that there are a lot of exception logged. Those are surfaced through the telemetry and needs to get triaged. If those logs are not actionable I suggest to use the EXCLUDE_TELEMETRY marker

@jandro996

Copy link
Copy Markdown
MemberAuthor

ok for apm-java (we only own the HttpServerTest) so our review is not blocking. However I left comments (not exhaustive since there are more occurrences) about the fact that there are a lot of exception logged. Those are surfaced through the telemetry and needs to get triaged. If those logs are not actionable I suggest to use the EXCLUDE_TELEMETRY marker

Good catch. These exceptions come from user-controlled data (malformed multipart parts, I/O failures reading temp files) and are not actionable from the agent side, so I've added EXCLUDE_TELEMETRY to all of them across the five modules. Applied in 4c96d0d.

The one exception is PartHelper.getAllParts a MethodHandle invocation failure there is instrumentation-internal and should reach telemetry, so it stays without the marker

jandro996 added a commit that referenced this pull request Jul 7, 2026
extractFormFields() bounded the bytes read per field but not the number
of fields processed, leaving total allocation unbounded as O(fields x
byteCap). Cap the field count via Config.get().getAppSecMaxFileContentCount(),
mirroring the MAX_FILES_TO_INSPECT pattern used by MultipartHelper#extractContents()
(PR #11706) for file content.
gh-worker-dd-mergequeue-cf854dBot pushed a commit that referenced this pull request Jul 7, 2026
…11876)
fix: bound unbounded multipart form-field buffering in Jetty 8 AppSec advice
PartHelper.readPartContent() copied a multipart Part's InputStream into an
unbounded ByteArrayOutputStream before any WAF size check applied, allowing
a single oversized text field to exhaust heap. Cap the read at
Config.get().getAppSecMaxFileContentBytes(), reusing the existing
file-content byte cap since there is no dedicated form-field knob.
fix: cap number of multipart form fields inspected in Jetty 8 PartHelper
extractFormFields() bounded the bytes read per field but not the number
of fields processed, leaving total allocation unbounded as O(fields x
byteCap). Cap the field count via Config.get().getAppSecMaxFileContentCount(),
mirroring the MAX_FILES_TO_INSPECT pattern used by MultipartHelper#extractContents()
(PR #11706) for file content.
Merge branch 'master' into APMSP-3580
Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
kaahos pushed a commit that referenced this pull request Jul 8, 2026
…11876)
fix: bound unbounded multipart form-field buffering in Jetty 8 AppSec advice
PartHelper.readPartContent() copied a multipart Part's InputStream into an
unbounded ByteArrayOutputStream before any WAF size check applied, allowing
a single oversized text field to exhaust heap. Cap the read at
Config.get().getAppSecMaxFileContentBytes(), reusing the existing
file-content byte cap since there is no dedicated form-field knob.
fix: cap number of multipart form fields inspected in Jetty 8 PartHelper
extractFormFields() bounded the bytes read per field but not the number
of fields processed, leaving total allocation unbounded as O(fields x
byteCap). Cap the field count via Config.get().getAppSecMaxFileContentCount(),
mirroring the MAX_FILES_TO_INSPECT pattern used by MultipartHelper#extractContents()
(PR #11706) for file content.
Merge branch 'master' into APMSP-3580
Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
- Add extractContents(), readFileContent(), and fireFilesContentEvent()
to MultipartHelper (9.2/9.3/9.4/11.0) and PartHelper (8.1.3)
- Fire files_content event sequentially after filenames event in all
five Jetty AppSec advice classes
- Add unit tests for extractContents in all five modules
- Enable testBodyFilesContent() in integration test classes for all
instrumented Jetty versions (8.x, 9.2, 9.3, 9.4, 10.0, 11.0)
…ring-sensitive test
- RequestGetPartsInstrumentation (Jetty 8): add bodyBlock == null guard before
fireFilesContentEvent in both GetFilenamesAdvice and GetPartAdvice, consistent
with Tomcat, Netty, and Jersey implementations (PR #11198, #11229)
- HttpServerTest: change max-files-limit assertion to count-based check; Jetty
returns parts in HashMap order (not insertion order), so checking for a specific
file number by position was fragile
Add EXCLUDE_TELEMETRY marker to all log.debug calls in
PartHelper/MultipartHelper that handle exceptions from user-controlled
data (malformed parts, stream I/O failures). These are not actionable
from the agent side and would pollute telemetry signal.
The MethodHandle invocation failure in PartHelper.getAllParts is
intentionally left without the marker — that failure IS actionable
as it indicates an instrumentation-internal issue.
The Javadoc introduced by #11876 referenced Config method names and
MultipartHelper (the jetty-9.x class) instead of the constants and
class name used in this module (PartHelper, jetty-8.x).
@jandro996
jandro996 added this pull request to the merge queueJul 13, 2026
@dd-octo-sts

Copy link
Copy Markdown
Contributor

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351Bot commented Jul 13, 2026

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-07-13 10:26:47 UTC ℹ️ Start processing command /merge


2026-07-13 10:26:53 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 2h (p90).


2026-07-13 11:25:47 UTC ℹ️ MergeQueue: This merge request was merged

@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Jul 13, 2026
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854dBot merged commit cd03735 into masterJul 13, 2026
782 of 784 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854dBot deleted the jetty-filecontent branch July 13, 2026 11:25
@github-actionsgithub-actionsBot added this to the 1.65.0 milestone Jul 13, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: asm wafApplication Security Management (WAF)type: featureEnhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@jandro996@amarziali@claponcet