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 = SetIdentity(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 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 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, 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, rateLimitPeriod)); } } } } } base.OnActionExecuting(actionContext); }
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 = SetIdentity(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 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 return(QuotaExceededResponse( request, content, QuotaExceededResponseCode, core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod))); } } } // no throttling required return(base.SendAsync(request, cancellationToken)); }