Skip to content

fix(appsec): explicitly set Content-Length header in block request handler#4496

Merged
RomainMuller merged 2 commits into
mainfrom
romain.marcadier/APPSEC-61286/block-handler-content-length
Mar 4, 2026
Merged

fix(appsec): explicitly set Content-Length header in block request handler#4496
RomainMuller merged 2 commits into
mainfrom
romain.marcadier/APPSEC-61286/block-handler-content-length

Conversation

@RomainMuller

Copy link
Copy Markdown
Contributor

Summary

  • The AppSec block request handler was not explicitly setting Content-Length on the ResponseWriter header map
  • Go's net/http auto-sets Content-Length on the wire but does not update w.Header(), so span tag collection via ResponseHeaderCopier missed it
  • The span tag http.response.headers.content-length was absent on blocked requests, causing system-tests Test_Headers_Event_Blocking to fail (APPSEC-61286)
  • The fix pre-computes the rendered response payload and explicitly sets Content-Length before WriteHeader()

Changes

  • instrumentation/appsec/emitter/waf/actions/block.go: newBlockRequestHandler now computes the response body upfront and sets Content-Length explicitly in the header map
  • instrumentation/appsec/emitter/waf/actions/block_test.go: New test file with table-driven tests covering JSON, HTML, auto-detect, and empty security response ID cases

…ndler

The block request handler was not explicitly setting the Content-Length
header on the ResponseWriter. Go's net/http automatically calculates and
sends Content-Length to the client, but does not update the Header() map
with this auto-detected value. This caused the AppSec header collection
code (which reads from w.Header() via ResponseHeaderCopier) to miss the
Content-Length, resulting in the span tag
http.response.headers.content-length being absent on blocked requests.

The fix pre-computes the rendered response payload and explicitly sets
Content-Length in the header map before calling WriteHeader, ensuring the
header is visible to span tag collection.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
JJ-Change-Id: yqmwrx
@RomainMuller
RomainMuller requested a review from a team as a code owner March 4, 2026 09:47
@RomainMuller
RomainMuller enabled auto-merge (squash) March 4, 2026 09:51
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Mar 4, 2026

Copy link
Copy Markdown

✅ Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: fcaf08d | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback!

@pr-commenter

pr-commenter Bot commented Mar 4, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-03-04 10:29:20

Comparing candidate commit fcaf08d in PR branch romain.marcadier/APPSEC-61286/block-handler-content-length with baseline commit 5793394 in branch main.

Found 0 performance improvements and 1 performance regressions! Performance is the same for 157 metrics, 6 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:BenchmarkParallelMetrics/rate/handle-reused-25

  • 🟥 execution_time [+1.719ns; +8.305ns] or [+2.345%; +11.328%]

…ponses

The appsec block handler now sets an explicit Content-Length header.
The envoy tests asserted on headers by index (SetHeaders[0]), which is
fragile since http.Header map iteration order is non-deterministic.

Replace index-based header assertions with a key-based lookup helper
(requireSetHeader), and update Len assertions from 1 to 2 to account
for the new Content-Length header.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
JJ-Change-Id: yurmxo
@RomainMuller
RomainMuller merged commit a7b9a19 into main Mar 4, 2026
180 checks passed
@RomainMuller
RomainMuller deleted the romain.marcadier/APPSEC-61286/block-handler-content-length branch March 4, 2026 10:31
RomainMuller added a commit to DataDog/system-tests that referenced this pull request Mar 4, 2026
Remove the bug (APPSEC-61286) marker from Test_Headers_Event_Blocking
in the golang manifest. The underlying issue (missing Content-Length span
tag on blocked responses) has been fixed in dd-trace-go by explicitly
setting the header in the block request handler.

See: DataDog/dd-trace-go#4496

Co-Authored-By: Claude Opus 4.6 <[email protected]>
JJ-Change-Id: oxwxwl
RomainMuller added a commit to DataDog/system-tests that referenced this pull request Mar 4, 2026
Replace the bug (APPSEC-61286) marker on Test_Headers_Event_Blocking
with a v2.7.0-dev version gate in the golang manifest. The underlying
issue (missing Content-Length span tag on blocked responses) has been
fixed in dd-trace-go by explicitly setting the header in the block
request handler.

See: DataDog/dd-trace-go#4496

Co-Authored-By: Claude Opus 4.6 <[email protected]>
JJ-Change-Id: xryqnp
RomainMuller added a commit to DataDog/system-tests that referenced this pull request Mar 5, 2026
## Summary

- Replace `bug (APPSEC-61286)` marker on `Test_Headers_Event_Blocking` with a `v2.7.0-dev` version gate in `manifests/golang.yml`
- The underlying issue (missing `Content-Length` span tag on blocked responses) has been fixed in dd-trace-go by explicitly setting the header in the block request handler
- Tracer fix: DataDog/dd-trace-go#4496

---

Co-authored-by: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants