2021-04-19 22:37:24 +02:00
|
|
|
using System;
|
|
|
|
using System.Net;
|
|
|
|
using System.Net.Http;
|
2020-08-31 16:47:38 +02:00
|
|
|
using System.Net.Http.Headers;
|
2020-10-02 21:30:31 +02:00
|
|
|
using System.Net.Mime;
|
2021-04-19 22:37:24 +02:00
|
|
|
using System.Text;
|
2023-10-11 16:33:00 +02:00
|
|
|
using Emby.Dlna.Extensions;
|
2023-01-14 03:37:37 +01:00
|
|
|
using Jellyfin.Api.Middleware;
|
2021-09-23 15:29:12 +02:00
|
|
|
using Jellyfin.MediaEncoding.Hls.Extensions;
|
2022-10-20 22:17:56 +02:00
|
|
|
using Jellyfin.Networking.HappyEyeballs;
|
2019-11-24 15:27:58 +01:00
|
|
|
using Jellyfin.Server.Extensions;
|
2022-12-30 03:40:39 +01:00
|
|
|
using Jellyfin.Server.HealthChecks;
|
2020-09-03 21:44:49 +02:00
|
|
|
using Jellyfin.Server.Implementations;
|
2022-10-21 11:55:32 +02:00
|
|
|
using Jellyfin.Server.Implementations.Extensions;
|
2021-09-11 12:31:29 +02:00
|
|
|
using Jellyfin.Server.Infrastructure;
|
2020-08-19 14:31:45 +02:00
|
|
|
using MediaBrowser.Common.Net;
|
2019-11-24 15:27:58 +01:00
|
|
|
using MediaBrowser.Controller;
|
|
|
|
using MediaBrowser.Controller.Configuration;
|
2020-09-02 16:03:15 +02:00
|
|
|
using MediaBrowser.Controller.Extensions;
|
2019-11-24 15:27:58 +01:00
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
using Microsoft.AspNetCore.Hosting;
|
2021-09-11 12:31:29 +02:00
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
2020-10-02 21:30:31 +02:00
|
|
|
using Microsoft.AspNetCore.StaticFiles;
|
2020-09-02 16:03:15 +02:00
|
|
|
using Microsoft.Extensions.Configuration;
|
2019-11-24 15:27:58 +01:00
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2020-09-02 16:03:15 +02:00
|
|
|
using Microsoft.Extensions.FileProviders;
|
2019-11-24 15:27:58 +01:00
|
|
|
using Microsoft.Extensions.Hosting;
|
2020-04-26 03:35:51 +02:00
|
|
|
using Prometheus;
|
2019-11-24 15:27:58 +01:00
|
|
|
|
|
|
|
namespace Jellyfin.Server
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Startup configuration for the Kestrel webhost.
|
|
|
|
/// </summary>
|
|
|
|
public class Startup
|
|
|
|
{
|
2023-11-14 20:21:34 +01:00
|
|
|
private readonly CoreAppHost _serverApplicationHost;
|
2023-01-12 04:07:41 +01:00
|
|
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
2019-11-24 15:27:58 +01:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="Startup" /> class.
|
|
|
|
/// </summary>
|
2023-01-12 04:07:41 +01:00
|
|
|
/// <param name="appHost">The server application host.</param>
|
|
|
|
public Startup(CoreAppHost appHost)
|
2019-11-24 15:27:58 +01:00
|
|
|
{
|
2023-01-12 04:07:41 +01:00
|
|
|
_serverApplicationHost = appHost;
|
|
|
|
_serverConfigurationManager = appHost.ConfigurationManager;
|
2019-11-24 15:27:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Configures the service collection for the webhost.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="services">The service collection.</param>
|
|
|
|
public void ConfigureServices(IServiceCollection services)
|
|
|
|
{
|
|
|
|
services.AddResponseCompression();
|
|
|
|
services.AddHttpContextAccessor();
|
2020-09-03 00:38:52 +02:00
|
|
|
services.AddHttpsRedirection(options =>
|
|
|
|
{
|
|
|
|
options.HttpsPort = _serverApplicationHost.HttpsPort;
|
|
|
|
});
|
2021-09-11 12:31:29 +02:00
|
|
|
|
|
|
|
// TODO remove once this is fixed upstream https://github.com/dotnet/aspnetcore/issues/34371
|
|
|
|
services.AddSingleton<IActionResultExecutor<PhysicalFileResult>, SymlinkFollowingPhysicalFileResultExecutor>();
|
2021-01-19 11:36:37 +01:00
|
|
|
services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.GetNetworkConfiguration());
|
2022-10-21 11:55:32 +02:00
|
|
|
services.AddJellyfinDbContext();
|
2019-11-24 15:27:58 +01:00
|
|
|
services.AddJellyfinApiSwagger();
|
|
|
|
|
|
|
|
// configure custom legacy authentication
|
|
|
|
services.AddCustomAuthentication();
|
|
|
|
|
|
|
|
services.AddJellyfinApiAuthorization();
|
2020-08-19 14:31:45 +02:00
|
|
|
|
2020-09-03 00:31:42 +02:00
|
|
|
var productHeader = new ProductInfoHeaderValue(
|
|
|
|
_serverApplicationHost.Name.Replace(' ', '-'),
|
|
|
|
_serverApplicationHost.ApplicationVersionString);
|
2020-11-19 15:35:34 +01:00
|
|
|
var acceptJsonHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json, 1.0);
|
|
|
|
var acceptXmlHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Xml, 0.9);
|
|
|
|
var acceptAnyHeader = new MediaTypeWithQualityHeaderValue("*/*", 0.8);
|
2022-10-20 22:17:56 +02:00
|
|
|
Func<IServiceProvider, HttpMessageHandler> eyeballsHttpClientHandlerDelegate = (_) => new SocketsHttpHandler()
|
|
|
|
{
|
|
|
|
AutomaticDecompression = DecompressionMethods.All,
|
|
|
|
RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8,
|
|
|
|
ConnectCallback = HttpClientExtension.OnConnect
|
|
|
|
};
|
|
|
|
|
2021-04-19 22:37:24 +02:00
|
|
|
Func<IServiceProvider, HttpMessageHandler> defaultHttpClientHandlerDelegate = (_) => new SocketsHttpHandler()
|
|
|
|
{
|
|
|
|
AutomaticDecompression = DecompressionMethods.All,
|
|
|
|
RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8
|
|
|
|
};
|
|
|
|
|
2023-01-12 04:07:41 +01:00
|
|
|
services.AddHttpClient(NamedClient.Default, c =>
|
2020-08-31 16:47:38 +02:00
|
|
|
{
|
2020-08-31 17:15:20 +02:00
|
|
|
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
|
2020-11-19 02:20:31 +01:00
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
|
2020-11-19 15:35:34 +01:00
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
|
2020-11-19 02:20:31 +01:00
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
|
2020-08-31 16:47:38 +02:00
|
|
|
})
|
2022-10-20 22:17:56 +02:00
|
|
|
.ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
|
2020-08-31 16:47:38 +02:00
|
|
|
|
|
|
|
services.AddHttpClient(NamedClient.MusicBrainz, c =>
|
|
|
|
{
|
2020-08-31 17:15:20 +02:00
|
|
|
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
|
2020-09-03 00:31:42 +02:00
|
|
|
c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})"));
|
2020-12-01 17:57:13 +01:00
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
|
2020-11-19 02:20:31 +01:00
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
|
2020-08-31 16:47:38 +02:00
|
|
|
})
|
2022-10-20 22:17:56 +02:00
|
|
|
.ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
|
|
|
|
|
|
|
|
services.AddHttpClient(NamedClient.DirectIp, c =>
|
|
|
|
{
|
|
|
|
c.DefaultRequestHeaders.UserAgent.Add(productHeader);
|
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
|
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
|
|
|
|
c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
|
|
|
|
})
|
2021-04-19 22:37:24 +02:00
|
|
|
.ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
|
2020-09-03 17:26:22 +02:00
|
|
|
|
|
|
|
services.AddHealthChecks()
|
2023-01-16 18:14:44 +01:00
|
|
|
.AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
|
2021-09-23 15:29:12 +02:00
|
|
|
|
|
|
|
services.AddHlsPlaylistGenerator();
|
2023-10-11 16:33:00 +02:00
|
|
|
services.AddDlnaServices(_serverApplicationHost);
|
2019-11-24 15:27:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Configures the app builder for the webhost.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="app">The application builder.</param>
|
|
|
|
/// <param name="env">The webhost environment.</param>
|
2020-09-02 16:03:15 +02:00
|
|
|
/// <param name="appConfig">The application config.</param>
|
2019-11-24 15:27:58 +01:00
|
|
|
public void Configure(
|
|
|
|
IApplicationBuilder app,
|
|
|
|
IWebHostEnvironment env,
|
2020-09-02 16:03:15 +02:00
|
|
|
IConfiguration appConfig)
|
2019-11-24 15:27:58 +01:00
|
|
|
{
|
2020-09-08 03:10:14 +02:00
|
|
|
app.UseBaseUrlRedirection();
|
2019-11-24 15:27:58 +01:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
// Wrap rest of configuration so everything only listens on BaseUrl.
|
2020-12-01 22:16:36 +01:00
|
|
|
var config = _serverConfigurationManager.GetNetworkConfiguration();
|
|
|
|
app.Map(config.BaseUrl, mainApp =>
|
2020-09-04 01:11:12 +02:00
|
|
|
{
|
|
|
|
if (env.IsDevelopment())
|
|
|
|
{
|
|
|
|
mainApp.UseDeveloperExceptionPage();
|
|
|
|
}
|
2020-04-21 15:36:22 +02:00
|
|
|
|
2020-09-10 11:05:46 +02:00
|
|
|
mainApp.UseForwardedHeaders();
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseMiddleware<ExceptionMiddleware>();
|
2020-07-14 13:26:47 +02:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseMiddleware<ResponseTimeMiddleware>();
|
2019-11-24 15:27:58 +01:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseWebSockets();
|
2019-11-24 15:27:58 +01:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseResponseCompression();
|
2020-09-03 14:05:16 +02:00
|
|
|
|
2020-09-05 17:10:05 +02:00
|
|
|
mainApp.UseCors();
|
2019-11-24 15:27:58 +01:00
|
|
|
|
2020-12-01 22:16:36 +01:00
|
|
|
if (config.RequireHttps && _serverApplicationHost.ListenWithHttps)
|
2020-09-02 16:03:15 +02:00
|
|
|
{
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseHttpsRedirection();
|
|
|
|
}
|
2020-04-26 17:28:17 +02:00
|
|
|
|
2020-12-10 16:17:02 +01:00
|
|
|
// This must be injected before any path related middleware.
|
|
|
|
mainApp.UsePathTrim();
|
2023-05-15 21:28:33 +02:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
if (appConfig.HostWebClient())
|
|
|
|
{
|
2020-10-02 21:30:31 +02:00
|
|
|
var extensionProvider = new FileExtensionContentTypeProvider();
|
|
|
|
|
2020-12-04 22:12:59 +01:00
|
|
|
// subtitles octopus requires .data, .mem files.
|
2020-10-02 21:30:31 +02:00
|
|
|
extensionProvider.Mappings.Add(".data", MediaTypeNames.Application.Octet);
|
2020-12-04 22:12:59 +01:00
|
|
|
extensionProvider.Mappings.Add(".mem", MediaTypeNames.Application.Octet);
|
2023-05-15 21:28:33 +02:00
|
|
|
mainApp.UseDefaultFiles(new DefaultFilesOptions
|
|
|
|
{
|
|
|
|
FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
|
|
|
|
RequestPath = "/web"
|
|
|
|
});
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseStaticFiles(new StaticFileOptions
|
|
|
|
{
|
|
|
|
FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
|
2020-10-02 21:30:31 +02:00
|
|
|
RequestPath = "/web",
|
|
|
|
ContentTypeProvider = extensionProvider
|
2020-09-04 01:11:12 +02:00
|
|
|
});
|
2020-12-07 03:40:43 +01:00
|
|
|
|
|
|
|
mainApp.UseRobotsRedirection();
|
2020-09-04 01:11:12 +02:00
|
|
|
}
|
2020-09-03 00:31:42 +02:00
|
|
|
|
2023-05-15 21:28:33 +02:00
|
|
|
mainApp.UseStaticFiles();
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseAuthentication();
|
|
|
|
mainApp.UseJellyfinApiSwagger(_serverConfigurationManager);
|
2021-05-05 23:52:39 +02:00
|
|
|
mainApp.UseQueryStringDecoding();
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseRouting();
|
|
|
|
mainApp.UseAuthorization();
|
2019-11-24 15:27:58 +01:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseLanFiltering();
|
2023-02-17 19:27:36 +01:00
|
|
|
mainApp.UseIPBasedAccessValidation();
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseWebSocketHandler();
|
|
|
|
mainApp.UseServerStartupMessage();
|
2020-09-03 00:31:42 +02:00
|
|
|
|
2020-04-26 17:28:17 +02:00
|
|
|
if (_serverConfigurationManager.Configuration.EnableMetrics)
|
|
|
|
{
|
2020-09-04 01:14:50 +02:00
|
|
|
// Must be registered after any middleware that could change HTTP response codes or the data will be bad
|
|
|
|
mainApp.UseHttpMetrics();
|
2020-04-26 17:28:17 +02:00
|
|
|
}
|
2020-09-04 01:14:50 +02:00
|
|
|
|
2020-09-04 01:11:12 +02:00
|
|
|
mainApp.UseEndpoints(endpoints =>
|
|
|
|
{
|
|
|
|
endpoints.MapControllers();
|
|
|
|
if (_serverConfigurationManager.Configuration.EnableMetrics)
|
|
|
|
{
|
2023-01-12 04:09:14 +01:00
|
|
|
endpoints.MapMetrics();
|
2020-09-04 01:11:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
endpoints.MapHealthChecks("/health");
|
|
|
|
});
|
2019-11-24 15:27:58 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|