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);
}
}
}