Skip to content

Commit

Permalink
feat: Range 请求的处理以及正确的 206 响应
Browse files Browse the repository at this point in the history
  • Loading branch information
SALTWOOD committed Apr 20, 2024
1 parent c402b12 commit 3970e86
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 64 deletions.
2 changes: 1 addition & 1 deletion CSharp-OpenBMCLAPI/Modules/Cluster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private void InitializeService()
{
//var builder = WebApplication.CreateBuilder();
X509Certificate2 cert = LoadAndConvertCert();
SimpleWebServer server = new(ClusterRequiredData.Config.PORT, cert);//cert);
SimpleWebServer server = new(ClusterRequiredData.Config.PORT, cert, this);//cert);
server.Start();
/*
builder.WebHost.UseKestrel(options =>
Expand Down
15 changes: 10 additions & 5 deletions CSharp-OpenBMCLAPI/Modules/HttpServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public static async Task Measure(HttpContext context, Cluster cluster)
public static async Task<FileAccessInfo> DownloadHash(HttpContext context, Cluster cluster)
{
FileAccessInfo fai = default;
var pairs = Utils.GetQueryStrings(context.Request.QueryString);
string? hash = context.Request.Path.Split('/').LastOrDefault();
var pairs = Utils.GetQueryStrings(context.Request.Path.Split('?').Last());
string? hash = context.Request.Path.Split('/').LastOrDefault()?.Split('?').First();
string? s = pairs.GetValueOrDefault("s");
string? e = pairs.GetValueOrDefault("e");

Expand All @@ -79,10 +79,14 @@ public static async Task<FileAccessInfo> DownloadHash(HttpContext context, Clust
{
try
{
if (context.Request.Header.Select(f => f.Key).Contains("Range"))
if (context.Request.Header.ContainsKey("Range"))
{
(long from, long to) = ToRangeByte(context.Request.Header["Range"].Split("=").Last().Split("-"));
//TODO: Range 请求
context.Response.Header["Content-Length"] = (to - from).ToString();
using Stream file = cluster.storage.ReadFileStream(Utils.HashToFileName(hash));
file.Seek(from, SeekOrigin.Begin);
file.CopyTo(context.Response.Stream);
context.Response.StatusCode = 206;
}
else
{
Expand All @@ -98,6 +102,7 @@ public static async Task<FileAccessInfo> DownloadHash(HttpContext context, Clust
else
{
context.Response.StatusCode = 403;
context.Response.Header.Remove("Content-Length");
await context.Response.WriteAsync($"Access to \"{context.Request.Path}\" has been blocked due to your request timeout or invalidity.");
}
return fai;
Expand All @@ -107,7 +112,7 @@ private static (long from, long to) ToRangeByte(string[]? rangeHeader)
{
int from, to;
if (string.IsNullOrWhiteSpace(rangeHeader?.FirstOrDefault()))
from = -1;
from = 0;
else
from = Convert.ToInt32(rangeHeader?.FirstOrDefault());
if (string.IsNullOrWhiteSpace(rangeHeader?.LastOrDefault()))
Expand Down
2 changes: 1 addition & 1 deletion CSharp-OpenBMCLAPI/Modules/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ static long ToDecimal(string hex)
public static Dictionary<string, string> GetQueryStrings(string? query)
{
Dictionary<string, string> pairs = new();
query?[1..].Split('&').ForEach(s =>
query?.Split('&').ForEach(s =>
{
var pair = s.Split('=');
pairs[pair[0]] = pair[1];
Expand Down
2 changes: 1 addition & 1 deletion CSharp-OpenBMCLAPI/Modules/WebServer/HttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public class HttpContext
{
public required Request Request { get; set; }
public required Response Response { get; set; }
public required IPEndPoint RemoteIPAddress { get; set; }
public required EndPoint RemoteIPAddress { get; set; }
}
}
3 changes: 2 additions & 1 deletion CSharp-OpenBMCLAPI/Modules/WebServer/Response.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ public class Response

public async Task Call(Client client, Request request, bool needCopy = true)
{
Header.Set("Content-Length", Stream.Length);
if (!Header.ContainsKey("Content-Length")) Header.Set("Content-Length", Stream.Length);
Header.Set("Server", "CSharp-SaltWood");
string responseHeader = $"HTTP/1.1 {StatusCode} {GetStatusMsg(StatusCode)}\r\n{Header}\r\n";
await client.Write(responseHeader.Encode());
Stream.Position = 0;
if (needCopy) Stream.CopyTo(client.Stream);
}

Expand Down
66 changes: 41 additions & 25 deletions CSharp-OpenBMCLAPI/Modules/WebServer/SimpleWebServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@
using TeraIO.Runnable;
using System.Text.RegularExpressions;
using TeraIO.Extension;
using System.Diagnostics;

namespace CSharpOpenBMCLAPI.Modules.WebServer
{
public class SimpleWebServer : RunnableBase
{
private int Port = 0; // TCP 随机端口
private readonly X509Certificate2? _certificate; // SSL证书
private Cluster cluster;
private readonly int bufferSize = 8192;

public SimpleWebServer(int port, X509Certificate2? certificate)
public SimpleWebServer(int port, X509Certificate2? certificate, Cluster cluster)
{
Port = port;
_certificate = certificate;
_certificate = null;
this.cluster = cluster;
}

protected override int Run(string[] args)
Expand Down Expand Up @@ -52,33 +56,36 @@ protected async Task<int> AsyncRun()
while (true)
{
TcpClient tcpClient = await listener.AcceptTcpClientAsync();
_ = Task.Run(() =>
_ = Task.Run(() => HandleRequest(tcpClient));
}
}

protected void HandleRequest(TcpClient tcpClient)
{
try
{
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)
{
try
{
Stream stream = tcpClient.GetStream();
if (_certificate != null)
{
SslStream sslStream = new SslStream(stream, true, ValidateServerCertificate, null);
sslStream.AuthenticateAsServer(this._certificate, false, false);
stream = sslStream;
}
if (Handle(new Client(tcpClient, stream)).Result && tcpClient.Connected)
{
stream.Close();
tcpClient.Close();
}
}
catch (Exception ex)
{
Logger.Instance.LogError(ex.ExceptionToDetail());
}
});
stream.Close();
tcpClient.Close();
}
}
catch (Exception ex)
{
Logger.Instance.LogError(ex.ExceptionToDetail());
}
}

protected async Task<bool> Handle(Client client) // 返回值代表是否关闭连接?
{

byte[] buffer = await client.Read(this.bufferSize);
Request request = new Request(client, buffer);
Response response = new Response();
Expand All @@ -88,9 +95,18 @@ protected async Task<bool> Handle(Client client) // 返回值代表是否关闭

response.Header.Add("Content-Type", "application/octet-stream");

var filePath = Path.Combine(ClusterRequiredData.Config.cacheDirectory, Utils.HashToFileName(match.Groups[1].Value));
FileInfo fileInfo = new FileInfo(filePath);
response.Stream = File.OpenRead(filePath);
HttpContext context = new HttpContext() { Request = request, RemoteIPAddress = client.TcpClient.Client.RemoteEndPoint!, Response = response };

try
{
var count = match.Groups.Count;
if (count == 0) return true;
await HttpServiceProvider.DownloadHash(context, cluster);
}
catch
{
Debugger.Break();
}

await response.Call(client, request); // 可以多次调用Response

Expand Down
68 changes: 38 additions & 30 deletions CSharp-OpenBMCLAPI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,45 +96,53 @@ protected Config GetConfig()

protected override int Run(string[] args)
{
ClusterRequiredData.Config = GetConfig();
LoadPlugins();
PluginManager.Instance.TriggerEvent(this, ProgramEventType.ProgramStarted);
try
{
ClusterRequiredData.Config = GetConfig();
LoadPlugins();
PluginManager.Instance.TriggerEvent(this, ProgramEventType.ProgramStarted);

int returns = 0;
int returns = 0;

if (File.Exists("totals.bson"))
{
DataStatistician t = Utils.BsonDeserializeObject<DataStatistician>(File.ReadAllBytes("totals.bson")).ThrowIfNull();
ClusterRequiredData.DataStatistician = t;
}
else
{
const string bsonFilePath = "totals.bson";
using (var file = File.Create(bsonFilePath))
if (File.Exists("totals.bson"))
{
file.Write(Utils.BsonSerializeObject(ClusterRequiredData.DataStatistician));
DataStatistician t = Utils.BsonDeserializeObject<DataStatistician>(File.ReadAllBytes("totals.bson")).ThrowIfNull();
ClusterRequiredData.DataStatistician = t;
}
else
{
const string bsonFilePath = "totals.bson";
using (var file = File.Create(bsonFilePath))
{
file.Write(Utils.BsonSerializeObject(ClusterRequiredData.DataStatistician));
}
}
}

// 从 .env.json 读取密钥然后 FetchToken
ClusterInfo info = JsonConvert.DeserializeObject<ClusterInfo>(File.ReadAllTextAsync(".env.json").Result);
ClusterRequiredData requiredData = new(info);
Logger.Instance.LogSystem($"Cluster id: {info.ClusterID}");
TokenManager token = new TokenManager(info);
token.FetchToken().Wait();
// 从 .env.json 读取密钥然后 FetchToken
ClusterInfo info = JsonConvert.DeserializeObject<ClusterInfo>(File.ReadAllTextAsync(".env.json").Result);
ClusterRequiredData requiredData = new(info);
Logger.Instance.LogSystem($"Cluster id: {info.ClusterID}");
TokenManager token = new TokenManager(info);
token.FetchToken().Wait();

requiredData.Token = token;
requiredData.Token = token;

Cluster cluster = new(requiredData);
Logger.Instance.LogSystem($"成功创建 Cluster 实例");
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Utils.ExitCluster(cluster).Wait();
Console.CancelKeyPress += (sender, e) => Utils.ExitCluster(cluster).Wait();
Cluster cluster = new(requiredData);
Logger.Instance.LogSystem($"成功创建 Cluster 实例");
AppDomain.CurrentDomain.ProcessExit += (sender, e) => Utils.ExitCluster(cluster).Wait();
Console.CancelKeyPress += (sender, e) => Utils.ExitCluster(cluster).Wait();

cluster.Start();
cluster.WaitForStop();
cluster.Start();
cluster.WaitForStop();

requiredData.PluginManager.TriggerEvent(this, ProgramEventType.ProgramStopped);
return returns;
requiredData.PluginManager.TriggerEvent(this, ProgramEventType.ProgramStopped);
return returns;
}
catch (Exception ex)
{
Console.WriteLine(ex.ExceptionToDetail());
return -1;
}
}
}
}

0 comments on commit 3970e86

Please sign in to comment.