Merge remote-tracking branch 'upstream/master' into api-doc-css

This commit is contained in:
crobibero
2020-09-03 08:06:40 -06:00
628 changed files with 10456 additions and 16078 deletions

View File

@@ -1,20 +1,20 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Emby.Drawing;
using Emby.Server.Implementations;
using Jellyfin.Drawing.Skia;
using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.Activity;
using Jellyfin.Server.Implementations.Events;
using Jellyfin.Server.Implementations.Users;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -33,30 +33,33 @@ namespace Jellyfin.Server
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
public CoreAppHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,
IFileSystem fileSystem,
INetworkManager networkManager)
INetworkManager networkManager,
IServiceCollection collection)
: base(
applicationPaths,
loggerFactory,
options,
fileSystem,
networkManager)
networkManager,
collection)
{
}
/// <inheritdoc/>
protected override void RegisterServices(IServiceCollection serviceCollection)
protected override void RegisterServices()
{
// Register an image encoder
bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable();
Type imageEncoderType = useSkiaEncoder
? typeof(SkiaEncoder)
: typeof(NullImageEncoder);
serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
ServiceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
// Log a warning if the Skia encoder could not be used
if (!useSkiaEncoder)
@@ -71,13 +74,15 @@ namespace Jellyfin.Server
// .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"),
// ServiceLifetime.Transient);
serviceCollection.AddSingleton<JellyfinDbProvider>();
ServiceCollection.AddEventServices();
ServiceCollection.AddSingleton<IEventManager, EventManager>();
ServiceCollection.AddSingleton<JellyfinDbProvider>();
serviceCollection.AddSingleton<IActivityManager, ActivityManager>();
serviceCollection.AddSingleton<IUserManager, UserManager>();
serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
ServiceCollection.AddSingleton<IActivityManager, ActivityManager>();
ServiceCollection.AddSingleton<IUserManager, UserManager>();
ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
base.RegisterServices(serviceCollection);
base.RegisterServices();
}
/// <inheritdoc />

View File

@@ -1,3 +1,4 @@
using Jellyfin.Server.Middleware;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Builder;
@@ -48,5 +49,55 @@ namespace Jellyfin.Server.Extensions
c.InjectStylesheet($"/{baseUrl}api-docs/redoc/custom.css");
});
}
/// <summary>
/// Adds IP based access validation to the application pipeline.
/// </summary>
/// <param name="appBuilder">The application builder.</param>
/// <returns>The updated application builder.</returns>
public static IApplicationBuilder UseIpBasedAccessValidation(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<IpBasedAccessValidationMiddleware>();
}
/// <summary>
/// Adds LAN based access filtering to the application pipeline.
/// </summary>
/// <param name="appBuilder">The application builder.</param>
/// <returns>The updated application builder.</returns>
public static IApplicationBuilder UseLanFiltering(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<LanFilteringMiddleware>();
}
/// <summary>
/// Adds base url redirection to the application pipeline.
/// </summary>
/// <param name="appBuilder">The application builder.</param>
/// <returns>The updated application builder.</returns>
public static IApplicationBuilder UseBaseUrlRedirection(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<BaseUrlRedirectionMiddleware>();
}
/// <summary>
/// Adds a custom message during server startup to the application pipeline.
/// </summary>
/// <param name="appBuilder">The application builder.</param>
/// <returns>The updated application builder.</returns>
public static IApplicationBuilder UseServerStartupMessage(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<ServerStartupMessageMiddleware>();
}
/// <summary>
/// Adds a WebSocket request handler to the application pipeline.
/// </summary>
/// <param name="appBuilder">The application builder.</param>
/// <returns>The updated application builder.</returns>
public static IApplicationBuilder UseWebSocketHandler(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<WebSocketHandlerMiddleware>();
}
}
}

View File

@@ -18,6 +18,7 @@ using Jellyfin.Api.Constants;
using Jellyfin.Api.Controllers;
using Jellyfin.Server.Formatters;
using Jellyfin.Server.Models;
using MediaBrowser.Common;
using MediaBrowser.Common.Json;
using MediaBrowser.Model.Entities;
using Microsoft.AspNetCore.Authentication;
@@ -135,10 +136,11 @@ namespace Jellyfin.Server.Extensions
/// </summary>
/// <param name="serviceCollection">The service collection.</param>
/// <param name="baseUrl">The base url for the API.</param>
/// <param name="pluginAssemblies">An IEnumberable containing all plugin assemblies with API controllers.</param>
/// <returns>The MVC builder.</returns>
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl)
public static IMvcBuilder AddJellyfinApi(this IServiceCollection serviceCollection, string baseUrl, IEnumerable<Assembly> pluginAssemblies)
{
return serviceCollection
IMvcBuilder mvcBuilder = serviceCollection
.AddCors(options =>
{
options.AddPolicy(ServerCorsPolicy.DefaultPolicyName, ServerCorsPolicy.DefaultPolicy);
@@ -168,6 +170,9 @@ namespace Jellyfin.Server.Extensions
// From JsonDefaults
options.JsonSerializerOptions.ReadCommentHandling = jsonOptions.ReadCommentHandling;
options.JsonSerializerOptions.WriteIndented = jsonOptions.WriteIndented;
options.JsonSerializerOptions.DefaultIgnoreCondition = jsonOptions.DefaultIgnoreCondition;
options.JsonSerializerOptions.NumberHandling = jsonOptions.NumberHandling;
options.JsonSerializerOptions.Converters.Clear();
foreach (var converter in jsonOptions.Converters)
{
@@ -176,8 +181,14 @@ namespace Jellyfin.Server.Extensions
// From JsonDefaults.PascalCase
options.JsonSerializerOptions.PropertyNamingPolicy = jsonOptions.PropertyNamingPolicy;
})
.AddControllersAsServices();
});
foreach (Assembly pluginAssembly in pluginAssemblies)
{
mvcBuilder.AddApplicationPart(pluginAssembly);
}
return mvcBuilder.AddControllersAsServices();
}
/// <summary>
@@ -194,7 +205,7 @@ namespace Jellyfin.Server.Extensions
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header,
Name = "X-Emby-Token",
Name = "X-Emby-Authorization",
Description = "API key header parameter"
});

View File

@@ -0,0 +1,62 @@
using System;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions;
namespace Jellyfin.Server.Middleware
{
/// <summary>
/// Redirect requests without baseurl prefix to the baseurl prefixed URL.
/// </summary>
public class BaseUrlRedirectionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<BaseUrlRedirectionMiddleware> _logger;
private readonly IConfiguration _configuration;
/// <summary>
/// Initializes a new instance of the <see cref="BaseUrlRedirectionMiddleware"/> class.
/// </summary>
/// <param name="next">The next delegate in the pipeline.</param>
/// <param name="logger">The logger.</param>
/// <param name="configuration">The application configuration.</param>
public BaseUrlRedirectionMiddleware(
RequestDelegate next,
ILogger<BaseUrlRedirectionMiddleware> logger,
IConfiguration configuration)
{
_next = next;
_logger = logger;
_configuration = configuration;
}
/// <summary>
/// Executes the middleware action.
/// </summary>
/// <param name="httpContext">The current HTTP context.</param>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
/// <returns>The async task.</returns>
public async Task Invoke(HttpContext httpContext, IServerConfigurationManager serverConfigurationManager)
{
var localPath = httpContext.Request.Path.ToString();
var baseUrlPrefix = serverConfigurationManager.Configuration.BaseUrl;
if (string.Equals(localPath, baseUrlPrefix + "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(localPath, baseUrlPrefix, StringComparison.OrdinalIgnoreCase)
|| string.Equals(localPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.IsNullOrEmpty(localPath)
|| !localPath.StartsWith(baseUrlPrefix, StringComparison.OrdinalIgnoreCase))
{
// Always redirect back to the default path if the base prefix is invalid or missing
_logger.LogDebug("Normalizing an URL at {LocalPath}", localPath);
httpContext.Response.Redirect(baseUrlPrefix + "/" + _configuration[ConfigurationExtensions.DefaultRedirectKey]);
return;
}
await _next(httpContext).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,76 @@
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Server.Middleware
{
/// <summary>
/// Validates the IP of requests coming from local networks wrt. remote access.
/// </summary>
public class IpBasedAccessValidationMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="IpBasedAccessValidationMiddleware"/> class.
/// </summary>
/// <param name="next">The next delegate in the pipeline.</param>
public IpBasedAccessValidationMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Executes the middleware action.
/// </summary>
/// <param name="httpContext">The current HTTP context.</param>
/// <param name="networkManager">The network manager.</param>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
/// <returns>The async task.</returns>
public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
{
if (httpContext.Request.IsLocal())
{
await _next(httpContext).ConfigureAwait(false);
return;
}
var remoteIp = httpContext.Request.RemoteIp();
if (serverConfigurationManager.Configuration.EnableRemoteAccess)
{
var addressFilter = serverConfigurationManager.Configuration.RemoteIPFilter.Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
if (addressFilter.Length > 0 && !networkManager.IsInLocalNetwork(remoteIp))
{
if (serverConfigurationManager.Configuration.IsRemoteIPFilterBlacklist)
{
if (networkManager.IsAddressInSubnets(remoteIp, addressFilter))
{
return;
}
}
else
{
if (!networkManager.IsAddressInSubnets(remoteIp, addressFilter))
{
return;
}
}
}
}
else
{
if (!networkManager.IsInLocalNetwork(remoteIp))
{
return;
}
}
await _next(httpContext).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Server.Middleware
{
/// <summary>
/// Validates the LAN host IP based on application configuration.
/// </summary>
public class LanFilteringMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="LanFilteringMiddleware"/> class.
/// </summary>
/// <param name="next">The next delegate in the pipeline.</param>
public LanFilteringMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Executes the middleware action.
/// </summary>
/// <param name="httpContext">The current HTTP context.</param>
/// <param name="networkManager">The network manager.</param>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
/// <returns>The async task.</returns>
public async Task Invoke(HttpContext httpContext, INetworkManager networkManager, IServerConfigurationManager serverConfigurationManager)
{
var currentHost = httpContext.Request.Host.ToString();
var hosts = serverConfigurationManager
.Configuration
.LocalNetworkAddresses
.Select(NormalizeConfiguredLocalAddress)
.ToList();
if (hosts.Count == 0)
{
await _next(httpContext).ConfigureAwait(false);
return;
}
currentHost ??= string.Empty;
if (networkManager.IsInPrivateAddressSpace(currentHost))
{
hosts.Add("localhost");
hosts.Add("127.0.0.1");
if (hosts.All(i => currentHost.IndexOf(i, StringComparison.OrdinalIgnoreCase) == -1))
{
return;
}
}
await _next(httpContext).ConfigureAwait(false);
}
private static string NormalizeConfiguredLocalAddress(string address)
{
var add = address.AsSpan().Trim('/');
int index = add.IndexOf('/');
if (index != -1)
{
add = add.Slice(index + 1);
}
return add.TrimStart('/').ToString();
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Net.Mime;
using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Model.Globalization;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Server.Middleware
{
/// <summary>
/// Shows a custom message during server startup.
/// </summary>
public class ServerStartupMessageMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="ServerStartupMessageMiddleware"/> class.
/// </summary>
/// <param name="next">The next delegate in the pipeline.</param>
public ServerStartupMessageMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Executes the middleware action.
/// </summary>
/// <param name="httpContext">The current HTTP context.</param>
/// <param name="serverApplicationHost">The server application host.</param>
/// <param name="localizationManager">The localization manager.</param>
/// <returns>The async task.</returns>
public async Task Invoke(
HttpContext httpContext,
IServerApplicationHost serverApplicationHost,
ILocalizationManager localizationManager)
{
if (serverApplicationHost.CoreStartupHasCompleted)
{
await _next(httpContext).ConfigureAwait(false);
return;
}
var message = localizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
httpContext.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
httpContext.Response.ContentType = MediaTypeNames.Text.Html;
await httpContext.Response.WriteAsync(message, httpContext.RequestAborted).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,40 @@
using System.Threading.Tasks;
using MediaBrowser.Controller.Net;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Server.Middleware
{
/// <summary>
/// Handles WebSocket requests.
/// </summary>
public class WebSocketHandlerMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketHandlerMiddleware"/> class.
/// </summary>
/// <param name="next">The next delegate in the pipeline.</param>
public WebSocketHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Executes the middleware action.
/// </summary>
/// <param name="httpContext">The current HTTP context.</param>
/// <param name="webSocketManager">The WebSocket connection manager.</param>
/// <returns>The async task.</returns>
public async Task Invoke(HttpContext httpContext, IWebSocketManager webSocketManager)
{
if (!httpContext.WebSockets.IsWebSocketRequest)
{
await _next(httpContext).ConfigureAwait(false);
return;
}
await webSocketManager.WebSocketRequestHandler(httpContext).ConfigureAwait(false);
}
}
}

View File

@@ -81,6 +81,11 @@ namespace Jellyfin.Server.Migrations.Routines
foreach (var result in results)
{
var dto = JsonSerializer.Deserialize<DisplayPreferencesDto>(result[3].ToString(), _jsonOptions);
if (dto == null)
{
continue;
}
var chromecastVersion = dto.CustomPrefs.TryGetValue("chromecastVersion", out var version)
? chromecastDict[version]
: ChromecastVersion.Stable;

View File

@@ -1,5 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Serialization;
using Jellyfin.Data.Entities;
@@ -74,7 +76,12 @@ namespace Jellyfin.Server.Migrations.Routines
foreach (var entry in queryResult)
{
UserMockup mockup = JsonSerializer.Deserialize<UserMockup>(entry[2].ToBlob(), JsonDefaults.GetOptions());
UserMockup? mockup = JsonSerializer.Deserialize<UserMockup>(entry[2].ToBlob(), JsonDefaults.GetOptions());
if (mockup == null)
{
continue;
}
var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
var config = File.Exists(Path.Combine(userDataDir, "config.xml"))
@@ -161,9 +168,9 @@ namespace Jellyfin.Server.Migrations.Routines
}
user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags);
user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels);
user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray());
user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices);
user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders);
user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders?.Select(i => i.ToString("N", CultureInfo.InvariantCulture)).ToArray());
user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders);
user.SetPreference(PreferenceKind.OrderedViews, config.OrderedViews);
user.SetPreference(PreferenceKind.GroupedFolders, config.GroupedFolders);

View File

@@ -11,7 +11,6 @@ using System.Threading;
using System.Threading.Tasks;
using CommandLine;
using Emby.Server.Implementations;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Networking;
using Jellyfin.Api.Controllers;
@@ -28,6 +27,7 @@ using Microsoft.Extensions.Logging.Abstractions;
using Serilog;
using Serilog.Extensions.Logging;
using SQLitePCL;
using ConfigurationExtensions = MediaBrowser.Controller.Extensions.ConfigurationExtensions;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Jellyfin.Server
@@ -154,13 +154,15 @@ namespace Jellyfin.Server
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
PerformStaticInitialization();
var serviceCollection = new ServiceCollection();
var appHost = new CoreAppHost(
appPaths,
_loggerFactory,
options,
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()));
new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()),
serviceCollection);
try
{
@@ -178,8 +180,7 @@ namespace Jellyfin.Server
}
}
ServiceCollection serviceCollection = new ServiceCollection();
appHost.Init(serviceCollection);
appHost.Init();
var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
@@ -593,7 +594,7 @@ namespace Jellyfin.Server
var inMemoryDefaultConfig = ConfigurationOptions.DefaultConfiguration;
if (startupConfig != null && !startupConfig.HostWebClient())
{
inMemoryDefaultConfig[HttpListenerHost.DefaultRedirectKey] = "api-docs/swagger";
inMemoryDefaultConfig[ConfigurationExtensions.DefaultRedirectKey] = "api-docs/swagger";
}
return config

View File

@@ -1,7 +1,12 @@
using System.Net.Http;
using System;
using System.ComponentModel;
using System.Net.Http.Headers;
using Jellyfin.Api.TypeConverters;
using Jellyfin.Server.Extensions;
using Jellyfin.Server.Middleware;
using Jellyfin.Server.Models;
using MediaBrowser.Common;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using Microsoft.AspNetCore.Builder;
@@ -18,14 +23,19 @@ namespace Jellyfin.Server
public class Startup
{
private readonly IServerConfigurationManager _serverConfigurationManager;
private readonly IServerApplicationHost _serverApplicationHost;
/// <summary>
/// Initializes a new instance of the <see cref="Startup" /> class.
/// </summary>
/// <param name="serverConfigurationManager">The server configuration manager.</param>
public Startup(IServerConfigurationManager serverConfigurationManager)
/// <param name="serverApplicationHost">The server application host.</param>
public Startup(
IServerConfigurationManager serverConfigurationManager,
IServerApplicationHost serverApplicationHost)
{
_serverConfigurationManager = serverConfigurationManager;
_serverApplicationHost = serverApplicationHost;
}
/// <summary>
@@ -36,7 +46,13 @@ namespace Jellyfin.Server
{
services.AddResponseCompression();
services.AddHttpContextAccessor();
services.AddJellyfinApi(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'));
services.AddHttpsRedirection(options =>
{
options.HttpsPort = _serverApplicationHost.HttpsPort;
});
services.AddJellyfinApi(
_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/'),
_serverApplicationHost.GetApiPluginAssemblies());
services.AddJellyfinApiSwagger();
@@ -44,7 +60,23 @@ namespace Jellyfin.Server
services.AddCustomAuthentication();
services.AddJellyfinApiAuthorization();
services.AddHttpClient();
var productHeader = new ProductInfoHeaderValue(
_serverApplicationHost.Name.Replace(' ', '-'),
_serverApplicationHost.ApplicationVersionString);
services
.AddHttpClient(NamedClient.Default, c =>
{
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
})
.ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler());
services.AddHttpClient(NamedClient.MusicBrainz, c =>
{
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})"));
})
.ConfigurePrimaryHttpMessageHandler(x => new DefaultHttpClientHandler());
}
/// <summary>
@@ -52,11 +84,9 @@ namespace Jellyfin.Server
/// </summary>
/// <param name="app">The application builder.</param>
/// <param name="env">The webhost environment.</param>
/// <param name="serverApplicationHost">The server application host.</param>
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env,
IServerApplicationHost serverApplicationHost)
IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
@@ -71,13 +101,18 @@ namespace Jellyfin.Server
app.UseResponseCompression();
// TODO app.UseMiddleware<WebSocketMiddleware>();
app.UseCors(ServerCorsPolicy.DefaultPolicyName);
if (_serverConfigurationManager.Configuration.RequireHttps
&& _serverApplicationHost.ListenWithHttps)
{
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseJellyfinApiSwagger(_serverConfigurationManager);
app.UseRouting();
app.UseCors(ServerCorsPolicy.DefaultPolicyName);
app.UseAuthorization();
if (_serverConfigurationManager.Configuration.EnableMetrics)
{
@@ -85,6 +120,12 @@ namespace Jellyfin.Server
app.UseHttpMetrics();
}
app.UseLanFiltering();
app.UseIpBasedAccessValidation();
app.UseBaseUrlRedirection();
app.UseWebSocketHandler();
app.UseServerStartupMessage();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
@@ -94,7 +135,8 @@ namespace Jellyfin.Server
}
});
app.Use(serverApplicationHost.ExecuteHttpHandlerAsync);
// Add type descriptor for legacy datetime parsing.
TypeDescriptor.AddAttributes(typeof(DateTime?), new TypeConverterAttribute(typeof(DateTimeTypeConverter)));
}
}
}