diff --git a/src/CSharp/EasyMicroservices.Laboratory.Tests/EasyMicroservices.Laboratory.Tests.csproj b/src/CSharp/EasyMicroservices.Laboratory.Tests/EasyMicroservices.Laboratory.Tests.csproj
index e40f70f..1340ee8 100644
--- a/src/CSharp/EasyMicroservices.Laboratory.Tests/EasyMicroservices.Laboratory.Tests.csproj
+++ b/src/CSharp/EasyMicroservices.Laboratory.Tests/EasyMicroservices.Laboratory.Tests.csproj
@@ -19,4 +19,22 @@
+
+
+
+ 7.0.0
+
+
+
+
+
+ 7.0.0
+
+
+
+
+
+ 7.0.0
+
+
diff --git a/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/BaseHandlerTest.cs b/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/BaseHandlerTest.cs
index 223d3f2..2eeb0bf 100644
--- a/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/BaseHandlerTest.cs
+++ b/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/BaseHandlerTest.cs
@@ -1,13 +1,12 @@
using EasyMicroservices.Laboratory.Constants;
using EasyMicroservices.Laboratory.Engine;
using EasyMicroservices.Laboratory.Engine.Net;
-using EasyMicroservices.Laboratory.Engine.Net.Http;
using EasyMicroservices.Laboratory.Models;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Net;
using System.Net.Http;
-using System.Text;
using System.Threading.Tasks;
using Xunit;
@@ -15,7 +14,26 @@ namespace EasyMicroservice.Laboratory.Tests.Engine.Net
{
public abstract class BaseHandlerTest
{
+ public HttpClient GetHttpClient()
+ {
+ HttpClient httpClient = default;
+// if (System.Environment.OSVersion.Platform != PlatformID.Unix)
+// {
+//#if (NET452)
+// httpClient = new HttpClient();
+//#else
+// var handler = new WinHttpHandler();
+// httpClient = new HttpClient(handler);
+//#endif
+// }
+// else
+ httpClient = new HttpClient();
+#if (!NET452 && !NET48)
+ httpClient.DefaultRequestVersion = HttpVersion.Version20;
+#endif
+ return httpClient;
+ }
protected abstract BaseHandler GetHandler(ResourceManager resourceManager);
public string GetHttpResponseHeaders(string response)
{
@@ -49,7 +67,7 @@ public async Task CheckSimpleRequestAndResponse(string request, string response)
resourceManager.Append(request, GetHttpResponseHeaders(response));
var port = await GetHandler(resourceManager).Start();
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
var data = new StringContent(request);
var httpResponse = await httpClient.PostAsync($"http://localhost:{port}", data);
Assert.Equal(await httpResponse.Content.ReadAsStringAsync(), response);
@@ -72,7 +90,7 @@ public async Task ConcurrentCheckSimpleRequestAndResponse(string request, string
{
all.Add(Task.Run(async () =>
{
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
var data = new StringContent(request);
var httpResponse = await httpClient.PostAsync($"http://localhost:{port}", data);
Assert.Equal(await httpResponse.Content.ReadAsStringAsync(), response);
@@ -94,10 +112,10 @@ public async Task ConcurrentSingleHttpClientCheckSimpleRequestAndResponse(string
ResourceManager resourceManager = new ResourceManager();
resourceManager.Append(request, GetHttpResponseHeaders(response));
var port = await GetHandler(resourceManager).Start();
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
List> all = new List>();
- for (int i = 0; i < 100; i++)
+ for (int i = 0; i < 20; i++)
{
all.Add(Task.Run(async () =>
{
@@ -120,7 +138,7 @@ public async Task CheckSimpleRequestToGiveMeFullRequestHeaderValue(string reques
ResourceManager resourceManager = new ResourceManager();
var port = await GetHandler(resourceManager).Start();
response = response.Replace("*MyPort*", port.ToString());
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
httpClient.DefaultRequestHeaders.ExpectContinue = false;
httpClient.DefaultRequestHeaders.Add(RequestTypeHeaderConstants.RequestTypeHeader, RequestTypeHeaderConstants.GiveMeFullRequestHeaderValue);
var data = new StringContent(request);
@@ -140,14 +158,14 @@ public async Task CheckSimpleRequestToGiveMeLastFullRequestHeaderValue(string re
ResourceManager resourceManager = new ResourceManager();
var port = await GetHandler(resourceManager).Start();
response = response.Replace("*MyPort*", port.ToString());
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
httpClient.DefaultRequestHeaders.ExpectContinue = false;
httpClient.DefaultRequestHeaders.Add(RequestTypeHeaderConstants.RequestTypeHeader, RequestTypeHeaderConstants.GiveMeFullRequestHeaderValue);
var data = new StringContent(request);
var httpResponse = await httpClient.PostAsync($"http://localhost:{port}", data);
var textResponse = await httpResponse.Content.ReadAsStringAsync();
- httpClient = new HttpClient();
+ httpClient = GetHttpClient();
httpClient.DefaultRequestHeaders.Add(RequestTypeHeaderConstants.RequestTypeHeader, RequestTypeHeaderConstants.GiveMeLastFullRequestHeaderValue);
httpResponse = await httpClient.GetAsync($"http://localhost:{port}");
textResponse = await httpResponse.Content.ReadAsStringAsync();
@@ -185,7 +203,7 @@ public async Task CheckComplex(string request, string response, string simpleRes
ResourceManager resourceManager = new ResourceManager();
resourceManager.Append(request, response);
var port = await GetHandler(resourceManager).Start();
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
httpClient.DefaultRequestHeaders.Add("x-amz-meta-title", "someTitle");
httpClient.DefaultRequestHeaders.Add("User-Agent", "aws-sdk-dotnet-coreclr/3.7.101.44 aws-sdk-dotnet-core/3.7.103.6 .NET_Core/6.0.11 OS/Microsoft_Windows_10.0.22000 ClientAsync");
httpClient.DefaultRequestHeaders.Add("amz-sdk-invocation-id", "guid");
@@ -259,19 +277,19 @@ public async Task CheckScope()
client.DefaultRequestHeaders.Add("Authorization", "empty");
client.DefaultRequestHeaders.Add("Host", "s3.eu-west-1.amazonaws.com");
};
- HttpClient httpClient = new HttpClient();
+ HttpClient httpClient = GetHttpClient();
addHeaders(httpClient);
var httpResponse = await httpClient.PutAsync($"http://localhost:{port}", null);
var textResponse = await httpResponse.Content.ReadAsStringAsync();
Assert.Equal("Ali", textResponse);
- httpClient = new HttpClient();
+ httpClient = GetHttpClient();
addHeaders(httpClient);
httpResponse = await httpClient.PutAsync($"http://localhost:{port}", null);
textResponse = await httpResponse.Content.ReadAsStringAsync();
Assert.Equal("Reza", textResponse);
- httpClient = new HttpClient();
+ httpClient = GetHttpClient();
addHeaders(httpClient);
httpResponse = await httpClient.PutAsync($"http://localhost:{port}", null);
textResponse = await httpResponse.Content.ReadAsStringAsync();
diff --git a/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/HostHttpHandlerTest.cs b/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/HostHttpHandlerTest.cs
new file mode 100644
index 0000000..cea81f1
--- /dev/null
+++ b/src/CSharp/EasyMicroservices.Laboratory.Tests/Engine/Net/HostHttpHandlerTest.cs
@@ -0,0 +1,17 @@
+#if(NET6_0_OR_GREATER)
+using EasyMicroservice.Laboratory.Tests.Engine.Net;
+using EasyMicroservices.Laboratory.Engine;
+using EasyMicroservices.Laboratory.Engine.Net;
+using EasyMicroservices.Laboratory.Engine.Net.Http;
+
+namespace EasyMicroservices.Laboratory.Tests.Engine.Net
+{
+ public class HostHttpHandlerTest : BaseHandlerTest
+ {
+ protected override BaseHandler GetHandler(ResourceManager resourceManager)
+ {
+ return new HostHttpHandler(resourceManager);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/CSharp/EasyMicroservices.Laboratory/EasyMicroservices.Laboratory.csproj b/src/CSharp/EasyMicroservices.Laboratory/EasyMicroservices.Laboratory.csproj
index 5526dcb..b5508a1 100644
--- a/src/CSharp/EasyMicroservices.Laboratory/EasyMicroservices.Laboratory.csproj
+++ b/src/CSharp/EasyMicroservices.Laboratory/EasyMicroservices.Laboratory.csproj
@@ -4,7 +4,7 @@
AnyCPU;x64;x86
EasyMicroservices
true
- 0.0.0.14
+ 0.0.0.15
Laboratory of http client.
EasyMicroservices@gmail.com
test,tests,http,https,httpclient,laboratory
@@ -19,4 +19,20 @@
+
+
+ 7.0.1
+
+
+
+
+ 7.0.1
+
+
+
+
+ 7.0.1
+
+
+
\ No newline at end of file
diff --git a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/BaseHandler.cs b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/BaseHandler.cs
index d7ed3e0..159f422 100644
--- a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/BaseHandler.cs
+++ b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/BaseHandler.cs
@@ -1,12 +1,5 @@
-using EasyMicroservices.Laboratory.Constants;
+using EasyMicroservices.Laboratory.Engine.Net.Http;
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
using System.Threading.Tasks;
namespace EasyMicroservices.Laboratory.Engine.Net
@@ -55,5 +48,21 @@ public int GetRandomPort()
{
return _random.Next(1111, 9999);
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static BaseHandler CreateOSHandler(ResourceManager resourceManager)
+ {
+#if (NET6_0_OR_GREATER)
+ if (System.Environment.OSVersion.Platform == PlatformID.Unix)
+ return new HostHttpHandler(resourceManager);
+ else
+ return new HttpHandler(resourceManager);
+#else
+ throw new NotSupportedException("Only support on net6.0 or grater!");
+#endif
+ }
}
}
\ No newline at end of file
diff --git a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandler.cs b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandler.cs
new file mode 100644
index 0000000..e33c3e6
--- /dev/null
+++ b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandler.cs
@@ -0,0 +1,69 @@
+#if(NET6_0_OR_GREATER)
+using Microsoft.AspNetCore.Http;
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EasyMicroservices.Laboratory.Engine.Net.Http
+{
+ ///
+ ///
+ ///
+ public class HostHttpHandler : HostHttpHandlerBase
+ {
+ ///
+ ///
+ ///
+ ///
+ public HostHttpHandler(ResourceManager resourceManager) : base(resourceManager)
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected override async Task HandleHttpClient(HttpContext httpClient)
+ {
+ var reader = new StreamReader(httpClient.Request.Body);
+ var requestBody = await reader.ReadToEndAsync();
+ var firstLine = $"{httpClient.Request.Method} {httpClient.Request.Path} {httpClient.Request.Protocol}";
+ var headers = httpClient.Request.Headers.ToDictionary((x) => x.Key, (v) => v.Value.FirstOrDefault());
+ StringBuilder fullBody = new StringBuilder();
+ fullBody.AppendLine(firstLine);
+ foreach (var item in headers.OrderBy(x => x.Key))
+ {
+ fullBody.AppendLine($"{item.Key}: {item.Value}");
+ }
+ fullBody.Append(requestBody);
+ var responseBody = await WriteResponseAsync(firstLine, headers, requestBody, fullBody);
+ using (var responseReader = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(responseBody))))
+ {
+ await responseReader.ReadLineAsync();
+ do
+ {
+ var line = await responseReader.ReadLineAsync();
+ if (string.IsNullOrEmpty(line))
+ break;
+ var header = line.Split(':');
+ if (header[0].Equals("content-length", StringComparison.OrdinalIgnoreCase))
+ continue;
+ httpClient.Response.Headers.Add(header[0], header[1]);
+ }
+ while (true);
+ var body = await responseReader.ReadToEndAsync();
+ var bytes = Encoding.UTF8.GetBytes(body);
+ httpClient.Response.ContentLength = bytes.Length;
+
+ await httpClient.Response.Body.WriteAsync(bytes, 0, bytes.Length);
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandlerBase.cs b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandlerBase.cs
new file mode 100644
index 0000000..8e69bd3
--- /dev/null
+++ b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HostHttpHandlerBase.cs
@@ -0,0 +1,203 @@
+#if (NET6_0_OR_GREATER)
+using EasyMicroservices.Laboratory.Constants;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace EasyMicroservices.Laboratory.Engine.Net.Http
+{
+ ///
+ ///
+ ///
+ public abstract class HostHttpHandlerBase : BaseHandler
+ {
+ ///
+ ///
+ ///
+ public HostHttpHandlerBase(ResourceManager resourceManager) : base(resourceManager)
+ {
+ }
+
+ ///
+ /// Start the Http listener
+ ///
+ ///
+ ///
+ public override Task Start(int port)
+ {
+ return InternalStart(port);
+ }
+
+ ///
+ /// start on any random port
+ ///
+ /// port to listen
+ public override async Task Start()
+ {
+ int port;
+ while (true)
+ {
+ port = GetRandomPort();
+ try
+ {
+ await InternalStart(port);
+ break;
+ }
+ catch
+ {
+ }
+ }
+ return port;
+ }
+
+ ///
+ ///
+ ///
+ public override void Stop()
+ {
+
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual async Task InternalStart(int port)
+ {
+ var builder = WebApplication.CreateBuilder();
+ builder.WebHost.UseUrls($"http://*:{port}");
+ var app = builder.Build();
+ app.Use(async (context, next) =>
+ {
+ await HandleHttpClient(context);
+ await next(context);
+ });
+ await Task.WhenAny(app.RunAsync(null), Task.Delay(3000));
+ }
+
+ ///
+ /// Handle a Http client
+ ///
+ ///
+ ///
+ protected abstract Task HandleHttpClient(HttpContext httpClient);
+
+ string _lastResponseBody = "";
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task WriteResponseAsync(string firstLine, Dictionary requestHeaders, string requestBody, StringBuilder fullBody)
+ {
+ string responseBody = "";
+ if (requestHeaders.TryGetValue(RequestTypeHeaderConstants.RequestTypeHeader, out string headerTypeValue))
+ {
+ switch (headerTypeValue)
+ {
+ case RequestTypeHeaderConstants.GiveMeFullRequestHeaderValue:
+ {
+ responseBody = GetGiveMeFullRequestHeaderValueResponse(firstLine, requestHeaders, requestBody);
+ break;
+ }
+ case RequestTypeHeaderConstants.GiveMeLastFullRequestHeaderValue:
+ {
+ responseBody = _lastResponseBody;
+ break;
+ }
+ }
+ }
+ else
+ responseBody = await _requestHandler.FindResponseBody(fullBody.ToString());
+ if (string.IsNullOrEmpty(responseBody))
+ responseBody = GetNoResponse(firstLine, requestHeaders, requestBody);
+ _lastResponseBody = responseBody;
+ return responseBody;
+ }
+
+ string GetGiveMeFullRequestHeaderValueResponse(string firstLine, Dictionary requestHeaders, string requestBody)
+ {
+ StringBuilder responseBuilder = new();
+ StringBuilder bodyBuilder = new();
+ responseBuilder.AppendLine(DefaultResponse());
+ bodyBuilder.AppendLine(firstLine);
+ foreach (var header in requestHeaders.Where(x => !x.Key.Equals(RequestTypeHeaderConstants.RequestTypeHeader, StringComparison.OrdinalIgnoreCase)).OrderBy(x => x.Key))
+ {
+ bodyBuilder.Append(header.Key);
+ bodyBuilder.Append(": ");
+ bodyBuilder.AppendLine(header.Value);
+ }
+ bodyBuilder.AppendLine();
+ bodyBuilder.Append(requestBody);
+
+ responseBuilder.AppendLine($"Content-Length: {bodyBuilder.Length}");
+ responseBuilder.AppendLine();
+ responseBuilder.Append(bodyBuilder);
+
+ return responseBuilder.ToString();
+ }
+
+ string DefaultResponse()
+ {
+ return @$"HTTP/1.1 200 OK
+Cache-Control: no-cache
+Pragma: no-cache
+Content-Type: text/plain; charset=utf-8
+Vary: Accept-Encoding";
+ }
+
+ string GetNoResponse(string firstLine, Dictionary requestHeaders, string requestBody)
+ {
+ StringBuilder stringBuilder = new StringBuilder();
+ StringBuilder bodyBuilder = new();
+ bodyBuilder.AppendLine(firstLine);
+ foreach (var header in requestHeaders.OrderBy(x => x.Key))
+ {
+ bodyBuilder.Append(header.Key);
+ bodyBuilder.Append(": ");
+ bodyBuilder.AppendLine(header.Value);
+ }
+ bodyBuilder.AppendLine();
+ bodyBuilder.Append(requestBody);
+ var defaultResponse = @$"HTTP/1.1 405 OK
+Cache-Control: no-cache
+Pragma: no-cache
+Content-Type: text/plain; charset=utf-8
+Vary: Accept-Encoding";
+ stringBuilder.AppendLine(defaultResponse);
+ stringBuilder.AppendLine($"Content-Length: {bodyBuilder.Length}");
+ stringBuilder.AppendLine();
+ stringBuilder.Append(bodyBuilder);
+ return stringBuilder.ToString();
+ }
+
+ string MergeRequest(string firstLine, Dictionary requestHeaders, string requestBody)
+ {
+ StringBuilder bodyBuilder = new();
+ bodyBuilder.AppendLine(firstLine);
+ foreach (var header in requestHeaders)
+ {
+ bodyBuilder.Append(header.Key);
+ bodyBuilder.Append(": ");
+ bodyBuilder.AppendLine(header.Value);
+ }
+ bodyBuilder.AppendLine();
+ bodyBuilder.Append(requestBody);
+ return bodyBuilder.ToString();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HttpHandlerBase.cs b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HttpHandlerBase.cs
index c2123c0..afb9fb4 100644
--- a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HttpHandlerBase.cs
+++ b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/Http/HttpHandlerBase.cs
@@ -38,6 +38,7 @@ public override Task Start(int port)
public override async Task Start()
{
int port;
+ int retry = 0;
while (true)
{
port = GetRandomPort();
@@ -48,6 +49,9 @@ public override async Task Start()
}
catch
{
+ retry++;
+ if (retry > 5)
+ throw;
}
}
return port;
diff --git a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/TcpHandlerBase.cs b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/TcpHandlerBase.cs
index fbc0af7..0ba6346 100644
--- a/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/TcpHandlerBase.cs
+++ b/src/CSharp/EasyMicroservices.Laboratory/Engine/Net/TcpHandlerBase.cs
@@ -39,6 +39,7 @@ public override Task Start(int port)
public override async Task Start()
{
int port;
+ int retry = 0;
while (true)
{
port = GetRandomPort();
@@ -49,6 +50,9 @@ public override async Task Start()
}
catch
{
+ retry++;
+ if (retry > 5)
+ throw;
}
}
return port;