ProcessRequest() 개인적인 메소드

private ProcessRequest ( RequestIdentity requestIdentity, System.TimeSpan timeSpan, RateLimitPeriod period, string &id ) : WebApiThrottle.ThrottleCounter
requestIdentity RequestIdentity
timeSpan System.TimeSpan
period RateLimitPeriod
id string
리턴 WebApiThrottle.ThrottleCounter
예제 #1
0
        public override async Task Invoke(IOwinContext context)
        {
            var response = context.Response;
            var request  = context.Request;

            // get policy from repo
            if (policyRepository != null)
            {
                policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());
            }

            if (policy == null || (!policy.IpThrottling && !policy.ClientThrottling && !policy.EndpointThrottling))
            {
                await Next.Invoke(context);

                return;
            }

            core.Repository = Repository;
            core.Policy     = policy;

            var identity = SetIdentity(request);

            if (core.IsWhitelisted(identity))
            {
                await Next.Invoke(context);

                return;
            }

            TimeSpan timeSpan = TimeSpan.FromSeconds(1);

            // get default rates
            var defRates = core.RatesWithDefaults(Policy.Rates.ToList());

            if (Policy.StackBlockedRequests)
            {
                // all requests including the rejected ones will stack in this order: week, day, hour, min, sec
                // if a client hits the hour limit then the minutes and seconds counters will expire and will eventually get erased from cache
                defRates.Reverse();
            }

            // apply policy
            foreach (var rate in defRates)
            {
                var rateLimitPeriod = rate.Key;
                var rateLimit       = rate.Value;

                timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod);

                // apply global rules
                core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit);

                if (rateLimit > 0)
                {
                    // increment counter
                    string requestId;
                    var    throttleCounter = core.ProcessRequest(identity, timeSpan, rateLimitPeriod, out requestId);

                    // check if key expired
                    if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                    {
                        continue;
                    }

                    // check if limit is reached
                    if (throttleCounter.TotalRequests > rateLimit)
                    {
                        // log blocked request
                        if (Logger != null)
                        {
                            Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, null));
                        }

                        var message = !string.IsNullOrEmpty(this.QuotaExceededMessage)
                            ? this.QuotaExceededMessage
                            : "API calls quota exceeded! maximum admitted {0} per {1}.";

                        // break execution
                        response.OnSendingHeaders(state =>
                        {
                            var resp = (OwinResponse)state;
                            resp.Headers.Add("Retry-After", new string[] { core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod) });
                            resp.StatusCode   = (int)QuotaExceededResponseCode;
                            resp.ReasonPhrase = string.Format(message, rateLimit, rateLimitPeriod);
                        }, response);

                        return;
                    }
                }
            }

            // no throttling required
            await Next.Invoke(context);
        }
예제 #2
0
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var applyThrottling = ApplyThrottling(actionContext, out EnableThrottlingAttribute attrPolicy);

            // get policy from repo
            if (PolicyRepository != null)
            {
                Policy = PolicyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());
            }

            if (Policy != null && applyThrottling)
            {
                core.Repository = Repository;
                core.Policy     = Policy;

                var identity = SetIdentity(actionContext.Request);

                if (!core.IsWhitelisted(identity))
                {
                    TimeSpan timeSpan    = TimeSpan.FromSeconds(1);
                    TimeSpan suspendSpan = TimeSpan.FromSeconds(0);

                    // get default rates
                    var defRates = core.RatesWithDefaults(Policy.Rates.ToList());
                    if (Policy.StackBlockedRequests)
                    {
                        // all requests including the rejected ones will stack in this order: week, day, hour, min, sec
                        // if a client hits the hour limit then the minutes and seconds counters will expire and will eventually get erased from cache
                        defRates.Reverse();
                    }

                    // apply policy
                    var suspendTime = Policy.SuspendTime;

                    foreach (var rate in defRates)
                    {
                        var rateLimitPeriod = rate.Key;
                        var rateLimit       = rate.Value;

                        timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod);

                        // apply EnableThrottlingAttribute policy
                        var attrLimit = attrPolicy.GetLimit(rateLimitPeriod);
                        if (attrLimit > 0)
                        {
                            rateLimit = attrLimit;
                        }

                        if (attrPolicy.SuspendTime > 0)
                        {
                            suspendTime = attrPolicy.SuspendTime;
                        }

                        // apply global rules
                        core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit, ref suspendTime);

                        if (rateLimit > 0)
                        {
                            // increment counter
                            var requestId       = ComputeThrottleKey(identity, rateLimitPeriod);
                            var throttleCounter = core.ProcessRequest(timeSpan, rateLimitPeriod, rateLimit, suspendTime, requestId);

                            if (throttleCounter.TotalRequests >= rateLimit && suspendTime > 0)
                            {
                                timeSpan = core.GetSuspendSpanFromPeriod(rateLimitPeriod, timeSpan, suspendTime);
                            }

                            // check if key expired
                            if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                            {
                                continue;
                            }

                            // check if limit is reached
                            if (throttleCounter.TotalRequests > rateLimit)
                            {
                                // log blocked request
                                Logger?.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, actionContext.Request));

                                var message = !string.IsNullOrEmpty(this.QuotaExceededMessage)
                                    ? this.QuotaExceededMessage
                                    : "API calls quota exceeded! maximum admitted {0} per {1}.";

                                var content = this.QuotaExceededContent != null
                                    ? this.QuotaExceededContent(rateLimit, rateLimitPeriod)
                                    : string.Format(message, rateLimit, rateLimitPeriod);

                                // add status code and retry after x seconds to response
                                actionContext.Response = QuotaExceededResponse(
                                    actionContext.Request,
                                    content,
                                    QuotaExceededResponseCode,
                                    core.RetryAfterFrom(throttleCounter.Timestamp, suspendTime, rateLimitPeriod));
                            }
                        }
                    }
                }
            }

            base.OnActionExecuting(actionContext);
        }
        public void OnEvent(HttpContextBase context)
        {
            HttpRequestBase  request  = context.Request;
            HttpResponseBase response = context.Response;

            // get policy from repo
            if (policyRepository != null)
            {
                policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());
            }

            if (policy == null || (!policy.IpThrottling && !policy.ClientThrottling && !policy.EndpointThrottling))
            {
                response.StatusCode = (int)HttpStatusCode.OK;
                return;
            }

            core.Repository = Repository;
            core.Policy     = policy;

            var identity = SetIdentity(request);

            if (core.IsWhitelisted(identity))
            {
                response.StatusCode = (int)HttpStatusCode.OK;
                return;
            }

            if (policy.Endpoints != null && policy.Endpoints.Count > 0)
            {
                if (!core.IsEndpointMonitored(identity))
                {
                    response.StatusCode = (int)HttpStatusCode.OK;
                    return;
                }
            }

            TimeSpan timeSpan = TimeSpan.FromSeconds(1);

            // get default rates
            var defRates = core.RatesWithDefaults(Policy.Rates.ToList());

            if (Policy.StackBlockedRequests)
            {
                // all requests including the rejected ones will stack in this order: week, day, hour, min, sec
                // if a client hits the hour limit then the minutes and seconds counters will expire and will eventually get erased from cache
                defRates.Reverse();
            }

            // apply policy
            foreach (var rate in defRates)
            {
                var rateLimitPeriod = rate.Key;
                var rateLimit       = rate.Value;

                timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod);

                // apply global rules
                core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit);

                if (rateLimit > 0)
                {
                    // increment counter
                    var requestId       = ComputeThrottleKey(identity, rateLimitPeriod);
                    var throttleCounter = core.ProcessRequest(timeSpan, requestId);

                    // check if key expired
                    if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                    {
                        continue;
                    }

                    // check if limit is reached
                    if (throttleCounter.TotalRequests > rateLimit)
                    {
                        // log blocked request
                        if (Logger != null)
                        {
                            Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, request));
                        }

                        var message = !string.IsNullOrEmpty(this.QuotaExceededMessage)
                            ? this.QuotaExceededMessage
                            : "API calls quota exceeded! maximum admitted {0} per {1}.";

                        var content = this.QuotaExceededContent != null
                            ? this.QuotaExceededContent(rateLimit, rateLimitPeriod)
                            : string.Format(message, rateLimit, rateLimitPeriod);

                        // break execution
                        response.StatusCode = (int)QuotaExceededResponseCode;
                        response.AddHeader("Retry-After", core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod));
                        response.Write(content);
                        return;
                    }
                }
            }

            // no throttling required
            response.StatusCode = (int)HttpStatusCode.OK;
            return;
        }
예제 #4
0
        protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // get policy from repo
            if (policyRepository != null)
            {
                policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());
            }

            if (policy == null || (!policy.IpThrottling && !policy.ClientThrottling && !policy.EndpointThrottling))
            {
                return(base.SendAsync(request, cancellationToken));
            }

            core.Repository = Repository;
            core.Policy     = policy;

            var identity = SetIndentity(request);

            if (core.IsWhitelisted(identity))
            {
                return(base.SendAsync(request, cancellationToken));
            }

            TimeSpan timeSpan = TimeSpan.FromSeconds(1);

            // get default rates
            var defRates = core.RatesWithDefaults(Policy.Rates.ToList());

            if (Policy.StackBlockedRequests)
            {
                // all requests including the rejected ones will stack in this order: week, day, hour, min, sec
                // if a client hits the hour limit then the minutes and seconds counters will expire and will eventually get erased from cache
                defRates.Reverse();
            }

            // apply policy
            foreach (var rate in defRates)
            {
                var rateLimitPeriod = rate.Key;
                var rateLimit       = rate.Value;

                timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod);

                // apply global rules
                core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit);

                if (rateLimit > 0)
                {
                    // increment counter
                    string requestId;
                    var    throttleCounter = core.ProcessRequest(identity, timeSpan, rateLimitPeriod, out requestId);

                    // check if key expired
                    if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                    {
                        continue;
                    }

                    // check if limit is reached
                    if (throttleCounter.TotalRequests > rateLimit * policy.WarningLevel)
                    {
                        // log blocked request
                        if (Logger != null)
                        {
                            Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, policy.WarningLevel, request));
                        }

                        if (throttleCounter.TotalRequests > rateLimit)
                        {
                            var message = !string.IsNullOrEmpty(this.QuotaExceededMessage)
                                ? this.QuotaExceededMessage
                                : "API calls quota exceeded! maximum admitted {0} per {1}.";

                            var content = this.QuotaExceededContent != null
                                ? this.QuotaExceededContent(rateLimit, rateLimitPeriod)
                                : string.Format(message, rateLimit, rateLimitPeriod);

                            // break execution
                            return(QuotaExceededResponse(
                                       request,
                                       content,
                                       QuotaExceededResponseCode,
                                       core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod)));
                        }
                    }
                }
            }

            // no throttling required
            return(base.SendAsync(request, cancellationToken));
        }
예제 #5
0
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            EnableThrottlingAttribute attrPolicy = null;
            var applyThrottling = ApplyThrottling(actionContext, out attrPolicy);

            // get policy from repo
            if (policyRepository != null)
            {
                policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey());
            }

            if (Policy != null && applyThrottling)
            {
                core.Repository = Repository;
                core.Policy     = Policy;

                var identity = SetIndentity(actionContext.Request);

                if (!core.IsWhitelisted(identity))
                {
                    TimeSpan timeSpan = TimeSpan.FromSeconds(1);

                    // get default rates
                    var defRates = core.RatesWithDefaults(Policy.Rates.ToList());
                    if (Policy.StackBlockedRequests)
                    {
                        // all requests including the rejected ones will stack in this order: week, day, hour, min, sec
                        // if a client hits the hour limit then the minutes and seconds counters will expire and will eventually get erased from cache
                        defRates.Reverse();
                    }

                    // apply policy
                    foreach (var rate in (Policy.ThrotthleBy.HasValue ? defRates.Where(j => j.Key == Policy.ThrotthleBy.Value) : defRates))
                    {
                        var rateLimitPeriod = rate.Key;
                        var rateLimit       = rate.Value;

                        timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod);

                        // apply EnableThrottlingAttribute policy
                        var attrLimit = attrPolicy.GetLimit(rateLimitPeriod);
                        if (attrLimit > 0)
                        {
                            rateLimit = attrLimit;
                        }

                        // apply global rules
                        core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit);

                        if (rateLimit > 0)
                        {
                            // increment counter
                            string requestId;
                            var    throttleCounter = core.ProcessRequest(identity, timeSpan, rateLimitPeriod, out requestId);

                            // check if key expired
                            if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                            {
                                continue;
                            }

                            // check if limit is reached
                            if (throttleCounter.TotalRequests > rateLimit)
                            {
                                // log blocked request
                                if (Logger != null)
                                {
                                    Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, rateLimitPeriod.ToString(), rateLimit, actionContext.Request));
                                }

                                var message = !string.IsNullOrEmpty(this.QuotaExceededMessage)
                                    ? this.QuotaExceededMessage
                                    : "API calls quota exceeded! maximum admitted {0} per {1}.";

                                // add status code and retry after x seconds to response
                                actionContext.Response = QuotaExceededResponse(
                                    actionContext.Request,
                                    string.Format(message, rateLimit, rateLimitPeriod),
                                    QuotaExceededResponseCode,
                                    core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod));
                            }
                            else
                            {
                                if (Policy.ThrotthleBy.HasValue)
                                {
                                    actionContext.Response.Headers.Add("X-Rate-Limit-Limit", rateLimit.ToString());
                                    actionContext.Response.Headers.Add("X-Rate-Limit-Remaining", (rateLimit - throttleCounter.TotalRequests).ToString());
                                    actionContext.Response.Headers.Add("X-Rate-Limit-Reset", core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod));
                                }
                            }
                        }
                    }
                }
            }

            base.OnActionExecuting(actionContext);
        }