forked from ddrilling/AsbCloudServer
fix #7582867
This commit is contained in:
parent
64641c5bc3
commit
698fb33651
@ -9,7 +9,42 @@ namespace AsbCloudWebApi.Tests.Middlware
|
|||||||
{
|
{
|
||||||
public class UserConnectionsLimitMiddlwareTest
|
public class UserConnectionsLimitMiddlwareTest
|
||||||
{
|
{
|
||||||
private readonly HttpClient httpClient;
|
const int iterations2Block = 8;
|
||||||
|
|
||||||
|
//Данные в тестовой БД
|
||||||
|
//select
|
||||||
|
// tw.id,
|
||||||
|
// t_stat.minDate,
|
||||||
|
// t_stat.maxDate
|
||||||
|
//from(
|
||||||
|
// select
|
||||||
|
|
||||||
|
// id_telemetry,
|
||||||
|
// count(1) as count,
|
||||||
|
// min("date") as minDate,
|
||||||
|
// max("date") as maxDate
|
||||||
|
|
||||||
|
// from t_telemetry_data_saub
|
||||||
|
|
||||||
|
// group by id_telemetry
|
||||||
|
//) as t_stat
|
||||||
|
//join t_well tw on tw.id_telemetry = t_stat.id_telemetry
|
||||||
|
//where tw is not null
|
||||||
|
//order by t_stat.count
|
||||||
|
//limit 10;
|
||||||
|
private readonly (int, DateTime, DateTime)[] wells = new[]
|
||||||
|
{
|
||||||
|
(191, new DateTime(2022, 09, 01, 21, 43, 00, DateTimeKind.Utc), new DateTime(2022, 09, 04, 07, 37, 31, DateTimeKind.Utc)),
|
||||||
|
(3 , new DateTime(2021, 09, 16, 06, 13, 33, DateTimeKind.Utc), new DateTime(2021, 09, 20, 00, 29, 28, DateTimeKind.Utc)),
|
||||||
|
(199, new DateTime(2022, 09, 15, 11, 27, 18, DateTimeKind.Utc), new DateTime(2022, 09, 20, 14, 00, 23, DateTimeKind.Utc)),
|
||||||
|
(6 , new DateTime(2021, 09, 20, 00, 35, 03, DateTimeKind.Utc), new DateTime(2021, 09, 25, 06, 46, 17, DateTimeKind.Utc)),
|
||||||
|
(41 , new DateTime(2021, 12, 10, 00, 59, 52, DateTimeKind.Utc), new DateTime(2022, 10, 31, 15, 29, 24, DateTimeKind.Utc)),
|
||||||
|
(100, new DateTime(2022, 04, 24, 03, 04, 05, DateTimeKind.Utc), new DateTime(2022, 04, 29, 11, 38, 36, DateTimeKind.Utc)),
|
||||||
|
(154, new DateTime(2022, 03, 28, 10, 09, 14, DateTimeKind.Utc), new DateTime(2022, 06, 14, 15, 01, 12, DateTimeKind.Utc)),
|
||||||
|
(5 , new DateTime(2021, 09, 25, 08, 09, 37, DateTimeKind.Utc), new DateTime(2021, 10, 01, 14, 39, 51, DateTimeKind.Utc)),
|
||||||
|
(1 , new DateTime(2021, 09, 10, 01, 32, 42, DateTimeKind.Utc), new DateTime(2021, 09, 18, 00, 35, 22, DateTimeKind.Utc)),
|
||||||
|
(112, new DateTime(2022, 04, 20, 16, 47, 51, DateTimeKind.Utc), new DateTime(2022, 04, 28, 15, 04, 33, DateTimeKind.Utc)),
|
||||||
|
};
|
||||||
|
|
||||||
public UserConnectionsLimitMiddlwareTest()
|
public UserConnectionsLimitMiddlwareTest()
|
||||||
{
|
{
|
||||||
@ -20,66 +55,53 @@ namespace AsbCloudWebApi.Tests.Middlware
|
|||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
host.Start();
|
host.Start();
|
||||||
httpClient = new ();
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new("Bearer", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjY1ODY2MjAsImV4cCI6MTY5ODE0NDIyMCwiaXNzIjoiYSIsImF1ZCI6ImEifQ.zqBdR4nYB87-Xyzv025waasN47i43c9FJ23RfzIvUsM");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Send_n_requests_and_get_blocked()
|
public async Task Send_n_requests_and_get_blocked()
|
||||||
{
|
{
|
||||||
//Данные в тестовой БД
|
|
||||||
//select
|
|
||||||
// tw.id,
|
|
||||||
// t_stat.minDate,
|
|
||||||
// t_stat.maxDate
|
|
||||||
//from(
|
|
||||||
// select
|
|
||||||
|
|
||||||
// id_telemetry,
|
|
||||||
// count(1) as count,
|
|
||||||
// min("date") as minDate,
|
|
||||||
// max("date") as maxDate
|
|
||||||
|
|
||||||
// from t_telemetry_data_saub
|
|
||||||
|
|
||||||
// group by id_telemetry
|
|
||||||
//) as t_stat
|
|
||||||
//join t_well tw on tw.id_telemetry = t_stat.id_telemetry
|
|
||||||
//where tw is not null
|
|
||||||
//order by t_stat.count
|
|
||||||
//limit 10;
|
|
||||||
|
|
||||||
var wells = new []
|
|
||||||
{
|
|
||||||
(191, new DateTime(2022, 09, 01, 21, 43, 00, DateTimeKind.Utc), new DateTime(2022, 09, 04, 07, 37, 31, DateTimeKind.Utc)),
|
|
||||||
(3 , new DateTime(2021, 09, 16, 06, 13, 33, DateTimeKind.Utc), new DateTime(2021, 09, 20, 00, 29, 28, DateTimeKind.Utc)),
|
|
||||||
(199, new DateTime(2022, 09, 15, 11, 27, 18, DateTimeKind.Utc), new DateTime(2022, 09, 20, 14, 00, 23, DateTimeKind.Utc)),
|
|
||||||
(6 , new DateTime(2021, 09, 20, 00, 35, 03, DateTimeKind.Utc), new DateTime(2021, 09, 25, 06, 46, 17, DateTimeKind.Utc)),
|
|
||||||
(41 , new DateTime(2021, 12, 10, 00, 59, 52, DateTimeKind.Utc), new DateTime(2022, 10, 31, 15, 29, 24, DateTimeKind.Utc)),
|
|
||||||
(100, new DateTime(2022, 04, 24, 03, 04, 05, DateTimeKind.Utc), new DateTime(2022, 04, 29, 11, 38, 36, DateTimeKind.Utc)),
|
|
||||||
(154, new DateTime(2022, 03, 28, 10, 09, 14, DateTimeKind.Utc), new DateTime(2022, 06, 14, 15, 01, 12, DateTimeKind.Utc)),
|
|
||||||
(5 , new DateTime(2021, 09, 25, 08, 09, 37, DateTimeKind.Utc), new DateTime(2021, 10, 01, 14, 39, 51, DateTimeKind.Utc)),
|
|
||||||
(1 , new DateTime(2021, 09, 10, 01, 32, 42, DateTimeKind.Utc), new DateTime(2021, 09, 18, 00, 35, 22, DateTimeKind.Utc)),
|
|
||||||
(112, new DateTime(2022, 04, 20, 16, 47, 51, DateTimeKind.Utc), new DateTime(2022, 04, 28, 15, 04, 33, DateTimeKind.Utc)),
|
|
||||||
};
|
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for (; i < 5; i++)
|
for (; i < iterations2Block; i++)
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var well = wells[i];
|
var well = wells[i];
|
||||||
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
||||||
var response = await httpClient.GetAsync(url);
|
var response = await MakeHttpClient().GetAsync(url);
|
||||||
//await response.Content.ReadAsStringAsync();
|
//await response.Content.ReadAsStringAsync();
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
var well = wells[i];
|
var well = wells[i];
|
||||||
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
||||||
var response = await httpClient.GetAsync(url);
|
var response = await MakeHttpClient().GetAsync(url);
|
||||||
Assert.Equal(System.Net.HttpStatusCode.TooManyRequests, response.StatusCode);
|
Assert.Equal(System.Net.HttpStatusCode.TooManyRequests, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Send_n_requests_and_get_blocked_then_restored()
|
||||||
|
{
|
||||||
|
var i = 0;
|
||||||
|
var tasks = new Task[iterations2Block];
|
||||||
|
for (; i < iterations2Block; i++)
|
||||||
|
tasks[i] = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
var well = wells[i];
|
||||||
|
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
||||||
|
var response = await MakeHttpClient().GetAsync(url);
|
||||||
|
await Task.Delay(1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
var well = wells[i];
|
||||||
|
var url = MakeUrl(well.Item1, well.Item2, well.Item3);
|
||||||
|
var response = await MakeHttpClient().GetAsync(url);
|
||||||
|
Assert.Equal(System.Net.HttpStatusCode.TooManyRequests, response.StatusCode);
|
||||||
|
|
||||||
|
Task.WaitAll(tasks);
|
||||||
|
response = await MakeHttpClient().GetAsync(url);
|
||||||
|
Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
private static string MakeUrl(int idWell, DateTime dateBegin, DateTime dateEnd)
|
private static string MakeUrl(int idWell, DateTime dateBegin, DateTime dateEnd)
|
||||||
{
|
{
|
||||||
var interval = (dateEnd - dateBegin).TotalSeconds;
|
var interval = (dateEnd - dateBegin).TotalSeconds;
|
||||||
@ -87,5 +109,13 @@ namespace AsbCloudWebApi.Tests.Middlware
|
|||||||
var url = $"http://127.0.0.1:5000/api/TelemetryDataSaub/{idWell}?begin={dateBeginString}&intervalSec={interval}&approxPointsCount={interval}";
|
var url = $"http://127.0.0.1:5000/api/TelemetryDataSaub/{idWell}?begin={dateBeginString}&intervalSec={interval}&approxPointsCount={interval}";
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HttpClient MakeHttpClient()
|
||||||
|
{
|
||||||
|
var httpClient = new HttpClient();
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new("Bearer", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZGV2IiwiaWRDb21wYW55IjoiMSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6InJvb3QiLCJuYmYiOjE2NjY1ODY2MjAsImV4cCI6MTY5ODE0NDIyMCwiaXNzIjoiYSIsImF1ZCI6ImEifQ.zqBdR4nYB87-Xyzv025waasN47i43c9FJ23RfzIvUsM");
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,25 +14,26 @@ namespace AsbCloudWebApi.Middlewares
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class UserConnectionsLimitMiddlware
|
class UserConnectionsLimitMiddlware
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate next;
|
|
||||||
private readonly int parallelRequestsToController;
|
private readonly int parallelRequestsToController;
|
||||||
private readonly byte[] body;
|
private readonly RequestDelegate next;
|
||||||
|
private readonly byte[] responseBody;
|
||||||
private readonly ConcurrentDictionary<int, ConcurrentDictionary<string, int>> stat = new ();
|
private readonly ConcurrentDictionary<int, ConcurrentDictionary<string, int>> stat = new ();
|
||||||
private readonly IEnumerable<string>? controllerNames;
|
private readonly IEnumerable<string>? controllerNames;
|
||||||
|
|
||||||
public UserConnectionsLimitMiddlware(RequestDelegate next, IConfiguration configuration)
|
public UserConnectionsLimitMiddlware(RequestDelegate next, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
const int parallelRequestsToControllerDefault = 8;
|
||||||
this.next = next;
|
this.next = next;
|
||||||
|
|
||||||
var parallelRequestsToController = configuration.GetSection("userLimits")?.GetValue<int>("parallelRequestsToController") ?? 5;
|
var parallelRequestsToController = configuration.GetSection("userLimits")?.GetValue<int>("parallelRequestsToController") ?? parallelRequestsToControllerDefault;
|
||||||
this.parallelRequestsToController = parallelRequestsToController > 0
|
this.parallelRequestsToController = parallelRequestsToController > 0
|
||||||
? parallelRequestsToController
|
? parallelRequestsToController
|
||||||
: 5;
|
: parallelRequestsToControllerDefault;
|
||||||
|
|
||||||
controllerNames = configuration.GetSection("userLimits")?.GetValue<IEnumerable<string>>("controllerNames");
|
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>";
|
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>";
|
||||||
body = System.Text.Encoding.UTF8.GetBytes(bodyText);
|
responseBody = System.Text.Encoding.UTF8.GetBytes(bodyText);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InvokeAsync(HttpContext context, int idUser, string controllerName)
|
public async Task InvokeAsync(HttpContext context, int idUser, string controllerName)
|
||||||
@ -41,14 +42,16 @@ namespace AsbCloudWebApi.Middlewares
|
|||||||
{
|
{
|
||||||
await next(context);
|
await next(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userStat = stat.GetOrAdd(idUser, idUser => new());
|
var userStat = stat.GetOrAdd(idUser, idUser => new());
|
||||||
var count = userStat.AddOrUpdate(controllerName, 1, (key, value) => value + 1);
|
var count = userStat.AddOrUpdate(controllerName, 0, (k, v) => v);
|
||||||
if(count < parallelRequestsToController)
|
|
||||||
|
if(count + 1 < parallelRequestsToController)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
userStat[controllerName]++;
|
||||||
await next(context);
|
await next(context);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -60,10 +63,9 @@ namespace AsbCloudWebApi.Middlewares
|
|||||||
{
|
{
|
||||||
context.Response.Clear();
|
context.Response.Clear();
|
||||||
context.Response.StatusCode = (int)System.Net.HttpStatusCode.TooManyRequests;
|
context.Response.StatusCode = (int)System.Net.HttpStatusCode.TooManyRequests;
|
||||||
|
|
||||||
context.Response.Headers.RetryAfter = "1000";
|
context.Response.Headers.RetryAfter = "1000";
|
||||||
context.Response.Headers.ContentType = "text/html";
|
context.Response.Headers.ContentType = "text/html";
|
||||||
await context.Response.BodyWriter.WriteAsync(body);
|
await context.Response.BodyWriter.WriteAsync(responseBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user