You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
7.3 KiB
180 lines
7.3 KiB
3 weeks ago
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Net.Http;
|
||
|
using System.Text;
|
||
|
using System.Threading.Tasks;
|
||
|
using Microsoft.AspNetCore.Builder;
|
||
|
using Microsoft.AspNetCore.Http;
|
||
|
|
||
|
namespace ReZero.SuperAPI
|
||
|
{
|
||
|
public class SuperAPIStaticFileMiddleware
|
||
|
{
|
||
|
private readonly RequestDelegate _next;
|
||
|
|
||
|
// Constants for ReZero paths and file locations
|
||
|
internal static string ReZeroDirName = "rezero";
|
||
|
internal static string RezeroPathPrefix = $"/{ReZeroDirName}/";
|
||
|
internal static string RezeroRootPath = $"/{ReZeroDirName}";
|
||
|
internal static string DefaultIndexPath = "index.html";
|
||
|
internal static string WwwRootPath = "wwwroot";
|
||
|
internal static string DefaultUiFolderName = "default_ui";
|
||
|
internal static string UiFolderPath { get; set; } = $"{ReZeroDirName}/{DefaultUiFolderName}";
|
||
|
|
||
|
public SuperAPIStaticFileMiddleware(RequestDelegate next)
|
||
|
{
|
||
|
_next = next ?? throw new ArgumentNullException(nameof(next));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Invokes the middleware to handle the request.
|
||
|
/// </summary>
|
||
|
/// <param name="context">The HttpContext for the request.</param>
|
||
|
public async Task InvokeAsync(HttpContext context)
|
||
|
{
|
||
|
// Get the lowercase path of the request
|
||
|
var path = (context.Request.Path.Value ?? string.Empty).ToLower();
|
||
|
|
||
|
// Check if the request is for the root URL of ReZero
|
||
|
if (IsRezeroRootUrl(path))
|
||
|
{
|
||
|
// Redirect to the default index.html if it is the root URL
|
||
|
context.Response.Redirect($"{RezeroPathPrefix}{DefaultIndexPath}");
|
||
|
return;
|
||
|
}
|
||
|
// Check if the request is for a ReZero static file
|
||
|
else if (IsRezeroFileUrl(path))
|
||
|
{
|
||
|
|
||
|
var filePathByCurrentDirectory = GetFilePathByCurrentDirectory(path);
|
||
|
var filePathByBaseDirectory = GetFilePathByBaseDirectory(path);
|
||
|
|
||
|
if (FileExistsAndIsNotHtml(filePathByCurrentDirectory))
|
||
|
{
|
||
|
await CopyToFile(context, filePathByCurrentDirectory);
|
||
|
return;
|
||
|
}
|
||
|
else if (FileExistsHtml(filePathByCurrentDirectory))
|
||
|
{
|
||
|
await CopyToHtml(context, filePathByCurrentDirectory);
|
||
|
return;
|
||
|
}
|
||
|
else if (FileExistsAndIsNotHtml(filePathByBaseDirectory))
|
||
|
{
|
||
|
await CopyToFile(context, filePathByBaseDirectory);
|
||
|
return;
|
||
|
}
|
||
|
else if (FileExistsHtml(filePathByBaseDirectory))
|
||
|
{
|
||
|
await CopyToHtml(context, filePathByBaseDirectory);
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If the file does not exist, return a 404 Not Found status
|
||
|
context.Response.StatusCode = 404;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If the request doesn't match ReZero paths, call the next middleware
|
||
|
await _next(context);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the requested file exists and is not an HTML file.
|
||
|
/// </summary>
|
||
|
/// <param name="filePath">The path of the file to check.</param>
|
||
|
/// <returns>True if the file exists and is not an HTML file, false otherwise.</returns>
|
||
|
private static bool FileExistsAndIsNotHtml(string filePath)
|
||
|
{
|
||
|
return File.Exists(filePath) && !filePath.Contains(".html");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the requested file exists and is an HTML file.
|
||
|
/// </summary>
|
||
|
/// <param name="filePath">The path of the file to check.</param>
|
||
|
/// <returns>True if the file exists and is an HTML file, false otherwise.</returns>
|
||
|
private static bool FileExistsHtml(string filePath)
|
||
|
{
|
||
|
return File.Exists(filePath) && filePath.Contains(".html");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Copies the content of the requested file to the response stream.
|
||
|
/// </summary>
|
||
|
/// <param name="context">The HttpContext for the request.</param>
|
||
|
/// <param name="filePath">The path of the file to copy.</param>
|
||
|
private static async Task CopyToFile(HttpContext context, string filePath)
|
||
|
{
|
||
|
// Read the file content and send it to the client
|
||
|
using (var fileStream = File.OpenRead(filePath))
|
||
|
{
|
||
|
await fileStream.CopyToAsync(context.Response.Body);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Copies the content of the requested HTML file to the response stream.
|
||
|
/// </summary>
|
||
|
/// <param name="context">The HttpContext for the request.</param>
|
||
|
/// <param name="filePath">The path of the HTML file to copy.</param>
|
||
|
private static async Task CopyToHtml(HttpContext context, string filePath)
|
||
|
{
|
||
|
// Read the file content
|
||
|
string fileContent;
|
||
|
using (var reader = new StreamReader(filePath))
|
||
|
{
|
||
|
fileContent = await reader.ReadToEndAsync();
|
||
|
}
|
||
|
// Check if the file is a master page
|
||
|
IUiManager defaultUiManager = UIFactory.uiManager;
|
||
|
if (defaultUiManager.IsMasterPage(fileContent))
|
||
|
{
|
||
|
// If the file is a master page, get the HTML and send it to the client
|
||
|
fileContent = await defaultUiManager.GetHtmlAsync(fileContent, filePath, context);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fileContent = await defaultUiManager.GetCustomPageHtmlAsync(fileContent, filePath, context);
|
||
|
}
|
||
|
// Send the file content to the client
|
||
|
await context.Response.WriteAsync(fileContent);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the requested URL is for a ReZero static file.
|
||
|
/// </summary>
|
||
|
/// <param name="path">The path of the requested URL.</param>
|
||
|
/// <returns>True if the requested URL is for a ReZero static file, false otherwise.</returns>
|
||
|
private static bool IsRezeroFileUrl(string path)
|
||
|
{
|
||
|
return path.StartsWith(RezeroPathPrefix) && path.Contains(".");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Checks if the requested URL is the root URL of ReZero.
|
||
|
/// </summary>
|
||
|
/// <param name="path">The path of the requested URL.</param>
|
||
|
/// <returns>True if the requested URL is the root URL of ReZero, false otherwise.</returns>
|
||
|
private static bool IsRezeroRootUrl(string path)
|
||
|
{
|
||
|
return path.TrimEnd('/') == RezeroRootPath;
|
||
|
}
|
||
|
|
||
|
|
||
|
internal static string GetFilePathByCurrentDirectory(string path)
|
||
|
{
|
||
|
var relativePath = path.Replace(RezeroPathPrefix, string.Empty);
|
||
|
var fullPath = Path.Combine(Directory.GetCurrentDirectory(), WwwRootPath, UiFolderPath, relativePath);
|
||
|
return Path.GetFullPath(fullPath);
|
||
|
}
|
||
|
internal static string GetFilePathByBaseDirectory(string path)
|
||
|
{
|
||
|
var relativePath = path.Replace(RezeroPathPrefix, string.Empty);
|
||
|
var fullPath = Path.Combine(AppContext.BaseDirectory, WwwRootPath, UiFolderPath, relativePath);
|
||
|
return Path.GetFullPath(fullPath);
|
||
|
}
|
||
|
}
|
||
|
}
|