Skip to content

Commit 1e6e9dd

Browse files
Fixes communicating retry-after in RateLimitingPlugin (#497)
1 parent abdfffd commit 1e6e9dd

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

dev-proxy-plugins/Behavior/RateLimitingPlugin.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using Microsoft.Extensions.Configuration;
55
using Microsoft.DevProxy.Abstractions;
6-
using Microsoft.DevProxy.Plugins.MockResponses;
76
using System.Net;
87
using System.Text.Json;
98
using System.Text.RegularExpressions;
@@ -35,7 +34,6 @@ public class RateLimitConfiguration
3534
public int ResetTimeWindowSeconds { get; set; } = 60;
3635
public int WarningThresholdPercent { get; set; } = 80;
3736
public int RateLimit { get; set; } = 120;
38-
public int RetryAfterSeconds { get; set; } = 5;
3937
public RateLimitResponseWhenLimitExceeded WhenLimitExceeded { get; set; } = RateLimitResponseWhenLimitExceeded.Throttle;
4038
public string CustomResponseFile { get; set; } = "rate-limit-response.json";
4139
public MockResponseResponse? CustomResponse { get; set; }
@@ -54,7 +52,7 @@ public class RateLimitingPlugin : BaseProxyPlugin
5452
private ThrottlingInfo ShouldThrottle(Request request, string throttlingKey)
5553
{
5654
var throttleKeyForRequest = BuildThrottleKey(request);
57-
return new ThrottlingInfo(throttleKeyForRequest == throttlingKey ? _configuration.RetryAfterSeconds : 0, _configuration.HeaderRetryAfter);
55+
return new ThrottlingInfo(throttleKeyForRequest == throttlingKey ? (int)(_resetTime - DateTime.Now).TotalSeconds : 0, _configuration.HeaderRetryAfter);
5856
}
5957

6058
private void ThrottleResponse(ProxyRequestArgs e) => UpdateProxyResponse(e, HttpStatusCode.TooManyRequests);
@@ -89,7 +87,7 @@ private void UpdateProxyResponse(ProxyHttpEventArgsBase e, HttpStatusCode errorS
8987
);
9088
}
9189

92-
headers.Add(new(_configuration.HeaderRetryAfter, _configuration.RetryAfterSeconds.ToString()));
90+
headers.Add(new(_configuration.HeaderRetryAfter, ((int)(_resetTime - DateTime.Now).TotalSeconds).ToString()));
9391

9492
e.Session.GenericResponse(body ?? string.Empty, errorStatus, headers.Select(h => new HttpHeader(h.Name, h.Value)).ToArray());
9593
return;
@@ -193,7 +191,7 @@ _urlsToWatch is null ||
193191
e.ThrottledRequests.Add(new ThrottlerInfo(
194192
BuildThrottleKey(request),
195193
ShouldThrottle,
196-
DateTime.Now.AddSeconds(_configuration.RetryAfterSeconds)
194+
_resetTime
197195
));
198196
ThrottleResponse(e);
199197
state.HasBeenSet = true;
@@ -202,9 +200,18 @@ _urlsToWatch is null ||
202200
{
203201
if (_configuration.CustomResponse is not null)
204202
{
205-
var headers = _configuration.CustomResponse.Headers is not null ?
206-
_configuration.CustomResponse.Headers.Select(h => new HttpHeader(h.Name, h.Value)).ToArray() :
207-
Array.Empty<HttpHeader>();
203+
var headersList = _configuration.CustomResponse.Headers is not null ?
204+
_configuration.CustomResponse.Headers.Select(h => new HttpHeader(h.Name, h.Value)).ToList() :
205+
new List<HttpHeader>();
206+
207+
var retryAfterHeader = headersList.FirstOrDefault(h => h.Name.Equals(_configuration.HeaderRetryAfter, StringComparison.OrdinalIgnoreCase));
208+
if (retryAfterHeader is not null && retryAfterHeader.Value == "@dynamic")
209+
{
210+
headersList.Add(new HttpHeader(_configuration.HeaderRetryAfter, ((int)(_resetTime - DateTime.Now).TotalSeconds).ToString()));
211+
headersList.Remove(retryAfterHeader);
212+
}
213+
214+
var headers = headersList.ToArray();
208215

209216
// allow custom throttling response
210217
var responseCode = (HttpStatusCode)(_configuration.CustomResponse.StatusCode ?? 200);
@@ -213,7 +220,7 @@ _urlsToWatch is null ||
213220
e.ThrottledRequests.Add(new ThrottlerInfo(
214221
BuildThrottleKey(request),
215222
ShouldThrottle,
216-
DateTime.Now.AddSeconds(_configuration.RetryAfterSeconds)
223+
_resetTime
217224
));
218225
}
219226

0 commit comments

Comments
 (0)