diff options
Diffstat (limited to 'Jellyfin.Server/Startup.cs')
| -rw-r--r-- | Jellyfin.Server/Startup.cs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs new file mode 100644 index 000000000..8085c2630 --- /dev/null +++ b/Jellyfin.Server/Startup.cs @@ -0,0 +1,197 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Mime; +using System.Text; +using Jellyfin.Networking.Configuration; +using Jellyfin.Server.Extensions; +using Jellyfin.Server.Implementations; +using Jellyfin.Server.Infrastructure; +using Jellyfin.Server.Middleware; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Extensions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Prometheus; + +namespace Jellyfin.Server +{ + /// <summary> + /// Startup configuration for the Kestrel webhost. + /// </summary> + 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> + /// <param name="serverApplicationHost">The server application host.</param> + public Startup( + IServerConfigurationManager serverConfigurationManager, + IServerApplicationHost serverApplicationHost) + { + _serverConfigurationManager = serverConfigurationManager; + _serverApplicationHost = serverApplicationHost; + } + + /// <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(); + services.AddHttpsRedirection(options => + { + options.HttpsPort = _serverApplicationHost.HttpsPort; + }); + + // TODO remove once this is fixed upstream https://github.com/dotnet/aspnetcore/issues/34371 + services.AddSingleton<IActionResultExecutor<PhysicalFileResult>, SymlinkFollowingPhysicalFileResultExecutor>(); + services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.GetNetworkConfiguration()); + + services.AddJellyfinApiSwagger(); + + // configure custom legacy authentication + services.AddCustomAuthentication(); + + services.AddJellyfinApiAuthorization(); + + var productHeader = new ProductInfoHeaderValue( + _serverApplicationHost.Name.Replace(' ', '-'), + _serverApplicationHost.ApplicationVersionString); + var acceptJsonHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json, 1.0); + var acceptXmlHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Xml, 0.9); + var acceptAnyHeader = new MediaTypeWithQualityHeaderValue("*/*", 0.8); + Func<IServiceProvider, HttpMessageHandler> defaultHttpClientHandlerDelegate = (_) => new SocketsHttpHandler() + { + AutomaticDecompression = DecompressionMethods.All, + RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8 + }; + + services + .AddHttpClient(NamedClient.Default, c => + { + c.DefaultRequestHeaders.UserAgent.Add(productHeader); + c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader); + c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader); + c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader); + }) + .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); + + services.AddHttpClient(NamedClient.MusicBrainz, c => + { + c.DefaultRequestHeaders.UserAgent.Add(productHeader); + c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.ApplicationUserAgentAddress})")); + c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader); + c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader); + }) + .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate); + + services.AddHealthChecks() + .AddDbContextCheck<JellyfinDb>(); + } + + /// <summary> + /// Configures the app builder for the webhost. + /// </summary> + /// <param name="app">The application builder.</param> + /// <param name="env">The webhost environment.</param> + /// <param name="appConfig">The application config.</param> + public void Configure( + IApplicationBuilder app, + IWebHostEnvironment env, + IConfiguration appConfig) + { + app.UseBaseUrlRedirection(); + + // Wrap rest of configuration so everything only listens on BaseUrl. + var config = _serverConfigurationManager.GetNetworkConfiguration(); + app.Map(config.BaseUrl, mainApp => + { + if (env.IsDevelopment()) + { + mainApp.UseDeveloperExceptionPage(); + } + + mainApp.UseForwardedHeaders(); + mainApp.UseMiddleware<ExceptionMiddleware>(); + + mainApp.UseMiddleware<ResponseTimeMiddleware>(); + + mainApp.UseWebSockets(); + + mainApp.UseResponseCompression(); + + mainApp.UseCors(); + + if (config.RequireHttps && _serverApplicationHost.ListenWithHttps) + { + mainApp.UseHttpsRedirection(); + } + + // This must be injected before any path related middleware. + mainApp.UsePathTrim(); + mainApp.UseStaticFiles(); + if (appConfig.HostWebClient()) + { + var extensionProvider = new FileExtensionContentTypeProvider(); + + // subtitles octopus requires .data, .mem files. + extensionProvider.Mappings.Add(".data", MediaTypeNames.Application.Octet); + extensionProvider.Mappings.Add(".mem", MediaTypeNames.Application.Octet); + mainApp.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath), + RequestPath = "/web", + ContentTypeProvider = extensionProvider + }); + + mainApp.UseRobotsRedirection(); + } + + mainApp.UseAuthentication(); + mainApp.UseJellyfinApiSwagger(_serverConfigurationManager); + mainApp.UseQueryStringDecoding(); + mainApp.UseRouting(); + mainApp.UseAuthorization(); + + mainApp.UseLanFiltering(); + mainApp.UseIpBasedAccessValidation(); + mainApp.UseWebSocketHandler(); + mainApp.UseServerStartupMessage(); + + if (_serverConfigurationManager.Configuration.EnableMetrics) + { + // Must be registered after any middleware that could change HTTP response codes or the data will be bad + mainApp.UseHttpMetrics(); + } + + mainApp.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + if (_serverConfigurationManager.Configuration.EnableMetrics) + { + endpoints.MapMetrics("/metrics"); + } + + endpoints.MapHealthChecks("/health"); + }); + }); + } + } +} |
