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); }
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)); }
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 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}."; 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, string.Format(message, rateLimit, rateLimitPeriod), QuotaExceededResponseCode, core.RetryAfterFrom(throttleCounter.Timestamp, 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; }