예제 #1
0
        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));
                    }
                }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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));
        }
예제 #4
0
        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));
        }
예제 #5
0
        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);
            }
        }
예제 #7
0
        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);
        }
예제 #8
0
        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;
                }
            }
        }
예제 #9
0
        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;
        }
예제 #10
0
 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;
     }
 }
예제 #11
0
        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);
        }
예제 #12
0
        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;
                }
            }
        }
예제 #14
0
        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;
                }
            }
        }
예제 #15
0
 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);
 }
예제 #16
0
        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);
            }
        }
예제 #17
0
        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;
        }
예제 #18
0
        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;
 }
예제 #20
0
 /// <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;
 }
예제 #21
0
        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;
        }
예제 #22
0
        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;
        }
예제 #23
0
        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;
        }
예제 #24
0
        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;
        }
예제 #25
0
 protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period)
 {
     return core.ComputeThrottleKey(requestIdentity, period);
 }
예제 #26
0
 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;
        }