public virtual async Task <RateLimitCounter> ProcessRequestAsync(ClientRequestIdentity requestIdentity, RateLimitRule rule) { var counter = new RateLimitCounter { Timestamp = DateTime.UtcNow, Count = 1 }; var counterId = BuildCounterKey(requestIdentity, rule); // serial reads and writes on same key using (await AsyncLock.WriterLockAsync(counterId).ConfigureAwait(false)) { var entry = await _counterStore.GetAsync(counterId); if (entry.IsNotNull()) { // entry has not expired if (entry.Timestamp + rule.PeriodTimespan.Value >= DateTime.UtcNow) { // increment request count var totalCount = entry.Count + _config.RateIncrementer?.Invoke() ?? 1; // deep copy counter = new RateLimitCounter { Timestamp = entry.Timestamp, Count = totalCount }; } } // stores: id (string) - timestamp (datetime) - total_requests (long) await _counterStore.SetAsync(counterId, counter, rule.PeriodTimespan.Value); } return(counter); }
public virtual RateLimitHeaders GetRateLimitHeaders(RateLimitCounter counter, RateLimitRule rule) { var headers = new RateLimitHeaders(); double remaining; DateTime reset; if (counter.IsNotNull()) { reset = counter.Timestamp + (rule.PeriodTimespan ?? rule.Period.ToTimeSpan()); remaining = rule.Limit - counter.Count; } else { reset = DateTime.UtcNow + (rule.PeriodTimespan ?? rule.Period.ToTimeSpan()); remaining = rule.Limit; } headers.Reset = reset.ToUniversalTime().ToString("o", DateTimeFormatInfo.InvariantInfo); headers.Limit = rule.Period; headers.Remaining = remaining.ToString(); return(headers); }
protected override void LogBlockedRequest(HttpContext httpContext, ClientRequestIdentity identity, RateLimitCounter counter, RateLimitRule rule) { _logger.LogInformation($"Request {identity.HttpVerb}:{identity.Path} from IP {identity.ClientIp} has been blocked, quota {rule.Limit}/{rule.Period} exceeded by {counter.Count}. Blocked by rule {rule.Endpoint}, TraceIdentifier {httpContext.TraceIdentifier}."); }
protected abstract void LogBlockedRequest(HttpContext httpContext, ClientRequestIdentity identity, RateLimitCounter counter, RateLimitRule rule);