11package com .datadog .appsec .api .security ;
22
33import com .datadog .appsec .gateway .AppSecRequestContext ;
4+ import datadog .trace .api .time .SystemTimeSource ;
5+ import datadog .trace .api .time .TimeSource ;
46import datadog .trace .util .NonBlockingSemaphore ;
57
68import javax .annotation .Nonnull ;
@@ -23,18 +25,20 @@ public class ApiSecurityRequestSampler {
2325 private final Deque <Long > apiAccessQueue ; // hashes ordered by access time
2426 private final long expirationTimeInMs ;
2527 private final int capacity ;
28+ private final TimeSource timeSource ;
2629
2730 final NonBlockingSemaphore counter = NonBlockingSemaphore .withPermitCount (MAX_POST_PROCESSING_TASKS );
2831
2932 public ApiSecurityRequestSampler () {
30- this (MAX_SIZE , INTERVAL_SECONDS * 1000 );
33+ this (MAX_SIZE , INTERVAL_SECONDS * 1000 , SystemTimeSource . INSTANCE );
3134 }
3235
33- public ApiSecurityRequestSampler (int capacity , long expirationTimeInMs ) {
36+ public ApiSecurityRequestSampler (int capacity , long expirationTimeInMs , @ Nonnull TimeSource timeSource ) {
3437 this .capacity = capacity ;
3538 this .expirationTimeInMs = expirationTimeInMs ;
3639 this .apiAccessMap = new ConcurrentHashMap <>(MAX_SIZE );
3740 this .apiAccessQueue = new ConcurrentLinkedDeque <>();
41+ this .timeSource = timeSource ;
3842 }
3943
4044 public void preSampleRequest (final @ Nonnull AppSecRequestContext ctx ) {
@@ -79,12 +83,12 @@ public boolean sampleRequest(AppSecRequestContext ctx) {
7983 * synchronization for updating data structures is not required.
8084 */
8185 public boolean updateApiAccessIfExpired (final long hash ) {
82- final long currentTime = System . currentTimeMillis ();
86+ final long currentTime = timeSource . getCurrentTimeMillis ();
8387
8488 // New or updated record
8589 boolean isNewOrUpdated = false ;
8690 if (!apiAccessMap .containsKey (hash )
87- || currentTime - apiAccessMap .get (hash ) > expirationTimeInMs ) {
91+ || currentTime - apiAccessMap .get (hash ) >= expirationTimeInMs ) {
8892
8993 cleanupExpiredEntries (currentTime );
9094
@@ -107,9 +111,9 @@ public boolean updateApiAccessIfExpired(final long hash) {
107111 }
108112
109113 public boolean isApiAccessExpired (final long hash ) {
110- long currentTime = System . currentTimeMillis ();
114+ long currentTime = timeSource . getCurrentTimeMillis ();
111115 return !apiAccessMap .containsKey (hash )
112- || currentTime - apiAccessMap .get (hash ) > expirationTimeInMs ;
116+ || currentTime - apiAccessMap .get (hash ) >= expirationTimeInMs ;
113117 }
114118
115119 private void cleanupExpiredEntries (final long currentTime ) {
@@ -118,7 +122,7 @@ private void cleanupExpiredEntries(final long currentTime) {
118122 if (oldestHash == null ) break ;
119123
120124 Long lastAccessTime = apiAccessMap .get (oldestHash );
121- if (lastAccessTime == null || currentTime - lastAccessTime > expirationTimeInMs ) {
125+ if (lastAccessTime == null || currentTime - lastAccessTime >= expirationTimeInMs ) {
122126 apiAccessQueue .pollFirst (); // remove from head
123127 apiAccessMap .remove (oldestHash );
124128 } else {
@@ -137,7 +141,7 @@ private long computeApiHash(final String route, final String method, final int s
137141
138142 public static final class NoOp extends ApiSecurityRequestSampler {
139143 public NoOp () {
140- super (0 , 0 );
144+ super (0 , 0 , SystemTimeSource . INSTANCE );
141145 }
142146
143147 @ Override
0 commit comments