using System; using System.ComponentModel; using System.Net.Http.Headers; using Jellyfin.Api.TypeConverters; using Jellyfin.Server.Extensions; using Jellyfin.Server.HealthChecks; using Jellyfin.Server.Middleware; using Jellyfin.Server.Models; 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.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using Prometheus; namespace Jellyfin.Server { /// /// Startup configuration for the Kestrel webhost. /// public class Startup { private readonly IServerConfigurationManager _serverConfigurationManager; private readonly IServerApplicationHost _serverApplicationHost; /// /// Initializes a new instance of the class. /// /// The server configuration manager. /// The server application host. public Startup( IServerConfigurationManager serverConfigurationManager, IServerApplicationHost serverApplicationHost) { _serverConfigurationManager = serverConfigurationManager; _serverApplicationHost = serverApplicationHost; } /// /// Configures the service collection for the webhost. /// /// The service collection. public void ConfigureServices(IServiceCollection services) { services.AddResponseCompression(); services.AddHttpContextAccessor(); services.AddHttpsRedirection(options => { options.HttpsPort = _serverApplicationHost.HttpsPort; }); services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies()); services.AddJellyfinApiSwagger(); // configure custom legacy authentication services.AddCustomAuthentication(); services.AddJellyfinApiAuthorization(); 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()); services.AddHealthChecks() .AddCheck("JellyfinDb"); } /// /// Configures the app builder for the webhost. /// /// The application builder. /// The webhost environment. /// The server application host. /// The application config. public void Configure( IApplicationBuilder app, IWebHostEnvironment env, IServerApplicationHost serverApplicationHost, IConfiguration appConfig) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMiddleware(); app.UseMiddleware(); app.UseWebSockets(); app.UseResponseCompression(); app.UseCors(ServerCorsPolicy.DefaultPolicyName); if (_serverConfigurationManager.Configuration.RequireHttps && _serverApplicationHost.ListenWithHttps) { app.UseHttpsRedirection(); } app.UseStaticFiles(); app.UsePathBase(_serverConfigurationManager.Configuration.BaseUrl); if (appConfig.HostWebClient()) { app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath), RequestPath = "/web" }); } app.UseAuthentication(); app.UseJellyfinApiSwagger(_serverConfigurationManager); app.UseRouting(); app.UseAuthorization(); if (_serverConfigurationManager.Configuration.EnableMetrics) { // Must be registered after any middleware that could change HTTP response codes or the data will be bad app.UseHttpMetrics(); } app.UseLanFiltering(); app.UseIpBasedAccessValidation(); app.UseBaseUrlRedirection(); app.UseWebSocketHandler(); app.UseServerStartupMessage(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); if (_serverConfigurationManager.Configuration.EnableMetrics) { endpoints.MapMetrics(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/') + "/metrics"); } endpoints.MapHealthChecks(_serverConfigurationManager.Configuration.BaseUrl.TrimStart('/') + "/health"); }); // Add type descriptor for legacy datetime parsing. TypeDescriptor.AddAttributes(typeof(DateTime?), new TypeConverterAttribute(typeof(DateTimeTypeConverter))); } } }