From e77f8a7c0654cdce57268f1cb1f2ed6426729529 Mon Sep 17 00:00:00 2001 From: SALTWOOD <105980161+SALTWOOD@users.noreply.github.com> Date: Sun, 14 Jul 2024 20:52:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8D=A2=E5=9B=9E=20ASP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BangbangAsp/BangbangAsp.csproj | 9 ++ BangbangAsp/Program.cs | 34 ++++ BangbangAsp/Properties/launchSettings.json | 38 +++++ BangbangAsp/appsettings.Development.json | 9 ++ BangbangAsp/appsettings.json | 9 ++ CSharp-OpenBMCLAPI.sln | 6 + CSharp-OpenBMCLAPI/CSharp-OpenBMCLAPI.csproj | 4 + CSharp-OpenBMCLAPI/Modules/Cluster.cs | 46 +++--- CSharp-OpenBMCLAPI/Modules/Config.cs | 2 +- CSharp-OpenBMCLAPI/Modules/HttpRequest.cs | 4 +- .../Modules/HttpServiceProvider.cs | 58 +++---- .../Modules/Plugin/PluginHttpEvent.cs | 2 +- .../Modules/Plugin/PluginManager.cs | 2 +- .../Modules/Storage/AlistStorage.cs | 6 +- .../Modules/Storage/CachedStorage.cs | 6 +- .../Modules/Storage/FileStorage.cs | 4 +- .../Modules/Storage/IStorage.cs | 3 +- .../Modules/Storage/WebDavStorage.cs | 6 +- .../Modules/WebServer/Client.cs | 53 ------ .../Modules/WebServer/Headers.cs | 123 -------------- .../Modules/WebServer/HttpContext.cs | 11 -- .../Modules/WebServer/Request.cs | 47 ------ .../Modules/WebServer/Response.cs | 117 -------------- CSharp-OpenBMCLAPI/Modules/WebServer/Route.cs | 33 ---- .../Modules/WebServer/ServeType.cs | 8 - .../Modules/WebServer/SimpleWebServer.cs | 151 ------------------ .../Modules/WebServer/WebUtils.cs | 85 ---------- 27 files changed, 171 insertions(+), 705 deletions(-) create mode 100644 BangbangAsp/BangbangAsp.csproj create mode 100644 BangbangAsp/Program.cs create mode 100644 BangbangAsp/Properties/launchSettings.json create mode 100644 BangbangAsp/appsettings.Development.json create mode 100644 BangbangAsp/appsettings.json delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/Client.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/Headers.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/Request.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/Route.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/ServeType.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs delete mode 100644 CSharp-OpenBMCLAPI/Modules/WebServer/WebUtils.cs diff --git a/BangbangAsp/BangbangAsp.csproj b/BangbangAsp/BangbangAsp.csproj new file mode 100644 index 0000000..1b28a01 --- /dev/null +++ b/BangbangAsp/BangbangAsp.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/BangbangAsp/Program.cs b/BangbangAsp/Program.cs new file mode 100644 index 0000000..0c4606f --- /dev/null +++ b/BangbangAsp/Program.cs @@ -0,0 +1,34 @@ +namespace BangbangAsp +{ + public class Program + { + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + // Add services to the container. + builder.Services.AddRazorPages(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (!app.Environment.IsDevelopment()) + { + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHttpsRedirection(); + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.MapRazorPages(); + + app.Run(); + } + } +} diff --git a/BangbangAsp/Properties/launchSettings.json b/BangbangAsp/Properties/launchSettings.json new file mode 100644 index 0000000..0966736 --- /dev/null +++ b/BangbangAsp/Properties/launchSettings.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:12008", + "sslPort": 44375 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5139", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7177;http://localhost:5139", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/BangbangAsp/appsettings.Development.json b/BangbangAsp/appsettings.Development.json new file mode 100644 index 0000000..770d3e9 --- /dev/null +++ b/BangbangAsp/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/BangbangAsp/appsettings.json b/BangbangAsp/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/BangbangAsp/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/CSharp-OpenBMCLAPI.sln b/CSharp-OpenBMCLAPI.sln index 04b1add..dcad6ab 100644 --- a/CSharp-OpenBMCLAPI.sln +++ b/CSharp-OpenBMCLAPI.sln @@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker compose", "Docker co docker-compose.yml = docker-compose.yml EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BangbangAsp", "BangbangAsp\BangbangAsp.csproj", "{3ABB5430-C505-42F6-A7FD-AAB8FFD94063}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -35,6 +37,10 @@ Global {F01E0E3F-BF3E-4D0D-BCB7-7DFEF1926310}.Debug|Any CPU.Build.0 = Debug|Any CPU {F01E0E3F-BF3E-4D0D-BCB7-7DFEF1926310}.Release|Any CPU.ActiveCfg = Release|Any CPU {F01E0E3F-BF3E-4D0D-BCB7-7DFEF1926310}.Release|Any CPU.Build.0 = Release|Any CPU + {3ABB5430-C505-42F6-A7FD-AAB8FFD94063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3ABB5430-C505-42F6-A7FD-AAB8FFD94063}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3ABB5430-C505-42F6-A7FD-AAB8FFD94063}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3ABB5430-C505-42F6-A7FD-AAB8FFD94063}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CSharp-OpenBMCLAPI/CSharp-OpenBMCLAPI.csproj b/CSharp-OpenBMCLAPI/CSharp-OpenBMCLAPI.csproj index 6c9da91..85d708f 100644 --- a/CSharp-OpenBMCLAPI/CSharp-OpenBMCLAPI.csproj +++ b/CSharp-OpenBMCLAPI/CSharp-OpenBMCLAPI.csproj @@ -20,6 +20,10 @@ + + + + Always diff --git a/CSharp-OpenBMCLAPI/Modules/Cluster.cs b/CSharp-OpenBMCLAPI/Modules/Cluster.cs index d561f5b..d028ba1 100644 --- a/CSharp-OpenBMCLAPI/Modules/Cluster.cs +++ b/CSharp-OpenBMCLAPI/Modules/Cluster.cs @@ -1,6 +1,8 @@ using CSharpOpenBMCLAPI.Modules.Plugin; using CSharpOpenBMCLAPI.Modules.Storage; -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using ShellProgressBar; using SocketIOClient; @@ -12,6 +14,7 @@ using System.Text.RegularExpressions; using TeraIO.Runnable; using ZstdSharp; +using static System.Net.Mime.MediaTypeNames; namespace CSharpOpenBMCLAPI.Modules { @@ -35,6 +38,7 @@ public class Cluster public CancellationTokenSource cancellationSrc = new CancellationTokenSource(); internal ClusterRequiredData requiredData; internal List files; + protected WebApplication? application; //List tasks = new List(); @@ -169,38 +173,28 @@ private async Task _KeepAlive() /// private void InitializeService() { - X509Certificate2 cert = LoadAndConvertCert(); - SimpleWebServer server = new(ClusterRequiredData.Config.PORT, cert, this);//cert); - - // 下载路由 - server.routes.Add(new Route + X509Certificate2? cert = LoadAndConvertCert(); + WebApplicationBuilder builder = WebApplication.CreateBuilder(); + builder.WebHost.UseKestrel(options => { - MatchRegex = new Regex(@"/download/[0-9a-fA-F]{32,40}?.*"), - ConditionExpressions = + options.ListenAnyIP(9388, cert != null ? configure => { - (path) => path.Contains("s=") && path.Contains("e=") - }, - Handler = (context, cluster, Match) => - { - FileAccessInfo fai = HttpServiceProvider.DownloadHash(context, cluster).Result; - this.counter.Add(fai); + configure.UseHttps(cert); } + : configure => { }); }); + application = builder.Build(); - // 测速路由 - server.routes.Add(new Route + // 下载路由 + application.MapGet("/download/{hash}", (HttpContext context, string hash) => { - MatchRegex = new Regex(@"/measure/\d"), - Handler = (context, cluster, match) => HttpServiceProvider.Measure(context, cluster).Wait() + FileAccessInfo fai = HttpServiceProvider.DownloadHash(context, this).Result; + this.counter.Add(fai); + return Task.CompletedTask; }); - // API 数据 - server.routes.Add(new Route - { - MatchRegex = new Regex(@"/api/(.*)"), - Handler = (context, cluster, match) => HttpServiceProvider.Api(context, match.Groups[1].Value, this).Wait(), - Methods = "GET" - }); + // 测速路由 + application.MapGet("/measure", (context) => HttpServiceProvider.Measure(context, this)); // 因为暂时禁用面板而注释掉 @@ -218,7 +212,7 @@ private void InitializeService() // Handler = (context, cluster, match) => HttpServiceProvider.Dashboard(context).Wait() // }); - server.Start(); + application.RunAsync(); } /// diff --git a/CSharp-OpenBMCLAPI/Modules/Config.cs b/CSharp-OpenBMCLAPI/Modules/Config.cs index bb0c777..fdda715 100644 --- a/CSharp-OpenBMCLAPI/Modules/Config.cs +++ b/CSharp-OpenBMCLAPI/Modules/Config.cs @@ -48,7 +48,7 @@ [注] 当此项启用时,"startupCheckMode"无效 [YamlMember(Description = "[开发变量]\n指示是否不执行快速上线,若为 true 则每次都不执行", Order = 10)] public bool noFastEnable; - + [YamlMember(Description = "[开发变量]\n是否使用开发环境(需要自己模拟用户请求)", Order = 10)] public bool StagingMode; diff --git a/CSharp-OpenBMCLAPI/Modules/HttpRequest.cs b/CSharp-OpenBMCLAPI/Modules/HttpRequest.cs index 070e372..c9a63e3 100644 --- a/CSharp-OpenBMCLAPI/Modules/HttpRequest.cs +++ b/CSharp-OpenBMCLAPI/Modules/HttpRequest.cs @@ -14,9 +14,9 @@ static HttpRequest() BaseAddress = ClusterRequiredData.Config.StagingMode ? new Uri("https://openbmclapi.staging.bangbang93.com/") : new Uri("https://openbmclapi.bangbang93.com/"), - - }; + + }; // 添加UserAgent,用于标识请求来源 client.DefaultRequestHeaders.UserAgent.Add(new("openbmclapi-cluster", ClusterRequiredData.Config.clusterVersion)); } diff --git a/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs b/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs index b1b6ba7..dab00a7 100644 --- a/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs +++ b/CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs @@ -1,6 +1,7 @@ using CSharpOpenBMCLAPI.Modules.Plugin; using CSharpOpenBMCLAPI.Modules.Storage; -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; using Newtonsoft.Json; namespace CSharpOpenBMCLAPI.Modules @@ -17,7 +18,8 @@ public static void LogAccess(HttpContext context) { if (!ClusterRequiredData.Config.disableAccessLog) { - Logger.Instance.LogInfo($"{context.Request.Method} {context.Request.Path.Split('?').First()} <{context.Response.StatusCode}> - [{context.RemoteIPAddress}] {context.Request.Headers.TryGetValue("user-agent")}"); + context.Request.Headers.TryGetValue("user-agent", out StringValues value); + Logger.Instance.LogInfo($"{context.Request.Method} {context.Request.Path.Value} <{context.Response.StatusCode}> - [{context.Connection.RemoteIpAddress}] {value.FirstOrDefault()}"); } } @@ -29,8 +31,8 @@ public static void LogAccess(HttpContext context) public static async Task Measure(HttpContext context, Cluster cluster) { PluginManager.Instance.TriggerHttpEvent(context, HttpEventType.ClientMeasure); - var pairs = Utils.GetQueryStrings(context.Request.Path.Split('?').Last()); - bool valid = Utils.CheckSign(context.Request.Path.Split('?').First() + var pairs = Utils.GetQueryStrings(context.Request.Path.Value?.Split('?').Last()); + bool valid = Utils.CheckSign(context.Request.Path.Value?.Split('?').First() , cluster.requiredData.ClusterInfo.ClusterSecret , pairs.GetValueOrDefault("s") , pairs.GetValueOrDefault("e") @@ -39,14 +41,13 @@ public static async Task Measure(HttpContext context, Cluster cluster) { context.Response.StatusCode = 200; byte[] buffer = new byte[1024]; - for (int i = 0; i < Convert.ToInt32(context.Request.Path.Split('/').Last().Split('?').First()); i++) + for (int i = 0; i < Convert.ToInt32(context.Request.Path.Value?.Split('/').Last().Split('?').First()); i++) { for (int j = 0; j < 1024; j++) { - await context.Response.Stream.WriteAsync(buffer); + await context.Response.Body.WriteAsync(buffer); } } - context.Response.ResetStreamPosition(); } else { @@ -67,8 +68,8 @@ public static async Task DownloadHash(HttpContext context, Clust PluginManager.Instance.TriggerHttpEvent(context, HttpEventType.ClientDownload); // 处理用户下载 FileAccessInfo fai = default; - var pairs = Utils.GetQueryStrings(context.Request.Path.Split('?').Last()); - string? hash = context.Request.Path.Split('/').LastOrDefault()?.Split('?').First(); + var pairs = Utils.GetQueryStrings(context.Request.Path.Value?.Split('?').Last()); + string? hash = context.Request.Path.Value?.Split('/').LastOrDefault()?.Split('?').First(); string? s = pairs.GetValueOrDefault("s"); string? e = pairs.GetValueOrDefault("e"); @@ -88,7 +89,7 @@ public static async Task DownloadHash(HttpContext context, Clust { // 206 处理部分 context.Response.StatusCode = 206; - (from, to) = ToRangeByte(context.Request.Headers["range"].Split("=").Last().Split("-")); + (from, to) = ToRangeByte(context.Request.Headers["range"].FirstOrDefault()?.Split("=").Last().Split("-")); if (to < from && to != -1) (from, to) = (to, from); long length = 0; @@ -97,25 +98,25 @@ public static async Task DownloadHash(HttpContext context, Clust if (to == -1) to = file.Length; length = (to - from + 1); - context.Response.Header["Content-Length"] = length.ToString(); + context.Response.Headers["Content-Length"] = length.ToString(); file.Seek(from, SeekOrigin.Begin); byte[] buffer = new byte[4096]; for (; file.Position < to;) { int count = file.Read(buffer, 0, buffer.Length); - if (file.Position > to && file.Position - count < to) context.Response.Stream.Write(buffer[..(int)(count - file.Position + to + 1)]); - else if (count != buffer.Length) context.Response.Stream.Write(buffer[..(count)]); - else context.Response.Stream.Write(buffer); + if (file.Position > to && file.Position - count < to) await context.Response.Body.WriteAsync(buffer[..(int)(count - file.Position + to + 1)]); + else if (count != buffer.Length) await context.Response.Body.WriteAsync(buffer[..(count)]); + else await context.Response.Body.WriteAsync(buffer); } + context.Response.Headers["Content-Range"] = $"{from}-{to}/{file.Length}"; } - context.Response.ResetStreamPosition(); - context.Response.Header["Content-Range"] = $"{from}-{to}/{context.Response.Stream.Length}"; - context.Response.Header["x-bmclapi-hash"] = hash; - context.Response.Header["Accept-Ranges"] = "bytes"; - context.Response.Header["Content-Type"] = "application/octet-stream"; - context.Response.Header["Connection"] = "closed"; + + context.Response.Headers["x-bmclapi-hash"] = hash; + context.Response.Headers["Accept-Ranges"] = "bytes"; + context.Response.Headers["Content-Type"] = "application/octet-stream"; + context.Response.Headers["Connection"] = "closed"; fai = new FileAccessInfo { hits = 1, @@ -126,14 +127,12 @@ public static async Task DownloadHash(HttpContext context, Clust else { fai = await cluster.storage.HandleRequest(Utils.HashToFileName(hash), context); - context.Response.ResetStreamPosition(); ClusterRequiredData.DataStatistician.DownloadCount(fai); } } catch (Exception ex) { Logger.Instance.LogError(ex.ExceptionToDetail()); - Logger.Instance.LogError(context.RemoteIPAddress); Logger.Instance.LogError(context.Request.Path); //Logger.Instance.LogError(ex.StackTrace); context.Response.StatusCode = 404; @@ -142,7 +141,7 @@ public static async Task DownloadHash(HttpContext context, Clust else { context.Response.StatusCode = 403; - context.Response.Header.Remove("Content-Length"); + context.Response.Headers.Remove("Content-Length"); await context.Response.WriteAsync($"Access to \"{context.Request.Path}\" has been blocked due to your request timeout or invalidity."); } LogAccess(context); @@ -166,8 +165,8 @@ private static (long from, long to) ToRangeByte(string[]? rangeHeader) public static async Task Api(HttpContext context, string query, Cluster cluster) { PluginManager.Instance.TriggerHttpEvent(context, HttpEventType.ClientOtherRequest); - context.Response.Header.Set("content-type", "application/json"); - context.Response.Header.Set("access-control-allow-origin", "*"); + context.Response.Headers["content-type"] = "application/json"; + context.Response.Headers["access-control-allow-origin"] = "*"; context.Response.StatusCode = 200; switch (query) { @@ -228,15 +227,6 @@ await context.Response.WriteAsync(JsonConvert.SerializeObject(new context.Response.StatusCode = 404; break; } - context.Response.ResetStreamPosition(); - } - - public static Task Dashboard(HttpContext context, string filePath = "index.html") - { - PluginManager.Instance.TriggerHttpEvent(context, HttpEventType.ClientOtherRequest); - context.Response.StatusCode = 200; - context.Response.Stream = Utils.GetEmbeddedFileStream($"Dashboard/{filePath}").ThrowIfNull(); - return Task.CompletedTask; } } } diff --git a/CSharp-OpenBMCLAPI/Modules/Plugin/PluginHttpEvent.cs b/CSharp-OpenBMCLAPI/Modules/Plugin/PluginHttpEvent.cs index 17f78f9..d232211 100644 --- a/CSharp-OpenBMCLAPI/Modules/Plugin/PluginHttpEvent.cs +++ b/CSharp-OpenBMCLAPI/Modules/Plugin/PluginHttpEvent.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; namespace CSharpOpenBMCLAPI.Modules.Plugin { diff --git a/CSharp-OpenBMCLAPI/Modules/Plugin/PluginManager.cs b/CSharp-OpenBMCLAPI/Modules/Plugin/PluginManager.cs index 2634237..43fbdc8 100644 --- a/CSharp-OpenBMCLAPI/Modules/Plugin/PluginManager.cs +++ b/CSharp-OpenBMCLAPI/Modules/Plugin/PluginManager.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; using System.Diagnostics; namespace CSharpOpenBMCLAPI.Modules.Plugin diff --git a/CSharp-OpenBMCLAPI/Modules/Storage/AlistStorage.cs b/CSharp-OpenBMCLAPI/Modules/Storage/AlistStorage.cs index 7d5d9f1..b0e8a4f 100644 --- a/CSharp-OpenBMCLAPI/Modules/Storage/AlistStorage.cs +++ b/CSharp-OpenBMCLAPI/Modules/Storage/AlistStorage.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using System.Net.Http.Json; @@ -91,8 +91,8 @@ public async Task HandleRequest(string hashPath, HttpContext con { string url = GetAbsolutePath(hashPath); context.Response.StatusCode = 302; - context.Response.Header["Location"] = url; - await context.Response.WriteAsync(Array.Empty()); + context.Response.Headers["Location"] = url; + await context.Response.Body.WriteAsync(Array.Empty()); return new FileAccessInfo { hits = 1, diff --git a/CSharp-OpenBMCLAPI/Modules/Storage/CachedStorage.cs b/CSharp-OpenBMCLAPI/Modules/Storage/CachedStorage.cs index eb5942b..3488646 100644 --- a/CSharp-OpenBMCLAPI/Modules/Storage/CachedStorage.cs +++ b/CSharp-OpenBMCLAPI/Modules/Storage/CachedStorage.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; namespace CSharpOpenBMCLAPI.Modules.Storage { @@ -53,7 +53,7 @@ public async Task HandleRequest(string hashPath, HttpContext con if (!cache.ContainsKey(hashPath)) { byte[] bytes = this.ReadFile(hashPath); - await context.Response.Stream.WriteAsync(bytes); + await context.Response.Body.WriteAsync(bytes); this[hashPath] = new CachedFile(bytes); return new FileAccessInfo { @@ -63,7 +63,7 @@ public async Task HandleRequest(string hashPath, HttpContext con } else { - await context.Response.WriteAsync(this[hashPath].Content); + await context.Response.Body.WriteAsync(this[hashPath].Content); return new FileAccessInfo { hits = 1, diff --git a/CSharp-OpenBMCLAPI/Modules/Storage/FileStorage.cs b/CSharp-OpenBMCLAPI/Modules/Storage/FileStorage.cs index 3bfb07d..0c8a6ad 100644 --- a/CSharp-OpenBMCLAPI/Modules/Storage/FileStorage.cs +++ b/CSharp-OpenBMCLAPI/Modules/Storage/FileStorage.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; using System.Text.RegularExpressions; namespace CSharpOpenBMCLAPI.Modules.Storage @@ -105,7 +105,7 @@ public Stream ReadFileStream(string hashPath) public async Task HandleRequest(string hashPath, HttpContext context) { string filePath = GetAbsolutePath(hashPath); - await context.Response.SendFile(filePath); + await context.Response.SendFileAsync(filePath); FileInfo fileInfo = new FileInfo(filePath); diff --git a/CSharp-OpenBMCLAPI/Modules/Storage/IStorage.cs b/CSharp-OpenBMCLAPI/Modules/Storage/IStorage.cs index 0e24085..6ea7a9c 100644 --- a/CSharp-OpenBMCLAPI/Modules/Storage/IStorage.cs +++ b/CSharp-OpenBMCLAPI/Modules/Storage/IStorage.cs @@ -1,4 +1,5 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; + namespace CSharpOpenBMCLAPI.Modules.Storage { /// diff --git a/CSharp-OpenBMCLAPI/Modules/Storage/WebDavStorage.cs b/CSharp-OpenBMCLAPI/Modules/Storage/WebDavStorage.cs index 9dece77..2426939 100644 --- a/CSharp-OpenBMCLAPI/Modules/Storage/WebDavStorage.cs +++ b/CSharp-OpenBMCLAPI/Modules/Storage/WebDavStorage.cs @@ -1,4 +1,4 @@ -using CSharpOpenBMCLAPI.Modules.WebServer; +using Microsoft.AspNetCore.Http; using TeraIO.Network.WebDav; namespace CSharpOpenBMCLAPI.Modules.Storage @@ -63,8 +63,8 @@ public async Task HandleRequest(string hashPath, HttpContext con { string file = GetAbsolutePath(hashPath); context.Response.StatusCode = 302; - context.Response.Header["Location"] = this.client.GetFileDownloadLink(file); - await context.Response.WriteAsync(Array.Empty()); + context.Response.Headers["Location"] = this.client.GetFileDownloadLink(file); + await context.Response.Body.WriteAsync(Array.Empty()); return new FileAccessInfo { hits = 1, diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Client.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Client.cs deleted file mode 100644 index 71a8ed4..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Client.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System.Net.Sockets; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class Client : IDisposable - { - public TcpClient TcpClient; - Stream stream; - - public Stream Stream { get => this.stream; } - - public Client(TcpClient client, Stream stream) - { - this.TcpClient = client; - this.stream = stream; - } - - public void Close() - { - this.stream.Close(); - this.TcpClient.Close(); - } - - public void Dispose() => this.Close(); - - public async Task Read(int n = 1) - { - byte[] buffer = new byte[n]; - long length = await this.stream.ReadAsync(buffer); - byte[] data = new byte[length]; - Array.Copy(buffer, data, length); - return data; - } - - public async Task Write(byte[] data) - { - await this.stream.WriteAsync(data); - await this.stream.FlushAsync(); - } - - public async Task CopyTo(Stream stream) - { - await this.stream.CopyToAsync(stream); - await this.stream.FlushAsync(); - } - - public async Task CopyFrom(Stream stream) - { - await stream.CopyToAsync(this.stream); - await stream.FlushAsync(); - } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Headers.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Headers.cs deleted file mode 100644 index 01c8de0..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Headers.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.Collections; -using System.Diagnostics.CodeAnalysis; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class Headers : IDictionary - { - Dictionary tables; - - public Headers(Dictionary tables) - { - this.tables = tables; - } - - public Headers() - { - this.tables = new Dictionary(); - } - - public static Headers FromBytes(byte[][] headers) - { - Dictionary tables = new Dictionary(); - foreach (var header in headers) - { - var h = WebUtils.SplitBytes(header, WebUtils.Encode(": "), 1).ToArray(); - if (h.Length < 1) - { - continue; - } - tables.TryAdd(WebUtils.Decode(h[0]).ToLower(), WebUtils.Decode(h[1])); - } - return new Headers(tables); - } - - public object Get(string key, object defaultValue) - { - return tables.ContainsKey(key) ? tables[key] : defaultValue; - } - - public void Set(string key, object value) - { - if (value == null) - { - if (tables.ContainsKey(key)) tables.Remove(key); - return; - } - tables.TryAdd(key, value + ""); - } - - public bool ContainsKey(string key) => tables.ContainsKey(key); - - public override string ToString() => string.Join("\r\n", from kvp in this select $"{kvp.Key}: {kvp.Value}"); - - // Auto generated. - - public string this[string key] { get => tables[key]; set => tables[key] = value; } - - public ICollection Keys => tables.Keys; - - public ICollection Values => tables.Values; - - public int Count => tables.Count; - - public bool IsReadOnly => ((ICollection>)tables).IsReadOnly; - - public void Add(string key, string value) - { - tables.Add(key, value); - } - - public void Add(KeyValuePair item) - { - ((ICollection>)tables).Add(item); - } - - public void Clear() - { - tables.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return tables.Contains(item); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - ((ICollection>)tables).CopyTo(array, arrayIndex); - } - - public IEnumerator> GetEnumerator() - { - return ((IEnumerable>)tables).GetEnumerator(); - } - - public bool Remove(string key) - { - return tables.Remove(key); - } - - public bool Remove(KeyValuePair item) - { - return ((ICollection>)tables).Remove(item); - } - - public bool TryGetValue(string key, [MaybeNullWhen(false)] out string value) - { - return tables.TryGetValue(key, out value); - } - - public string? TryGetValue(string key) - { - string? value; - tables.TryGetValue(key, out value); - return value; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)tables).GetEnumerator(); - } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs deleted file mode 100644 index b662ea4..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Net; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class HttpContext - { - public required Request Request { get; set; } - public required Response Response { get; set; } - public required EndPoint RemoteIPAddress { get; set; } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Request.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Request.cs deleted file mode 100644 index a81ca2f..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Request.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class Request - { - internal string? QueryString = ""; - - public string Method { get; set; } - public string Path { get; set; } - public string Protocol { get; set; } - public Headers Headers { get; set; } - public int BodyLength { get; set; } - public Client Client { get; set; } - public byte[] BodyData { get; set; } - - public Request(Client client, byte[] data) - { - this.Client = client; - byte[][] temp = WebUtils.SplitBytes(data, WebUtils.Encode("\r\n\r\n"), 2).ToArray(); - this.BodyData = temp[1]; - byte[][] requestHeader = WebUtils.SplitBytes(temp[0], WebUtils.Encode("\r\n")).ToArray(); - temp = WebUtils.SplitBytes(requestHeader[0], WebUtils.Encode(" "), 3).ToArray(); - (Method, Path, Protocol) = (WebUtils.Decode(temp[0]), WebUtils.Decode(temp[1]), WebUtils.Decode(temp[2])); - Headers = Headers.FromBytes(requestHeader[1..]); - BodyLength = int.Parse(Headers.Get("content-length", 0) + ""); - } - - public async Task SkipContent() - { - await this.Client.Read(BodyLength - BodyData.Length); - } - - public override string ToString() - { - string result = $""" - {Method} {Path} {Protocol} - - Headers: - {string.Join("\n ", this.Headers.Select(f => $"{f.Key}: {f.Value}"))} - - Data: - - {Convert.ToHexString(this.BodyData)} - """; - return result; - } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs deleted file mode 100644 index 9524c8f..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Text; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class Response - { - public int StatusCode { get; set; } = 200; - public Headers Header { get; set; } = new Headers(); - public Stream Stream { get; set; } = new MemoryStream(); - - public async Task Call(Client client, Request request) - { - if (!Header.ContainsKey("Content-Length")) Header.Set("Content-Length", Stream.Length); - Header.Set("X-Powered-By", "CSharp-SaltWood"); - string responseHeader = $"HTTP/1.1 {StatusCode} {GetStatusMsg(StatusCode)}\r\n{Header}\r\n\r\n"; - await client.Write(responseHeader.Encode()); - Stream.CopyTo(client.Stream); - client.Stream.Flush(); - Stream.Close(); - } - - /// - /// HTTP 状态码 - /// - public static readonly Dictionary STATUS_CODES = new Dictionary - { - { 100, "Continue" }, // 继续 - { 101, "Switching Protocols" }, // 切换协议 - { 102, "Processing" }, // 处理中 - { 103, "Early Hints" }, // 预加载资源 - { 200, "OK" }, // 请求成功 - { 201, "Created" }, // 成功创建资源 - { 202, "Accepted" }, // 收到请求 - { 203, "Non-Authoritative Information" }, // 服务器成功处理请求,但返回信息可能不是原始服务器上的有效集合,可能是本地或第三方拷贝 - { 204, "No Content" }, // 没有 body - { 205, "Reset Content" }, // 重置文档 - { 206, "Partial Content" }, // 部分资源 - { 207, "Multi-Status" }, // 不知道选哪个状态码,所以干脆全都丢给你 - { 208, "Already Reported" }, // 在 DAV 里面使用 响应元素以避免重复枚举多个绑定的内部成员到同一个集合 - { 226, "IM Used" }, // 服务器已经完成了对资源的GET请求,并且响应是对当前实例应用的一个或多个实例操作结果的表示 - { 300, "Multiple Choices" }, // 不知道你要哪个,干脆全部丢给你,让你自己选 - { 301, "Moved Pemanently" }, // 资源永久迁移啦 - { 302, "Found" }, // 暂时搬走了,去这里找;以后有啥更改,还是在老地方通知 - { 303, "See Other" }, // 用 GET 方法去这个地方找资源,别来我这儿 - { 304, "Not Modified" }, // 改都没改 - { 305, "Use Proxy" }, // 你还是开个代理吧 - { 306, "Unused" }, // 鬼知道有什么用 - { 307, "Temporary Redirect" }, // 跟 302 一样,但你用的什么方法原来是什么,现在也必须也用什么 - { 308, "308 Permanent Redirect" }, // 跟 301 一样,但你用的是方法原来是什么,现在也必须也用什么 - { 400, "Bad Request" }, // 你的锅,给我整不会了 - { 401, "Unauthorized" }, // 你谁啊? - { 402, "Payment Required" }, // V 我 50 - { 403, "Forbidden" }, // 禁 止 访 问 - { 404, "Not Found" }, // 没 有 - { 405, "Method Not Allowed" }, // 方 法 不 对 - { 406, "Not Acceptable" }, // 当 web 服务器在执行服务端驱动型内容协商机制后,没有发现任何符合用户代理给定标准的内容时,就会发送此响应 - { 407, "Proxy Authentication Required" }, // 你代理谁啊? - { 408, "Request Time-out" }, // 超 时 了 - { 409, "Conflict" }, // 公 交 车(划)冲 突 了 - { 410, "Gone" }, // 资 源 死 了 , 删 了 吧 - { 411, "Length Required" }, // 你要多长,你不告诉我,我咋知道 - { 412, "Precondition Failed" }, // 不是不报,条件未满足 - { 413, "Payload Too Large" }, // 请 求 实 体 太 大 - { 414, "URI Too Long" }, // 链 接 太 长 - { 415, "Unsupported Media Type" }, // 请求数据的媒体格式不支持 - { 416, "Range Not Satisfiable" }, // 你范围太大了 - { 417, "Expectation Failed" }, // 对不起,我做不到(指 Expect) - { 418, "I'm a teapot" }, // 我 是 茶 壶 - { 421, "Misdirected Request" }, // 请求被定向到无法生成响应的服务器 - { 422, "Unprocessable Entity" }, // 格式正确但语义错误 - { 423, "Locked" }, // 锁上了 - { 424, "Failed Dependency" }, // 多米诺骨牌倒了,上一个请求炸了,这个也不行 - { 425, "Too Early" }, // 你来的真早!当前服务器不愿意冒风险处理请求,请稍等几分钟 - { 426, "Upgrade Required" }, // 发 现 新 版 本 - { 428, "Precondition Required" }, // 我是有条件嘀~ - { 429, "Too Many Requests" }, // 太快了,停下来! - { 431, "Request Header Fields Too Large" }, // 请求头太大了 - { 451, "Unavailable For Legal Reasons" }, // 法 律 封 锁 - { 500, "Internal Server Eror" }, // 给服务器整不会了 - { 501, "Not Implemented" }, // 我 不 会 - { 502, "Bad Gateway" }, // 网关炸了 - { 503, "Service Unavailable" }, // 伺 服 器 維 護 中 , 將 結 束 應 用 程 式 。 - { 504, "Gateway Time-out" }, // 网关超时 - { 505, "HTTP Version not supported" }, // HTTP 版本不支持 - { 506, "Variant Also Negotiates" }, // 服务器配置文件炸了 - { 507, "Insufficient Storage" }, // 无法在资源上执行该方法 - { 508, "Loop Detected" }, // 死 循 环 辣 - { 510, "Not Extended" }, // 你得扩展扩展 - { 511, "Network Authentication Required" } // 登 录 校 园 网 - }; - - public static string GetStatusMsg(int status) - { - return STATUS_CODES.ContainsKey(status) ? STATUS_CODES[status] : STATUS_CODES[status / 100 * 100]; - } - - public ValueTask SendFile(string filePath) - { - this.Stream = File.OpenRead(filePath); - return ValueTask.CompletedTask; - } - - public Task WriteAsync(byte[] buffer, int offset, int count) - { - return this.Stream.WriteAsync(buffer, offset, count); - } - - public Task WriteAsync(byte[] buffer) - { - return this.Stream.WriteAsync(buffer, 0, buffer.Length); - } - - public Task WriteAsync(string data) => this.WriteAsync(Encoding.UTF8.GetBytes(data)); - - public void ResetStreamPosition() => this.Stream.Position = 0; - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/Route.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/Route.cs deleted file mode 100644 index 413ee3c..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/Route.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.RegularExpressions; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public struct Route - { - public required Regex MatchRegex; - public List> ConditionExpressions = new(); - public Action? Handler; - public string Methods - { - get => string.Join(' ', this._allowedMethods); - set - { - this._allowedMethods.Clear(); - foreach (string method in value.Split(" ").Where(s => !string.IsNullOrWhiteSpace(s))) - { - this._allowedMethods.Add(method); - } - } - } - - private List _allowedMethods = new() - { - "GET" - }; - - public Route() - { - - } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/ServeType.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/ServeType.cs deleted file mode 100644 index 04d3059..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/ServeType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public enum ServeType - { - SimpleWeb, - AspDotNet - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs deleted file mode 100644 index c0a3d48..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System.Net; -using System.Net.Security; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using System.Text; -using TeraIO.Runnable; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public class SimpleWebServer : RunnableBase - { - private int Port = 0; // TCP 随机端口 - private readonly X509Certificate2? _certificate; // SSL证书 - private Cluster cluster; - public readonly List routes = new(); - private readonly int bufferSize = 8192; - - public SimpleWebServer(int port, X509Certificate2? certificate, Cluster cluster) - { - Port = port; - _certificate = certificate; - this.cluster = cluster; - } - - protected override int Run(string[] args) - { - while (true) - { - int result = -1; - try - { - result = AsyncRun().Result; - return result; - } - catch (Exception ex) - { - ex.GetType(); - Logger.Instance.LogError(ex.ExceptionToDetail()); - return result; - } - } - } - - protected async Task AsyncRun() - { - TcpListener listener = new TcpListener(IPAddress.Any, Port); - listener.Start(); - - HttpListener httpListener = new(); - - while (true) - { - TcpClient? tcpClient = null; - try - { - tcpClient = await listener.AcceptTcpClientAsync(); - _ = Task.Run(() => HandleRequest(tcpClient)); - } - catch (Exception ex) - { - Logger.Instance.LogError(ex.ExceptionToDetail()); - if (tcpClient != null && tcpClient.Connected) - { - tcpClient?.Close(); - } - } - } - } - - protected void HandleRequest(TcpClient tcpClient) - { - Stream stream = tcpClient.GetStream(); - if (_certificate != null) - { - SslStream sslStream = new SslStream(stream, false, ValidateServerCertificate, null); - sslStream.AuthenticateAsServer(this._certificate, false, false); - stream = sslStream; - } - if (Handle(new Client(tcpClient, stream)).Result && tcpClient.Connected) - { - stream.Close(); - tcpClient.Close(); - } - } - - protected async Task Handle(Client client) // 返回值代表是否关闭连接? - { - - byte[] buffer = await client.Read(this.bufferSize); - var str = Encoding.UTF8.GetString(buffer); - Request request = new Request(client, buffer); - Response response = new Response(); - HttpContext context = new HttpContext() { Request = request, RemoteIPAddress = client.TcpClient.Client.RemoteEndPoint!, Response = response }; - - foreach (Route route in this.routes) - { - if (route.MatchRegex.Match(context.Request.Path).Success) - { - if (!route.Methods.Contains(context.Request.Method)) - { - context.Response.StatusCode = 405; - await context.Response.WriteAsync("405 Method Not Allowed"); - context.Response.ResetStreamPosition(); - break; - } - foreach (var func in route.ConditionExpressions) - { - bool result = func.Invoke(context.Request.Path); - if (!result) goto NextOne; - } - // 已经判断符合所有条件 - - route.Handler?.Invoke(context, cluster, route.MatchRegex.Match(context.Request.Path)); - break; - } - NextOne: continue; - } - - await response.Call(client, request); // 可以多次调用Response - - //SharedData.Logger.LogInfo($"{request.Method} {request.Path} <{response.StatusCode}> - [{request.Client.TcpClient.Client.RemoteEndPoint}] {request.Header.TryGetValue("User-Agent")}"); - - return true; - } - - private bool ValidateServerCertificate(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) - { - return _certificate != null; - } - - private static void PrintBytes(byte[] bytes) - { - string text = ""; - foreach (var byte_ in bytes) - { - text += ByteToString(byte_); - } - Console.WriteLine(text); - } - - private static void PrintArrayBytes(byte[][] bytes) - { - bytes.ForEach(e => PrintBytes(e)); - } - - private static string ByteToString(byte hex) - { - return hex <= 8 || (hex >= 11 && hex <= 12) || (hex >= 14 && hex <= 31) || (hex >= 127 && hex <= 255) ? "\\x" + BitConverter.ToString(new byte[] { hex }) : (hex == 9 ? "\\t" : (hex == 10 ? "\\n" : (hex == 13 ? "\\r" : Encoding.ASCII.GetString(new byte[] { hex })))); - } - } -} diff --git a/CSharp-OpenBMCLAPI/Modules/WebServer/WebUtils.cs b/CSharp-OpenBMCLAPI/Modules/WebServer/WebUtils.cs deleted file mode 100644 index a1244a3..0000000 --- a/CSharp-OpenBMCLAPI/Modules/WebServer/WebUtils.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Text; - -namespace CSharpOpenBMCLAPI.Modules.WebServer -{ - public static class WebUtils - { - public static List SplitBytes(this byte[] data, byte[] key, int count = -1) - { - if (count <= -1) - { - count = 0; - } - else - { - count++; - } - - int dataLength = data.Length; - int keyLength = key.Length; - List splittedData = new List(); - int start = 0; - int currentCount = 0; - - for (int i = 0; i < dataLength; i++) - { - if (data[i] == key[0] && i + keyLength <= dataLength) - { - bool checkedAllBytes = true; - for (int j = 1; j < keyLength; j++) - { - if (data[i + j] != key[j]) - { - checkedAllBytes = false; - break; - } - } - - if (checkedAllBytes) - { - splittedData.Add(SubArray(data, start, i - start)); - currentCount++; - start = i + keyLength; - } - } - - if (count != 0 && currentCount >= count) - { - break; - } - } - - if (count == 0 || currentCount < count) - { - splittedData.Add(SubArray(data, start, dataLength - start)); - } - - return splittedData; - } - - // Helper method to create a subarray from an existing array - public static byte[] SubArray(this byte[] data, int start, int length) - { - byte[] result = new byte[length]; - Array.Copy(data, start, result, 0, length); - return result; - } - - public static object[] SubArray(this object[] data, int start, int length) - { - object[] result = new object[length]; - Array.Copy(data, start, result, 0, length); - return result; - } - - public static string Decode(this byte[] data) - { - return Encoding.UTF8.GetString(data); - } - - public static byte[] Encode(this string data) - { - return Encoding.UTF8.GetBytes(data).ToArray(); - } - } -}