mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-10 23:33:38 -07:00
New: Use ASP.NET Core instead of Nancy
This commit is contained in:
parent
fe956f340c
commit
c247d07e84
161 changed files with 2893 additions and 3665 deletions
|
@ -1,124 +1,173 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Nancy;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
|
||||
namespace Lidarr.Http.Extensions
|
||||
{
|
||||
public static class RequestExtensions
|
||||
{
|
||||
public static bool IsApiRequest(this Request request)
|
||||
// See src/Lidarr.Api.V1/Queue/QueueModule.cs
|
||||
private static readonly HashSet<string> VALID_SORT_KEYS = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
return request.Path.StartsWith("/api/", StringComparison.InvariantCultureIgnoreCase);
|
||||
"authors.sortname", //Workaround authors table properties not being added on isValidSortKey call
|
||||
"timeleft",
|
||||
"estimatedCompletionTime",
|
||||
"protocol",
|
||||
"indexer",
|
||||
"downloadClient",
|
||||
"quality",
|
||||
"status",
|
||||
"title",
|
||||
"progress"
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> EXCLUDED_KEYS = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
"page",
|
||||
"pageSize",
|
||||
"sortKey",
|
||||
"sortDirection",
|
||||
"filterKey",
|
||||
"filterValue",
|
||||
};
|
||||
|
||||
public static bool IsApiRequest(this HttpRequest request)
|
||||
{
|
||||
return request.Path.StartsWithSegments("/api", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsFeedRequest(this Request request)
|
||||
{
|
||||
return request.Path.StartsWith("/feed/", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsSignalRRequest(this Request request)
|
||||
{
|
||||
return request.Path.StartsWith("/signalr/", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsLocalRequest(this Request request)
|
||||
{
|
||||
return request.UserHostAddress.Equals("localhost") ||
|
||||
request.UserHostAddress.Equals("127.0.0.1") ||
|
||||
request.UserHostAddress.Equals("::1");
|
||||
}
|
||||
|
||||
public static bool IsLoginRequest(this Request request)
|
||||
{
|
||||
return request.Path.Equals("/login", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsContentRequest(this Request request)
|
||||
{
|
||||
return request.Path.StartsWith("/Content/", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool GetBooleanQueryParameter(this Request request, string parameter, bool defaultValue = false)
|
||||
public static bool GetBooleanQueryParameter(this HttpRequest request, string parameter, bool defaultValue = false)
|
||||
{
|
||||
var parameterValue = request.Query[parameter];
|
||||
|
||||
if (parameterValue.HasValue)
|
||||
if (parameterValue.Any())
|
||||
{
|
||||
return bool.Parse(parameterValue.Value);
|
||||
return bool.Parse(parameterValue.ToString());
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static bool IsBundledJsRequest(this Request request)
|
||||
public static PagingResource<TResource> ReadPagingResourceFromRequest<TResource>(this HttpRequest request)
|
||||
{
|
||||
return !request.Path.EqualsIgnoreCase("/initialize.js") && request.Path.EndsWith(".js", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsSharedContentRequest(this Request request)
|
||||
{
|
||||
return request.Path.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
request.Path.StartsWith("/Content/Images/", StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static int GetIntegerQueryParameter(this Request request, string parameter, int defaultValue = 0)
|
||||
{
|
||||
var parameterValue = request.Query[parameter];
|
||||
|
||||
if (parameterValue.HasValue)
|
||||
if (!int.TryParse(request.Query["PageSize"].ToString(), out var pageSize))
|
||||
{
|
||||
return int.Parse(parameterValue.Value);
|
||||
pageSize = 10;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static Guid GetGuidQueryParameter(this Request request, string parameter, Guid defaultValue = default)
|
||||
{
|
||||
var parameterValue = request.Query[parameter];
|
||||
|
||||
if (parameterValue.HasValue)
|
||||
if (!int.TryParse(request.Query["Page"].ToString(), out var page))
|
||||
{
|
||||
return Guid.Parse(parameterValue.Value);
|
||||
page = 1;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static int? GetNullableIntegerQueryParameter(this Request request, string parameter, int? defaultValue = null)
|
||||
{
|
||||
var parameterValue = request.Query[parameter];
|
||||
|
||||
if (parameterValue.HasValue)
|
||||
var pagingResource = new PagingResource<TResource>
|
||||
{
|
||||
return int.Parse(parameterValue.Value);
|
||||
PageSize = pageSize,
|
||||
Page = page,
|
||||
Filters = new List<PagingResourceFilter>()
|
||||
};
|
||||
|
||||
if (request.Query["SortKey"].Any())
|
||||
{
|
||||
var sortKey = request.Query["SortKey"].ToString();
|
||||
|
||||
if (!VALID_SORT_KEYS.Contains(sortKey) &&
|
||||
!TableMapping.Mapper.IsValidSortKey(sortKey))
|
||||
{
|
||||
throw new BadRequestException($"Invalid sort key {sortKey}");
|
||||
}
|
||||
|
||||
pagingResource.SortKey = sortKey;
|
||||
|
||||
if (request.Query["SortDirection"].Any())
|
||||
{
|
||||
pagingResource.SortDirection = request.Query["SortDirection"].ToString()
|
||||
.Equals("ascending", StringComparison.InvariantCultureIgnoreCase)
|
||||
? SortDirection.Ascending
|
||||
: SortDirection.Descending;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
// For backwards compatibility with v2
|
||||
if (request.Query["FilterKey"].Any())
|
||||
{
|
||||
var filter = new PagingResourceFilter
|
||||
{
|
||||
Key = request.Query["FilterKey"].ToString()
|
||||
};
|
||||
|
||||
if (request.Query["FilterValue"].Any())
|
||||
{
|
||||
filter.Value = request.Query["FilterValue"].ToString();
|
||||
}
|
||||
|
||||
pagingResource.Filters.Add(filter);
|
||||
}
|
||||
|
||||
// v3 uses filters in key=value format
|
||||
foreach (var pair in request.Query)
|
||||
{
|
||||
if (EXCLUDED_KEYS.Contains(pair.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pagingResource.Filters.Add(new PagingResourceFilter
|
||||
{
|
||||
Key = pair.Key,
|
||||
Value = pair.Value.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
return pagingResource;
|
||||
}
|
||||
|
||||
public static string GetRemoteIP(this NancyContext context)
|
||||
public static PagingResource<TResource> ApplyToPage<TResource, TModel>(this PagingSpec<TModel> pagingSpec, Func<PagingSpec<TModel>, PagingSpec<TModel>> function, Converter<TModel, TResource> mapper)
|
||||
{
|
||||
if (context == null || context.Request == null)
|
||||
pagingSpec = function(pagingSpec);
|
||||
|
||||
return new PagingResource<TResource>
|
||||
{
|
||||
Page = pagingSpec.Page,
|
||||
PageSize = pagingSpec.PageSize,
|
||||
SortDirection = pagingSpec.SortDirection,
|
||||
SortKey = pagingSpec.SortKey,
|
||||
TotalRecords = pagingSpec.TotalRecords,
|
||||
Records = pagingSpec.Records.ConvertAll(mapper)
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetRemoteIP(this HttpContext context)
|
||||
{
|
||||
return context?.Request?.GetRemoteIP() ?? "Unknown";
|
||||
}
|
||||
|
||||
public static string GetRemoteIP(this HttpRequest request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
var remoteAddress = context.Request.UserHostAddress;
|
||||
IPAddress remoteIP;
|
||||
var remoteIP = request.HttpContext.Connection.RemoteIpAddress;
|
||||
var remoteAddress = remoteIP.ToString();
|
||||
|
||||
// Only check if forwarded by a local network reverse proxy
|
||||
if (IPAddress.TryParse(remoteAddress, out remoteIP) && remoteIP.IsLocalAddress())
|
||||
if (remoteIP.IsLocalAddress())
|
||||
{
|
||||
var realIPHeader = context.Request.Headers["X-Real-IP"];
|
||||
var realIPHeader = request.Headers["X-Real-IP"];
|
||||
if (realIPHeader.Any())
|
||||
{
|
||||
return realIPHeader.First().ToString();
|
||||
}
|
||||
|
||||
var forwardedForHeader = context.Request.Headers["X-Forwarded-For"];
|
||||
var forwardedForHeader = request.Headers["X-Forwarded-For"];
|
||||
if (forwardedForHeader.Any())
|
||||
{
|
||||
// Get the first address that was forwarded by a local IP to prevent remote clients faking another proxy
|
||||
|
@ -141,5 +190,18 @@ namespace Lidarr.Http.Extensions
|
|||
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
public static void DisableCache(this IHeaderDictionary headers)
|
||||
{
|
||||
headers["Cache-Control"] = "no-cache, no-store";
|
||||
headers["Expires"] = "-1";
|
||||
headers["Pragma"] = "no-cache";
|
||||
}
|
||||
|
||||
public static void EnableCache(this IHeaderDictionary headers)
|
||||
{
|
||||
headers["Cache-Control"] = "max-age=31536000, public";
|
||||
headers["Last-Modified"] = BuildInfo.BuildDateTime.ToString("r");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue