2021-11-19 16:11:12 +01:00
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
|
|
|
|
namespace zero.Routing;
|
|
|
|
|
|
|
|
|
|
public class RequestUrlResolver : IRequestUrlResolver
|
|
|
|
|
{
|
|
|
|
|
public IRequestUrlResolver Backoffice { get; private set; }
|
|
|
|
|
|
|
|
|
|
protected IHttpContextAccessor HttpContextAccessor { get; private set; }
|
|
|
|
|
|
|
|
|
|
protected IZeroOptions Options { get; private set; }
|
|
|
|
|
|
|
|
|
|
protected ILogger<RequestUrlResolver> Logger { get; private set; }
|
|
|
|
|
|
|
|
|
|
static string[] Protocols = new[] { "http://", "https://", "ftp://", "ftps://", "sftp://", "udp://" };
|
|
|
|
|
|
|
|
|
|
bool IsBackoffice = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public RequestUrlResolver(IHttpContextAccessor httpContextAccessor, ILogger<RequestUrlResolver> logger, IZeroOptions options, bool isBackoffice = false)
|
|
|
|
|
{
|
|
|
|
|
HttpContextAccessor = httpContextAccessor;
|
|
|
|
|
Logger = logger;
|
|
|
|
|
Options = options;
|
|
|
|
|
IsBackoffice = isBackoffice;
|
|
|
|
|
if (!isBackoffice)
|
|
|
|
|
{
|
|
|
|
|
Backoffice = new RequestUrlResolver(httpContextAccessor, logger, options, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public string ToAbsolute(string path)
|
|
|
|
|
{
|
|
|
|
|
if (!CanResolve())
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (String.IsNullOrWhiteSpace(path))
|
|
|
|
|
{
|
|
|
|
|
return GetRoot();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Protocols.Any(p => path.StartsWith(p, StringComparison.InvariantCultureIgnoreCase)))
|
|
|
|
|
{
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path = path.Trim().TrimEnd('/');
|
|
|
|
|
|
|
|
|
|
if (path.StartsWith("~/"))
|
|
|
|
|
{
|
|
|
|
|
path = path.Substring(1);
|
|
|
|
|
}
|
|
|
|
|
if (!path.StartsWith("/"))
|
|
|
|
|
{
|
|
|
|
|
return GetRoot(includePath: true) + '/' + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return GetRoot() + path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public string GetRoot(bool includePath = false)
|
|
|
|
|
{
|
|
|
|
|
if (!CanResolve())
|
|
|
|
|
{
|
|
|
|
|
Logger.LogWarning("Tried to resolve an URL but no HttpRequest is available");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HttpRequest request = HttpContextAccessor.HttpContext.Request;
|
|
|
|
|
|
2021-11-26 12:31:33 +01:00
|
|
|
string suffix = IsBackoffice ? Options.ZeroPath : String.Empty;
|
2021-11-19 16:11:12 +01:00
|
|
|
|
|
|
|
|
return $"{request.Scheme}://{request.Host.Host}{GetPortUrlPart(request)}{suffix}{(includePath ? request.PathBase.ToUriComponent() : String.Empty)}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Require a request in order to resolve the URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected bool CanResolve() => HttpContextAccessor?.HttpContext?.Request != null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Resolves the port as part of the URL
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected string GetPortUrlPart(HttpRequest request)
|
|
|
|
|
{
|
|
|
|
|
if (!request.Host.Port.HasValue || request.Host.Port == 80 || (request.Host.Port == 443 && request.IsHttps))
|
|
|
|
|
{
|
|
|
|
|
return String.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ":" + request.Host.Port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public interface IRequestUrlResolver
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// URL resolver for backoffice links
|
|
|
|
|
/// </summary>
|
|
|
|
|
IRequestUrlResolver Backoffice { get; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Converts a relative to an absolute path for the currently used domain
|
|
|
|
|
/// </summary>
|
|
|
|
|
string ToAbsolute(string path);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get protocol + domain and optional port
|
|
|
|
|
/// </summary>
|
|
|
|
|
string GetRoot(bool includePath = false);
|
|
|
|
|
}
|