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

@jandro996 jandro996 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.

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

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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-5 Bot 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-sts Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
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
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.74 s 14.63 s [-0.1%; +1.5%] (no difference)
startup:insecure-bank:tracing:Agent 13.67 s 13.63 s [-0.4%; +1.0%] (no difference)
startup:petclinic:appsec:Agent 16.94 s 16.64 s [+0.9%; +2.7%] (maybe worse)
startup:petclinic:iast:Agent 16.83 s 16.54 s [-2.5%; +6.0%] (no difference)
startup:petclinic:profiling:Agent 16.61 s 16.88 s [-3.0%; -0.3%] (maybe better)
startup:petclinic:sca:Agent 16.91 s 16.48 s [-1.8%; +7.1%] (no difference)
startup:petclinic:tracing:Agent 15.61 s 16.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
Member Author

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 owners June 23, 2026 13:38
@jandro996 jandro996 requested review from amarziali, claponcet, manuel-alvarez-alvarez and vandonr and removed request for a team June 23, 2026 13:38
@jandro996 jandro996 requested a review from claponcet June 24, 2026 11:52

@amarziali amarziali 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
Member Author

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-cf854d Bot 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>
jandro996 added 4 commits July 9, 2026 09:44
- 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.
@jandro996 jandro996 force-pushed the jetty-filecontent branch from 4c96d0d to 36f84a6 Compare July 9, 2026 07:47
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 queue Jul 13, 2026
@dd-octo-sts

dd-octo-sts Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351 Bot 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-queue Bot 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-cf854d Bot merged commit cd03735 into master Jul 13, 2026
782 of 784 checks passed
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot deleted the jetty-filecontent branch July 13, 2026 11:25
@github-actions github-actions Bot added this to the 1.65.0 milestone Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: asm waf Application Security Management (WAF) type: feature Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants