From 85670c04df38dfd9de4800fb60efcf27c6e080cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20=C3=81lvarez=20=C3=81lvarez?= Date: Fri, 9 Jan 2026 11:04:43 +0100 Subject: [PATCH] Convert downstream requests header keys to lower case --- .../datadog/appsec/gateway/GatewayBridge.java | 18 ++++++++++++++++-- .../gateway/GatewayBridgeSpecification.groovy | 10 ++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java index 65ae99aa17c..174f977ff21 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/GatewayBridge.java @@ -58,6 +58,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -358,7 +359,7 @@ private Flow onHttpClientRequest(RequestContext ctx_, HttpClientRequest re new MapDataBundle.Builder(CAPACITY_3_4) .add(KnownAddresses.IO_NET_URL, request.getUrl()) .add(KnownAddresses.IO_NET_REQUEST_METHOD, request.getMethod()) - .add(KnownAddresses.IO_NET_REQUEST_HEADERS, request.getHeaders()); + .add(KnownAddresses.IO_NET_REQUEST_HEADERS, toLowerCaseHeaders(request.getHeaders())); if (downstreamSampler().isSampled(ctx, request.getRequestId())) { final Object body = parseHttpClientBody(ctx, request); @@ -398,7 +399,7 @@ private Flow onHttpClientResponse(RequestContext ctx_, HttpClientResponse final MapDataBundle.Builder bundleBuilder = new MapDataBundle.Builder(CAPACITY_3_4) .add(KnownAddresses.IO_NET_RESPONSE_STATUS, Integer.toString(response.getStatus())) - .add(KnownAddresses.IO_NET_RESPONSE_HEADERS, response.getHeaders()); + .add(KnownAddresses.IO_NET_RESPONSE_HEADERS, toLowerCaseHeaders(response.getHeaders())); // ignore the response if not sampled if (downstreamSampler().isSampled(ctx, response.getRequestId())) { final Object body = parseHttpClientBody(ctx, response); @@ -429,6 +430,19 @@ private Flow onHttpClientResponse(RequestContext ctx_, HttpClientResponse } } + private Map> toLowerCaseHeaders(final Map> headers) { + if (headers == null || headers.isEmpty()) { + return headers; + } + final Map> result = new HashMap<>(headers.size()); + for (final Map.Entry> entry : headers.entrySet()) { + final String key = entry.getKey(); + final List value = entry.getValue(); + result.put(key == null ? null : key.toLowerCase(Locale.ROOT), value); + } + return result; + } + private Object parseHttpClientBody( final AppSecRequestContext ctx, final HttpClientPayload payload) { if (payload.getContentType() == null || payload.getBody() == null) { diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy index 5c323ef6d1b..7213740364f 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/gateway/GatewayBridgeSpecification.groovy @@ -989,7 +989,7 @@ class GatewayBridgeSpecification extends DDSpecification { bundle.size() == (sampled ? 4 : 3) bundle.get(KnownAddresses.IO_NET_URL) == url bundle.get(KnownAddresses.IO_NET_REQUEST_METHOD) == method - bundle.get(KnownAddresses.IO_NET_REQUEST_HEADERS) == headers + bundle.get(KnownAddresses.IO_NET_REQUEST_HEADERS) == toLowerCaseHeaders(headers) if (sampled) { bundle.get(KnownAddresses.IO_NET_REQUEST_BODY) == ['Hello': 'World!'] } @@ -1029,7 +1029,7 @@ class GatewayBridgeSpecification extends DDSpecification { } bundle.size() == (sampled ? 3 : 2) bundle.get(KnownAddresses.IO_NET_RESPONSE_STATUS) == Integer.toString(status) - bundle.get(KnownAddresses.IO_NET_RESPONSE_HEADERS) == headers + bundle.get(KnownAddresses.IO_NET_RESPONSE_HEADERS) == toLowerCaseHeaders(headers) if (sampled) { bundle.get(KnownAddresses.IO_NET_RESPONSE_BODY) == ['Hello': 'World!'] } @@ -1615,4 +1615,10 @@ class GatewayBridgeSpecification extends DDSpecification { assert body['test'] == 'this is a test' } } + + static toLowerCaseHeaders(final Map> headers) { + return headers.collectEntries { + [(it.key.toLowerCase(Locale.ROOT)): it.value] + } + } }