1
1
package com .datadog .appsec .api .security ;
2
2
3
3
import com .datadog .appsec .gateway .AppSecRequestContext ;
4
+ import datadog .trace .api .time .SystemTimeSource ;
5
+ import datadog .trace .api .time .TimeSource ;
4
6
import datadog .trace .util .NonBlockingSemaphore ;
5
7
6
8
import javax .annotation .Nonnull ;
@@ -23,18 +25,20 @@ public class ApiSecurityRequestSampler {
23
25
private final Deque <Long > apiAccessQueue ; // hashes ordered by access time
24
26
private final long expirationTimeInMs ;
25
27
private final int capacity ;
28
+ private final TimeSource timeSource ;
26
29
27
30
final NonBlockingSemaphore counter = NonBlockingSemaphore .withPermitCount (MAX_POST_PROCESSING_TASKS );
28
31
29
32
public ApiSecurityRequestSampler () {
30
- this (MAX_SIZE , INTERVAL_SECONDS * 1000 );
33
+ this (MAX_SIZE , INTERVAL_SECONDS * 1000 , SystemTimeSource . INSTANCE );
31
34
}
32
35
33
- public ApiSecurityRequestSampler (int capacity , long expirationTimeInMs ) {
36
+ public ApiSecurityRequestSampler (int capacity , long expirationTimeInMs , @ Nonnull TimeSource timeSource ) {
34
37
this .capacity = capacity ;
35
38
this .expirationTimeInMs = expirationTimeInMs ;
36
39
this .apiAccessMap = new ConcurrentHashMap <>(MAX_SIZE );
37
40
this .apiAccessQueue = new ConcurrentLinkedDeque <>();
41
+ this .timeSource = timeSource ;
38
42
}
39
43
40
44
public void preSampleRequest (final @ Nonnull AppSecRequestContext ctx ) {
@@ -79,12 +83,12 @@ public boolean sampleRequest(AppSecRequestContext ctx) {
79
83
* synchronization for updating data structures is not required.
80
84
*/
81
85
public boolean updateApiAccessIfExpired (final long hash ) {
82
- final long currentTime = System . currentTimeMillis ();
86
+ final long currentTime = timeSource . getCurrentTimeMillis ();
83
87
84
88
// New or updated record
85
89
boolean isNewOrUpdated = false ;
86
90
if (!apiAccessMap .containsKey (hash )
87
- || currentTime - apiAccessMap .get (hash ) > expirationTimeInMs ) {
91
+ || currentTime - apiAccessMap .get (hash ) >= expirationTimeInMs ) {
88
92
89
93
cleanupExpiredEntries (currentTime );
90
94
@@ -107,9 +111,9 @@ public boolean updateApiAccessIfExpired(final long hash) {
107
111
}
108
112
109
113
public boolean isApiAccessExpired (final long hash ) {
110
- long currentTime = System . currentTimeMillis ();
114
+ long currentTime = timeSource . getCurrentTimeMillis ();
111
115
return !apiAccessMap .containsKey (hash )
112
- || currentTime - apiAccessMap .get (hash ) > expirationTimeInMs ;
116
+ || currentTime - apiAccessMap .get (hash ) >= expirationTimeInMs ;
113
117
}
114
118
115
119
private void cleanupExpiredEntries (final long currentTime ) {
@@ -118,7 +122,7 @@ private void cleanupExpiredEntries(final long currentTime) {
118
122
if (oldestHash == null ) break ;
119
123
120
124
Long lastAccessTime = apiAccessMap .get (oldestHash );
121
- if (lastAccessTime == null || currentTime - lastAccessTime > expirationTimeInMs ) {
125
+ if (lastAccessTime == null || currentTime - lastAccessTime >= expirationTimeInMs ) {
122
126
apiAccessQueue .pollFirst (); // remove from head
123
127
apiAccessMap .remove (oldestHash );
124
128
} else {
@@ -137,7 +141,7 @@ private long computeApiHash(final String route, final String method, final int s
137
141
138
142
public static final class NoOp extends ApiSecurityRequestSampler {
139
143
public NoOp () {
140
- super (0 , 0 );
144
+ super (0 , 0 , SystemTimeSource . INSTANCE );
141
145
}
142
146
143
147
@ Override
0 commit comments