Uwaa/HTTP/Routing/FileEndpoint.cs

108 lines
3.5 KiB
C#
Raw Normal View History

2024-11-22 07:40:43 +01:00
using System.Text.RegularExpressions;
namespace Uwaa.HTTP.Routing;
/// <summary>
/// Special router which serves static files from the filesystem.
/// </summary>
public partial class FileEndpoint : RouterBase
{
static MIMEType GuessMIMEType(string extension)
{
return extension switch
{
".txt" => new("text", "plain"),
".htm" or "html" => new("text", "html"),
".js" => new("text", "javascript"),
".css" => new("text", "css"),
".csv" => new("text", "csv"),
".bin" => new("application", "octet-stream"),
".zip" => new("application", "zip"),
".7z" => new("application", "x-7z-compressed"),
".gz" => new("application", "gzip"),
".xml" => new("application", "xml"),
".pdf" => new("application", "pdf"),
".json" => new("application", "json"),
".bmp" => new("image", "bmp"),
".png" => new("image", "png"),
".jpg" or "jpeg" => new("image", "jpeg"),
".gif" => new("image", "gif"),
".webp" => new("image", "webp"),
".svg" => new("image", "svg+xml"),
".ico" => new("image", "vnd.microsoft.icon"),
".mid" or ".midi" => new("audio", "midi"),
".mp3" => new("audio", "mpeg"),
".ogg" or ".oga" or ".opus" => new("audio", "ogg"),
".wav" => new("audio", "wav"),
".weba" => new("audio", "webm"),
".webm" => new("video", "webm"),
".mp4" => new("video", "mp4"),
".mpeg" => new("video", "mpeg"),
".ogv" => new("video", "ogg"),
".otf" => new("font", "otf"),
".ttf" => new("font", "ttf"),
".woff" => new("font", "woff"),
".woff2" => new("font", "woff2"),
_ => new("application", "octet-stream"), //Unknown
};
}
/// <summary>
/// The source directory from which assets should be served.
/// </summary>
public string Directory;
public override HttpMethod Method => HttpMethod.GET;
public override int Arguments => 1;
public FileEndpoint(string directory)
{
Directory = directory;
}
protected override async Task<HttpResponse?> GetResponseInner(HttpRequest req, HttpClientInfo info, ArraySegment<string> path)
{
string? asset = path[0];
if (string.IsNullOrWhiteSpace(asset))
return null;
if (FilenameChecker().IsMatch(asset))
return HttpResponse.BadRequest("Illegal chars in asset path");
string assetPath = $"{Directory}/{asset}";
FileInfo fileInfo = new FileInfo(assetPath);
MIMEType mime;
if (string.IsNullOrEmpty(fileInfo.Extension))
{
mime = new MIMEType("text", "html");
assetPath += ".htm";
}
else
{
mime = GuessMIMEType(fileInfo.Extension);
}
if (!File.Exists(assetPath))
return null;
return new HttpContent(mime, await File.ReadAllBytesAsync(assetPath));
}
/// <summary>
/// Ensures filenames are legal.
/// </summary>
/// <remarks>
/// Enforcing a set of legal characters in filenames reduces the potential attack surface against the server.
/// </remarks>
/// <returns>Returns a regular expression which checks for invalid characters.</returns>
[GeneratedRegex(@"[^a-zA-Z0-9_\-.()\[\] ]")]
private static partial Regex FilenameChecker();
}