Skip to content

Commit

Permalink
Add Rate-Limiter for RSS Feed
Browse files Browse the repository at this point in the history
  • Loading branch information
linkdotnet committed Sep 10, 2024
1 parent e40ac8d commit e94c5a3
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/LinkDotNet.Blog.Web/Controller/RssFeedController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
using LinkDotNet.Blog.Infrastructure.Persistence;
using LinkDotNet.Blog.Web.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Extensions.Options;
using InvalidOperationException = System.InvalidOperationException;

namespace LinkDotNet.Blog.Web.Controller;

[Route("feed.rss")]
[EnableRateLimiting("ip")]
public sealed class RssFeedController : ControllerBase
{
private static readonly XmlWriterSettings Settings = CreateXmlWriterSettings();
Expand Down
15 changes: 15 additions & 0 deletions src/LinkDotNet.Blog.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Threading.RateLimiting;
using System.Threading.Tasks;
using Blazored.Toast;
using Blazorise;
Expand All @@ -8,6 +10,7 @@
using LinkDotNet.Blog.Web.RegistrationExtensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

Expand Down Expand Up @@ -40,6 +43,17 @@ private static void RegisterServices(WebApplicationBuilder builder)
options.MaximumReceiveMessageSize = 1024 * 1024;
});

builder.Services.AddRateLimiter(options =>
{
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
options.AddPolicy<string>("ip", httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
httpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty,
_ => new FixedWindowRateLimiterOptions { PermitLimit = 15, Window = TimeSpan.FromMinutes(1) })
);
});

builder.Services.AddConfiguration();

builder.Services.AddBlazoredToast();
Expand Down Expand Up @@ -91,6 +105,7 @@ private static void ConfigureApp(WebApplication app)
app.UseAuthentication();
app.UseAuthorization();

app.UseRateLimiter();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
Expand Down
21 changes: 17 additions & 4 deletions tests/LinkDotNet.Blog.IntegrationTests/SmokeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,26 @@ public async Task ShouldAllowDotsForFreeTextSearch()
result.IsSuccessStatusCode.ShouldBeTrue();
}

[Fact]
public async Task RssFeedShouldBeRateLimited()
{
const int numberOfRequests = 16;
using var client = factory.CreateClient();

for (var i = 0; i < numberOfRequests - 1; i++)
{
var result = await client.GetAsync("/feed.rss");
result.IsSuccessStatusCode.ShouldBeTrue();
}

var lastResult = await client.GetAsync("/feed.rss");
lastResult.IsSuccessStatusCode.ShouldBeFalse();
}

public void Dispose() => factory?.Dispose();

public async ValueTask DisposeAsync()
{
if (factory is not null)
{
await factory.DisposeAsync();
}
await factory.DisposeAsync();
}
}

0 comments on commit e94c5a3

Please sign in to comment.