New: Use ASP.NET Core instead of Nancy

(cherry picked from commit 58ddbcd77e17ef95ecfad4b746084ee9326116f3)
This commit is contained in:
ta264
2021-03-15 21:32:12 +00:00
parent 7d494f9743
commit dbdc527f2e
122 changed files with 2177 additions and 2838 deletions

View File

@@ -0,0 +1,35 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Prowlarr.Http.Extensions;
namespace Prowlarr.Http.Middleware
{
public class CacheHeaderMiddleware
{
private readonly RequestDelegate _next;
private readonly ICacheableSpecification _cacheableSpecification;
public CacheHeaderMiddleware(RequestDelegate next, ICacheableSpecification cacheableSpecification)
{
_next = next;
_cacheableSpecification = cacheableSpecification;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.Request.Method != "OPTIONS")
{
if (_cacheableSpecification.IsCacheable(context))
{
context.Response.Headers.EnableCache();
}
else
{
context.Response.Headers.DisableCache();
}
}
await _next(context);
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using Microsoft.AspNetCore.Http;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace Prowlarr.Http.Middleware
{
public interface ICacheableSpecification
{
bool IsCacheable(HttpContext context);
}
public class CacheableSpecification : ICacheableSpecification
{
public bool IsCacheable(HttpContext context)
{
if (!RuntimeInfo.IsProduction)
{
return false;
}
if (context.Request.Query.ContainsKey("h"))
{
return true;
}
if (context.Request.Path.StartsWithSegments("/api", StringComparison.CurrentCultureIgnoreCase))
{
if (context.Request.Path.ToString().ContainsIgnoreCase("/MediaCover"))
{
return true;
}
return false;
}
if (context.Request.Path.StartsWithSegments("/signalr", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Request.Path.Equals("/index.js"))
{
return false;
}
if (context.Request.Path.Equals("/initialize.js"))
{
return false;
}
if (context.Request.Path.StartsWithSegments("/feed", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Request.Path.StartsWithSegments("/log", StringComparison.CurrentCultureIgnoreCase) &&
context.Request.Path.ToString().EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Response != null)
{
if (context.Response.ContentType?.Contains("text/html") ?? false || context.Response.StatusCode >= 400)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,43 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
using Prowlarr.Http.Extensions;
namespace Prowlarr.Http.Middleware
{
public class IfModifiedMiddleware
{
private readonly RequestDelegate _next;
private readonly ICacheableSpecification _cacheableSpecification;
private readonly IContentTypeProvider _mimeTypeProvider;
public IfModifiedMiddleware(RequestDelegate next, ICacheableSpecification cacheableSpecification)
{
_next = next;
_cacheableSpecification = cacheableSpecification;
_mimeTypeProvider = new FileExtensionContentTypeProvider();
}
public async Task InvokeAsync(HttpContext context)
{
if (_cacheableSpecification.IsCacheable(context) && context.Request.Headers["IfModifiedSince"].Any())
{
context.Response.StatusCode = 304;
context.Response.Headers.EnableCache();
if (!_mimeTypeProvider.TryGetContentType(context.Request.Path.ToString(), out var mimeType))
{
mimeType = "application/octet-stream";
}
context.Response.ContentType = mimeType;
return;
}
await _next(context);
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using NLog;
using NzbDrone.Common.Extensions;
using Prowlarr.Http.ErrorManagement;
using Prowlarr.Http.Extensions;
namespace Prowlarr.Http.Middleware
{
public class LoggingMiddleware
{
private static readonly Logger _loggerHttp = LogManager.GetLogger("Http");
private static readonly Logger _loggerApi = LogManager.GetLogger("Api");
private static int _requestSequenceID;
private readonly ProwlarrErrorPipeline _errorHandler;
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next,
ProwlarrErrorPipeline errorHandler)
{
_next = next;
_errorHandler = errorHandler;
}
public async Task InvokeAsync(HttpContext context)
{
LogStart(context);
await _next(context);
LogEnd(context);
}
private void LogStart(HttpContext context)
{
var id = Interlocked.Increment(ref _requestSequenceID);
context.Items["ApiRequestSequenceID"] = id;
context.Items["ApiRequestStartTime"] = DateTime.UtcNow;
var reqPath = GetRequestPathAndQuery(context.Request);
_loggerHttp.Trace("Req: {0} [{1}] {2} (from {3})", id, context.Request.Method, reqPath, GetOrigin(context));
}
private void LogEnd(HttpContext context)
{
var id = (int)context.Items["ApiRequestSequenceID"];
var startTime = (DateTime)context.Items["ApiRequestStartTime"];
var endTime = DateTime.UtcNow;
var duration = endTime - startTime;
var reqPath = GetRequestPathAndQuery(context.Request);
_loggerHttp.Trace("Res: {0} [{1}] {2}: {3}.{4} ({5} ms)", id, context.Request.Method, reqPath, context.Response.StatusCode, (HttpStatusCode)context.Response.StatusCode, (int)duration.TotalMilliseconds);
if (context.Request.IsApiRequest())
{
_loggerApi.Debug("[{0}] {1}: {2}.{3} ({4} ms)", context.Request.Method, reqPath, context.Response.StatusCode, (HttpStatusCode)context.Response.StatusCode, (int)duration.TotalMilliseconds);
}
}
private static string GetRequestPathAndQuery(HttpRequest request)
{
if (request.QueryString.Value.IsNotNullOrWhiteSpace() && request.QueryString.Value != "?")
{
return string.Concat(request.Path, request.QueryString);
}
else
{
return request.Path;
}
}
private static string GetOrigin(HttpContext context)
{
if (context.Request.Headers["UserAgent"].ToString().IsNullOrWhiteSpace())
{
return context.GetRemoteIP();
}
else
{
return $"{context.GetRemoteIP()} {context.Request.Headers["UserAgent"]}";
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using NzbDrone.Common.Extensions;
namespace Prowlarr.Http.Middleware
{
public class UrlBaseMiddleware
{
private readonly RequestDelegate _next;
private readonly string _urlBase;
public UrlBaseMiddleware(RequestDelegate next, string urlBase)
{
_next = next;
_urlBase = urlBase;
}
public async Task InvokeAsync(HttpContext context)
{
if (_urlBase.IsNotNullOrWhiteSpace() && context.Request.PathBase.Value.IsNullOrWhiteSpace())
{
context.Response.Redirect($"{_urlBase}{context.Request.Path}{context.Request.QueryString}");
return;
}
await _next(context);
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using NzbDrone.Common.EnvironmentInfo;
namespace Prowlarr.Http.Middleware
{
public class VersionMiddleware
{
private const string VERSIONHEADER = "X-ApplicationVersion";
private readonly RequestDelegate _next;
private readonly string _version;
public VersionMiddleware(RequestDelegate next)
{
_next = next;
_version = BuildInfo.Version.ToString();
}
public async Task InvokeAsync(HttpContext context)
{
if (!context.Response.Headers.ContainsKey(VERSIONHEADER))
{
context.Response.Headers.Add(VERSIONHEADER, _version);
}
await _next(context);
}
}
}