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)); } /// /// Invokes the middleware to handle the request. /// /// The HttpContext for the request. 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); } /// /// Checks if the requested file exists and is not an HTML file. /// /// The path of the file to check. /// True if the file exists and is not an HTML file, false otherwise. private static bool FileExistsAndIsNotHtml(string filePath) { return File.Exists(filePath) && !filePath.Contains(".html"); } /// /// Checks if the requested file exists and is an HTML file. /// /// The path of the file to check. /// True if the file exists and is an HTML file, false otherwise. private static bool FileExistsHtml(string filePath) { return File.Exists(filePath) && filePath.Contains(".html"); } /// /// Copies the content of the requested file to the response stream. /// /// The HttpContext for the request. /// The path of the file to copy. 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); } } /// /// Copies the content of the requested HTML file to the response stream. /// /// The HttpContext for the request. /// The path of the HTML file to copy. 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); } /// /// Checks if the requested URL is for a ReZero static file. /// /// The path of the requested URL. /// True if the requested URL is for a ReZero static file, false otherwise. private static bool IsRezeroFileUrl(string path) { return path.StartsWith(RezeroPathPrefix) && path.Contains("."); } /// /// Checks if the requested URL is the root URL of ReZero. /// /// The path of the requested URL. /// True if the requested URL is the root URL of ReZero, false otherwise. 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); } } }