Skip to content

Commit 86d3d3d

Browse files
committed
V2
1 parent 8db72c0 commit 86d3d3d

File tree

1 file changed

+49
-36
lines changed

1 file changed

+49
-36
lines changed

dd-java-agent/appsec/src/main/java/com/datadog/appsec/gateway/AppSecRequestContext.java

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.util.Arrays;
2020
import java.util.Collection;
2121
import java.util.Collections;
22-
import java.util.HashMap;
2322
import java.util.HashSet;
2423
import java.util.Iterator;
2524
import java.util.LinkedHashMap;
@@ -140,7 +139,8 @@ public class AppSecRequestContext implements DataBundle, Closeable {
140139
private boolean responseBodyPublished;
141140
private boolean respDataPublished;
142141
private boolean pathParamsPublished;
143-
private volatile Map<String, Object> derivatives;
142+
private volatile ConcurrentHashMap<String, Object> derivatives;
143+
private final Object derivativesSwapLock = new Object();
144144

145145
private final AtomicBoolean rateLimited = new AtomicBoolean(false);
146146
private volatile boolean throttled;
@@ -649,10 +649,7 @@ public void close() {
649649
requestHeaders.clear();
650650
responseHeaders.clear();
651651
persistentData.clear();
652-
if (derivatives != null) {
653-
derivatives.clear();
654-
derivatives = null;
655-
}
652+
derivatives = null;
656653
}
657654
}
658655

@@ -743,9 +740,16 @@ public void reportDerivatives(Map<String, Object> data) {
743740
log.debug("Reporting derivatives: {}", data);
744741
if (data == null || data.isEmpty()) return;
745742

746-
// Store raw derivatives
747-
if (derivatives == null) {
748-
derivatives = new HashMap<>();
743+
// Ensure derivatives map exists with lock only for initialization check
744+
ConcurrentHashMap<String, Object> map = derivatives;
745+
if (map == null) {
746+
synchronized (derivativesSwapLock) {
747+
map = derivatives;
748+
if (map == null) {
749+
map = new ConcurrentHashMap<>();
750+
derivatives = map;
751+
}
752+
}
749753
}
750754

751755
// Process each attribute according to the specification
@@ -762,7 +766,7 @@ public void reportDerivatives(Map<String, Object> data) {
762766
Object literalValue = config.get("value");
763767
if (literalValue != null) {
764768
// Preserve the original type - don't convert to string
765-
derivatives.put(attributeKey, literalValue);
769+
map.put(attributeKey, literalValue);
766770
log.debug(
767771
"Added literal attribute: {} = {} (type: {})",
768772
attributeKey,
@@ -781,13 +785,13 @@ else if (config.containsKey("address")) {
781785
Object extractedValue = extractValueFromRequestData(address, keyPath, transformers);
782786
if (extractedValue != null) {
783787
// For extracted values, convert to string as they come from request data
784-
derivatives.put(attributeKey, extractedValue.toString());
788+
map.put(attributeKey, extractedValue.toString());
785789
log.debug("Added extracted attribute: {} = {}", attributeKey, extractedValue);
786790
}
787791
}
788792
} else {
789793
// Handle plain string/numeric values
790-
derivatives.put(attributeKey, attributeConfig);
794+
map.put(attributeKey, attributeConfig);
791795
log.debug("Added direct attribute: {} = {}", attributeKey, attributeConfig);
792796
}
793797
}
@@ -938,45 +942,54 @@ private Object applyTransformers(Object value, List<String> transformers) {
938942
}
939943

940944
public boolean commitDerivatives(TraceSegment traceSegment) {
941-
log.debug("Committing derivatives: {} for {}", derivatives, traceSegment);
942945
if (traceSegment == null) {
943946
return false;
944947
}
945948

949+
// Atomically swap out the map to iterate safely
950+
ConcurrentHashMap<String, Object> snapshot;
951+
synchronized (derivativesSwapLock) {
952+
snapshot = derivatives;
953+
derivatives = null;
954+
}
955+
956+
if (snapshot == null || snapshot.isEmpty()) {
957+
return true;
958+
}
959+
960+
log.debug("Committing derivatives: {} for {}", snapshot, traceSegment);
961+
946962
// Process and commit derivatives directly
947-
if (derivatives != null && !derivatives.isEmpty()) {
948-
for (Map.Entry<String, Object> entry : derivatives.entrySet()) {
949-
String key = entry.getKey();
950-
Object value = entry.getValue();
951-
952-
// Handle different value types
953-
if (value instanceof Number) {
954-
traceSegment.setTagTop(key, (Number) value);
955-
} else if (value instanceof String) {
956-
// Try to parse as numeric, otherwise use as string
957-
Number parsedNumber = convertToNumericAttribute((String) value);
958-
if (parsedNumber != null) {
959-
traceSegment.setTagTop(key, parsedNumber);
960-
} else {
961-
traceSegment.setTagTop(key, value);
962-
}
963-
} else if (value instanceof Boolean) {
964-
traceSegment.setTagTop(key, value);
963+
for (Map.Entry<String, Object> entry : snapshot.entrySet()) {
964+
String key = entry.getKey();
965+
Object value = entry.getValue();
966+
967+
// Handle different value types
968+
if (value instanceof Number) {
969+
traceSegment.setTagTop(key, (Number) value);
970+
} else if (value instanceof String) {
971+
// Try to parse as numeric, otherwise use as string
972+
Number parsedNumber = convertToNumericAttribute((String) value);
973+
if (parsedNumber != null) {
974+
traceSegment.setTagTop(key, parsedNumber);
965975
} else {
966-
// Convert other types to string
967-
traceSegment.setTagTop(key, value.toString());
976+
traceSegment.setTagTop(key, value);
968977
}
978+
} else if (value instanceof Boolean) {
979+
traceSegment.setTagTop(key, value);
980+
} else {
981+
// Convert other types to string
982+
traceSegment.setTagTop(key, value.toString());
969983
}
970984
}
971985

972-
// Clear all attribute maps
973-
derivatives = null;
974986
return true;
975987
}
976988

977989
// Mainly used for testing and logging
978990
Set<String> getDerivativeKeys() {
979-
return derivatives == null ? emptySet() : new HashSet<>(derivatives.keySet());
991+
ConcurrentHashMap<String, Object> map = derivatives;
992+
return map == null ? emptySet() : new HashSet<>(map.keySet());
980993
}
981994

982995
public boolean isThrottled(RateLimiter rateLimiter) {

0 commit comments

Comments
 (0)