상속: System.Web.Mvc.ActionFilterAttribute, IActionFilter
예제 #1
0
        private bool ApplyThrottling(ActionExecutingContext filterContext, out EnableThrottlingAttribute attr)
        {
            var applyThrottling = false;

            attr = null;

            if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(EnableThrottlingAttribute), true))
            {
                attr            = (EnableThrottlingAttribute)filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(EnableThrottlingAttribute), true).First();
                applyThrottling = true;
            }

            //disabled on the class
            if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DisableThrottlingAttribute), true))
            {
                applyThrottling = false;
            }

            if (filterContext.ActionDescriptor.IsDefined(typeof(EnableThrottlingAttribute), true))
            {
                attr            = (EnableThrottlingAttribute)filterContext.ActionDescriptor.GetCustomAttributes(typeof(EnableThrottlingAttribute), true).First();
                applyThrottling = true;
            }

            //explicit disabled
            if (filterContext.ActionDescriptor.IsDefined(typeof(DisableThrottlingAttribute), true))
            {
                applyThrottling = false;
            }

            return(applyThrottling);
        }
예제 #2
0
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            EnableThrottlingAttribute attrPolicy = null;
            var applyThrottling = ApplyThrottling(filterContext, out attrPolicy);

            if (Policy != null && applyThrottling)
            {
                var identity = SetIdentity(filterContext.HttpContext.Request);

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

                    var rates = Policy.Rates.AsEnumerable();
                    if (Policy.StackBlockedRequests)
                    {
                        //all requests including the rejected ones will stack in this order: 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
                        rates = Policy.Rates.Reverse();
                    }

                    //apply policy
                    //the IP rules are applied last and will overwrite any client rule you might defined
                    foreach (var rate in rates)
                    {
                        var rateLimitPeriod = rate.Key;
                        var rateLimit       = rate.Value;

                        switch (rateLimitPeriod)
                        {
                        case RateLimitPeriod.Second:
                            timeSpan = TimeSpan.FromSeconds(1);
                            break;

                        case RateLimitPeriod.Minute:
                            timeSpan = TimeSpan.FromMinutes(1);
                            break;

                        case RateLimitPeriod.Hour:
                            timeSpan = TimeSpan.FromHours(1);
                            break;

                        case RateLimitPeriod.Day:
                            timeSpan = TimeSpan.FromDays(1);
                            break;

                        case RateLimitPeriod.Week:
                            timeSpan = TimeSpan.FromDays(7);
                            break;
                        }

                        //increment counter
                        string requestId;
                        var    throttleCounter = ProcessRequest(identity, timeSpan, rateLimitPeriod, out requestId);

                        if (throttleCounter.Timestamp + timeSpan < DateTime.UtcNow)
                        {
                            continue;
                        }

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

                        //apply endpoint rate limits
                        if (Policy.EndpointRules != null)
                        {
                            var rules = Policy.EndpointRules.Where(x => identity.Endpoint.IndexOf(x.Key, 0, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
                            if (rules.Any())
                            {
                                //get the lower limit from all applying rules
                                var customRate = (from r in rules let rateValue = r.Value.GetLimit(rateLimitPeriod) select rateValue).Min();

                                if (customRate > 0)
                                {
                                    rateLimit = customRate;
                                }
                            }
                        }

                        //apply custom rate limit for clients that will override endpoint limits
                        if (Policy.ClientRules != null && Policy.ClientRules.Keys.Contains(identity.ClientKey))
                        {
                            var limit = Policy.ClientRules[identity.ClientKey].GetLimit(rateLimitPeriod);
                            if (limit > 0)
                            {
                                rateLimit = limit;
                            }
                        }

                        //apply custom rate limit for user agent
                        if (Policy.UserAgentRules != null && !string.IsNullOrEmpty(identity.UserAgent))
                        {
                            var rules = Policy.UserAgentRules.Where(x => identity.UserAgent.IndexOf(x.Key, 0, StringComparison.InvariantCultureIgnoreCase) != -1).ToList();
                            if (rules.Any())
                            {
                                //get the lower limit from all applying rules
                                var customRate = (from r in rules let rateValue = r.Value.GetLimit(rateLimitPeriod) select rateValue).Min();
                                rateLimit = customRate;
                            }
                        }

                        //enforce ip rate limit as is most specific
                        string ipRule = null;
                        if (Policy.IpRules != null && IpAddressParser.ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, out ipRule))
                        {
                            var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod);
                            if (limit > 0)
                            {
                                rateLimit = limit;
                            }
                        }

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

                            //break execution and return 409
                            var message = string.IsNullOrEmpty(QuotaExceededMessage) ?
                                          "HTTP request quota exceeded! maximum admitted {0} per {1}" : QuotaExceededMessage;

                            //add status code and retry after x seconds to response
                            filterContext.HttpContext.Response.StatusCode = (int)QuotaExceededResponseCode;
                            filterContext.HttpContext.Response.Headers.Set("Retry-After", RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod));

                            filterContext.Result = QuotaExceededResult(
                                filterContext.RequestContext,
                                string.Format(message, rateLimit, rateLimitPeriod),
                                QuotaExceededResponseCode,
                                requestId);

                            return;
                        }
                    }
                }
            }

            base.OnActionExecuting(filterContext);
        }
예제 #3
0
        private bool ApplyThrottling(ActionExecutingContext filterContext, out EnableThrottlingAttribute attr)
        {
            var applyThrottling = false;
            attr = null;

            if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(EnableThrottlingAttribute), true))
            {
                attr = (EnableThrottlingAttribute)filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(EnableThrottlingAttribute), true).First();
                applyThrottling = true;
            }

            if (filterContext.ActionDescriptor.IsDefined(typeof(EnableThrottlingAttribute), true))
            {
                attr = (EnableThrottlingAttribute)filterContext.ActionDescriptor.GetCustomAttributes(typeof(EnableThrottlingAttribute), true).First();
                applyThrottling = true;
            }

            //explicit disabled
            if (filterContext.ActionDescriptor.IsDefined(typeof(DisableThrottingAttribute), true))
            {
                applyThrottling = false;
            }

            return applyThrottling;
        }