示例#1
0
        public RateLimitHeaders GetRateLimitHeaders(ClientRequestIdentity requestIdentity, RateLimitRule rule)
        {
            var headers   = new RateLimitHeaders();
            var counterId = ComputeCounterKey(requestIdentity, rule);
            var entry     = _counterStore.Get(counterId);

            if (entry.HasValue)
            {
                headers.Reset = (entry.Value.Timestamp + ConvertToTimeSpan(rule.Period)).ToUniversalTime()
                                .ToString("o", DateTimeFormatInfo.InvariantInfo);
                headers.Limit     = rule.Period;
                headers.Remaining = (rule.Limit - entry.Value.TotalRequests).ToString();
            }
            else
            {
                headers.Reset = (DateTime.UtcNow + ConvertToTimeSpan(rule.Period)).ToUniversalTime()
                                .ToString("o", DateTimeFormatInfo.InvariantInfo);
                headers.Limit     = rule.Period;
                headers.Remaining = rule.Limit.ToString();
            }

            return(headers);
        }
示例#2
0
        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 httpContext)
        {
            // check if rate limiting is enabled
            if (_options == null)
            {
                await _next.Invoke(httpContext);

                return;
            }

            // get request details
            var clientRequest = httpContext.GetClientRequest(_options.ClientIdHeader);

            // check white list
            if (_processor.IsWhitelisted(clientRequest))
            {
                await _next.Invoke(httpContext);

                return;
            }

            var             rules  = _processor.GetMatchingRules(clientRequest);
            RateLimitResult result = null;

            foreach (var rule in rules)
            {
                // if limit is zero or less, block the request.
                if (rule.Limit <= 0)
                {
                    // log blocked request
                    LogBlockedRequest(httpContext, clientRequest, rule);

                    // return quote exceeded
                    await ReturnQuotaExceededResponse(httpContext, rule);

                    return;
                }

                // process request
                result = await _processor.ProcessRequestAsync(clientRequest, rule);

                // check if limit is exceeded
                if (!result.Success)
                {
                    //compute retry after value
                    var retryAfter = Convert.ToInt32((result.Expiry - DateTime.UtcNow).TotalSeconds).ToString(CultureInfo.InvariantCulture);

                    // log blocked request
                    LogBlockedRequest(httpContext, clientRequest, rule);

                    // return quote exceeded
                    await ReturnQuotaExceededResponse(httpContext, rule, retryAfter);

                    return;
                }
            }

            // set X-Rate-Limit headers
            if (result != null && !_options.DisableRateLimitHeaders)
            {
                var rule    = rules.Last();
                var headers = new RateLimitHeaders
                {
                    Reset     = result.Expiry.ToString("o", DateTimeFormatInfo.InvariantInfo),
                    Limit     = rule.Period,
                    Remaining = result.Remaining.ToString()
                };

                httpContext.Response.OnStarting(state => {
                    try
                    {
                        var context = (HttpContext)state;
                        context.Response.Headers["X-Rate-Limit-Limit"]     = headers.Limit;
                        context.Response.Headers["X-Rate-Limit-Remaining"] = headers.Remaining;
                        context.Response.Headers["X-Rate-Limit-Reset"]     = headers.Reset;
                    }
                    catch
                    {
                        // ignore exception adding headers
                    }
                    return(Task.FromResult(0));
                }, httpContext);
            }

            await _next.Invoke(httpContext);
        }