From a0ca9365549e5c05e674f160f09a64ab894fd1a6 Mon Sep 17 00:00:00 2001 From: Harald Wolff-Thobaben Date: Mon, 7 Aug 2023 10:38:29 +0200 Subject: [PATCH] Several massive changes and additions --- ln.http.helpers/HttpCaptcha.cs | 291 ++++++++++++++++++++++++ ln.http.helpers/HttpMailer.cs | 80 +++++++ ln.http.helpers/ln.http.helpers.csproj | 20 ++ ln.http.service/Program.cs | 15 +- ln.http.service/bootstrap.json | 61 +++-- ln.http.service/ln.http.HttpServer.json | 63 +++++ ln.http.service/ln.http.service.csproj | 14 +- ln.http.service/localhost.crt | Bin 0 -> 4039 bytes ln.http.sln | 18 ++ ln.http.tests/CaptchaTests.cs | 25 ++ ln.http.tests/UnitTest1.cs | 43 ++-- ln.http.tests/ln.http.tests.csproj | 7 +- 12 files changed, 579 insertions(+), 58 deletions(-) create mode 100644 ln.http.helpers/HttpCaptcha.cs create mode 100644 ln.http.helpers/HttpMailer.cs create mode 100644 ln.http.helpers/ln.http.helpers.csproj create mode 100644 ln.http.service/ln.http.HttpServer.json create mode 100644 ln.http.service/localhost.crt create mode 100644 ln.http.tests/CaptchaTests.cs diff --git a/ln.http.helpers/HttpCaptcha.cs b/ln.http.helpers/HttpCaptcha.cs new file mode 100644 index 0000000..5a0f053 --- /dev/null +++ b/ln.http.helpers/HttpCaptcha.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using ln.http.route; +using ln.json; +using ln.json.mapping; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace ln.http.helpers +{ + + public class HttpCaptcha : HttpRoute + { + private Dictionary _captchaInstances = new Dictionary(); + private CaptchaEndpoints _captchaEndpoints; + + public HtmlColor[] CaptchaColors { get; } = new HtmlColor[] + { + HtmlColor.Red, HtmlColor.Green, HtmlColor.Blue, HtmlColor.Yellow, HtmlColor.Violett, HtmlColor.turquoise + }; + + public Random _random = new Random(Environment.TickCount + Thread.CurrentThread.GetHashCode()); + + public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(10); + public int SolutionLength { get; set; } + public int GroupLength { get; set; } + + public HttpCaptcha(HttpRouter httpRouter, string mapPath) + :this(httpRouter, mapPath, 25, 5) + {} + public HttpCaptcha(HttpRouter httpRouter, string mapPath, int groupLength, int solutionLength) + : base(HttpMethod.ANY, mapPath) + { + _captchaEndpoints = new CaptchaEndpoints(this); + _routerDelegate = _captchaEndpoints.RouteRequest; + + GroupLength = groupLength; + SolutionLength = solutionLength; + + httpRouter.Map(this); + } + + public CaptchaInstance CreateInstance() => new CaptchaInstance(this); + + public bool Authorize(HttpRequest httpRequest) + { + return false; + } + + class CaptchaEndpoints : HttpEndpointController + { + private HttpCaptcha _httpCaptcha; + + public CaptchaEndpoints(HttpCaptcha httpCaptcha) + { + _httpCaptcha = httpCaptcha; + } + + [Map(HttpMethod.GET,"")] + public HttpResponse GetCaptcha() + { + return HttpResponse + .OK() + .Content( + _httpCaptcha + .CreateInstance() + .Json() + ); + } + + [Map(HttpMethod.GET, "/:instance/:combination")] + public HttpResponse DrawCombination(Guid instance, int combination) + { + int imageSize = 48; + + if (!_httpCaptcha._captchaInstances.TryGetValue(instance, out CaptchaInstance captchaInstance) || + ((combination < 0) || (combination >= captchaInstance.Combinations.Length))) + return HttpResponse.NotFound(); + + CaptchaCombination captchaCombination = captchaInstance.Combinations[combination]; + + Image combinationImage = new Image(imageSize, imageSize, new Rgb24(255,255,255)); + IPath combinationPath = null; + + switch (captchaCombination.Form) + { + case CaptchaForm.Stern: + combinationPath = new Star((float)(imageSize / 2.0), + (float)(imageSize / 2.0), captchaCombination.Corners, + (float)(imageSize / 6.0), (float)(imageSize / 2.3)); + break; + case CaptchaForm.Vieleck: + combinationPath = new RegularPolygon((float)(imageSize / 2.0), + (float)(imageSize / 2.0), captchaCombination.Corners, + (float)(imageSize / 2.3)); + break; + default: + return HttpResponse.InternalServerError(); + } + + combinationImage.Mutate(x => x.Fill(captchaCombination.Color, combinationPath.RotateDegree(_httpCaptcha._random.Next(360)))); + + StreamedContent streamedContent = new StreamedContent("image/png"); + combinationImage.SaveAsPng(streamedContent.ContentStream); + + HttpResponse httpResponse = HttpResponse.OK().Content(streamedContent); + return httpResponse; + } + + [Map(HttpMethod.POST, "/:instance")] + public HttpResponse Solve(Guid instance, [HttpArgumentSource(HttpArgumentSource.CONTENT)] JSONValue body) + { + if (!_httpCaptcha._captchaInstances.TryGetValue(instance, out CaptchaInstance captchaInstance)) + return HttpResponse.NotFound(); + + if (body is JSONArray jsonSolution) + { + int[] solution = JSONMapper.DefaultMapper.FromJson(jsonSolution); + + if (captchaInstance.Solve(solution)) + { + return HttpResponse.NoContent(); + } + return HttpResponse.Forbidden(); + } + else + { + return HttpResponse.BadRequest(); + } + } + } + + public class CaptchaInstance : IDisposable + { + public Guid Guid { get; } + + public CaptchaCombination[] Combinations { get; private set; } + public int[] Solution { get; private set; } + + + private HttpCaptcha _httpCaptcha; + private Timer _timer; + + public CaptchaInstance(HttpCaptcha httpCaptcha) + { + _httpCaptcha = httpCaptcha; + Guid = Guid.NewGuid(); + + _httpCaptcha._captchaInstances.Add(Guid, this); + _timer = new Timer((state) => Dispose(), null, _httpCaptcha.Timeout, TimeSpan.Zero); + + Initialize(); + } + + private void Initialize() + { + HashSet hashSet = new HashSet(); + while (hashSet.Count < _httpCaptcha.GroupLength) + hashSet.Add(new CaptchaCombination(this._httpCaptcha)); + + List combinationPool = hashSet.ToList(); + + Combinations = new CaptchaCombination[combinationPool.Count]; + for (int n = 0; n < Combinations.Length; n++) + { + Combinations[n] = combinationPool[_httpCaptcha._random.Next(combinationPool.Count)]; + combinationPool.Remove(Combinations[n]); + } + + hashSet.Clear(); + + while (hashSet.Count < _httpCaptcha.SolutionLength) + hashSet.Add(Combinations[_httpCaptcha._random.Next(Combinations.Length)]); + + Solution = hashSet.Select(cs => Array.IndexOf(Combinations, cs)).ToArray(); + Console.WriteLine(String.Join('-', Solution)); + Array.Sort(Solution); + Console.WriteLine(String.Join('-', Solution)); + } + + public bool Solve(int[] possibleSolution) + { + lock (this) + { + try + { + possibleSolution = possibleSolution.Distinct().ToArray(); + Array.Sort(possibleSolution); + + return Solution.SequenceEqual(possibleSolution); + } + finally + { + Dispose(); + } + } + } + + public JSONObject Json() + { + JSONObject json = new JSONObject() + .Add("uuid", Guid) + .Add("questions", Solution.Select(n => Combinations[n].ToString()).ToArray()) + .Add("group", Combinations.Length); + ; + return json; + } + + + public void Dispose() + { + lock (this) + { + _timer.Dispose(); + _httpCaptcha?._captchaInstances.Remove(Guid); + } + } + + public override string ToString() => String.Join(", ", Solution.Select(n => Combinations[n].ToString())); + } + + public class CaptchaCombination + { + public HtmlColor Color { get; } + public int Corners { get; } + public CaptchaForm Form { get; } + + public CaptchaCombination(HttpCaptcha httpCaptcha) + { + Color = httpCaptcha.CaptchaColors[httpCaptcha._random.Next(httpCaptcha.CaptchaColors.Length)]; + Corners = 4 + httpCaptcha._random.Next(4); + + CaptchaForm[] captchaForms = Enum.GetValues(); + Form = captchaForms[httpCaptcha._random.Next(captchaForms.Length)]; + } + + public override bool Equals(object? obj) => obj is CaptchaCombination other && Color.Equals(other.Color) && + Corners.Equals(other.Corners) && Form.Equals(other.Form); + + public override int GetHashCode() => Color.GetHashCode() ^ Corners ^ Form.GetHashCode(); + + public override string ToString() => $"ein {Form} mit {Corners} {(Form == CaptchaForm.Stern ? "Strahlen" : "Ecken")} in {Color.Name}"; + } + + public enum CaptchaForm + { + Stern, + Vieleck + } + + public class HtmlColor + { + public static readonly HtmlColor Red = new HtmlColor(255, 0, 0, "Rot"); + public static readonly HtmlColor Green = new HtmlColor(0, 255, 0, "Grün"); + public static readonly HtmlColor Blue = new HtmlColor(0, 0, 255, "Blau"); + public static readonly HtmlColor Yellow = new HtmlColor(240, 240, 0, "Gelb"); + public static readonly HtmlColor Violett = new HtmlColor(255, 0, 255, "Lila"); + public static readonly HtmlColor turquoise = new HtmlColor(0, 255, 255, "Türkis"); + + + public byte R { get; } + public byte G { get; } + public byte B { get; } + + public string Name { get; } + + public HtmlColor(byte r, byte g, byte b) : this(r, g, b, null) + { + } + + public HtmlColor(byte r, byte g, byte b, string name) + { + R = r; + G = g; + B = b; + Name = name; + } + + public override string ToString() => $"#{Red:X2}{Green:X2}{Blue:X2}"; + + public static implicit operator Color(HtmlColor htmlColor) => + new Rgb24(htmlColor.R, htmlColor.G, htmlColor.B); + } + + } +} \ No newline at end of file diff --git a/ln.http.helpers/HttpMailer.cs b/ln.http.helpers/HttpMailer.cs new file mode 100644 index 0000000..9c2ff9a --- /dev/null +++ b/ln.http.helpers/HttpMailer.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; +using ln.http.route; +using MimeKit; + +namespace ln.http.helpers +{ + + public class HttpMailer : HttpRoute, IDisposable + { + private HttpRouter _httpRouter; + private HttpCaptcha _httpCaptcha; + private HttpMailerOptions _httpMailerOptions; + private HttpMailerEndpoints _httpMailerEndpoints; + + public HttpMailer(HttpRouter httpRouter, string mapPath, HttpMailerOptions mailerOptions) + : this(httpRouter, mapPath, mailerOptions, null) + { + } + + public HttpMailer(HttpRouter httpRouter, string mapPath, HttpMailerOptions mailerOptions, + HttpCaptcha httpCaptcha) + : base(HttpMethod.ANY, mapPath) + { + _httpRouter = httpRouter; + _httpCaptcha = httpCaptcha; + _httpMailerOptions = mailerOptions; + _httpMailerEndpoints = new HttpMailerEndpoints(this); + _routerDelegate = _httpMailerEndpoints.RouteRequest; + + httpRouter.Map(this); + } + + public class HttpMailerOptions + { + public string Hostname { get; set; } = "localhost"; + public int Port { get; set; } = 25; + + public string? Username { get; set; } + public string? Password { get; set; } + + public SmtpEncryption Encryption { get; set; } = SmtpEncryption.None; + } + + class HttpMailerEndpoints : HttpEndpointController + { + private HttpMailer _httpMailer; + + public HttpMailerEndpoints(HttpMailer httpMailer) + { + _httpMailer = httpMailer; + } + + + [Map(HttpMethod.POST, "/mail")] + public HttpResponse PostMail(HttpRequest httpRequest) + { + using (FileStream fs = new FileStream("/tmp/post.txt", FileMode.Create, FileAccess.Write)) + httpRequest.ContentStream.CopyTo(fs); + + return HttpResponse.NoContent(); + } + + } + + public void Dispose() + { + _httpRouter?.UnMap(this); + _httpMailerEndpoints.Dispose(); + } + } + + public enum SmtpEncryption + { + None, + Tls, + StartTls + } + +} diff --git a/ln.http.helpers/ln.http.helpers.csproj b/ln.http.helpers/ln.http.helpers.csproj new file mode 100644 index 0000000..73b93fa --- /dev/null +++ b/ln.http.helpers/ln.http.helpers.csproj @@ -0,0 +1,20 @@ + + + + enable + net5.0;net6.0 + true + 0.9.0-test1 + + + + + + + + + + + + + diff --git a/ln.http.service/Program.cs b/ln.http.service/Program.cs index b7f4b7b..06459ad 100644 --- a/ln.http.service/Program.cs +++ b/ln.http.service/Program.cs @@ -1,8 +1,7 @@ using System.IO; using System.Reflection; -using System.Threading; using ln.bootstrap; -using ln.http.router; +using ln.templates; using ln.templates.html; namespace ln.http.service @@ -13,19 +12,18 @@ namespace ln.http.service { Bootstrap .DefaultInstance - .ServiceContainer.RegisterService(); - Bootstrap - .DefaultInstance + //.AddService() .Start(); } } + /* class HttpServiceHelper : HttpRouter { private TemplateDocument _templateDocument; - public HttpServiceHelper(HttpServer httpServer) - :base(httpServer) + public HttpServiceHelper(HttpRouter httpRouter) + :base() { using (StreamReader reader = new StreamReader( Assembly @@ -44,7 +42,7 @@ namespace ln.http.service { HttpResponse httpResponse = new HttpResponse(httpContext.HttpException?.HttpStatusCode ?? HttpStatusCode.InternalServerError); - + RenderContext renderContext = new RenderContext(httpResponse.ContentWriter); renderContext .GetEngine() @@ -56,4 +54,5 @@ namespace ln.http.service } } +*/ } diff --git a/ln.http.service/bootstrap.json b/ln.http.service/bootstrap.json index fca3f71..387cdf2 100644 --- a/ln.http.service/bootstrap.json +++ b/ln.http.service/bootstrap.json @@ -1,31 +1,50 @@ { - "ln.http.HttpServer, ln.http": { - "services": [ - ], - "properties": { + "System.IO.StreamWriter, System.Runtime": { + "domain": "log.http", + "set": { + "parameters": { + "path": "http.access.log" + } } }, - "ln.http.HttpListener, ln.http": { - "services": [ - - ], - "properties": { - "DefaultPort": 8180 + "ln.http.HttpServer": { + "resolve": { + "parameters": { + "accessLogWriter": "(log.http) System.IO.StreamWriter, System.Runtime", + "logWriter": "(log.console) ln.logging.LogWriter" + } } }, - "ln.http.HttpsListener, ln.http": { - "services": [ - - ], - "properties": { - "DefaultPort": 8443 + "ln.http.HttpListener": { + "set": { + "properties": { + "DefaultPort": 8180 + } } }, - "ln.http.FileSystemRouter, ln.http": { - "services": [ - ], - "parameters": { - "path": "." + "ln.http.HttpsListener": { + "set": { + "properties": { + "DefaultPort": 8443 + } + } + }, + "ln.logging.ConsoleLogSink": { + "domain": "log.console" + }, + "ln.logging.LogWriter": { + "domain": "log.console", + "resolve": { + "parameter": { + "logSink": "(log.console) ln.logging.ILogSink" + } + } + }, + "ln.logging.ConsoleWrapper": { + "resolve": { + "parameters": { + "logSink": "(log.console) ln.logging.ILogSink" + } } } } \ No newline at end of file diff --git a/ln.http.service/ln.http.HttpServer.json b/ln.http.service/ln.http.HttpServer.json new file mode 100644 index 0000000..f42104b --- /dev/null +++ b/ln.http.service/ln.http.HttpServer.json @@ -0,0 +1,63 @@ +{ + "ln.http.HttpRouter, ln.http": { + "resolve": { + "parameters": { + "httpServer": "ln.http.HttpServer" + } + } + }, + "ln.http.templates.FileSystemTemplateRouter, ln.http.templates": { + "set": { + "parameters": { + "path": "/home/haraldwolff/src/www/dambacher", + "mappingPath": "/*" + } + }, + "resolve": { + "parameters": { + "httpRouter" : "ln.http.HttpRouter" + } + } + }, + "ln.http.FileSystemRouter, ln.http": { + "set": { + "parameters": { + "path": "/home/haraldwolff/src/www/dambacher", + "mappingPath": "/*" + } + }, + "resolve": { + "parameters": { + "httpRouter" : "ln.http.HttpRouter" + } + } + }, + "ln.http.helpers.HttpCaptcha": { + "resolve": { + "parameters": { + "httpRouter": "ln.http.HttpRouter" + } + }, + "set": { + "parameters": { + "mapPath": "/captcha/*" + } + } + }, + "ln.http.helpers.HttpMailer": { + "resolve": { + "parameters": { + "httpRouter": "ln.http.HttpRouter" + } + }, + "set": { + "parameters": { + "mapPath": "/mailer/*", + "mailerOptions": { + "HostName": "smtp.l--n.de", + "Port": 465 + } + } + } +} +} \ No newline at end of file diff --git a/ln.http.service/ln.http.service.csproj b/ln.http.service/ln.http.service.csproj index 326fb24..44ae0d2 100644 --- a/ln.http.service/ln.http.service.csproj +++ b/ln.http.service/ln.http.service.csproj @@ -4,23 +4,29 @@ Exe 9 net6.0 + 1.0.1 + + - - - - + + + + Always + + Always + diff --git a/ln.http.service/localhost.crt b/ln.http.service/localhost.crt new file mode 100644 index 0000000000000000000000000000000000000000..b54e5ab3c084adfd0b338f66f5bcb664431dced6 GIT binary patch literal 4039 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 literal 0 HcmV?d00001 diff --git a/ln.http.sln b/ln.http.sln index 59b57ce..11e6cd5 100644 --- a/ln.http.sln +++ b/ln.http.sln @@ -11,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http.service", "ln.http. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.protocols.helper", "..\ln.protocols.helper\ln.protocols.helper.csproj", "{1C1D3A17-A615-4686-90BD-F0E221EAC89C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http.templates", "..\ln.templates\ln.http.templates\ln.http.templates.csproj", "{45709176-EA57-4BB3-815B-91D161CEB7A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.templates", "..\ln.templates\ln.templates\ln.templates.csproj", "{D6BA640C-352F-41BF-85EF-4B76FD928BEC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.http.helpers", "ln.http.helpers\ln.http.helpers.csproj", "{FAC3F9BE-6C09-4523-8584-2BD5B08BB70D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,5 +75,17 @@ Global {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x64.Build.0 = Release|Any CPU {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x86.ActiveCfg = Release|Any CPU {1C1D3A17-A615-4686-90BD-F0E221EAC89C}.Release|x86.Build.0 = Release|Any CPU + {45709176-EA57-4BB3-815B-91D161CEB7A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {45709176-EA57-4BB3-815B-91D161CEB7A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {45709176-EA57-4BB3-815B-91D161CEB7A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {45709176-EA57-4BB3-815B-91D161CEB7A6}.Release|Any CPU.Build.0 = Release|Any CPU + {D6BA640C-352F-41BF-85EF-4B76FD928BEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6BA640C-352F-41BF-85EF-4B76FD928BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6BA640C-352F-41BF-85EF-4B76FD928BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6BA640C-352F-41BF-85EF-4B76FD928BEC}.Release|Any CPU.Build.0 = Release|Any CPU + {FAC3F9BE-6C09-4523-8584-2BD5B08BB70D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAC3F9BE-6C09-4523-8584-2BD5B08BB70D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAC3F9BE-6C09-4523-8584-2BD5B08BB70D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAC3F9BE-6C09-4523-8584-2BD5B08BB70D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/ln.http.tests/CaptchaTests.cs b/ln.http.tests/CaptchaTests.cs new file mode 100644 index 0000000..716d14d --- /dev/null +++ b/ln.http.tests/CaptchaTests.cs @@ -0,0 +1,25 @@ +using System; +using ln.http.helpers; +using NUnit.Framework; + +namespace ln.http.tests +{ + [TestFixture] + public class CaptchaTests + { + + + [Test] + public void TestCaptcha() + { + HttpCaptcha httpCaptcha = new HttpCaptcha(null, null); + + for (int n = 0; n < 1024; n++) + { + HttpCaptcha.CaptchaInstance captchaInstance = httpCaptcha.CreateInstance(); + Console.WriteLine(captchaInstance.ToString()); + } + } + + } +} \ No newline at end of file diff --git a/ln.http.tests/UnitTest1.cs b/ln.http.tests/UnitTest1.cs index 71eef86..c5c18f8 100644 --- a/ln.http.tests/UnitTest1.cs +++ b/ln.http.tests/UnitTest1.cs @@ -3,44 +3,42 @@ using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using ln.http.router; using ln.json; -using ln.type; using NUnit.Framework; namespace ln.http.tests { public class Tests { - HttpServer server; - int testPort; + private HttpRouter TestRouter; + private int TestPort; + private Listener _httpListener; [SetUp] public void Setup() { - if (server != null) - return; + TestRouter = new HttpRouter(); + TestRouter.Map(new TestApiController()); + FileSystemRouter fileSystemRouter = new FileSystemRouter("/static/", AppContext.BaseDirectory); + TestRouter.Map(fileSystemRouter); - server = new HttpServer(); - - HttpRouter testRouter = new HttpRouter(server); - testRouter.Map(HttpMethod.ANY, "/controller/*", HttpRoutePriority.NORMAL, new TestApiController().Route); + _httpListener = new Listener(TestRouter, IPAddress.Any, 0); + TestPort = _httpListener.LocalEndpoint.Port; + TestContext.Error.WriteLine("Using Port {0}", TestPort); + } - FileSystemRouter fileSystemRouter = new FileSystemRouter(AppContext.BaseDirectory); - testRouter.Map(HttpMethod.ANY, "/static/*", fileSystemRouter.Route); - - HttpListener.DefaultPort = 0; - HttpListener httpListener = new HttpListener(server); - - testPort = httpListener.LocalEndpoint.Port; - TestContext.Error.WriteLine("Using Port {0}", testPort); + [TearDown] + public void TearDown() + { + _httpListener?.Dispose(); + TestRouter?.Dispose(); } [Test] public void Test1() { HttpClient client = new HttpClient(); - HttpResponseMessage response = client.GetAsync(String.Format("http://localhost:{0}/static/test.txt", testPort)).Result; + HttpResponseMessage response = client.GetAsync(String.Format("http://localhost:{0}/static/test.txt", TestPort)).Result; Assert.AreEqual(System.Net.HttpStatusCode.OK, response.StatusCode); @@ -49,8 +47,6 @@ namespace ln.http.tests CollectionAssert.AreEqual(fileBytes, contentBytes); - //server.Stop(); - Assert.Pass(); } @@ -59,17 +55,18 @@ namespace ln.http.tests { JSONObject jsonPutObject = new JSONObject(); jsonPutObject["PutTest"] = JSONTrue.Instance; - StringContent jsonStringContent = new StringContent(jsonPutObject.ToString()); + System.Net.Http.StringContent jsonStringContent = new System.Net.Http.StringContent(jsonPutObject.ToString()); jsonStringContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); HttpClient client = new HttpClient(); - HttpResponseMessage response = client.PutAsync(String.Format("http://localhost:{0}/controller/put", testPort), jsonStringContent).Result; + HttpResponseMessage response = client.PutAsync(String.Format("http://localhost:{0}/controller/put", TestPort), jsonStringContent).Result; Assert.AreEqual(System.Net.HttpStatusCode.OK, response.StatusCode); Assert.Pass(); } } + [Map(HttpMethod.ANY, "/controller")] class TestApiController : HttpEndpointController { [Map(HttpMethod.PUT, "/put")] diff --git a/ln.http.tests/ln.http.tests.csproj b/ln.http.tests/ln.http.tests.csproj index 066f518..404432f 100644 --- a/ln.http.tests/ln.http.tests.csproj +++ b/ln.http.tests/ln.http.tests.csproj @@ -1,11 +1,12 @@ - net5.0 false 9 + + net5.0;net6.0 @@ -14,11 +15,13 @@ - + Always + +