Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added some useful things #343

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/AspNetCoreRateLimit/Core/RateLimitProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,12 @@ protected virtual List<RateLimitRule> GetMatchingRules(ClientRequestIdentity ide

foreach (var generalLimit in generalLimits)
{
// add general rule if no specific rule is declared for the specified period
if (!limits.Exists(l => l.Period == generalLimit.Period))

if (// add general rule if no specific rule is declared when DiscardEndpointGeneralRulesWhenExistsIPOrClienIdRule is enabled
(_options.DiscardEndpointGeneralRulesWhenExistsIPOrClienIdRule && !limits.Any())
||
// add general rule if no specific rule is declared for the specified period when DiscardEndpointGeneralRulesWhenExistsIPOrClienIdRule is disabled
(!_options.DiscardEndpointGeneralRulesWhenExistsIPOrClienIdRule && !limits.Exists(l => l.Period == generalLimit.Period)))
{
limits.Add(generalLimit);
}
Expand Down
7 changes: 6 additions & 1 deletion src/AspNetCoreRateLimit/Middleware/RateLimitMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,12 @@ public virtual Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLim
{
httpContext.Response.Headers["Retry-After"] = retryAfter;
}

if (rule.Limit == 0 && _options.HttpStatusCodeForLimitZeroRequests.HasValue)
{
httpContext.Response.StatusCode = _options.HttpStatusCodeForLimitZeroRequests.Value;
httpContext.Response.ContentType = "text/plain";
return httpContext.Response.WriteAsync("");
}
httpContext.Response.StatusCode = _options.QuotaExceededResponse?.StatusCode ?? _options.HttpStatusCode;
httpContext.Response.ContentType = _options.QuotaExceededResponse?.ContentType ?? "text/plain";

Expand Down
11 changes: 11 additions & 0 deletions src/AspNetCoreRateLimit/Models/RateLimitOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public class RateLimitOptions
/// </summary>
public int HttpStatusCode { get; set; } = 429;

/// <summary>
/// Gets or sets the HTTP Status code returned when rate limiting occurs, by default value is HttpStatusCode value.
/// </summary>
public int? HttpStatusCodeForLimitZeroRequests { get; set; }

/// <summary>
/// Gets or sets a value that will be used as a formatter for the QuotaExceeded response message.
/// If none specified the default will be:
Expand Down Expand Up @@ -57,6 +62,12 @@ public class RateLimitOptions
/// </summary>
public bool EnableEndpointRateLimiting { get; set; }

/// <summary>
/// Defines if general rules for an endpoint should be discarded if an ip o client id rule is defined for the same endpoint.
/// By default they are only discarded if there is any rule for the same period.
/// </summary>
public bool DiscardEndpointGeneralRulesWhenExistsIPOrClienIdRule { get; set; }

/// <summary>
/// Disables X-Rate-Limit and Retry-After headers
/// </summary>
Expand Down
34 changes: 31 additions & 3 deletions src/AspNetCoreRateLimit/Net/IPAddressRange.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
Expand All @@ -21,10 +22,13 @@ public class IpAddressRange

public IPAddress End { get; set; }

public List<IPAddress> IPList { get; set; }

public IpAddressRange()
{
Begin = new IPAddress(0L);
End = new IPAddress(0L);
IPList = new List<IPAddress>();
}

public IpAddressRange(string ipRangeString)
Expand Down Expand Up @@ -73,14 +77,31 @@ public IpAddressRange(string ipRangeString)
return;
}

// Pattern 5. List of ips: "169.258.0.0,169.258.0.255"
var m5 = Regex.Match(ipRangeString, @"^([\da-f\.:]+)(,[\da-f\.:]+)*$", RegexOptions.IgnoreCase);
if (m5.Success)
{
IPList = new List<IPAddress>();
IPList.AddRange(ipRangeString.Split(',').Select(ipString=> IPAddress.Parse(ipString)));
return;
}

throw new FormatException("Unknown IP range string.");
}

public bool Contains(IPAddress ipaddress)
{
if (ipaddress.AddressFamily != Begin.AddressFamily) return false;
var adrBytes = ipaddress.GetAddressBytes();
return Bits.GE(Begin.GetAddressBytes(), adrBytes) && Bits.LE(End.GetAddressBytes(), adrBytes);
if (IPList != null)
{
var adrBytes = ipaddress.GetAddressBytes();
return IPList.Any(e => ipaddress.AddressFamily == e.AddressFamily && Bits.EQ(e.GetAddressBytes(), adrBytes));
}
else
{
if (Begin == null || ipaddress.AddressFamily != Begin.AddressFamily) return false;
var adrBytes = ipaddress.GetAddressBytes();
return Bits.GE(Begin.GetAddressBytes(), adrBytes) && Bits.LE(End.GetAddressBytes(), adrBytes);
}
}
}

Expand Down Expand Up @@ -108,6 +129,13 @@ internal static bool GE(byte[] A, byte[] B)
.FirstOrDefault() >= 0;
}

internal static bool EQ(byte[] A, byte[] B)
{
return A.Zip(B, (a, b) => a == b ? 0 : 1)
.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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public Task SetAsync(string id, T entry, TimeSpan? expirationTime = null, Cancel

if (expirationTime.HasValue)
{
if (expirationTime.Value.TotalMilliseconds == 0)
{
return Task.CompletedTask;
}
options.SetAbsoluteExpiration(expirationTime.Value);
}

Expand Down