public virtual RateLimitHeaders GetRateLimitHeaders(RateLimitCounter?counter, RateLimitRule rule, CancellationToken cancellationToken = default) { var headers = new RateLimitHeaders(); double remaining; DateTime reset; if (counter.HasValue) { reset = counter.Value.Timestamp + (rule.PeriodTimespan ?? rule.Period.ToTimeSpan()); remaining = rule.Limit - counter.Value.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); }
public async Task Invoke(HttpContext context) { if (_options == null) { await _next(context); return; } ClientRequestIdentity identity = await ResolveIdentityAsync(context); TProcessor processor = _processor; if (processor.IsWhitelisted(identity)) { await _next(context); return; } processor = _processor; IEnumerable <RateLimitRule> rules = await processor.GetMatchingRulesAsync(identity, context.RequestAborted); Dictionary <RateLimitRule, RateLimitCounter> rulesDict = new Dictionary <RateLimitRule, RateLimitCounter>(); foreach (RateLimitRule rule2 in rules) { processor = _processor; RateLimitCounter rateLimitCounter = await processor.ProcessRequestAsync(identity, rule2, context.RequestAborted); if (rule2.Limit > 0.0) { if (rateLimitCounter.Timestamp + rule2.PeriodTimespan.Value < DateTime.UtcNow) { continue; } if (rateLimitCounter.Count > rule2.Limit) { string retryAfter = rateLimitCounter.Timestamp.RetryAfterFrom(rule2); LogBlockedRequest(context, identity, rateLimitCounter, rule2); if (_options.RequestBlockedBehaviorAsync != null) { await _options.RequestBlockedBehaviorAsync(context, identity, rateLimitCounter, rule2); } if (!rule2.MonitorMode) { await ReturnQuotaExceededResponse(context, rule2, retryAfter); return; } } } else { LogBlockedRequest(context, identity, rateLimitCounter, rule2); if (_options.RequestBlockedBehaviorAsync != null) { await _options.RequestBlockedBehaviorAsync(context, identity, rateLimitCounter, rule2); } if (!rule2.MonitorMode) { await ReturnQuotaExceededResponse(context, rule2, int.MaxValue.ToString(CultureInfo.InvariantCulture)); return; } } rulesDict.Add(rule2, rateLimitCounter); } if (rulesDict.Any() && !_options.DisableRateLimitHeaders) { KeyValuePair <RateLimitRule, RateLimitCounter> rule = rulesDict.OrderByDescending((KeyValuePair <RateLimitRule, RateLimitCounter> x) => x.Key.PeriodTimespan).FirstOrDefault(); processor = _processor; RateLimitHeaders headers = processor.GetRateLimitHeaders(rule.Value, rule.Key, context.RequestAborted); headers.Context = context; context.Response.OnStarting(new Func <object, Task>(SetRateLimitHeaders), headers); } await _next(context); }