mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-10-03 01:01:34 +02:00
New: Use ASP.NET Core instead of Nancy
(cherry picked from commit 58ddbcd77e17ef95ecfad4b746084ee9326116f3)
This commit is contained in:
35
src/Prowlarr.Http/Middleware/CacheHeaderMiddleware.cs
Normal file
35
src/Prowlarr.Http/Middleware/CacheHeaderMiddleware.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
74
src/Prowlarr.Http/Middleware/CacheableSpecification.cs
Normal file
74
src/Prowlarr.Http/Middleware/CacheableSpecification.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
43
src/Prowlarr.Http/Middleware/IfModifiedMiddleware.cs
Normal file
43
src/Prowlarr.Http/Middleware/IfModifiedMiddleware.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
92
src/Prowlarr.Http/Middleware/LoggingMiddleware.cs
Normal file
92
src/Prowlarr.Http/Middleware/LoggingMiddleware.cs
Normal 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"]}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
src/Prowlarr.Http/Middleware/UrlBaseMiddleware.cs
Normal file
29
src/Prowlarr.Http/Middleware/UrlBaseMiddleware.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
30
src/Prowlarr.Http/Middleware/VersionMiddleware.cs
Normal file
30
src/Prowlarr.Http/Middleware/VersionMiddleware.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user