2022-11-01 17:14:19 +05:00
using Microsoft.AspNetCore.Http ;
using Microsoft.Extensions.Configuration ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
namespace AsbCloudWebApi.Middlewares
{
#nullable enable
/// <summary>
/// This is not real middleware it`s part of PermissionsMiddlware.
/// DO NOT register it in setup.cs as middleware.
/// </summary>
class UserConnectionsLimitMiddlware
{
private readonly int parallelRequestsToController ;
2022-11-10 13:59:48 +05:00
private readonly RequestDelegate next ;
private readonly byte [ ] responseBody ;
2022-11-01 17:14:19 +05:00
private readonly ConcurrentDictionary < int , ConcurrentDictionary < string , int > > stat = new ( ) ;
private readonly IEnumerable < string > ? controllerNames ;
public UserConnectionsLimitMiddlware ( RequestDelegate next , IConfiguration configuration )
{
2022-11-10 13:59:48 +05:00
const int parallelRequestsToControllerDefault = 8 ;
2022-11-01 17:14:19 +05:00
this . next = next ;
2022-11-10 13:59:48 +05:00
var parallelRequestsToController = configuration . GetSection ( "userLimits" ) ? . GetValue < int > ( "parallelRequestsToController" ) ? ? parallelRequestsToControllerDefault ;
2022-11-01 17:14:19 +05:00
this . parallelRequestsToController = parallelRequestsToController > 0
? parallelRequestsToController
2022-11-10 13:59:48 +05:00
: parallelRequestsToControllerDefault ;
2022-11-01 17:14:19 +05:00
controllerNames = configuration . GetSection ( "userLimits" ) ? . GetValue < IEnumerable < string > > ( "controllerNames" ) ;
var bodyText = $"<html><head><title>Too Many Requests</title></head><body><h1>Too Many Requests</h1><p>I only allow {parallelRequestsToController} parallel requests per user. Try again soon.</p></body></html>" ;
2022-11-10 13:59:48 +05:00
responseBody = System . Text . Encoding . UTF8 . GetBytes ( bodyText ) ;
2022-11-01 17:14:19 +05:00
}
public async Task InvokeAsync ( HttpContext context , int idUser , string controllerName )
{
if ( controllerNames ? . Any ( n = > controllerName . StartsWith ( n ) ) = = false )
{
await next ( context ) ;
return ;
2022-11-10 13:59:48 +05:00
}
2022-11-01 17:14:19 +05:00
var userStat = stat . GetOrAdd ( idUser , idUser = > new ( ) ) ;
2022-11-10 13:59:48 +05:00
var count = userStat . AddOrUpdate ( controllerName , 0 , ( k , v ) = > v ) ;
if ( count + 1 < parallelRequestsToController )
2022-11-01 17:14:19 +05:00
{
try
{
2022-11-10 13:59:48 +05:00
userStat [ controllerName ] + + ;
2022-11-01 17:14:19 +05:00
await next ( context ) ;
}
finally
{
userStat [ controllerName ] - - ;
}
}
else
{
context . Response . Clear ( ) ;
context . Response . StatusCode = ( int ) System . Net . HttpStatusCode . TooManyRequests ;
context . Response . Headers . RetryAfter = "1000" ;
context . Response . Headers . ContentType = "text/html" ;
2022-11-10 13:59:48 +05:00
await context . Response . BodyWriter . WriteAsync ( responseBody ) ;
2022-11-01 17:14:19 +05:00
}
}
}
#nullable disable
}