From 6f733eb1c15011f57b1b3e05d519a264cc30d0c6 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Fri, 13 Oct 2017 09:22:26 -0400 Subject: [PATCH 1/5] packages updated --- .../WebApiThrottle.StrongName.csproj | 13 ++++--- WebApiThrottle.StrongName/app.config | 11 ++++++ WebApiThrottle.StrongName/packages.config | 4 +- .../WebApiThrottle.Tests.csproj | 39 ++++++++++++------- WebApiThrottle.Tests/app.config | 11 ++++++ WebApiThrottle.Tests/packages.config | 13 ++++--- WebApiThrottle.WebApiDemo/Web.config | 6 +-- .../WebApiThrottle.WebApiDemo.csproj | 21 +++++----- WebApiThrottle.WebApiDemo/packages.config | 6 +-- WebApiThrottle/WebApiThrottle.csproj | 11 +++--- WebApiThrottle/app.config | 2 +- WebApiThrottle/packages.config | 4 +- WebApiThrottler.SelfHostOwinDemo/App.config | 4 +- .../WebApiThrottler.SelfHostOwinDemo.csproj | 23 ++++++----- .../packages.config | 8 ++-- 15 files changed, 104 insertions(+), 72 deletions(-) create mode 100644 WebApiThrottle.StrongName/app.config create mode 100644 WebApiThrottle.Tests/app.config diff --git a/WebApiThrottle.StrongName/WebApiThrottle.StrongName.csproj b/WebApiThrottle.StrongName/WebApiThrottle.StrongName.csproj index c8c002a..702d255 100644 --- a/WebApiThrottle.StrongName/WebApiThrottle.StrongName.csproj +++ b/WebApiThrottle.StrongName/WebApiThrottle.StrongName.csproj @@ -36,13 +36,12 @@ WebApiThrottle.snk - - False - ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + + ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll + True - - False - ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll False @@ -75,6 +74,8 @@ + + diff --git a/WebApiThrottle.StrongName/app.config b/WebApiThrottle.StrongName/app.config new file mode 100644 index 0000000..dde2c3c --- /dev/null +++ b/WebApiThrottle.StrongName/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/WebApiThrottle.StrongName/packages.config b/WebApiThrottle.StrongName/packages.config index 45e9e93..7f67226 100644 --- a/WebApiThrottle.StrongName/packages.config +++ b/WebApiThrottle.StrongName/packages.config @@ -2,7 +2,7 @@ - - + + \ No newline at end of file diff --git a/WebApiThrottle.Tests/WebApiThrottle.Tests.csproj b/WebApiThrottle.Tests/WebApiThrottle.Tests.csproj index c54f60d..a311f07 100644 --- a/WebApiThrottle.Tests/WebApiThrottle.Tests.csproj +++ b/WebApiThrottle.Tests/WebApiThrottle.Tests.csproj @@ -1,5 +1,6 @@  + Debug @@ -11,6 +12,8 @@ WebApiThrottle.Tests v4.5.2 512 + + true @@ -39,36 +42,44 @@ - ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll - True + ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - - ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll - True + + ..\packages\xunit.assert.2.3.0\lib\netstandard1.1\xunit.assert.dll - - ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll - True + + ..\packages\xunit.extensibility.core.2.3.0\lib\netstandard1.1\xunit.core.dll - - ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll - True + + ..\packages\xunit.extensibility.execution.2.3.0\lib\net452\xunit.execution.desktop.dll - - - {FBF3012B-08EF-408C-9E7D-175ABF286CB4} WebApiThrottle.StrongName + + + + + + + + + + Este proyecto hace referencia a los paquetes NuGet que faltan en este equipo. Use la restauración de paquetes NuGet para descargarlos. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=322105. El archivo que falta es {0}. + + + + + @@ -25,7 +27,7 @@ - + @@ -35,7 +37,8 @@ - + @@ -60,8 +63,13 @@ - - + + - + \ No newline at end of file diff --git a/WebApiThrottle.WebApiDemo/packages.config b/WebApiThrottle.WebApiDemo/packages.config index df24291..176c87e 100644 --- a/WebApiThrottle.WebApiDemo/packages.config +++ b/WebApiThrottle.WebApiDemo/packages.config @@ -1,4 +1,5 @@  + diff --git a/WebApiThrottle/Attributes/DisableThrottingAttribute.cs b/WebApiThrottle/Attributes/DisableThrottingAttribute.cs index 39b9ba1..025f28c 100644 --- a/WebApiThrottle/Attributes/DisableThrottingAttribute.cs +++ b/WebApiThrottle/Attributes/DisableThrottingAttribute.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http.Filters; +using System.Web.Http.Filters; -namespace WebApiThrottle +namespace WebApiThrottle.Attributes { public class DisableThrottingAttribute : ActionFilterAttribute, IActionFilter { } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Attributes/EnableThrottlingAttribute.cs b/WebApiThrottle/Attributes/EnableThrottlingAttribute.cs index a95f1b6..9ddf2cb 100644 --- a/WebApiThrottle/Attributes/EnableThrottlingAttribute.cs +++ b/WebApiThrottle/Attributes/EnableThrottlingAttribute.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http.Filters; +using System.Web.Http.Filters; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Attributes { public class EnableThrottlingAttribute : ActionFilterAttribute, IActionFilter { @@ -38,4 +34,4 @@ public long GetLimit(RateLimitPeriod period) } } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Configuration/ThrottlePolicyConfiguration.cs b/WebApiThrottle/Configuration/ThrottlePolicyConfiguration.cs index a67861c..6a6382c 100644 --- a/WebApiThrottle/Configuration/ThrottlePolicyConfiguration.cs +++ b/WebApiThrottle/Configuration/ThrottlePolicyConfiguration.cs @@ -1,116 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; -namespace WebApiThrottle +namespace WebApiThrottle.Configuration { public class ThrottlePolicyConfiguration : ConfigurationSection { [ConfigurationProperty("limitPerSecond", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerSecond - { - get - { - return (long)this["limitPerSecond"]; - } - } + public long LimitPerSecond => (long) this["limitPerSecond"]; [ConfigurationProperty("limitPerMinute", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerMinute - { - get - { - return (long)this["limitPerMinute"]; - } - } + public long LimitPerMinute => (long) this["limitPerMinute"]; [ConfigurationProperty("limitPerHour", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerHour - { - get - { - return (long)this["limitPerHour"]; - } - } + public long LimitPerHour => (long) this["limitPerHour"]; [ConfigurationProperty("limitPerDay", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerDay - { - get - { - return (long)this["limitPerDay"]; - } - } + public long LimitPerDay => (long) this["limitPerDay"]; [ConfigurationProperty("limitPerWeek", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerWeek - { - get - { - return (long)this["limitPerWeek"]; - } - } + public long LimitPerWeek => (long) this["limitPerWeek"]; [ConfigurationProperty("ipThrottling", DefaultValue = "false", IsRequired = false)] - public bool IpThrottling - { - get - { - return (bool)this["ipThrottling"]; - } - } + public bool IpThrottling => (bool) this["ipThrottling"]; [ConfigurationProperty("clientThrottling", DefaultValue = "false", IsRequired = false)] - public bool ClientThrottling - { - get - { - return (bool)this["clientThrottling"]; - } - } + public bool ClientThrottling => (bool) this["clientThrottling"]; [ConfigurationProperty("endpointThrottling", DefaultValue = "false", IsRequired = false)] - public bool EndpointThrottling - { - get - { - return (bool)this["endpointThrottling"]; - } - } + public bool EndpointThrottling => (bool) this["endpointThrottling"]; [ConfigurationProperty("stackBlockedRequests", DefaultValue = "false", IsRequired = false)] - public bool StackBlockedRequests - { - get - { - return (bool)this["stackBlockedRequests"]; - } - } + public bool StackBlockedRequests => (bool) this["stackBlockedRequests"]; [ConfigurationProperty("rules")] - public ThrottlePolicyRuleConfigurationCollection Rules - { - get - { - return this["rules"] as ThrottlePolicyRuleConfigurationCollection; - } - } + public ThrottlePolicyRuleConfigurationCollection Rules => + this["rules"] as ThrottlePolicyRuleConfigurationCollection; [ConfigurationProperty("whitelists")] - public ThrottlePolicyWhitelistConfigurationCollection Whitelists - { - get - { - return this["whitelists"] as ThrottlePolicyWhitelistConfigurationCollection; - } - } + public ThrottlePolicyWhitelistConfigurationCollection Whitelists => + this["whitelists"] as ThrottlePolicyWhitelistConfigurationCollection; } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationCollection.cs b/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationCollection.cs index 374af2c..e14628d 100644 --- a/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationCollection.cs +++ b/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationCollection.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; -namespace WebApiThrottle +namespace WebApiThrottle.Configuration { - public class ThrottlePolicyRuleConfigurationCollection : ConfigurationElementCollection + public abstract class ThrottlePolicyRuleConfigurationCollection : ConfigurationElementCollection { - protected override ConfigurationElement CreateNewElement() { return new ThrottlePolicyRuleConfigurationElement(); @@ -17,7 +11,7 @@ protected override ConfigurationElement CreateNewElement() protected override object GetElementKey(ConfigurationElement element) { - return ((ThrottlePolicyRuleConfigurationElement)element).Entry; + return ((ThrottlePolicyRuleConfigurationElement) element).Entry; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationElement.cs b/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationElement.cs index 519c05c..b87ea2c 100644 --- a/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationElement.cs +++ b/WebApiThrottle/Configuration/ThrottlePolicyRuleConfigurationElement.cs @@ -1,80 +1,33 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; -namespace WebApiThrottle +namespace WebApiThrottle.Configuration { public class ThrottlePolicyRuleConfigurationElement : ConfigurationElement { [ConfigurationProperty("limitPerSecond", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerSecond - { - get - { - return (long)this["limitPerSecond"]; - } - } + public long LimitPerSecond => (long) this["limitPerSecond"]; [ConfigurationProperty("limitPerMinute", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerMinute - { - get - { - return (long)this["limitPerMinute"]; - } - } + public long LimitPerMinute => (long) this["limitPerMinute"]; [ConfigurationProperty("limitPerHour", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerHour - { - get - { - return (long)this["limitPerHour"]; - } - } + public long LimitPerHour => (long) this["limitPerHour"]; [ConfigurationProperty("limitPerDay", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerDay - { - get - { - return (long)this["limitPerDay"]; - } - } + public long LimitPerDay => (long) this["limitPerDay"]; [ConfigurationProperty("limitPerWeek", DefaultValue = "0", IsRequired = false)] [LongValidator(ExcludeRange = false, MinValue = 0)] - public long LimitPerWeek - { - get - { - return (long)this["limitPerWeek"]; - } - } + public long LimitPerWeek => (long) this["limitPerWeek"]; [ConfigurationProperty("entry", IsRequired = true)] - public string Entry - { - get - { - return this["entry"] as string; - } - } + public string Entry => this["entry"] as string; [ConfigurationProperty("policyType", IsRequired = true)] - public int PolicyType - { - get - { - return (int)this["policyType"]; - } - } + public int PolicyType => (int) this["policyType"]; } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationCollection.cs b/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationCollection.cs index 827590a..daf9914 100644 --- a/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationCollection.cs +++ b/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationCollection.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; -namespace WebApiThrottle +namespace WebApiThrottle.Configuration { - public class ThrottlePolicyWhitelistConfigurationCollection : ConfigurationElementCollection + public abstract class ThrottlePolicyWhitelistConfigurationCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { @@ -16,7 +11,7 @@ protected override ConfigurationElement CreateNewElement() protected override object GetElementKey(ConfigurationElement element) { - return ((ThrottlePolicyWhitelistConfigurationElement)element).Entry; + return ((ThrottlePolicyWhitelistConfigurationElement) element).Entry; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationElement.cs b/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationElement.cs index f4956aa..a589839 100644 --- a/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationElement.cs +++ b/WebApiThrottle/Configuration/ThrottlePolicyWhitelistConfigurationElement.cs @@ -1,30 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Configuration; -namespace WebApiThrottle +namespace WebApiThrottle.Configuration { public class ThrottlePolicyWhitelistConfigurationElement : ConfigurationElement { [ConfigurationProperty("entry", IsRequired = true)] - public string Entry - { - get - { - return this["entry"] as string; - } - } + public string Entry => this["entry"] as string; [ConfigurationProperty("policyType", IsRequired = true)] - public int PolicyType - { - get - { - return (int)this["policyType"]; - } - } + public int PolicyType => (int) this["policyType"]; } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Logging/IThrottleLogger.cs b/WebApiThrottle/Logging/IThrottleLogger.cs index 49936b5..99618fd 100644 --- a/WebApiThrottle/Logging/IThrottleLogger.cs +++ b/WebApiThrottle/Logging/IThrottleLogger.cs @@ -1,16 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WebApiThrottle +namespace WebApiThrottle.Logging { /// - /// Log requests that exceed the limit + /// Log requests that exceed the limit /// public interface IThrottleLogger { void Log(ThrottleLogEntry entry); } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Logging/ThrottleLogEntry.cs b/WebApiThrottle/Logging/ThrottleLogEntry.cs index d8882ba..ad3686f 100644 --- a/WebApiThrottle/Logging/ThrottleLogEntry.cs +++ b/WebApiThrottle/Logging/ThrottleLogEntry.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Logging { [Serializable] public class ThrottleLogEntry @@ -30,4 +26,4 @@ public class ThrottleLogEntry public HttpRequestMessage Request { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Logging/TracingThrottleLogger.cs b/WebApiThrottle/Logging/TracingThrottleLogger.cs index a9dee72..d7857f4 100644 --- a/WebApiThrottle/Logging/TracingThrottleLogger.cs +++ b/WebApiThrottle/Logging/TracingThrottleLogger.cs @@ -1,31 +1,28 @@ using System.Web.Http.Tracing; -namespace WebApiThrottle +namespace WebApiThrottle.Logging { public class TracingThrottleLogger : IThrottleLogger { - private readonly ITraceWriter traceWriter; - + private readonly ITraceWriter _traceWriter; + public TracingThrottleLogger(ITraceWriter traceWriter) { - this.traceWriter = traceWriter; + _traceWriter = traceWriter; } - + public void Log(ThrottleLogEntry entry) { - if (null != traceWriter) - { - traceWriter.Info( - entry.Request, - "WebApiThrottle", - "{0} Request {1} from {2} has been throttled (blocked), quota {3}/{4} exceeded by {5}", - entry.LogDate, - entry.RequestId, - entry.ClientIp, - entry.RateLimit, - entry.RateLimitPeriod, - entry.TotalRequests); - } + _traceWriter?.Info( + entry.Request, + "WebApiThrottle", + "{0} Request {1} from {2} has been throttled (blocked), quota {3}/{4} exceeded by {5}", + entry.LogDate, + entry.RequestId, + entry.ClientIp, + entry.RateLimit, + entry.RateLimitPeriod, + entry.TotalRequests); } } } \ No newline at end of file diff --git a/WebApiThrottle/Models/IPAddressRange.cs b/WebApiThrottle/Models/IPAddressRange.cs index 8821705..bea6ee9 100644 --- a/WebApiThrottle/Models/IPAddressRange.cs +++ b/WebApiThrottle/Models/IPAddressRange.cs @@ -3,33 +3,28 @@ using System.Linq; using System.Net; using System.Runtime.Serialization; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { /// - /// IP v4 and v6 range helper by jsakamoto - /// Fork from https://github.com/jsakamoto/ipaddressrange + /// IP v4 and v6 range helper by jsakamoto + /// Fork from https://github.com/jsakamoto/ipaddressrange /// /// - /// "192.168.0.0/24" - /// "fe80::/10" - /// "192.168.0.0/255.255.255.0" - /// "192.168.0.0-192.168.0.255" + /// "192.168.0.0/24" + /// "fe80::/10" + /// "192.168.0.0/255.255.255.0" + /// "192.168.0.0-192.168.0.255" /// [Serializable] + // ReSharper disable once InconsistentNaming public class IPAddressRange : ISerializable { - public IPAddress Begin { get; set; } - - public IPAddress End { get; set; } - public IPAddressRange() { - this.Begin = new IPAddress(0L); - this.End = new IPAddress(0L); + Begin = new IPAddress(0L); + End = new IPAddress(0L); } public IPAddressRange(string ipRangeString) @@ -44,8 +39,8 @@ public IPAddressRange(string ipRangeString) var baseAdrBytes = IPAddress.Parse(m1.Groups["adr"].Value).GetAddressBytes(); var maskBytes = Bits.GetBitMask(baseAdrBytes.Length, int.Parse(m1.Groups["maskLen"].Value)); baseAdrBytes = Bits.And(baseAdrBytes, maskBytes); - this.Begin = new IPAddress(baseAdrBytes); - this.End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); + Begin = new IPAddress(baseAdrBytes); + End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); return; } @@ -53,28 +48,30 @@ public IPAddressRange(string ipRangeString) var m2 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)$", RegexOptions.IgnoreCase); if (m2.Success) { - this.Begin = this.End = IPAddress.Parse(ipRangeString); + Begin = End = IPAddress.Parse(ipRangeString); return; } // Pattern 3. Begin end range: "169.258.0.0-169.258.0.255" - var m3 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)-(?[\da-f\.:]+)$", RegexOptions.IgnoreCase); + var m3 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)-(?[\da-f\.:]+)$", + RegexOptions.IgnoreCase); if (m3.Success) { - this.Begin = IPAddress.Parse(m3.Groups["begin"].Value); - this.End = IPAddress.Parse(m3.Groups["end"].Value); + Begin = IPAddress.Parse(m3.Groups["begin"].Value); + End = IPAddress.Parse(m3.Groups["end"].Value); return; } // Pattern 4. Bit mask range: "192.168.0.0/255.255.255.0" - var m4 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)/(?[\da-f\.:]+)$", RegexOptions.IgnoreCase); + var m4 = Regex.Match(ipRangeString, @"^(?[\da-f\.:]+)/(?[\da-f\.:]+)$", + RegexOptions.IgnoreCase); if (m4.Success) { var baseAdrBytes = IPAddress.Parse(m4.Groups["adr"].Value).GetAddressBytes(); var maskBytes = IPAddress.Parse(m4.Groups["bitmask"].Value).GetAddressBytes(); baseAdrBytes = Bits.And(baseAdrBytes, maskBytes); - this.Begin = new IPAddress(baseAdrBytes); - this.End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); + Begin = new IPAddress(baseAdrBytes); + End = new IPAddress(Bits.Or(baseAdrBytes, Bits.Not(maskBytes))); return; } @@ -86,25 +83,29 @@ protected IPAddressRange(SerializationInfo info, StreamingContext context) var names = new List(); foreach (var item in info) names.Add(item.Name); - Func deserialize = (name) => names.Contains(name) ? - IPAddress.Parse(info.GetValue(name, typeof(object)).ToString()) : - new IPAddress(0L); + Func deserialize = name => names.Contains(name) + ? IPAddress.Parse(info.GetValue(name, typeof(object)).ToString()) + : new IPAddress(0L); - this.Begin = deserialize("Begin"); - this.End = deserialize("End"); + Begin = deserialize("Begin"); + End = deserialize("End"); } - public bool Contains(IPAddress ipaddress) + public IPAddress Begin { get; set; } + + public IPAddress End { get; set; } + + public void GetObjectData(SerializationInfo info, StreamingContext context) { - if (ipaddress.AddressFamily != this.Begin.AddressFamily) return false; - var adrBytes = ipaddress.GetAddressBytes(); - return Bits.GE(this.Begin.GetAddressBytes(), adrBytes) && Bits.LE(this.End.GetAddressBytes(), adrBytes); + info.AddValue("Begin", Begin?.ToString() ?? ""); + info.AddValue("End", End?.ToString() ?? ""); } - public void GetObjectData(SerializationInfo info, StreamingContext context) + public bool Contains(IPAddress ipaddress) { - info.AddValue("Begin", this.Begin != null ? this.Begin.ToString() : ""); - info.AddValue("End", this.End != null ? this.End.ToString() : ""); + if (ipaddress.AddressFamily != Begin.AddressFamily) return false; + var adrBytes = ipaddress.GetAddressBytes(); + return Bits.GE(Begin.GetAddressBytes(), adrBytes) && Bits.LE(End.GetAddressBytes(), adrBytes); } } @@ -112,31 +113,31 @@ internal static class Bits { internal static byte[] Not(byte[] bytes) { - return bytes.Select(b => (byte)~b).ToArray(); + return bytes.Select(b => (byte) ~b).ToArray(); } internal static byte[] And(byte[] A, byte[] B) { - return A.Zip(B, (a, b) => (byte)(a & b)).ToArray(); + return A.Zip(B, (a, b) => (byte) (a & b)).ToArray(); } internal static byte[] Or(byte[] A, byte[] B) { - return A.Zip(B, (a, b) => (byte)(a | b)).ToArray(); + return A.Zip(B, (a, b) => (byte) (a | b)).ToArray(); } internal static bool GE(byte[] A, byte[] B) { return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1) - .SkipWhile(c => c == 0) - .FirstOrDefault() >= 0; + .SkipWhile(c => c == 0) + .FirstOrDefault() >= 0; } internal static bool LE(byte[] A, byte[] B) { return A.Zip(B, (a, b) => a == b ? 0 : a < b ? 1 : -1) - .SkipWhile(c => c == 0) - .FirstOrDefault() <= 0; + .SkipWhile(c => c == 0) + .FirstOrDefault() <= 0; } internal static byte[] GetBitMask(int sizeOfBuff, int bitLen) @@ -144,13 +145,12 @@ internal static byte[] GetBitMask(int sizeOfBuff, int bitLen) var maskBytes = new byte[sizeOfBuff]; var bytesLen = bitLen / 8; var bitsLen = bitLen % 8; - for (int i = 0; i < bytesLen; i++) - { + for (var i = 0; i < bytesLen; i++) maskBytes[i] = 0xff; - } - if (bitsLen > 0) maskBytes[bytesLen] = (byte)~Enumerable.Range(1, 8 - bitsLen).Select(n => 1 << n - 1).Aggregate((a, b) => a | b); + if (bitsLen > 0) + maskBytes[bytesLen] = (byte) ~Enumerable.Range(1, 8 - bitsLen).Select(n => 1 << (n - 1)) + .Aggregate((a, b) => a | b); return maskBytes; } - } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/RateLimitPeriod.cs b/WebApiThrottle/Models/RateLimitPeriod.cs index 00efff6..93937fd 100644 --- a/WebApiThrottle/Models/RateLimitPeriod.cs +++ b/WebApiThrottle/Models/RateLimitPeriod.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WebApiThrottle +namespace WebApiThrottle.Models { public enum RateLimitPeriod { @@ -14,4 +8,4 @@ public enum RateLimitPeriod Day, Week } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/RateLimits.cs b/WebApiThrottle/Models/RateLimits.cs index ec4da3c..2a824d9 100644 --- a/WebApiThrottle/Models/RateLimits.cs +++ b/WebApiThrottle/Models/RateLimits.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { [Serializable] public class RateLimits @@ -38,4 +34,4 @@ public long GetLimit(RateLimitPeriod period) } } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/RequestIdentity.cs b/WebApiThrottle/Models/RequestIdentity.cs index a681ba3..54c93ea 100644 --- a/WebApiThrottle/Models/RequestIdentity.cs +++ b/WebApiThrottle/Models/RequestIdentity.cs @@ -1,13 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { /// - /// Stores the client IP, key and endpoint + /// Stores the client IP, key and endpoint /// [Serializable] public class RequestIdentity @@ -20,4 +16,4 @@ public class RequestIdentity public bool ForceWhiteList { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/ThrottleCounter.cs b/WebApiThrottle/Models/ThrottleCounter.cs index 64ba3b1..8859c0c 100644 --- a/WebApiThrottle/Models/ThrottleCounter.cs +++ b/WebApiThrottle/Models/ThrottleCounter.cs @@ -1,13 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { /// - /// Stores the initial access time and the numbers of calls made from that point + /// Stores the initial access time and the numbers of calls made from that point /// [Serializable] public struct ThrottleCounter @@ -16,4 +12,4 @@ public struct ThrottleCounter public long TotalRequests { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/ThrottlePolicyRule.cs b/WebApiThrottle/Models/ThrottlePolicyRule.cs index 6408c23..96d9fe7 100644 --- a/WebApiThrottle/Models/ThrottlePolicyRule.cs +++ b/WebApiThrottle/Models/ThrottlePolicyRule.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { [Serializable] public class ThrottlePolicyRule @@ -23,4 +19,4 @@ public class ThrottlePolicyRule public ThrottlePolicyType PolicyType { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/ThrottlePolicySettings.cs b/WebApiThrottle/Models/ThrottlePolicySettings.cs index 9cf30f7..a11a0f8 100644 --- a/WebApiThrottle/Models/ThrottlePolicySettings.cs +++ b/WebApiThrottle/Models/ThrottlePolicySettings.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { [Serializable] public class ThrottlePolicySettings @@ -27,4 +23,4 @@ public class ThrottlePolicySettings public bool StackBlockedRequests { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/ThrottlePolicyType.cs b/WebApiThrottle/Models/ThrottlePolicyType.cs index 6a7cda3..9f8b9e2 100644 --- a/WebApiThrottle/Models/ThrottlePolicyType.cs +++ b/WebApiThrottle/Models/ThrottlePolicyType.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WebApiThrottle +namespace WebApiThrottle.Models { - public enum ThrottlePolicyType : int + public enum ThrottlePolicyType { IpThrottling = 1, ClientThrottling, EndpointThrottling } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Models/ThrottlePolicyWhitelist.cs b/WebApiThrottle/Models/ThrottlePolicyWhitelist.cs index cca55f9..18cb434 100644 --- a/WebApiThrottle/Models/ThrottlePolicyWhitelist.cs +++ b/WebApiThrottle/Models/ThrottlePolicyWhitelist.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace WebApiThrottle +namespace WebApiThrottle.Models { [Serializable] public class ThrottlePolicyWhitelist @@ -13,4 +9,4 @@ public class ThrottlePolicyWhitelist public ThrottlePolicyType PolicyType { get; set; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Net/DefaultIpAddressParser.cs b/WebApiThrottle/Net/DefaultIpAddressParser.cs index 476fefa..72f1bfa 100644 --- a/WebApiThrottle/Net/DefaultIpAddressParser.cs +++ b/WebApiThrottle/Net/DefaultIpAddressParser.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; -using System.ServiceModel.Channels; -using System.Web; namespace WebApiThrottle.Net { @@ -27,6 +25,5 @@ public IPAddress ParseIp(string ipAddress) { return IpAddressUtil.ParseIp(ipAddress); } - } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Net/HttpRequestExtensions.cs b/WebApiThrottle/Net/HttpRequestExtensions.cs index 1ab8b65..77fec31 100644 --- a/WebApiThrottle/Net/HttpRequestExtensions.cs +++ b/WebApiThrottle/Net/HttpRequestExtensions.cs @@ -1,61 +1,48 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Net; using System.Net.Http; using System.ServiceModel.Channels; using System.Web; +using Microsoft.Owin; namespace WebApiThrottle.Net { public static class HttpRequestExtensions { /// - /// /// /// /// public static string GetClientIpAddress(this HttpRequestMessage request) { // Always return all zeroes for any failure (my calling code expects it) - string ipAddress = "0.0.0.0"; + var ipAddress = "0.0.0.0"; if (request.Properties.ContainsKey("MS_HttpContext")) - { - ipAddress = ((HttpContextBase)request.Properties["MS_HttpContext"]).Request.UserHostAddress; - } + ipAddress = ((HttpContextBase) request.Properties["MS_HttpContext"]).Request.UserHostAddress; else if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name)) - { - ipAddress = ((RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name]).Address; - } + ipAddress = ((RemoteEndpointMessageProperty) request.Properties[RemoteEndpointMessageProperty.Name]) + .Address; if (request.Properties.ContainsKey("MS_OwinContext")) - { - ipAddress = ((Microsoft.Owin.OwinContext) request.Properties["MS_OwinContext"]).Request.RemoteIpAddress; - } + ipAddress = ((OwinContext) request.Properties["MS_OwinContext"]).Request.RemoteIpAddress; // get the X-Forward-For headers (should only really be one) - IEnumerable xForwardForList; - if (!request.Headers.TryGetValues("X-Forwarded-For", out xForwardForList)) - { - return ipAddress; - } + if (!request.Headers.TryGetValues("X-Forwarded-For", out IEnumerable xForwardForList)) + return ipAddress; var xForwardedFor = xForwardForList.FirstOrDefault(); // check that we have a value if (string.IsNullOrEmpty(xForwardedFor)) - { return ipAddress; - } // Get a list of public ip addresses in the X_FORWARDED_FOR variable - var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IpAddressUtil.IsPrivateIpAddress(ip)).ToList(); + var publicForwardingIps = xForwardedFor.Split(',').Where(ip => !IpAddressUtil.IsPrivateIpAddress(ip)) + .ToList(); // If we found any, return the last one, otherwise return the user host address return publicForwardingIps.Any() ? publicForwardingIps.Last() : ipAddress; - } - } } \ No newline at end of file diff --git a/WebApiThrottle/Net/IIpAddressParser.cs b/WebApiThrottle/Net/IIpAddressParser.cs index 4ebe0c5..f7a5b07 100644 --- a/WebApiThrottle/Net/IIpAddressParser.cs +++ b/WebApiThrottle/Net/IIpAddressParser.cs @@ -14,4 +14,4 @@ public interface IIpAddressParser IPAddress ParseIp(string ipAddress); } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Net/IpAddressUtil.cs b/WebApiThrottle/Net/IpAddressUtil.cs index a7dd73a..abdbd86 100644 --- a/WebApiThrottle/Net/IpAddressUtil.cs +++ b/WebApiThrottle/Net/IpAddressUtil.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Net; +using WebApiThrottle.Models; namespace WebApiThrottle.Net { @@ -11,16 +11,12 @@ public class IpAddressUtil public static bool ContainsIp(List ipRules, string clientIp) { var ip = ParseIp(clientIp); - if (ipRules != null && ipRules.Any()) + if (ipRules == null || !ipRules.Any()) return false; + foreach (var rule in ipRules) { - foreach (var rule in ipRules) - { - var range = new IPAddressRange(rule); - if (range.Contains(ip)) - { - return true; - } - } + var range = new IPAddressRange(rule); + if (range.Contains(ip)) + return true; } return false; @@ -30,17 +26,13 @@ public static bool ContainsIp(List ipRules, string clientIp, out string { rule = null; var ip = ParseIp(clientIp); - if (ipRules != null && ipRules.Any()) + if (ipRules == null || !ipRules.Any()) return false; + foreach (var r in ipRules) { - foreach (var r in ipRules) - { - var range = new IPAddressRange(r); - if (range.Contains(ip)) - { - rule = r; - return true; - } - } + var range = new IPAddressRange(r); + if (!range.Contains(ip)) continue; + rule = r; + return true; } return false; @@ -49,16 +41,14 @@ public static bool ContainsIp(List ipRules, string clientIp, out string public static IPAddress ParseIp(string ipAddress) { ipAddress = ipAddress.Trim(); - int portDelimiterPos = ipAddress.LastIndexOf(":", StringComparison.InvariantCultureIgnoreCase); - bool ipv6WithPortStart = ipAddress.StartsWith("["); - int ipv6End = ipAddress.IndexOf("]"); + var portDelimiterPos = ipAddress.LastIndexOf(":", StringComparison.InvariantCultureIgnoreCase); + var ipv6WithPortStart = ipAddress.StartsWith("["); + var ipv6End = ipAddress.IndexOf("]"); if (portDelimiterPos != -1 && portDelimiterPos == ipAddress.IndexOf(":", StringComparison.InvariantCultureIgnoreCase) || ipv6WithPortStart && ipv6End != -1 && ipv6End < portDelimiterPos) - { ipAddress = ipAddress.Substring(0, portDelimiterPos); - } - + return IPAddress.Parse(ipAddress); } @@ -74,27 +64,24 @@ public static bool IsPrivateIpAddress(string ipAddress) var ip = ParseIp(ipAddress); var octets = ip.GetAddressBytes(); - bool isIpv6 = octets.Length == 16; + var isIpv6 = octets.Length == 16; if (isIpv6) { - bool isUniqueLocalAddress = octets[0] == 253; + var isUniqueLocalAddress = octets[0] == 253; return isUniqueLocalAddress; } - else - { - var is24BitBlock = octets[0] == 10; - if (is24BitBlock) return true; // Return to prevent further processing + var is24BitBlock = octets[0] == 10; + if (is24BitBlock) return true; // Return to prevent further processing - var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31; - if (is20BitBlock) return true; // Return to prevent further processing + var is20BitBlock = octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31; + if (is20BitBlock) return true; // Return to prevent further processing - var is16BitBlock = octets[0] == 192 && octets[1] == 168; - if (is16BitBlock) return true; // Return to prevent further processing + var is16BitBlock = octets[0] == 192 && octets[1] == 168; + if (is16BitBlock) return true; // Return to prevent further processing - var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254; - return isLinkLocalAddress; - } + var isLinkLocalAddress = octets[0] == 169 && octets[1] == 254; + return isLinkLocalAddress; } } } \ No newline at end of file diff --git a/WebApiThrottle/Properties/AssemblyInfo.cs b/WebApiThrottle/Properties/AssemblyInfo.cs index 950c1c4..2879c77 100644 --- a/WebApiThrottle/Properties/AssemblyInfo.cs +++ b/WebApiThrottle/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -33,4 +32,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.4.0.0")] -[assembly: AssemblyFileVersion("1.4.0.0")] +[assembly: AssemblyFileVersion("1.4.0.0")] \ No newline at end of file diff --git a/WebApiThrottle/Providers/IThrottlePolicyProvider.cs b/WebApiThrottle/Providers/IThrottlePolicyProvider.cs index d56650e..511b4d9 100644 --- a/WebApiThrottle/Providers/IThrottlePolicyProvider.cs +++ b/WebApiThrottle/Providers/IThrottlePolicyProvider.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Providers { /// - /// Implement this interface if you want to load the policy rules from a persistent store + /// Implement this interface if you want to load the policy rules from a persistent store /// public interface IThrottlePolicyProvider { @@ -17,4 +14,4 @@ public interface IThrottlePolicyProvider IEnumerable AllWhitelists(); } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Providers/PolicyConfigurationProvider.cs b/WebApiThrottle/Providers/PolicyConfigurationProvider.cs index c7df3ab..e7bd59f 100644 --- a/WebApiThrottle/Providers/PolicyConfigurationProvider.cs +++ b/WebApiThrottle/Providers/PolicyConfigurationProvider.cs @@ -1,34 +1,32 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Configuration; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Configuration; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Providers { public class PolicyConfigurationProvider : IThrottlePolicyProvider { - private readonly ThrottlePolicyConfiguration policyConfig; + private readonly ThrottlePolicyConfiguration _policyConfig; public PolicyConfigurationProvider() { - this.policyConfig = ConfigurationManager.GetSection("throttlePolicy") as ThrottlePolicyConfiguration; + _policyConfig = ConfigurationManager.GetSection("throttlePolicy") as ThrottlePolicyConfiguration; } public ThrottlePolicySettings ReadSettings() { - var settings = new ThrottlePolicySettings() + var settings = new ThrottlePolicySettings { - IpThrottling = policyConfig.IpThrottling, - ClientThrottling = policyConfig.ClientThrottling, - EndpointThrottling = policyConfig.EndpointThrottling, - StackBlockedRequests = policyConfig.StackBlockedRequests, - LimitPerSecond = policyConfig.LimitPerSecond, - LimitPerMinute = policyConfig.LimitPerMinute, - LimitPerHour = policyConfig.LimitPerHour, - LimitPerDay = policyConfig.LimitPerDay, - LimitPerWeek = policyConfig.LimitPerWeek + IpThrottling = _policyConfig.IpThrottling, + ClientThrottling = _policyConfig.ClientThrottling, + EndpointThrottling = _policyConfig.EndpointThrottling, + StackBlockedRequests = _policyConfig.StackBlockedRequests, + LimitPerSecond = _policyConfig.LimitPerSecond, + LimitPerMinute = _policyConfig.LimitPerMinute, + LimitPerHour = _policyConfig.LimitPerHour, + LimitPerDay = _policyConfig.LimitPerDay, + LimitPerWeek = _policyConfig.LimitPerWeek }; return settings; @@ -37,41 +35,33 @@ public ThrottlePolicySettings ReadSettings() public IEnumerable AllRules() { var rules = new List(); - if (policyConfig.Rules != null) - { - foreach (ThrottlePolicyRuleConfigurationElement rule in policyConfig.Rules) - { + if (_policyConfig.Rules != null) + foreach (ThrottlePolicyRuleConfigurationElement rule in _policyConfig.Rules) rules.Add(new ThrottlePolicyRule { Entry = rule.Entry, - PolicyType = (ThrottlePolicyType)rule.PolicyType, + PolicyType = (ThrottlePolicyType) rule.PolicyType, LimitPerSecond = rule.LimitPerSecond, LimitPerMinute = rule.LimitPerMinute, LimitPerHour = rule.LimitPerHour, LimitPerDay = rule.LimitPerDay, LimitPerWeek = rule.LimitPerWeek }); - } - } return rules; } public IEnumerable AllWhitelists() { var whitelists = new List(); - if (policyConfig.Whitelists != null) - { - foreach (ThrottlePolicyWhitelistConfigurationElement whitelist in policyConfig.Whitelists) - { + if (_policyConfig.Whitelists != null) + foreach (ThrottlePolicyWhitelistConfigurationElement whitelist in _policyConfig.Whitelists) whitelists.Add(new ThrottlePolicyWhitelist { Entry = whitelist.Entry, - PolicyType = (ThrottlePolicyType)whitelist.PolicyType, + PolicyType = (ThrottlePolicyType) whitelist.PolicyType }); - } - } return whitelists; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/CacheRepository.cs b/WebApiThrottle/Repositories/CacheRepository.cs index 7bf88e2..1bfc199 100644 --- a/WebApiThrottle/Repositories/CacheRepository.cs +++ b/WebApiThrottle/Repositories/CacheRepository.cs @@ -1,38 +1,32 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Web; using System.Web.Caching; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Stores throttle metrics in asp.net cache + /// Stores throttle metrics in asp.net cache /// public class CacheRepository : IThrottleRepository { /// - /// Insert or update + /// Insert or update /// /// - /// The id. + /// The id. /// /// - /// The throttle Counter. + /// The throttle Counter. /// /// - /// The expiration Time. + /// The expiration Time. /// public void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime) { if (HttpContext.Current.Cache[id] != null) - { HttpContext.Current.Cache[id] = throttleCounter; - } else - { HttpContext.Current.Cache.Add( id, throttleCounter, @@ -41,7 +35,6 @@ public void Save(string id, ThrottleCounter throttleCounter, TimeSpan expiration expirationTime, CacheItemPriority.Low, null); - } } public bool Any(string id) @@ -51,7 +44,7 @@ public bool Any(string id) public ThrottleCounter? FirstOrDefault(string id) { - return (ThrottleCounter?)HttpContext.Current.Cache[id]; + return (ThrottleCounter?) HttpContext.Current.Cache[id]; } public void Remove(string id) @@ -63,12 +56,8 @@ public void Clear() { var cacheEnumerator = HttpContext.Current.Cache.GetEnumerator(); while (cacheEnumerator.MoveNext()) - { if (cacheEnumerator.Value is ThrottleCounter) - { HttpContext.Current.Cache.Remove(cacheEnumerator.Key.ToString()); - } - } } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs b/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs index 305db01..5481611 100644 --- a/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs +++ b/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs @@ -1,18 +1,17 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Stores throttle metrics in a thread safe dictionary, has no clean-up mechanism, expired counters are deleted on renewal + /// Stores throttle metrics in a thread safe dictionary, has no clean-up mechanism, expired counters are deleted on + /// renewal /// - public class ConcurrentDictionaryRepository : IThrottleRepository + public partial class ConcurrentDictionaryRepository : IThrottleRepository { - private static ConcurrentDictionary cache = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary cache = + new ConcurrentDictionary(); public bool Any(string id) { @@ -20,33 +19,32 @@ public bool Any(string id) } /// - /// Insert or update + /// Insert or update /// /// - /// The id. + /// The id. /// /// - /// The . + /// The . /// public ThrottleCounter? FirstOrDefault(string id) { - var entry = new ThrottleCounterWrapper(); + ThrottleCounterWrapper entry; - if (cache.TryGetValue(id, out entry)) - { - // remove expired entry - if (entry.Timestamp + entry.ExpirationTime < DateTime.UtcNow) + if (!cache.TryGetValue(id, out entry)) + return new ThrottleCounter { - cache.TryRemove(id, out entry); - return null; - } - } - - return new ThrottleCounter - { - Timestamp = entry.Timestamp, - TotalRequests = entry.TotalRequests - }; + Timestamp = entry.Timestamp, + TotalRequests = entry.TotalRequests + }; + if (entry.Timestamp + entry.ExpirationTime >= DateTime.UtcNow) + return new ThrottleCounter + { + Timestamp = entry.Timestamp, + TotalRequests = entry.TotalRequests + }; + cache.TryRemove(id, out entry); + return null; } public void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime) @@ -63,23 +61,12 @@ public void Save(string id, ThrottleCounter throttleCounter, TimeSpan expiration public void Remove(string id) { - var entry = new ThrottleCounterWrapper(); - cache.TryRemove(id, out entry); + cache.TryRemove(id, out ThrottleCounterWrapper entry); } public void Clear() { cache.Clear(); } - - [Serializable] - internal struct ThrottleCounterWrapper - { - public DateTime Timestamp { get; set; } - - public long TotalRequests { get; set; } - - public TimeSpan ExpirationTime { get; set; } - } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/IPolicyRepository.cs b/WebApiThrottle/Repositories/IPolicyRepository.cs index bba837e..84027e6 100644 --- a/WebApiThrottle/Repositories/IPolicyRepository.cs +++ b/WebApiThrottle/Repositories/IPolicyRepository.cs @@ -1,5 +1,4 @@ -using System; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { public interface IPolicyRepository { @@ -9,4 +8,4 @@ public interface IPolicyRepository void Save(string id, ThrottlePolicy policy); } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/IThrottleRepository.cs b/WebApiThrottle/Repositories/IThrottleRepository.cs index 2175593..23202be 100644 --- a/WebApiThrottle/Repositories/IThrottleRepository.cs +++ b/WebApiThrottle/Repositories/IThrottleRepository.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Implement this interface if you want to create a persistent store for the throttle metrics + /// Implement this interface if you want to create a persistent store for the throttle metrics /// public interface IThrottleRepository { @@ -21,4 +18,4 @@ public interface IThrottleRepository void Clear(); } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/MemoryCacheRepository.cs b/WebApiThrottle/Repositories/MemoryCacheRepository.cs index 5c20a35..6159e3a 100644 --- a/WebApiThrottle/Repositories/MemoryCacheRepository.cs +++ b/WebApiThrottle/Repositories/MemoryCacheRepository.cs @@ -1,61 +1,53 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Runtime.Caching; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Models; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Stors throttle metrics in runtime cache, intented for owin self host. + /// Stors throttle metrics in runtime cache, intented for owin self host. /// public class MemoryCacheRepository : IThrottleRepository { - ObjectCache memCache = MemoryCache.Default; + private readonly ObjectCache _memCache = MemoryCache.Default; /// - /// Insert or update + /// Insert or update /// public void Save(string id, ThrottleCounter throttleCounter, TimeSpan expirationTime) { - if (memCache[id] != null) - { - memCache[id] = throttleCounter; - } + if (_memCache[id] != null) + _memCache[id] = throttleCounter; else - { - memCache.Add( + _memCache.Add( id, - throttleCounter, new CacheItemPolicy() + throttleCounter, new CacheItemPolicy { SlidingExpiration = expirationTime }); - } } public bool Any(string id) { - return memCache[id] != null; + return _memCache[id] != null; } public ThrottleCounter? FirstOrDefault(string id) { - return (ThrottleCounter?)memCache[id]; + return (ThrottleCounter?) _memCache[id]; } public void Remove(string id) { - memCache.Remove(id); + _memCache.Remove(id); } public void Clear() { - var cacheKeys = memCache.Where(kvp => kvp.Value is ThrottleCounter).Select(kvp => kvp.Key).ToList(); - foreach (string cacheKey in cacheKeys) - { - memCache.Remove(cacheKey); - } + var cacheKeys = _memCache.Where(kvp => kvp.Value is ThrottleCounter).Select(kvp => kvp.Key).ToList(); + foreach (var cacheKey in cacheKeys) + _memCache.Remove(cacheKey); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/PolicyCacheRepository.cs b/WebApiThrottle/Repositories/PolicyCacheRepository.cs index 548cb1e..0d105ce 100644 --- a/WebApiThrottle/Repositories/PolicyCacheRepository.cs +++ b/WebApiThrottle/Repositories/PolicyCacheRepository.cs @@ -1,26 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web; +using System.Web; using System.Web.Caching; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Stores policy in asp.net cache + /// Stores policy in asp.net cache /// public class PolicyCacheRepository : IPolicyRepository { public void Save(string id, ThrottlePolicy policy) { if (HttpContext.Current.Cache[id] != null) - { HttpContext.Current.Cache[id] = policy; - } else - { HttpContext.Current.Cache.Add( id, policy, @@ -29,12 +21,11 @@ public void Save(string id, ThrottlePolicy policy) Cache.NoSlidingExpiration, CacheItemPriority.High, null); - } } public ThrottlePolicy FirstOrDefault(string id) { - var policy = (ThrottlePolicy)HttpContext.Current.Cache[id]; + var policy = (ThrottlePolicy) HttpContext.Current.Cache[id]; return policy; } @@ -43,4 +34,4 @@ public void Remove(string id) HttpContext.Current.Cache.Remove(id); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/PolicyMemoryCacheRepository.cs b/WebApiThrottle/Repositories/PolicyMemoryCacheRepository.cs index dff2e35..7ef21ca 100644 --- a/WebApiThrottle/Repositories/PolicyMemoryCacheRepository.cs +++ b/WebApiThrottle/Repositories/PolicyMemoryCacheRepository.cs @@ -1,43 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Caching; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.Caching; -namespace WebApiThrottle +namespace WebApiThrottle.Repositories { /// - /// Stores policy in runtime cache, intended for OWIN self host. + /// Stores policy in runtime cache, intended for OWIN self host. /// public class PolicyMemoryCacheRepository : IPolicyRepository { - private ObjectCache memCache = MemoryCache.Default; + private readonly ObjectCache _memCache = MemoryCache.Default; public void Save(string id, ThrottlePolicy policy) { - if (memCache[id] != null) - { - memCache[id] = policy; - } + if (_memCache[id] != null) + _memCache[id] = policy; else - { - memCache.Add( + _memCache.Add( id, - policy, + policy, new CacheItemPolicy()); - } } public ThrottlePolicy FirstOrDefault(string id) { - var policy = (ThrottlePolicy)memCache[id]; + var policy = (ThrottlePolicy) _memCache[id]; return policy; } public void Remove(string id) { - memCache.Remove(id); + _memCache.Remove(id); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/Repositories/ThrottleCounterWrapper.cs b/WebApiThrottle/Repositories/ThrottleCounterWrapper.cs new file mode 100644 index 0000000..4fbf570 --- /dev/null +++ b/WebApiThrottle/Repositories/ThrottleCounterWrapper.cs @@ -0,0 +1,17 @@ +using System; + +namespace WebApiThrottle.Repositories +{ + public partial class ConcurrentDictionaryRepository + { + [Serializable] + private struct ThrottleCounterWrapper + { + public DateTime Timestamp { get; set; } + + public long TotalRequests { get; set; } + + public TimeSpan ExpirationTime { get; set; } + } + } +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottleManager.cs b/WebApiThrottle/ThrottleManager.cs index f2e9978..cdbf7f3 100644 --- a/WebApiThrottle/ThrottleManager.cs +++ b/WebApiThrottle/ThrottleManager.cs @@ -1,75 +1,33 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Providers; +using WebApiThrottle.Repositories; namespace WebApiThrottle { /// - /// Allows changing the cache keys prefix and suffix, exposes ways to refresh the policy object at runtime. + /// Allows changing the cache keys prefix and suffix, exposes ways to refresh the policy object at runtime. /// public static class ThrottleManager { - private static string applicationName = string.Empty; - - private static string throttleKey = "throttle"; - - private static string policyKey = "throttle_policy"; - /// - /// Gets or sets the global prefix + /// Gets or sets the global prefix /// - public static string ApplicationName - { - get - { - return applicationName; - } - - set - { - applicationName = value; - } - } + public static string ApplicationName { get; set; } = string.Empty; /// - /// Gets or sets the key prefix for rate limits + /// Gets or sets the key prefix for rate limits /// - public static string ThrottleKey - { - get - { - return throttleKey; - } - - set - { - throttleKey = value; - } - } + public static string ThrottleKey { get; set; } = "throttle"; /// - /// Gets or sets the policy key suffix + /// Gets or sets the policy key suffix /// - public static string PolicyKey - { - get - { - return policyKey; - } - - set - { - policyKey = value; - } - } + public static string PolicyKey { get; set; } = "throttle_policy"; /// - /// Returns key prefix for rate limits + /// Returns key prefix for rate limits /// /// - /// The throttle key. + /// The throttle key. /// public static string GetThrottleKey() { @@ -77,10 +35,10 @@ public static string GetThrottleKey() } /// - /// Returns the policy key (global prefix + policy key suffix) + /// Returns the policy key (global prefix + policy key suffix) /// /// - /// The policy key. + /// The policy key. /// public static string GetPolicyKey() { @@ -88,13 +46,13 @@ public static string GetPolicyKey() } /// - /// Updates the policy object cached value + /// Updates the policy object cached value /// /// - /// The policy. + /// The policy. /// /// - /// The policy repository. + /// The policy repository. /// public static void UpdatePolicy(ThrottlePolicy policy, IPolicyRepository cacheRepository) { @@ -102,13 +60,13 @@ public static void UpdatePolicy(ThrottlePolicy policy, IPolicyRepository cacheRe } /// - /// Reads the policy object from store and updates the cache + /// Reads the policy object from store and updates the cache /// /// - /// The store provider. + /// The store provider. /// /// - /// The cache repository. + /// The cache repository. /// public static void UpdatePolicy(IThrottlePolicyProvider storeProvider, IPolicyRepository cacheRepository) { @@ -116,4 +74,4 @@ public static void UpdatePolicy(IThrottlePolicyProvider storeProvider, IPolicyRe cacheRepository.Save(GetPolicyKey(), policy); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottlePolicy.cs b/WebApiThrottle/ThrottlePolicy.cs index 80894f7..7fee7bd 100644 --- a/WebApiThrottle/ThrottlePolicy.cs +++ b/WebApiThrottle/ThrottlePolicy.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using WebApiThrottle.Models; +using WebApiThrottle.Providers; namespace WebApiThrottle { /// - /// Rate limits policy + /// Rate limits policy /// [Serializable] public class ThrottlePolicy @@ -24,41 +24,32 @@ public ThrottlePolicy() } /// - /// Configure default request limits per second, minute, hour or day + /// Configure default request limits per second, minute, hour or day /// - public ThrottlePolicy(long? perSecond = null, long? perMinute = null, long? perHour = null, long? perDay = null, long? perWeek = null) + public ThrottlePolicy(long? perSecond = null, long? perMinute = null, long? perHour = null, long? perDay = null, + long? perWeek = null) : this() { Rates = new Dictionary(); if (perSecond.HasValue) - { Rates.Add(RateLimitPeriod.Second, perSecond.Value); - } if (perMinute.HasValue) - { Rates.Add(RateLimitPeriod.Minute, perMinute.Value); - } if (perHour.HasValue) - { Rates.Add(RateLimitPeriod.Hour, perHour.Value); - } if (perDay.HasValue) - { Rates.Add(RateLimitPeriod.Day, perDay.Value); - } if (perWeek.HasValue) - { Rates.Add(RateLimitPeriod.Week, perWeek.Value); - } } /// - /// Gets or sets a value indicating whether IP throttling is enabled. + /// Gets or sets a value indicating whether IP throttling is enabled. /// public bool IpThrottling { get; set; } @@ -67,7 +58,7 @@ public ThrottlePolicy(long? perSecond = null, long? perMinute = null, long? perH public IDictionary IpRules { get; set; } /// - /// Gets or sets a value indicating whether client key throttling is enabled. + /// Gets or sets a value indicating whether client key throttling is enabled. /// public bool ClientThrottling { get; set; } @@ -76,7 +67,7 @@ public ThrottlePolicy(long? perSecond = null, long? perMinute = null, long? perH public IDictionary ClientRules { get; set; } /// - /// Gets or sets a value indicating whether route throttling is enabled + /// Gets or sets a value indicating whether route throttling is enabled /// public bool EndpointThrottling { get; set; } @@ -85,7 +76,8 @@ public ThrottlePolicy(long? perSecond = null, long? perMinute = null, long? perH public IDictionary EndpointRules { get; set; } /// - /// Gets or sets a value indicating whether all requests, including the rejected ones, should be stacked in this order: day, hour, min, sec + /// Gets or sets a value indicating whether all requests, including the rejected ones, should be stacked in this order: + /// day, hour, min, sec /// public bool StackBlockedRequests { get; set; } @@ -98,34 +90,34 @@ public static ThrottlePolicy FromStore(IThrottlePolicyProvider provider) var rules = provider.AllRules(); var policy = new ThrottlePolicy( - perSecond: settings.LimitPerSecond, - perMinute: settings.LimitPerMinute, - perHour: settings.LimitPerHour, - perDay: settings.LimitPerDay, - perWeek: settings.LimitPerWeek); - - policy.IpThrottling = settings.IpThrottling; - policy.ClientThrottling = settings.ClientThrottling; - policy.EndpointThrottling = settings.EndpointThrottling; - policy.StackBlockedRequests = settings.StackBlockedRequests; - - policy.IpRules = new Dictionary(); - policy.ClientRules = new Dictionary(); - policy.EndpointRules = new Dictionary(); - policy.EndpointWhitelist = new List(); - policy.IpWhitelist = new List(); - policy.ClientWhitelist = new List(); + settings.LimitPerSecond, + settings.LimitPerMinute, + settings.LimitPerHour, + settings.LimitPerDay, + settings.LimitPerWeek) + { + IpThrottling = settings.IpThrottling, + ClientThrottling = settings.ClientThrottling, + EndpointThrottling = settings.EndpointThrottling, + StackBlockedRequests = settings.StackBlockedRequests, + IpRules = new Dictionary(), + ClientRules = new Dictionary(), + EndpointRules = new Dictionary(), + EndpointWhitelist = new List(), + IpWhitelist = new List(), + ClientWhitelist = new List() + }; foreach (var item in rules) { var rateLimit = new RateLimits - { - PerSecond = item.LimitPerSecond, - PerMinute = item.LimitPerMinute, - PerHour = item.LimitPerHour, - PerDay = item.LimitPerDay, - PerWeek = item.LimitPerWeek - }; + { + PerSecond = item.LimitPerSecond, + PerMinute = item.LimitPerMinute, + PerHour = item.LimitPerHour, + PerDay = item.LimitPerDay, + PerWeek = item.LimitPerWeek + }; switch (item.PolicyType) { @@ -141,13 +133,16 @@ public static ThrottlePolicy FromStore(IThrottlePolicyProvider provider) } } - if (whitelists != null) - { - policy.IpWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.IpThrottling).Select(x => x.Entry)); - policy.ClientWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.ClientThrottling).Select(x => x.Entry)); - policy.EndpointWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.EndpointThrottling).Select(x => x.Entry)); - } + if (whitelists == null) return policy; + + policy.IpWhitelist.AddRange(whitelists.Where(x => x.PolicyType == ThrottlePolicyType.IpThrottling) + .Select(x => x.Entry)); + policy.ClientWhitelist.AddRange(whitelists + .Where(x => x.PolicyType == ThrottlePolicyType.ClientThrottling).Select(x => x.Entry)); + policy.EndpointWhitelist.AddRange(whitelists + .Where(x => x.PolicyType == ThrottlePolicyType.EndpointThrottling).Select(x => x.Entry)); + return policy; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottlingCore.cs b/WebApiThrottle/ThrottlingCore.cs index 747ca66..55d54f5 100644 --- a/WebApiThrottle/ThrottlingCore.cs +++ b/WebApiThrottle/ThrottlingCore.cs @@ -1,25 +1,30 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; +using System.Security.Cryptography; using System.Text; +using WebApiThrottle.Logging; +using WebApiThrottle.Models; using WebApiThrottle.Net; +using WebApiThrottle.Repositories; namespace WebApiThrottle { /// - /// Common code shared between ThrottlingHandler and ThrottlingFilter + /// Common code shared between ThrottlingHandler and ThrottlingFilter /// internal class ThrottlingCore { + private static readonly object ProcessLocker = new object(); + public ThrottlingCore() { IpAddressParser = new DefaultIpAddressParser(); } - private static readonly object ProcessLocker = new object(); - internal ThrottlePolicy Policy { get; set; } internal IThrottleRepository Repository { get; set; } @@ -41,7 +46,8 @@ internal IPAddress GetClientIp(HttpRequestMessage request) return IpAddressParser.GetClientIp(request); } - internal ThrottleLogEntry ComputeLogEntry(string requestId, RequestIdentity identity, ThrottleCounter throttleCounter, string rateLimitPeriod, long rateLimit, HttpRequestMessage request) + internal ThrottleLogEntry ComputeLogEntry(string requestId, RequestIdentity identity, + ThrottleCounter throttleCounter, string rateLimitPeriod, long rateLimit, HttpRequestMessage request) { return new ThrottleLogEntry { @@ -78,65 +84,46 @@ internal string RetryAfterFrom(DateTime timestamp, RateLimitPeriod period) break; } retryAfter = retryAfter > 1 ? retryAfter - secondsPast : 1; - return retryAfter.ToString(System.Globalization.CultureInfo.InvariantCulture); + return retryAfter.ToString(CultureInfo.InvariantCulture); } internal bool IsWhitelisted(RequestIdentity requestIdentity) { if (requestIdentity.ForceWhiteList) - { return true; - } if (Policy.IpThrottling) - { if (Policy.IpWhitelist != null && ContainsIp(Policy.IpWhitelist, requestIdentity.ClientIp)) - { return true; - } - } if (Policy.ClientThrottling) - { if (Policy.ClientWhitelist != null && Policy.ClientWhitelist.Contains(requestIdentity.ClientKey)) - { return true; - } - } if (Policy.EndpointThrottling) - { if (Policy.EndpointWhitelist != null - && Policy.EndpointWhitelist.Any(x => requestIdentity.Endpoint.IndexOf(x, 0, StringComparison.InvariantCultureIgnoreCase) != -1)) - { + && Policy.EndpointWhitelist.Any( + x => requestIdentity.Endpoint.IndexOf(x, 0, StringComparison.InvariantCultureIgnoreCase) != -1)) return true; - } - } return false; } internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { - var keyValues = new List() - { - ThrottleManager.GetThrottleKey() - }; + var keyValues = new List + { + 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()); @@ -145,48 +132,39 @@ internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPer byte[] hashBytes; - using (var algorithm = System.Security.Cryptography.HashAlgorithm.Create("SHA1")) + using (var algorithm = HashAlgorithm.Create("SHA1")) { hashBytes = algorithm.ComputeHash(idBytes); } - + var hex = BitConverter.ToString(hashBytes).Replace("-", string.Empty); return hex; } - internal List> RatesWithDefaults(List> defRates) + internal List> RatesWithDefaults( + List> defRates) { - if (!defRates.Any(x => x.Key == RateLimitPeriod.Second)) - { + if (defRates.All(x => x.Key != RateLimitPeriod.Second)) defRates.Insert(0, new KeyValuePair(RateLimitPeriod.Second, 0)); - } - if (!defRates.Any(x => x.Key == RateLimitPeriod.Minute)) - { + if (defRates.All(x => x.Key != RateLimitPeriod.Minute)) defRates.Insert(1, new KeyValuePair(RateLimitPeriod.Minute, 0)); - } - if (!defRates.Any(x => x.Key == RateLimitPeriod.Hour)) - { + if (defRates.All(x => x.Key != RateLimitPeriod.Hour)) defRates.Insert(2, new KeyValuePair(RateLimitPeriod.Hour, 0)); - } - if (!defRates.Any(x => x.Key == RateLimitPeriod.Day)) - { + if (defRates.All(x => x.Key != RateLimitPeriod.Day)) defRates.Insert(3, new KeyValuePair(RateLimitPeriod.Day, 0)); - } - if (!defRates.Any(x => x.Key == RateLimitPeriod.Week)) - { + if (defRates.All(x => x.Key != RateLimitPeriod.Week)) defRates.Insert(4, new KeyValuePair(RateLimitPeriod.Week, 0)); - } return defRates; } internal ThrottleCounter ProcessRequest(TimeSpan timeSpan, string id) { - var throttleCounter = new ThrottleCounter() + var throttleCounter = new ThrottleCounter { Timestamp = DateTime.UtcNow, TotalRequests = 1 @@ -197,8 +175,6 @@ internal ThrottleCounter ProcessRequest(TimeSpan timeSpan, string id) { var entry = Repository.FirstOrDefault(id); if (entry.HasValue) - { - // entry has not expired if (entry.Value.Timestamp + timeSpan >= DateTime.UtcNow) { // increment request count @@ -211,7 +187,6 @@ internal ThrottleCounter ProcessRequest(TimeSpan timeSpan, string id) TotalRequests = totalRequests }; } - } // stores: id (string) - timestamp (datetime) - total (long) Repository.Save(id, throttleCounter, timeSpan); @@ -246,21 +221,23 @@ internal TimeSpan GetTimeSpanFromPeriod(RateLimitPeriod rateLimitPeriod) return timeSpan; } - internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitPeriod rateLimitPeriod, ref long rateLimit) + internal void ApplyRules(RequestIdentity identity, TimeSpan time, 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 => 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(); + var customRate = + (from r in rules let rateValue = r.Value.GetLimit(rateLimitPeriod) select rateValue).Min(); if (customRate > 0) - { - rateLimit = customRate; - } + rateLimit = customRate; } } @@ -269,21 +246,17 @@ internal void ApplyRules(RequestIdentity identity, TimeSpan timeSpan, RateLimitP { 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)) + if (Policy.IpRules == null || !ContainsIp(Policy.IpRules.Keys.ToList(), identity.ClientIp, + out string ipRule)) return; { var limit = Policy.IpRules[ipRule].GetLimit(rateLimitPeriod); if (limit > 0) - { rateLimit = limit; - } } } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottlingFilter.cs b/WebApiThrottle/ThrottlingFilter.cs index 97dfdf1..9d9bfdf 100644 --- a/WebApiThrottle/ThrottlingFilter.cs +++ b/WebApiThrottle/ThrottlingFilter.cs @@ -1,164 +1,141 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; -using System.Text; -using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Web.Http.Filters; +using WebApiThrottle.Attributes; +using WebApiThrottle.Logging; +using WebApiThrottle.Models; using WebApiThrottle.Net; +using WebApiThrottle.Repositories; namespace WebApiThrottle { /// - /// Throttle action filter + /// Throttle action filter /// + // ReSharper disable once RedundantExtendsListEntry public class ThrottlingFilter : ActionFilterAttribute, IActionFilter { - private readonly ThrottlingCore core; - - private IPolicyRepository policyRepository; - - private ThrottlePolicy policy; + private readonly ThrottlingCore _core; /// - /// Initializes a new instance of the class. - /// By default, the property - /// is set to 429 (Too Many Requests). + /// Initializes a new instance of the class. + /// By default, the property + /// is set to 429 (Too Many Requests). /// public ThrottlingFilter() { - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; Repository = new CacheRepository(); - core = new ThrottlingCore(); + _core = new ThrottlingCore(); } /// - /// Initializes a new instance of the class. - /// Persists the policy object in cache using implementation. - /// The policy object can be updated by at runtime. + /// Initializes a new instance of the class. + /// Persists the policy object in cache using implementation. + /// The policy object can be updated by at runtime. /// /// - /// The policy. + /// The policy. /// /// - /// The policy repository. + /// The policy repository. /// /// - /// The repository. + /// The repository. /// /// - /// The logger. + /// The logger. /// /// - /// The ip address provider + /// The ip address provider /// - public ThrottlingFilter(ThrottlePolicy policy, - IPolicyRepository policyRepository, - IThrottleRepository repository, - IThrottleLogger logger, + public ThrottlingFilter(ThrottlePolicy policy, + IPolicyRepository policyRepository, + IThrottleRepository repository, + IThrottleLogger logger, IIpAddressParser ipAddressParser = null) { - core = new ThrottlingCore(); - core.Repository = repository; + _core = new ThrottlingCore(); + _core.Repository = repository; Repository = repository; Logger = logger; if (ipAddressParser != null) - { - core.IpAddressParser = ipAddressParser; - } + _core.IpAddressParser = ipAddressParser; - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; - this.policy = policy; - this.policyRepository = policyRepository; + Policy = policy; + PolicyRepository = policyRepository; if (policyRepository != null) - { policyRepository.Save(ThrottleManager.GetPolicyKey(), policy); - } } /// - /// Gets or sets a repository used to access throttling rate limits policy. + /// Gets or sets a repository used to access throttling rate limits policy. /// - public IPolicyRepository PolicyRepository - { - get { return policyRepository; } - set { policyRepository = value; } - } + public IPolicyRepository PolicyRepository { get; set; } /// - /// Gets or sets the throttling rate limits policy + /// Gets or sets the throttling rate limits policy /// - public ThrottlePolicy Policy - { - get { return policy; } - set { policy = value; } - } + public ThrottlePolicy Policy { get; set; } /// - /// Gets or sets the throttle metrics storage + /// Gets or sets the throttle metrics storage /// public IThrottleRepository Repository { get; set; } /// - /// Gets or sets an instance of that will log blocked requests + /// Gets or sets an instance of that will log blocked requests /// public IThrottleLogger Logger { get; set; } /// - /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. - /// If none specified the default will be: - /// API calls quota exceeded! maximum admitted {0} per {1} + /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. + /// If none specified the default will be: + /// API calls quota exceeded! maximum admitted {0} per {1} /// public string QuotaExceededMessage { get; set; } /// - /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. - /// If none specified the default will be: - /// API calls quota exceeded! maximum admitted {0} per {1} + /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. + /// If none specified the default will be: + /// API calls quota exceeded! maximum admitted {0} per {1} /// public Func QuotaExceededContent { get; set; } /// - /// Gets or sets the value to return as the HTTP status - /// code when a request is rejected because of the - /// throttling policy. The default value is 429 (Too Many Requests). + /// Gets or sets the value to return as the HTTP status + /// code when a request is rejected because of the + /// throttling policy. The default value is 429 (Too Many Requests). /// public HttpStatusCode QuotaExceededResponseCode { get; set; } public override void OnActionExecuting(HttpActionContext actionContext) { - EnableThrottlingAttribute attrPolicy = null; - var applyThrottling = ApplyThrottling(actionContext, out attrPolicy); + var applyThrottling = ApplyThrottling(actionContext, out EnableThrottlingAttribute attrPolicy); // get policy from repo - if(policyRepository != null) - { - policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); - } + if (PolicyRepository != null) + Policy = PolicyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); if (Policy != null && applyThrottling) { - core.Repository = Repository; - core.Policy = Policy; + _core.Repository = Repository; + _core.Policy = Policy; var identity = SetIdentity(actionContext.Request); - if (!core.IsWhitelisted(identity)) + if (!_core.IsWhitelisted(identity)) { - TimeSpan timeSpan = TimeSpan.FromSeconds(1); - // get default rates - var defRates = core.RatesWithDefaults(Policy.Rates.ToList()); + 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) @@ -166,55 +143,46 @@ public override void OnActionExecuting(HttpActionContext actionContext) var rateLimitPeriod = rate.Key; var rateLimit = rate.Value; - timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod); + var 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)); - } - } + _core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit); + + if (rateLimit <= 0) continue; + + // 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) continue; + // log blocked request + Logger?.Log(_core.ComputeLogEntry(requestId, identity, throttleCounter, + rateLimitPeriod.ToString(), rateLimit, actionContext.Request)); + + 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); + + // add status code and retry after x seconds to response + actionContext.Response = QuotaExceededResponse( + actionContext.Request, + content, + QuotaExceededResponseCode, + _core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod)); } } } @@ -224,28 +192,33 @@ public override void OnActionExecuting(HttpActionContext actionContext) protected virtual RequestIdentity SetIdentity(HttpRequestMessage request) { - var entry = new RequestIdentity(); - entry.ClientIp = core.GetClientIp(request).ToString(); - entry.Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant(); - entry.ClientKey = request.Headers.Contains("Authorization-Token") ? request.Headers.GetValues("Authorization-Token").First() : "anon"; + var entry = new RequestIdentity + { + ClientIp = _core.GetClientIp(request).ToString(), + Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant(), + ClientKey = request.Headers.Contains("Authorization-Token") + ? request.Headers.GetValues("Authorization-Token").First() + : "anon" + }; return entry; } protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { - return core.ComputeThrottleKey(requestIdentity, period); + return _core.ComputeThrottleKey(requestIdentity, period); } protected IPAddress GetClientIp(HttpRequestMessage request) { - return core.GetClientIp(request); + return _core.GetClientIp(request); } - protected virtual HttpResponseMessage QuotaExceededResponse(HttpRequestMessage request, object content, HttpStatusCode responseCode, string retryAfter) + protected virtual HttpResponseMessage QuotaExceededResponse(HttpRequestMessage request, object content, + HttpStatusCode responseCode, string retryAfter) { var response = request.CreateResponse(responseCode, content); - response.Headers.Add("Retry-After", new string[] { retryAfter }); + response.Headers.Add("Retry-After", new[] {retryAfter}); return response; } @@ -254,9 +227,11 @@ private bool ApplyThrottling(HttpActionContext filterContext, out EnableThrottli var applyThrottling = false; attr = null; - if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(true).Any()) + if (filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(true) + .Any()) { - attr = filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(true).First(); + attr = filterContext.ActionDescriptor.ControllerDescriptor + .GetCustomAttributes(true).First(); applyThrottling = true; } @@ -268,11 +243,9 @@ private bool ApplyThrottling(HttpActionContext filterContext, out EnableThrottli // explicit disabled if (filterContext.ActionDescriptor.GetCustomAttributes(true).Any()) - { applyThrottling = false; - } return applyThrottling; } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottlingHandler.cs b/WebApiThrottle/ThrottlingHandler.cs index 93e5bb1..04a7bf3 100644 --- a/WebApiThrottle/ThrottlingHandler.cs +++ b/WebApiThrottle/ThrottlingHandler.cs @@ -1,61 +1,58 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; -using System.ServiceModel.Channels; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Web; +using WebApiThrottle.Logging; +using WebApiThrottle.Models; using WebApiThrottle.Net; +using WebApiThrottle.Repositories; namespace WebApiThrottle { /// - /// Throttle message handler + /// Throttle message handler /// public class ThrottlingHandler : DelegatingHandler { - private ThrottlingCore core; - private IPolicyRepository policyRepository; - private ThrottlePolicy policy; + private readonly ThrottlingCore core; /// - /// Initializes a new instance of the class. - /// By default, the property - /// is set to 429 (Too Many Requests). + /// Initializes a new instance of the class. + /// By default, the property + /// is set to 429 (Too Many Requests). /// public ThrottlingHandler() { - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; Repository = new CacheRepository(); core = new ThrottlingCore(); } /// - /// Initializes a new instance of the class. - /// Persists the policy object in cache using implementation. - /// The policy object can be updated by at runtime. + /// Initializes a new instance of the class. + /// Persists the policy object in cache using implementation. + /// The policy object can be updated by at runtime. /// /// - /// The policy. + /// The policy. /// /// - /// The policy repository. + /// The policy repository. /// /// - /// The repository. + /// The repository. /// /// - /// The logger. + /// The logger. /// /// - /// The IpAddressParser + /// The IpAddressParser /// - public ThrottlingHandler(ThrottlePolicy policy, - IPolicyRepository policyRepository, - IThrottleRepository repository, + public ThrottlingHandler(ThrottlePolicy policy, + IPolicyRepository policyRepository, + IThrottleRepository repository, IThrottleLogger logger, IIpAddressParser ipAddressParser = null) { @@ -65,103 +62,82 @@ public ThrottlingHandler(ThrottlePolicy policy, Logger = logger; if (ipAddressParser != null) - { core.IpAddressParser = ipAddressParser; - } - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; - this.policy = policy; - this.policyRepository = policyRepository; + Policy = policy; + PolicyRepository = policyRepository; if (policyRepository != null) - { policyRepository.Save(ThrottleManager.GetPolicyKey(), policy); - } } /// - /// Gets or sets the throttling rate limits policy repository + /// Gets or sets the throttling rate limits policy repository /// - public IPolicyRepository PolicyRepository - { - get { return policyRepository; } - set { policyRepository = value; } - } + public IPolicyRepository PolicyRepository { get; set; } /// - /// Gets or sets the throttling rate limits policy + /// Gets or sets the throttling rate limits policy /// - public ThrottlePolicy Policy - { - get { return policy; } - set { policy = value; } - } + public ThrottlePolicy Policy { get; set; } /// - /// Gets or sets the throttle metrics storage + /// Gets or sets the throttle metrics storage /// public IThrottleRepository Repository { get; set; } /// - /// Gets or sets an instance of that logs traffic and blocked requests + /// Gets or sets an instance of that logs traffic and blocked requests /// public IThrottleLogger Logger { get; set; } /// - /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. - /// If none specified the default will be: - /// API calls quota exceeded! maximum admitted {0} per {1} + /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. + /// If none specified the default will be: + /// API calls quota exceeded! maximum admitted {0} per {1} /// public string QuotaExceededMessage { get; set; } /// - /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. - /// If none specified the default will be: - /// API calls quota exceeded! maximum admitted {0} per {1} + /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. + /// If none specified the default will be: + /// API calls quota exceeded! maximum admitted {0} per {1} /// public Func QuotaExceededContent { get; set; } /// - /// Gets or sets the value to return as the HTTP status - /// code when a request is rejected because of the - /// throttling policy. The default value is 429 (Too Many Requests). + /// Gets or sets the value to return as the HTTP status + /// code when a request is rejected because of the + /// throttling policy. The default value is 429 (Too Many Requests). /// public HttpStatusCode QuotaExceededResponseCode { get; set; } - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + protected override Task SendAsync(HttpRequestMessage request, + CancellationToken cancellationToken) { // get policy from repo - if (policyRepository != null) - { - policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); - } + if (PolicyRepository != null) + Policy = PolicyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); - if (policy == null || (!policy.IpThrottling && !policy.ClientThrottling && !policy.EndpointThrottling)) - { + if (Policy == null || !Policy.IpThrottling && !Policy.ClientThrottling && !Policy.EndpointThrottling) return base.SendAsync(request, cancellationToken); - } core.Repository = Repository; - core.Policy = policy; + core.Policy = Policy; var identity = SetIdentity(request); if (core.IsWhitelisted(identity)) - { return base.SendAsync(request, cancellationToken); - } - TimeSpan timeSpan = TimeSpan.FromSeconds(1); + var 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) @@ -182,25 +158,22 @@ protected override Task SendAsync(HttpRequestMessage reques // 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)); - } + Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, + rateLimitPeriod.ToString(), rateLimit, request)); - var message = !string.IsNullOrEmpty(this.QuotaExceededMessage) - ? this.QuotaExceededMessage + var message = !string.IsNullOrEmpty(QuotaExceededMessage) + ? QuotaExceededMessage : "API calls quota exceeded! maximum admitted {0} per {1}."; - var content = this.QuotaExceededContent != null - ? this.QuotaExceededContent(rateLimit, rateLimitPeriod) + var content = QuotaExceededContent != null + ? QuotaExceededContent(rateLimit, rateLimitPeriod) : string.Format(message, rateLimit, rateLimitPeriod); // break execution @@ -227,8 +200,8 @@ protected virtual RequestIdentity SetIdentity(HttpRequestMessage request) var entry = new RequestIdentity(); entry.ClientIp = core.GetClientIp(request).ToString(); entry.Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant(); - entry.ClientKey = request.Headers.Contains("Authorization-Token") - ? request.Headers.GetValues("Authorization-Token").First() + entry.ClientKey = request.Headers.Contains("Authorization-Token") + ? request.Headers.GetValues("Authorization-Token").First() : "anon"; return entry; @@ -239,11 +212,12 @@ protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, Rat return core.ComputeThrottleKey(requestIdentity, period); } - protected virtual Task QuotaExceededResponse(HttpRequestMessage request, object content, HttpStatusCode responseCode, string retryAfter) + protected virtual Task QuotaExceededResponse(HttpRequestMessage request, object content, + HttpStatusCode responseCode, string retryAfter) { var response = request.CreateResponse(responseCode, content); - response.Headers.Add("Retry-After", new string[] { retryAfter }); + response.Headers.Add("Retry-After", new[] {retryAfter}); return Task.FromResult(response); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/ThrottlingMiddleware.cs b/WebApiThrottle/ThrottlingMiddleware.cs index 0178d16..5392ff4 100644 --- a/WebApiThrottle/ThrottlingMiddleware.cs +++ b/WebApiThrottle/ThrottlingMiddleware.cs @@ -1,58 +1,56 @@ -using Microsoft.Owin; -using System; -using System.Collections.Generic; +using System; using System.Linq; using System.Net; -using System.Net.Http; -using System.Text; using System.Threading.Tasks; +using Microsoft.Owin; +using WebApiThrottle.Logging; +using WebApiThrottle.Models; using WebApiThrottle.Net; +using WebApiThrottle.Repositories; namespace WebApiThrottle { public class ThrottlingMiddleware : OwinMiddleware { - private ThrottlingCore core; - private IPolicyRepository policyRepository; - private ThrottlePolicy policy; + private readonly ThrottlingCore core; /// - /// Initializes a new instance of the class. - /// By default, the property - /// is set to 429 (Too Many Requests). + /// Initializes a new instance of the class. + /// By default, the property + /// is set to 429 (Too Many Requests). /// public ThrottlingMiddleware(OwinMiddleware next) : base(next) { - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; Repository = new CacheRepository(); core = new ThrottlingCore(); } /// - /// Initializes a new instance of the class. - /// Persists the policy object in cache using implementation. - /// The policy object can be updated by at runtime. + /// Initializes a new instance of the class. + /// Persists the policy object in cache using implementation. + /// The policy object can be updated by at runtime. /// /// - /// The policy. + /// The policy. /// /// - /// The policy repository. + /// The policy repository. /// /// - /// The repository. + /// The repository. /// /// - /// The logger. + /// The logger. /// /// - /// The IpAddressParser + /// The IpAddressParser /// - public ThrottlingMiddleware(OwinMiddleware next, - ThrottlePolicy policy, - IPolicyRepository policyRepository, - IThrottleRepository repository, + public ThrottlingMiddleware(OwinMiddleware next, + ThrottlePolicy policy, + IPolicyRepository policyRepository, + IThrottleRepository repository, IThrottleLogger logger, IIpAddressParser ipAddressParser) : base(next) @@ -63,60 +61,48 @@ public ThrottlingMiddleware(OwinMiddleware next, Logger = logger; if (ipAddressParser != null) - { core.IpAddressParser = ipAddressParser; - } - QuotaExceededResponseCode = (HttpStatusCode)429; + QuotaExceededResponseCode = (HttpStatusCode) 429; - this.policy = policy; - this.policyRepository = policyRepository; + Policy = policy; + PolicyRepository = policyRepository; if (policyRepository != null) - { policyRepository.Save(ThrottleManager.GetPolicyKey(), policy); - } } /// - /// Gets or sets the throttling rate limits policy repository + /// Gets or sets the throttling rate limits policy repository /// - public IPolicyRepository PolicyRepository - { - get { return policyRepository; } - set { policyRepository = value; } - } + public IPolicyRepository PolicyRepository { get; set; } /// - /// Gets or sets the throttling rate limits policy + /// Gets or sets the throttling rate limits policy /// - public ThrottlePolicy Policy - { - get { return policy; } - set { policy = value; } - } + public ThrottlePolicy Policy { get; set; } /// - /// Gets or sets the throttle metrics storage + /// Gets or sets the throttle metrics storage /// public IThrottleRepository Repository { get; set; } /// - /// Gets or sets an instance of that logs traffic and blocked requests + /// Gets or sets an instance of that logs traffic and blocked requests /// public IThrottleLogger Logger { get; set; } /// - /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. - /// If none specified the default will be: - /// API calls quota exceeded! maximum admitted {0} per {1} + /// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message. + /// If none specified the default will be: + /// API calls quota exceeded! maximum admitted {0} per {1} /// public string QuotaExceededMessage { get; set; } /// - /// Gets or sets the value to return as the HTTP status - /// code when a request is rejected because of the - /// throttling policy. The default value is 429 (Too Many Requests). + /// Gets or sets the value to return as the HTTP status + /// code when a request is rejected because of the + /// throttling policy. The default value is 429 (Too Many Requests). /// public HttpStatusCode QuotaExceededResponseCode { get; set; } @@ -126,19 +112,17 @@ public override async Task Invoke(IOwinContext context) var request = context.Request; // get policy from repo - if (policyRepository != null) - { - policy = policyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); - } + if (PolicyRepository != null) + Policy = PolicyRepository.FirstOrDefault(ThrottleManager.GetPolicyKey()); - if (policy == null || (!policy.IpThrottling && !policy.ClientThrottling && !policy.EndpointThrottling)) + if (Policy == null || !Policy.IpThrottling && !Policy.ClientThrottling && !Policy.EndpointThrottling) { await Next.Invoke(context); return; } core.Repository = Repository; - core.Policy = policy; + core.Policy = Policy; var identity = SetIdentity(request); @@ -148,16 +132,12 @@ public override async Task Invoke(IOwinContext context) return; } - TimeSpan timeSpan = TimeSpan.FromSeconds(1); + var 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) @@ -178,29 +158,27 @@ public override async Task Invoke(IOwinContext context) // 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)); - } + Logger.Log(core.ComputeLogEntry(requestId, identity, throttleCounter, + rateLimitPeriod.ToString(), rateLimit, null)); - var message = !string.IsNullOrEmpty(this.QuotaExceededMessage) - ? this.QuotaExceededMessage + var message = !string.IsNullOrEmpty(QuotaExceededMessage) + ? 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; + var resp = (OwinResponse) state; + resp.Headers.Add("Retry-After", + new[] {core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod)}); + resp.StatusCode = (int) QuotaExceededResponseCode; resp.ReasonPhrase = string.Format(message, rateLimit, rateLimitPeriod); }, response); @@ -230,4 +208,4 @@ protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, Rat return core.ComputeThrottleKey(requestIdentity, period); } } -} +} \ No newline at end of file diff --git a/WebApiThrottle/WebApiThrottle.csproj b/WebApiThrottle/WebApiThrottle.csproj index 9d65b27..d38cbeb 100644 --- a/WebApiThrottle/WebApiThrottle.csproj +++ b/WebApiThrottle/WebApiThrottle.csproj @@ -88,6 +88,7 @@ + diff --git a/WebApiThrottle/app.config b/WebApiThrottle/app.config index 099a367..55a9304 100644 --- a/WebApiThrottle/app.config +++ b/WebApiThrottle/app.config @@ -1,4 +1,5 @@  + diff --git a/WebApiThrottle/packages.config b/WebApiThrottle/packages.config index 7f67226..c2077d7 100644 --- a/WebApiThrottle/packages.config +++ b/WebApiThrottle/packages.config @@ -1,4 +1,5 @@  + diff --git a/WebApiThrottler.SelfHostOwinDemo/App.config b/WebApiThrottler.SelfHostOwinDemo/App.config index bdb2850..b233119 100644 --- a/WebApiThrottler.SelfHostOwinDemo/App.config +++ b/WebApiThrottler.SelfHostOwinDemo/App.config @@ -1,9 +1,11 @@  +
- + @@ -17,9 +19,9 @@ - - - + + + diff --git a/WebApiThrottler.SelfHostOwinDemo/Program.cs b/WebApiThrottler.SelfHostOwinDemo/Program.cs index 6530923..478bc54 100644 --- a/WebApiThrottler.SelfHostOwinDemo/Program.cs +++ b/WebApiThrottler.SelfHostOwinDemo/Program.cs @@ -1,24 +1,20 @@ -using Microsoft.Owin.Hosting; -using System; -using System.Collections.Generic; -using System.Linq; +using System; using System.Net.Http; -using System.Text; -using System.Threading.Tasks; +using Microsoft.Owin.Hosting; namespace WebApiThrottler.SelfHostOwinDemo { - class Program + internal class Program { - static void Main(string[] args) + private static void Main(string[] args) { - string baseAddress = "http://localhost:9000/"; + var baseAddress = "http://localhost:9000/"; // Start OWIN host - using (WebApp.Start(url: baseAddress)) + using (WebApp.Start(baseAddress)) { // Create HttpCient and make a request to api/values - HttpClient client = new HttpClient(); + var client = new HttpClient(); var response = client.GetAsync(baseAddress + "api/values").Result; @@ -30,4 +26,4 @@ static void Main(string[] args) } } } -} +} \ No newline at end of file diff --git a/WebApiThrottler.SelfHostOwinDemo/Properties/AssemblyInfo.cs b/WebApiThrottler.SelfHostOwinDemo/Properties/AssemblyInfo.cs index 8655c3c..befc64e 100644 --- a/WebApiThrottler.SelfHostOwinDemo/Properties/AssemblyInfo.cs +++ b/WebApiThrottler.SelfHostOwinDemo/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -33,4 +32,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/WebApiThrottler.SelfHostOwinDemo/Startup.cs b/WebApiThrottler.SelfHostOwinDemo/Startup.cs index 1335f69..361d85a 100644 --- a/WebApiThrottler.SelfHostOwinDemo/Startup.cs +++ b/WebApiThrottler.SelfHostOwinDemo/Startup.cs @@ -1,11 +1,8 @@ -using Owin; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Web.Http; +using System.Web.Http; +using Owin; using WebApiThrottle; +using WebApiThrottle.Providers; +using WebApiThrottle.Repositories; namespace WebApiThrottler.SelfHostOwinDemo { @@ -16,27 +13,27 @@ public class Startup public void Configuration(IAppBuilder appBuilder) { // Configure Web API for self-host. - HttpConfiguration config = new HttpConfiguration(); + var config = new HttpConfiguration(); config.Routes.MapHttpRoute( - name: "DefaultApi", - routeTemplate: "api/{controller}/{id}", - defaults: new { id = RouteParameter.Optional } + "DefaultApi", + "api/{controller}/{id}", + new {id = RouteParameter.Optional} ); //middleware with policy loaded from app.config - appBuilder.Use(typeof(ThrottlingMiddleware), - ThrottlePolicy.FromStore(new PolicyConfigurationProvider()), - new PolicyMemoryCacheRepository(), - new MemoryCacheRepository(), - null, - null); + //appBuilder.Use(typeof(ThrottlingMiddleware), + // ThrottlePolicy.FromStore(new PolicyConfigurationProvider()), + // new PolicyMemoryCacheRepository(), + // new MemoryCacheRepository(), + // null, + // null); //Web API throttling load policy from app.config - //config.MessageHandlers.Add(new ThrottlingHandler() - //{ - // Policy = ThrottlePolicy.FromStore(new PolicyConfigurationProvider()), - // Repository = new MemoryCacheRepository() - //}); + config.MessageHandlers.Add(new ThrottlingHandler + { + Policy = ThrottlePolicy.FromStore(new PolicyConfigurationProvider()), + Repository = new MemoryCacheRepository() + }); //Web API throttling hardcoded policy //config.MessageHandlers.Add(new ThrottlingHandler() @@ -76,5 +73,5 @@ public void Configuration(IAppBuilder appBuilder) appBuilder.UseWebApi(config); } - } -} + } +} \ No newline at end of file diff --git a/WebApiThrottler.SelfHostOwinDemo/ValuesController.cs b/WebApiThrottler.SelfHostOwinDemo/ValuesController.cs index 45fe15a..7c7da06 100644 --- a/WebApiThrottler.SelfHostOwinDemo/ValuesController.cs +++ b/WebApiThrottler.SelfHostOwinDemo/ValuesController.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using System.Web.Http; namespace WebApiThrottler.SelfHostOwinDemo @@ -12,7 +8,7 @@ public class ValuesController : ApiController // GET api/values public IEnumerable Get() { - return new string[] { "value1", "value2" }; + return new[] {"value1", "value2"}; } // GET api/values/5 @@ -22,12 +18,12 @@ public string Get(int id) } // POST api/values - public void Post([FromBody]string value) + public void Post([FromBody] string value) { } // PUT api/values/5 - public void Put(int id, [FromBody]string value) + public void Put(int id, [FromBody] string value) { } @@ -35,5 +31,5 @@ public void Put(int id, [FromBody]string value) public void Delete(int id) { } - } -} + } +} \ No newline at end of file diff --git a/WebApiThrottler.SelfHostOwinDemo/packages.config b/WebApiThrottler.SelfHostOwinDemo/packages.config index efec32c..39343fe 100644 --- a/WebApiThrottler.SelfHostOwinDemo/packages.config +++ b/WebApiThrottler.SelfHostOwinDemo/packages.config @@ -1,4 +1,5 @@  + From ff59f121ce4d8ec4e6c2d6c091cf96dd49829ab0 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Fri, 13 Oct 2017 11:51:21 -0400 Subject: [PATCH 3/5] formateo codigo --- WebApiThrottle/ThrottlingCore.cs | 13 +--- WebApiThrottle/ThrottlingHandler.cs | 109 +++++++++++++--------------- 2 files changed, 55 insertions(+), 67 deletions(-) diff --git a/WebApiThrottle/ThrottlingCore.cs b/WebApiThrottle/ThrottlingCore.cs index 55d54f5..f073b8e 100644 --- a/WebApiThrottle/ThrottlingCore.cs +++ b/WebApiThrottle/ThrottlingCore.cs @@ -100,13 +100,10 @@ internal bool IsWhitelisted(RequestIdentity requestIdentity) if (Policy.ClientWhitelist != null && Policy.ClientWhitelist.Contains(requestIdentity.ClientKey)) return true; - if (Policy.EndpointThrottling) - if (Policy.EndpointWhitelist != null - && Policy.EndpointWhitelist.Any( - x => requestIdentity.Endpoint.IndexOf(x, 0, StringComparison.InvariantCultureIgnoreCase) != -1)) - return true; - - return false; + if (!Policy.EndpointThrottling) return false; + return Policy.EndpointWhitelist != null + && Policy.EndpointWhitelist.Any( + x => requestIdentity.Endpoint.IndexOf(x, 0, StringComparison.InvariantCultureIgnoreCase) != -1); } internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) @@ -133,9 +130,7 @@ internal string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPer byte[] hashBytes; using (var algorithm = HashAlgorithm.Create("SHA1")) - { hashBytes = algorithm.ComputeHash(idBytes); - } var hex = BitConverter.ToString(hashBytes).Replace("-", string.Empty); return hex; diff --git a/WebApiThrottle/ThrottlingHandler.cs b/WebApiThrottle/ThrottlingHandler.cs index 04a7bf3..ec9331e 100644 --- a/WebApiThrottle/ThrottlingHandler.cs +++ b/WebApiThrottle/ThrottlingHandler.cs @@ -16,7 +16,7 @@ namespace WebApiThrottle /// public class ThrottlingHandler : DelegatingHandler { - private readonly ThrottlingCore core; + private readonly ThrottlingCore _core; /// /// Initializes a new instance of the class. @@ -27,7 +27,7 @@ public ThrottlingHandler() { QuotaExceededResponseCode = (HttpStatusCode) 429; Repository = new CacheRepository(); - core = new ThrottlingCore(); + _core = new ThrottlingCore(); } /// @@ -56,21 +56,19 @@ public ThrottlingHandler(ThrottlePolicy policy, IThrottleLogger logger, IIpAddressParser ipAddressParser = null) { - core = new ThrottlingCore(); - core.Repository = repository; + _core = new ThrottlingCore {Repository = repository}; Repository = repository; Logger = logger; if (ipAddressParser != null) - core.IpAddressParser = ipAddressParser; + _core.IpAddressParser = ipAddressParser; QuotaExceededResponseCode = (HttpStatusCode) 429; Policy = policy; PolicyRepository = policyRepository; - if (policyRepository != null) - policyRepository.Save(ThrottleManager.GetPolicyKey(), policy); + policyRepository?.Save(ThrottleManager.GetPolicyKey(), policy); } /// @@ -124,18 +122,16 @@ protected override Task SendAsync(HttpRequestMessage reques if (Policy == null || !Policy.IpThrottling && !Policy.ClientThrottling && !Policy.EndpointThrottling) return base.SendAsync(request, cancellationToken); - core.Repository = Repository; - core.Policy = Policy; + _core.Repository = Repository; + _core.Policy = Policy; var identity = SetIdentity(request); - if (core.IsWhitelisted(identity)) + if (_core.IsWhitelisted(identity)) return base.SendAsync(request, cancellationToken); - var timeSpan = TimeSpan.FromSeconds(1); - // get default rates - var defRates = core.RatesWithDefaults(Policy.Rates.ToList()); + var defRates = _core.RatesWithDefaults(Policy.Rates.ToList()); if (Policy.StackBlockedRequests) defRates.Reverse(); @@ -145,45 +141,40 @@ protected override Task SendAsync(HttpRequestMessage reques var rateLimitPeriod = rate.Key; var rateLimit = rate.Value; - timeSpan = core.GetTimeSpanFromPeriod(rateLimitPeriod); + var 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(QuotaExceededMessage) - ? QuotaExceededMessage - : "API calls quota exceeded! maximum admitted {0} per {1}."; - - var content = QuotaExceededContent != null - ? QuotaExceededContent(rateLimit, rateLimitPeriod) - : string.Format(message, rateLimit, rateLimitPeriod); - - // break execution - return QuotaExceededResponse( - request, - content, - QuotaExceededResponseCode, - core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod)); - } - } + _core.ApplyRules(identity, timeSpan, rateLimitPeriod, ref rateLimit); + + if (rateLimit <= 0) continue; + // 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) continue; + // log blocked request + Logger?.Log(_core.ComputeLogEntry(requestId, identity, throttleCounter, + rateLimitPeriod.ToString(), rateLimit, request)); + + 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); + + // break execution + return QuotaExceededResponse( + request, + content, + QuotaExceededResponseCode, + _core.RetryAfterFrom(throttleCounter.Timestamp, rateLimitPeriod)); } // no throttling required @@ -192,24 +183,26 @@ protected override Task SendAsync(HttpRequestMessage reques protected IPAddress GetClientIp(HttpRequestMessage request) { - return core.GetClientIp(request); + return _core.GetClientIp(request); } protected virtual RequestIdentity SetIdentity(HttpRequestMessage request) { - var entry = new RequestIdentity(); - entry.ClientIp = core.GetClientIp(request).ToString(); - entry.Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant(); - entry.ClientKey = request.Headers.Contains("Authorization-Token") - ? request.Headers.GetValues("Authorization-Token").First() - : "anon"; + var entry = new RequestIdentity + { + ClientIp = _core.GetClientIp(request).ToString(), + Endpoint = request.RequestUri.AbsolutePath.ToLowerInvariant(), + ClientKey = request.Headers.Contains("Authorization-Token") + ? request.Headers.GetValues("Authorization-Token").First() + : "anon" + }; return entry; } protected virtual string ComputeThrottleKey(RequestIdentity requestIdentity, RateLimitPeriod period) { - return core.ComputeThrottleKey(requestIdentity, period); + return _core.ComputeThrottleKey(requestIdentity, period); } protected virtual Task QuotaExceededResponse(HttpRequestMessage request, object content, From f9707e82039aa22b4460158ec104ccb283cbf520 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Sun, 11 Feb 2018 18:22:05 -0300 Subject: [PATCH 4/5] formateo codigo --- WebApiThrottle/Models/IPAddressRange.cs | 6 +++--- .../ConcurrentDictionaryRepository.cs | 4 +--- WebApiThrottle/ThrottlingFilter.cs | 9 +++++---- WebApiThrottle/ThrottlingMiddleware.cs | 20 +++++++++++-------- WebApiThrottle/WebApiThrottle.csproj | 6 ------ 5 files changed, 21 insertions(+), 24 deletions(-) diff --git a/WebApiThrottle/Models/IPAddressRange.cs b/WebApiThrottle/Models/IPAddressRange.cs index bea6ee9..2e79c10 100644 --- a/WebApiThrottle/Models/IPAddressRange.cs +++ b/WebApiThrottle/Models/IPAddressRange.cs @@ -83,12 +83,12 @@ protected IPAddressRange(SerializationInfo info, StreamingContext context) var names = new List(); foreach (var item in info) names.Add(item.Name); - Func deserialize = name => names.Contains(name) + IPAddress Deserialize(string name) => names.Contains(name) ? IPAddress.Parse(info.GetValue(name, typeof(object)).ToString()) : new IPAddress(0L); - Begin = deserialize("Begin"); - End = deserialize("End"); + Begin = Deserialize("Begin"); + End = Deserialize("End"); } public IPAddress Begin { get; set; } diff --git a/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs b/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs index 5481611..29c0fc9 100644 --- a/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs +++ b/WebApiThrottle/Repositories/ConcurrentDictionaryRepository.cs @@ -29,9 +29,7 @@ public bool Any(string id) /// public ThrottleCounter? FirstOrDefault(string id) { - ThrottleCounterWrapper entry; - - if (!cache.TryGetValue(id, out entry)) + if (!cache.TryGetValue(id, out var entry)) return new ThrottleCounter { Timestamp = entry.Timestamp, diff --git a/WebApiThrottle/ThrottlingFilter.cs b/WebApiThrottle/ThrottlingFilter.cs index 9d9bfdf..ba22c34 100644 --- a/WebApiThrottle/ThrottlingFilter.cs +++ b/WebApiThrottle/ThrottlingFilter.cs @@ -58,8 +58,10 @@ public ThrottlingFilter(ThrottlePolicy policy, IThrottleLogger logger, IIpAddressParser ipAddressParser = null) { - _core = new ThrottlingCore(); - _core.Repository = repository; + _core = new ThrottlingCore + { + Repository = repository + }; Repository = repository; Logger = logger; if (ipAddressParser != null) @@ -70,8 +72,7 @@ public ThrottlingFilter(ThrottlePolicy policy, Policy = policy; PolicyRepository = policyRepository; - if (policyRepository != null) - policyRepository.Save(ThrottleManager.GetPolicyKey(), policy); + policyRepository?.Save(ThrottleManager.GetPolicyKey(), policy); } /// diff --git a/WebApiThrottle/ThrottlingMiddleware.cs b/WebApiThrottle/ThrottlingMiddleware.cs index 5392ff4..d15a9cd 100644 --- a/WebApiThrottle/ThrottlingMiddleware.cs +++ b/WebApiThrottle/ThrottlingMiddleware.cs @@ -55,8 +55,10 @@ public ThrottlingMiddleware(OwinMiddleware next, IIpAddressParser ipAddressParser) : base(next) { - core = new ThrottlingCore(); - core.Repository = repository; + core = new ThrottlingCore + { + Repository = repository + }; Repository = repository; Logger = logger; @@ -193,12 +195,14 @@ public override async Task Invoke(IOwinContext context) protected virtual RequestIdentity SetIdentity(IOwinRequest request) { - var entry = new RequestIdentity(); - entry.ClientIp = request.RemoteIpAddress; - entry.Endpoint = request.Uri.AbsolutePath.ToLowerInvariant(); - entry.ClientKey = request.Headers.Keys.Contains("Authorization-Token") - ? request.Headers.GetValues("Authorization-Token").First() - : "anon"; + var entry = new RequestIdentity + { + ClientIp = request.RemoteIpAddress, + Endpoint = request.Uri.AbsolutePath.ToLowerInvariant(), + ClientKey = request.Headers.Keys.Contains("Authorization-Token") + ? request.Headers.GetValues("Authorization-Token").First() + : "anon" + }; return entry; } diff --git a/WebApiThrottle/WebApiThrottle.csproj b/WebApiThrottle/WebApiThrottle.csproj index d38cbeb..6f96f7c 100644 --- a/WebApiThrottle/WebApiThrottle.csproj +++ b/WebApiThrottle/WebApiThrottle.csproj @@ -54,17 +54,11 @@ - False ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll - - - - - From 24e79c79ebccabdd0c62a1e0b9adfad292be4a62 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Tue, 13 Feb 2018 14:24:43 -0300 Subject: [PATCH 5/5] configuracion path ensamblados --- WebApiThrottle/WebApiThrottle.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebApiThrottle/WebApiThrottle.csproj b/WebApiThrottle/WebApiThrottle.csproj index 6f96f7c..12c4f71 100644 --- a/WebApiThrottle/WebApiThrottle.csproj +++ b/WebApiThrottle/WebApiThrottle.csproj @@ -57,7 +57,7 @@ False - ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + ..\..\upublicapi\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll