Skip to content

Commit 1ddcaf3

Browse files
Merge branch 'master' into bdu/spotbugs-bump-need-jdk11-min
2 parents 99153b9 + 5db793a commit 1ddcaf3

File tree

8 files changed

+344
-61
lines changed

8 files changed

+344
-61
lines changed

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

Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.concurrent.atomic.AtomicBoolean;
3737
import java.util.concurrent.atomic.AtomicInteger;
3838
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
39+
import java.util.concurrent.atomic.AtomicReference;
3940
import org.slf4j.Logger;
4041
import org.slf4j.LoggerFactory;
4142

@@ -142,7 +143,7 @@ public class AppSecRequestContext implements DataBundle, Closeable {
142143
private boolean responseBodyPublished;
143144
private boolean respDataPublished;
144145
private boolean pathParamsPublished;
145-
private volatile Map<String, Object> derivatives;
146+
private final AtomicReference<Map<String, Object>> derivatives = new AtomicReference<>();
146147

147148
private final AtomicBoolean rateLimited = new AtomicBoolean(false);
148149
private volatile boolean throttled;
@@ -651,9 +652,9 @@ public void close() {
651652
requestHeaders.clear();
652653
responseHeaders.clear();
653654
persistentData.clear();
655+
final Map<String, Object> derivatives = this.derivatives.getAndSet(null);
654656
if (derivatives != null) {
655657
derivatives.clear();
656-
derivatives = null;
657658
}
658659
}
659660
}
@@ -745,54 +746,57 @@ public void reportDerivatives(Map<String, Object> data) {
745746
log.debug("Reporting derivatives: {}", data);
746747
if (data == null || data.isEmpty()) return;
747748

748-
// Store raw derivatives
749-
if (derivatives == null) {
750-
derivatives = new HashMap<>();
751-
}
752-
753-
// Process each attribute according to the specification
754-
for (Map.Entry<String, Object> entry : data.entrySet()) {
755-
String attributeKey = entry.getKey();
756-
Object attributeConfig = entry.getValue();
757-
758-
if (attributeConfig instanceof Map) {
759-
@SuppressWarnings("unchecked")
760-
Map<String, Object> config = (Map<String, Object>) attributeConfig;
761-
762-
// Check if it's a literal value schema
763-
if (config.containsKey("value")) {
764-
Object literalValue = config.get("value");
765-
if (literalValue != null) {
766-
// Preserve the original type - don't convert to string
767-
derivatives.put(attributeKey, literalValue);
768-
log.debug(
769-
"Added literal attribute: {} = {} (type: {})",
770-
attributeKey,
771-
literalValue,
772-
literalValue.getClass().getSimpleName());
749+
// Initialize or update derivatives atomically
750+
derivatives.updateAndGet(
751+
current -> {
752+
Map<String, Object> updated = current != null ? new HashMap<>(current) : new HashMap<>();
753+
754+
// Process each attribute according to the specification
755+
for (Map.Entry<String, Object> entry : data.entrySet()) {
756+
String attributeKey = entry.getKey();
757+
Object attributeConfig = entry.getValue();
758+
759+
if (attributeConfig instanceof Map) {
760+
@SuppressWarnings("unchecked")
761+
Map<String, Object> config = (Map<String, Object>) attributeConfig;
762+
763+
// Check if it's a literal value schema
764+
if (config.containsKey("value")) {
765+
Object literalValue = config.get("value");
766+
if (literalValue != null) {
767+
// Preserve the original type - don't convert to string
768+
updated.put(attributeKey, literalValue);
769+
log.debug(
770+
"Added literal attribute: {} = {} (type: {})",
771+
attributeKey,
772+
literalValue,
773+
literalValue.getClass().getSimpleName());
774+
}
775+
}
776+
// Check if it's a request data schema
777+
else if (config.containsKey("address")) {
778+
String address = (String) config.get("address");
779+
@SuppressWarnings("unchecked")
780+
List<String> keyPath = (List<String>) config.get("key_path");
781+
@SuppressWarnings("unchecked")
782+
List<String> transformers = (List<String>) config.get("transformers");
783+
784+
Object extractedValue = extractValueFromRequestData(address, keyPath, transformers);
785+
if (extractedValue != null) {
786+
// For extracted values, convert to string as they come from request data
787+
updated.put(attributeKey, extractedValue.toString());
788+
log.debug("Added extracted attribute: {} = {}", attributeKey, extractedValue);
789+
}
790+
}
791+
} else {
792+
// Handle plain string/numeric values
793+
updated.put(attributeKey, attributeConfig);
794+
log.debug("Added direct attribute: {} = {}", attributeKey, attributeConfig);
795+
}
773796
}
774-
}
775-
// Check if it's a request data schema
776-
else if (config.containsKey("address")) {
777-
String address = (String) config.get("address");
778-
@SuppressWarnings("unchecked")
779-
List<String> keyPath = (List<String>) config.get("key_path");
780-
@SuppressWarnings("unchecked")
781-
List<String> transformers = (List<String>) config.get("transformers");
782797

783-
Object extractedValue = extractValueFromRequestData(address, keyPath, transformers);
784-
if (extractedValue != null) {
785-
// For extracted values, convert to string as they come from request data
786-
derivatives.put(attributeKey, extractedValue.toString());
787-
log.debug("Added extracted attribute: {} = {}", attributeKey, extractedValue);
788-
}
789-
}
790-
} else {
791-
// Handle plain string/numeric values
792-
derivatives.put(attributeKey, attributeConfig);
793-
log.debug("Added direct attribute: {} = {}", attributeKey, attributeConfig);
794-
}
795-
}
798+
return updated;
799+
});
796800
}
797801

798802
/**
@@ -940,14 +944,17 @@ private Object applyTransformers(Object value, List<String> transformers) {
940944
}
941945

942946
public boolean commitDerivatives(TraceSegment traceSegment) {
943-
log.debug("Committing derivatives: {} for {}", derivatives, traceSegment);
944947
if (traceSegment == null) {
945948
return false;
946949
}
947950

951+
// Get and clear derivatives atomically
952+
Map<String, Object> derivativesToCommit = derivatives.getAndSet(null);
953+
log.debug("Committing derivatives: {} for {}", derivativesToCommit, traceSegment);
954+
948955
// Process and commit derivatives directly
949-
if (derivatives != null && !derivatives.isEmpty()) {
950-
for (Map.Entry<String, Object> entry : derivatives.entrySet()) {
956+
if (derivativesToCommit != null && !derivativesToCommit.isEmpty()) {
957+
for (Map.Entry<String, Object> entry : derivativesToCommit.entrySet()) {
951958
String key = entry.getKey();
952959
Object value = entry.getValue();
953960

@@ -971,14 +978,13 @@ public boolean commitDerivatives(TraceSegment traceSegment) {
971978
}
972979
}
973980

974-
// Clear all attribute maps
975-
derivatives = null;
976981
return true;
977982
}
978983

979984
// Mainly used for testing and logging
980985
Set<String> getDerivativeKeys() {
981-
return derivatives == null ? emptySet() : new HashSet<>(derivatives.keySet());
986+
Map<String, Object> current = derivatives.get();
987+
return current == null ? emptySet() : new HashSet<>(current.keySet());
982988
}
983989

984990
public boolean isThrottled(RateLimiter rateLimiter) {

0 commit comments

Comments
 (0)