internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { using (var ms = new MemoryStream()) using (var sw = new StreamWriter(ms, Encoding.UTF8)) { sw.Write(ThrottleManager.GetThrottleKey()); if (Policy.IpThrottling) { sw.Write(requestIdentity.ClientIp); } if (Policy.ClientThrottling) { sw.Write(requestIdentity.ClientKey); } if (Policy.EndpointThrottling) { sw.Write(requestIdentity.Endpoint); } sw.Write(period); sw.Flush(); ms.Position = 0; using (var algorithm = new SHA1Managed()) { var hash = algorithm.ComputeHash(ms); return(Convert.ToBase64String(hash)); } } }
internal TimeSpan GetSuspendSpanFromPeriod(RateLimitPeriod rateLimitPeriod, TimeSpan timeSpan, long suspendTime) { switch (rateLimitPeriod) { case RateLimitPeriod.Second: timeSpan = (suspendTime > 1) ? TimeSpan.FromSeconds(suspendTime) : timeSpan; break; case RateLimitPeriod.Minute: timeSpan = (suspendTime > 60) ? TimeSpan.FromSeconds(suspendTime) : (timeSpan + TimeSpan.FromSeconds(suspendTime)); break; case RateLimitPeriod.Hour: timeSpan += TimeSpan.FromSeconds(suspendTime); break; case RateLimitPeriod.Day: timeSpan += TimeSpan.FromSeconds(suspendTime); break; case RateLimitPeriod.Week: timeSpan += TimeSpan.FromSeconds(suspendTime); break; } return(timeSpan); }
private string RetryAfterFrom(DateTime timestamp, RateLimitPeriod period) { var secondsPast = Convert.ToInt32((DateTime.UtcNow - timestamp).TotalSeconds); var retryAfter = 1; switch (period) { case RateLimitPeriod.Minute: retryAfter = 60; break; case RateLimitPeriod.Hour: retryAfter = 60 * 60; break; case RateLimitPeriod.Day: retryAfter = 60 * 60 * 24; break; case RateLimitPeriod.Week: retryAfter = 60 * 60 * 24 * 7; break; } retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1; return(retryAfter.ToString(CultureInfo.InvariantCulture)); }
internal string RetryAfterFrom(DateTime timestamp, long suspendTime, RateLimitPeriod period) { var secondsPast = Convert.ToInt32((DateTime.UtcNow - timestamp).TotalSeconds); var retryAfter = 1; switch (period) { case RateLimitPeriod.Second: retryAfter = (suspendTime > 1) ? (int)suspendTime : 1; break; case RateLimitPeriod.Minute: retryAfter = (suspendTime > 60) ? (int)suspendTime : (60 + (int)suspendTime); break; case RateLimitPeriod.Hour: retryAfter = (60 * 60) + (int)suspendTime; break; case RateLimitPeriod.Day: retryAfter = (60 * 60 * 24) + (int)suspendTime; break; case RateLimitPeriod.Week: retryAfter = (60 * 60 * 24 * 7) + (int)suspendTime; break; } retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1; return(retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture)); }
internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { var keyValues = new List <string>() { ThrottleManager.GetThrottleKey() }; if (Policy.IpThrottling) { keyValues.Add(requestIdentity.ClientIp); } if (Policy.ClientThrottling) { keyValues.Add(requestIdentity.ClientKey); } if (Policy.EndpointThrottling) { keyValues.Add(requestIdentity.Endpoint); } keyValues.Add(period.ToString()); var id = string.Join("_", keyValues); var idBytes = Encoding.UTF8.GetBytes(id); var hashBytes = new System.Security.Cryptography.SHA1Managed().ComputeHash(idBytes); var hex = BitConverter.ToString(hashBytes).Replace("-", string.Empty); return(hex); }
public long GetLimit(RateLimitPeriod period) { switch (period) { case RateLimitPeriod.Second: return(PerSecond); case RateLimitPeriod.Minute: return(PerMinute); case RateLimitPeriod.Hour: return(PerHour); case RateLimitPeriod.Day: return(PerDay); case RateLimitPeriod.Week: return(PerWeek); case RateLimitPeriod.FiveSecond: return(PerFiveSecond); case RateLimitPeriod.TenSecond: return(PerTenSecond); case RateLimitPeriod.FifteenSecond: return(PerFifteenSecond); default: return(PerSecond); } }
internal TimeSpan GetTimeSpanFromPeriod(RateLimitPeriod rateLimitPeriod) { var timeSpan = TimeSpan.FromSeconds(1); 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; } return(timeSpan); }
internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitPeriod rateLimitPeriod, ref long rateLimit, ref long suspend) { // 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.Count > 0) { // get the lower limit from all applying rules var customRate = (from r in rules let rateValue = r.Value.GetLimit(rateLimitPeriod) select rateValue).Min(); var customSuspend = (from r in rules let suspendTime = r.Value.SuspendTime select suspendTime).Max(); if (customRate > 0) { rateLimit = customRate; } if (customSuspend > 0) { suspend = customSuspend; } } } // apply custom rate limit for clients that will override endpoint limits if (Policy.ClientRules?.Keys.Contains(identity.ClientKey) == true) { var limit = Policy.ClientRules[identity.ClientKey].GetLimit(rateLimitPeriod); if (limit > 0) { rateLimit = limit; } var customSuspend = Policy.ClientRules[identity.ClientKey].SuspendTime; if (customSuspend > 0) { suspend = customSuspend; } } // enforce ip rate limit as is most specific if (Policy.IpRules != null && ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, out string ipRule)) { var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod); if (limit > 0) { rateLimit = limit; } var customSuspend = Policy.IpRules[ipRule].SuspendTime; if (customSuspend > 0) { suspend = customSuspend; } } }
private void ProcessQuotaExceeded(RateLimitPeriod rateLimitPeriod, long rateLimit, string retryAfter) { var message = !string.IsNullOrEmpty(QuotaExceededMessage) ? QuotaExceededMessage : "API calls quota exceeded! maximum admitted {0} per {1}."; var content = QuotaExceededContent != null ? QuotaExceededContent(rateLimit, rateLimitPeriod) : string.Format(message, rateLimit, rateLimitPeriod); processResult.IsPass = false; processResult.Message = message; processResult.Content = content; processResult.RetryAfter = retryAfter; processResult.StatusCode = (int)QuotaExceededResponseCode; }
public long GetLimit(RateLimitPeriod period) { switch (period) { case RateLimitPeriod.Second: return PerSecond; case RateLimitPeriod.Minute: return PerMinute; case RateLimitPeriod.Hour: return PerHour; case RateLimitPeriod.Day: return PerDay; default: return PerSecond; } }
internal ThrottleCounter ProcessRequest(TimeSpan timeSpan, RateLimitPeriod period, long rateLimit, long suspendTime, string id) { var throttleCounter = new ThrottleCounter() { Timestamp = DateTime.UtcNow, TotalRequests = 1 }; TimeSpan suspendSpan = TimeSpan.FromSeconds(0); // serial reads and writes lock (ProcessLocker) { var entry = Repository.FirstOrDefault(id); if (entry.HasValue) { var timeStamp = entry.Value.Timestamp; if (entry.Value.TotalRequests >= rateLimit && suspendTime > 0) { timeSpan = GetSuspendSpanFromPeriod(period, timeSpan, suspendTime); } // entry has not expired if (entry.Value.Timestamp + timeSpan >= DateTime.UtcNow) { // increment request count var totalRequests = entry.Value.TotalRequests + 1; // deep copy throttleCounter = new ThrottleCounter { Timestamp = timeStamp, TotalRequests = totalRequests }; } } // stores: id (string) - timestamp (datetime) - total (long) Repository.Save(id, throttleCounter, timeSpan); } return(throttleCounter); }
internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitPeriod rateLimitPeriod, ref long rateLimit) { // apply endpoint rate limits if (Policy.EndpointRules != null) { var rules = Policy.EndpointRules.Where(x => identity.Endpoint.IndexOf(x.Key, 0, StringComparison.InvariantCultureIgnoreCase) != -1).ToList(); //var rules = Policy.EndpointRules.Where(x => Regex.IsMatch(identity.Endpoint, x.Key, RegexOptions.IgnoreCase)).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; } } // enforce ip rate limit as is most specific string ipRule = null; if (Policy.IpRules != null && ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, out ipRule)) { var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod); if (limit > 0) { rateLimit = limit; } } }
internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitPeriod rateLimitPeriod, ref long rateLimit) { // apply endpoint rate limits if (Policy.EndpointRules != null) { var rules = Policy.EndpointRules.Where(x => x.Match(identity)).ToList(); if (rules.Any()) { // get the lower limit from all applying rules var customRate = (from r in rules let rateValue = r.limits.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; } } // enforce ip rate limit as is most specific string ipRule = null; if (Policy.IpRules != null && ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, out ipRule)) { var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod); if (limit > 0) { rateLimit = limit; } } }
internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitPeriod rateLimitPeriod, ref long rateLimit) { // apply endpoint rate limits if (Policy.EndpointRules != null) { var rules = Policy.EndpointRules.Where(x => identity.EndpointWithMethod.Contains(x.Key.ToLowerInvariant())).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; } } // enforce ip rate limit as is most specific string ipRule = null; if (Policy.IpRules != null && ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, out ipRule)) { var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod); if (limit > 0) { rateLimit = limit; } } }
internal string RetryAfterFrom(DateTime timestamp, RateLimitPeriod period) { var secondsPast = Convert.ToInt32((DateTime.UtcNow - timestamp).TotalSeconds); var retryAfter = 1; switch (period) { case RateLimitPeriod.Minute: retryAfter = 60; break; case RateLimitPeriod.Hour: retryAfter = 60 * 60; break; case RateLimitPeriod.Day: retryAfter = 60 * 60 * 24; break; case RateLimitPeriod.Week: retryAfter = 60 * 60 * 24 * 7; break; } retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1; return retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture); }
public virtual long GetLimit(RateLimitPeriod period) { switch (period) { case RateLimitPeriod.Second: return(PerSecond); case RateLimitPeriod.Minute: return(PerMinute); case RateLimitPeriod.Hour: return(PerHour); case RateLimitPeriod.Day: return(PerDay); case RateLimitPeriod.Week: return(PerWeek); default: return(PerSecond); } }
protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { var keyValues = new List<string>() { "throttle" }; if (Policy.IpThrottling) keyValues.Add(requestIdentity.ClientIp); if (Policy.ClientThrottling) keyValues.Add(requestIdentity.ClientKey); if (Policy.EndpointThrottling) keyValues.Add(requestIdentity.Endpoint); keyValues.Add(period.ToString()); var id = string.Join("_", keyValues); var idBytes = Encoding.UTF8.GetBytes(id); var hashBytes = new System.Security.Cryptography.SHA1Managed().ComputeHash(idBytes); var hex = BitConverter.ToString(hashBytes).Replace("-", ""); return hex; }
private ThrottleCounter ProcessRequest(RequestIdentity requestIdentity, TimeSpan timeSpan, RateLimitPeriod period, out string id) { var throttleCounter = new ThrottleCounter() { Timestamp = DateTime.UtcNow, TotalRequests = 1 }; id = ComputeThrottleKey(requestIdentity, period); //serial reads and writes lock (_processLocker) { var entry = Repository.FirstOrDefault(id); if (entry.HasValue) { //entry has not expired if (entry.Value.Timestamp + timeSpan >= DateTime.UtcNow) { //increment request count var totalRequests = entry.Value.TotalRequests + 1; //deep copy throttleCounter = new ThrottleCounter { Timestamp = entry.Value.Timestamp, TotalRequests = totalRequests }; } } //stores: id (string) - timestamp (datetime) - total (long) Repository.Save(id, throttleCounter, timeSpan); } return(throttleCounter); }
/// <summary> /// 节流属性注入 /// </summary> /// <param name="maxRate"> 基于<see cref="RateLimitPeriod"/>的最大请求</param> /// <param name="maxBurst">最大突发请求</param> /// <param name="periodType">限制速率的周期类型</param> public EnableThrottlingAttribute(long maxRate, long maxBurst, RateLimitPeriod periodType) { MaxRate = maxRate; MaxBurst = maxBurst; PeriodType = periodType; }
/// <summary> /// Initializes a new instance of the <see cref="RateQuota"/> class. /// </summary> /// <param name="maxRate">基于<see cref="RateLimitPeriod" />的最大请求</param> /// <param name="maxBurst">最大突发请求</param> /// <param name="periodType"><see cref="RateLimitPeriod" /></param> public RateQuota(long maxRate, long maxBurst, RateLimitPeriod periodType) { MaxRate = maxRate; MaxBurst = maxBurst; PeriodType = periodType; }
internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { var keyValues = new List<string>() { ThrottleManager.GetThrottleKey() }; if (Policy.IpThrottling) { keyValues.Add(requestIdentity.ClientIp); } if (Policy.ClientThrottling) { keyValues.Add(requestIdentity.ClientKey); } if (Policy.EndpointThrottling) { if (Policy.EndpointThrottleMethod == EndpointThrottlingMethod.Action && !string.IsNullOrWhiteSpace(requestIdentity.ActionName) && !string.IsNullOrWhiteSpace(requestIdentity.ControllerName)) { //TODO: think of a better way to do this keyValues.Add(requestIdentity.ControllerName + "." + requestIdentity.ActionName); } else if (Policy.EndpointThrottleMethod == EndpointThrottlingMethod.Url) { keyValues.Add(requestIdentity.Endpoint); } } keyValues.Add(period.ToString()); var id = string.Join("_", keyValues); var idBytes = Encoding.UTF8.GetBytes(id); byte[] hashBytes; using (var algorithm = System.Security.Cryptography.HashAlgorithm.Create("SHA1")) { hashBytes = algorithm.ComputeHash(idBytes); } var hex = BitConverter.ToString(hashBytes).Replace("-", string.Empty); return hex; }
internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { var keyValues = new List<string>() { ThrottleManager.GetThrottleKey() }; if (Policy.IpThrottling) { keyValues.Add(requestIdentity.ClientIp); } if (Policy.ClientThrottling) { keyValues.Add(requestIdentity.ClientKey); } if (Policy.EndpointThrottling) { keyValues.Add(requestIdentity.Endpoint); } keyValues.Add(period.ToString()); var id = string.Join("_", keyValues); var idBytes = Encoding.UTF8.GetBytes(id); byte[] hashBytes; using (var algorithm = System.Security.Cryptography.HashAlgorithm.Create("SHA1")) { hashBytes = algorithm.ComputeHash(idBytes); } var hex = BitConverter.ToString(hashBytes).Replace("-", string.Empty); return hex; }
internal TimeSpan GetTimeSpanFromPeriod(RateLimitPeriod rateLimitPeriod) { var timeSpan = TimeSpan.FromSeconds(1); 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; } return timeSpan; }
private ThrottleCounter ProcessRequest(RequestIdentity requestIdentity, TimeSpan timeSpan, RateLimitPeriod period, out string id) { var throttleCounter = new ThrottleCounter() { Timestamp = DateTime.UtcNow, TotalRequests = 1 }; id = ComputeThrottleKey(requestIdentity, period); //serial reads and writes lock (_processLocker) { var entry = Repository.FirstOrDefault(id); if (entry.HasValue) { //entry has not expired if (entry.Value.Timestamp + timeSpan >= DateTime.UtcNow) { //increment request count var totalRequests = entry.Value.TotalRequests + 1; //deep copy throttleCounter = new ThrottleCounter { Timestamp = entry.Value.Timestamp, TotalRequests = totalRequests }; } } //stores: id (string) - timestamp (datetime) - total (long) Repository.Save(id, throttleCounter, timeSpan); } return throttleCounter; }
protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { return core.ComputeThrottleKey(requestIdentity, period); }
protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { return(core.ComputeThrottleKey(requestIdentity, period)); }
private ThrottleCounter ProcessRequest(ThrottlePolicy throttlePolicy, RequestIndentity throttleEntry, TimeSpan timeSpan, RateLimitPeriod period, out string id) { var throttleCounter = new ThrottleCounter(); throttleCounter.Timestamp = DateTime.UtcNow; throttleCounter.TotalRequests = 1; //computed request unique id from IP, client key, url and period id = "throttle"; if (throttlePolicy.IpThrottling) { if (throttlePolicy.IpWhitelist != null && throttlePolicy.IpWhitelist.Contains(throttleEntry.ClientIp)) { return throttleCounter; } id += "_" + throttleEntry.ClientIp; } if (throttlePolicy.ClientThrottling) { if (throttlePolicy.ClientWhitelist != null && throttlePolicy.ClientWhitelist.Contains(throttleEntry.ClientKey)) { return throttleCounter; } id += "_" + throttleEntry.ClientKey; } if (throttlePolicy.EndpointThrottling) { if (throttlePolicy.EndpointWhitelist != null && Policy.EndpointWhitelist.Any(x => throttleEntry.Endpoint.Contains(x))) { return throttleCounter; } id += "_" + throttleEntry.Endpoint; } id += "_" + period; //get the hash value of the computed id var hashId = ComputeHash(id); //serial reads and writes lock (_processLocker) { var entry = Repository.FirstOrDefault(hashId); if (entry.HasValue) { //entry has not expired if (entry.Value.Timestamp + timeSpan >= DateTime.UtcNow) { //increment request count var totalRequests = entry.Value.TotalRequests + 1; //deep copy throttleCounter = new ThrottleCounter { Timestamp = entry.Value.Timestamp, TotalRequests = totalRequests }; } } //stores: id (string) - timestamp (datetime) - total (long) Repository.Save(hashId, throttleCounter, timeSpan); } return throttleCounter; }