< Summary - Jellyfin

Information
Class: Jellyfin.Server.Startup
Assembly: jellyfin
File(s): /srv/git/jellyfin/Jellyfin.Server/Startup.cs
Line coverage
99%
Covered lines: 166
Uncovered lines: 1
Coverable lines: 167
Total lines: 261
Line coverage: 99.4%
Branch coverage
50%
Covered branches: 1
Total branches: 2
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 5/16/2026 - 12:15:55 AM Line coverage: 99.3% (165/166) Branch coverage: 50% (1/2) Total lines: 25910/29/2026 - 12:17:11 AM Line coverage: 99.4% (166/167) Branch coverage: 50% (1/2) Total lines: 261 5/16/2026 - 12:15:55 AM Line coverage: 99.3% (165/166) Branch coverage: 50% (1/2) Total lines: 25910/29/2026 - 12:17:11 AM Line coverage: 99.4% (166/167) Branch coverage: 50% (1/2) Total lines: 261

Coverage delta

Coverage delta 1 -1

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ConfigureServices(...)50%2298.71%
Configure(...)100%11100%

File(s)

/srv/git/jellyfin/Jellyfin.Server/Startup.cs

#LineLine coverage
 1using System;
 2using System.Globalization;
 3using System.IO;
 4using System.Net;
 5using System.Net.Http;
 6using System.Net.Http.Headers;
 7using System.Net.Mime;
 8using System.Text;
 9using Emby.Server.Implementations.EntryPoints;
 10using Emby.Server.Implementations.Localization;
 11using Jellyfin.Api.Middleware;
 12using Jellyfin.Database.Implementations;
 13using Jellyfin.LiveTv.Extensions;
 14using Jellyfin.LiveTv.Recordings;
 15using Jellyfin.MediaEncoding.Hls.Extensions;
 16using Jellyfin.Networking;
 17using Jellyfin.Networking.HappyEyeballs;
 18using Jellyfin.Server.Extensions;
 19using Jellyfin.Server.HealthChecks;
 20using Jellyfin.Server.Implementations.Extensions;
 21using Jellyfin.Server.Implementations.Users;
 22using MediaBrowser.Common.Net;
 23using MediaBrowser.Controller.Configuration;
 24using MediaBrowser.Controller.Extensions;
 25using MediaBrowser.XbmcMetadata;
 26using Microsoft.AspNetCore.Builder;
 27using Microsoft.AspNetCore.Hosting;
 28using Microsoft.AspNetCore.Localization;
 29using Microsoft.AspNetCore.StaticFiles;
 30using Microsoft.Extensions.Configuration;
 31using Microsoft.Extensions.DependencyInjection;
 32using Microsoft.Extensions.FileProviders;
 33using Microsoft.Extensions.Hosting;
 34using Microsoft.Extensions.Primitives;
 35using Prometheus;
 36
 37namespace Jellyfin.Server
 38{
 39    /// <summary>
 40    /// Startup configuration for the Kestrel webhost.
 41    /// </summary>
 42    public class Startup
 43    {
 44        private readonly CoreAppHost _serverApplicationHost;
 45        private readonly IConfiguration _configuration;
 46        private readonly IServerConfigurationManager _serverConfigurationManager;
 47
 48        /// <summary>
 49        /// Initializes a new instance of the <see cref="Startup" /> class.
 50        /// </summary>
 51        /// <param name="appHost">The server application host.</param>
 52        /// <param name="configuration">The used Configuration.</param>
 53        public Startup(CoreAppHost appHost, IConfiguration configuration)
 54        {
 2855            _serverApplicationHost = appHost;
 2856            _configuration = configuration;
 2857            _serverConfigurationManager = appHost.ConfigurationManager;
 2858        }
 59
 60        /// <summary>
 61        /// Configures the service collection for the webhost.
 62        /// </summary>
 63        /// <param name="services">The service collection.</param>
 64        public void ConfigureServices(IServiceCollection services)
 65        {
 2866            services.AddResponseCompression();
 2867            services.AddHttpContextAccessor();
 2868            services.AddHttpsRedirection(options =>
 2869            {
 2870                options.HttpsPort = _serverApplicationHost.HttpsPort;
 2871            });
 72
 2873            services.AddJellyfinApi(_serverApplicationHost.GetApiPluginAssemblies(), _serverConfigurationManager.GetNetw
 2874            services.AddJellyfinDbContext(_serverApplicationHost.ConfigurationManager, _configuration);
 2875            services.AddJellyfinApiSwagger();
 76
 77            // configure custom legacy authentication
 2878            services.AddCustomAuthentication();
 79
 2880            services.AddJellyfinApiAuthorization();
 81
 2882            var productHeader = new ProductInfoHeaderValue(
 2883                _serverApplicationHost.Name.Replace(' ', '-'),
 2884                _serverApplicationHost.ApplicationVersionString);
 2885            var acceptJsonHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json, 1.0);
 2886            var acceptXmlHeader = new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Xml, 0.9);
 2887            var acceptAnyHeader = new MediaTypeWithQualityHeaderValue("*/*", 0.8);
 2888            Func<IServiceProvider, HttpMessageHandler> eyeballsHttpClientHandlerDelegate = (_) => new SocketsHttpHandler
 2889            {
 2890                AutomaticDecompression = DecompressionMethods.All,
 2891                RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8,
 2892                ConnectCallback = HttpClientExtension.OnConnect
 2893            };
 94
 2895            Func<IServiceProvider, HttpMessageHandler> defaultHttpClientHandlerDelegate = (_) => new SocketsHttpHandler(
 2896            {
 2897                AutomaticDecompression = DecompressionMethods.All,
 2898                RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8
 2899            };
 100
 28101            services.AddHttpClient(NamedClient.Default, c =>
 28102                {
 28103                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 28104                    c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
 28105                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 28106                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 28107                })
 28108                .ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
 109
 28110            services.AddHttpClient(NamedClient.MusicBrainz, c =>
 28111                {
 28112                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 28113                    c.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue($"({_serverApplicationHost.Applicat
 28114                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 28115                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 28116                })
 28117                .ConfigurePrimaryHttpMessageHandler(eyeballsHttpClientHandlerDelegate);
 118
 28119            services.AddHttpClient(NamedClient.DirectIp, c =>
 28120                {
 28121                    c.DefaultRequestHeaders.UserAgent.Add(productHeader);
 28122                    c.DefaultRequestHeaders.Accept.Add(acceptJsonHeader);
 28123                    c.DefaultRequestHeaders.Accept.Add(acceptXmlHeader);
 28124                    c.DefaultRequestHeaders.Accept.Add(acceptAnyHeader);
 28125                })
 28126                .ConfigurePrimaryHttpMessageHandler(defaultHttpClientHandlerDelegate);
 127
 28128            services.AddHealthChecks()
 28129                .AddCheck<DbContextFactoryHealthCheck<JellyfinDbContext>>(nameof(JellyfinDbContext));
 130
 28131            services.AddHlsPlaylistGenerator();
 28132            services.AddLiveTvServices();
 133
 28134            var serverUICulture = _serverConfigurationManager.Configuration.UICulture;
 28135            if (string.IsNullOrEmpty(serverUICulture))
 136            {
 0137                serverUICulture = "en-US";
 138            }
 139
 28140            CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(serverUICulture);
 141
 28142            services.Configure<RequestLocalizationOptions>(options =>
 28143            {
 28144                var supportedUICultures = LocalizationManager.GetSupportedUICultures();
 28145                options.SupportedCultures = supportedUICultures;
 28146                options.SupportedUICultures = supportedUICultures;
 28147                options.DefaultRequestCulture = new RequestCulture(serverUICulture);
 28148                options.ApplyCurrentCultureToResponseHeaders = true;
 28149                options.FallBackToParentCultures = true;
 28150                options.FallBackToParentUICultures = true;
 28151            });
 152
 28153            services.AddHostedService<RecordingsHost>();
 28154            services.AddHostedService<AutoDiscoveryHost>();
 28155            services.AddHostedService<NfoUserDataSaver>();
 28156            services.AddHostedService<LibraryChangedNotifier>();
 28157            services.AddHostedService<UserDataChangeNotifier>();
 28158            services.AddHostedService<RecordingNotifier>();
 28159            services.AddHostedService<DeviceAccessHost>();
 28160        }
 161
 162        /// <summary>
 163        /// Configures the app builder for the webhost.
 164        /// </summary>
 165        /// <param name="app">The application builder.</param>
 166        /// <param name="env">The webhost environment.</param>
 167        /// <param name="appConfig">The application config.</param>
 168        public void Configure(
 169            IApplicationBuilder app,
 170            IWebHostEnvironment env,
 171            IConfiguration appConfig)
 172        {
 27173            app.UseBaseUrlRedirection();
 174
 175            // Wrap rest of configuration so everything only listens on BaseUrl.
 27176            var config = _serverConfigurationManager.GetNetworkConfiguration();
 27177            app.Map(config.BaseUrl, mainApp =>
 27178            {
 27179                if (env.IsDevelopment())
 27180                {
 27181                    mainApp.UseDeveloperExceptionPage();
 27182                }
 27183
 27184                mainApp.UseForwardedHeaders();
 27185                mainApp.UseMiddleware<ExceptionMiddleware>();
 27186
 27187                mainApp.UseMiddleware<ResponseTimeMiddleware>();
 27188
 27189                mainApp.UseWebSockets();
 27190
 27191                mainApp.UseResponseCompression();
 27192
 27193                mainApp.UseCors();
 27194
 27195                mainApp.UseRequestLocalization();
 27196
 27197                if (config.RequireHttps && _serverApplicationHost.ListenWithHttps)
 27198                {
 27199                    mainApp.UseHttpsRedirection();
 27200                }
 27201
 27202                if (appConfig.HostWebClient())
 27203                {
 27204                    var extensionProvider = new FileExtensionContentTypeProvider();
 27205
 27206                    // subtitles octopus requires .data, .mem files.
 27207                    extensionProvider.Mappings.Add(".data", MediaTypeNames.Application.Octet);
 27208                    extensionProvider.Mappings.Add(".mem", MediaTypeNames.Application.Octet);
 27209                    mainApp.UseDefaultFiles(new DefaultFilesOptions
 27210                    {
 27211                        FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
 27212                        RequestPath = "/web"
 27213                    });
 27214                    mainApp.UseStaticFiles(new StaticFileOptions
 27215                    {
 27216                        FileProvider = new PhysicalFileProvider(_serverConfigurationManager.ApplicationPaths.WebPath),
 27217                        RequestPath = "/web",
 27218                        ContentTypeProvider = extensionProvider,
 27219                        OnPrepareResponse = (context) =>
 27220                        {
 27221                            if (Path.GetFileName(context.File.Name).Equals("index.html", StringComparison.Ordinal))
 27222                            {
 27223                                context.Context.Response.Headers.CacheControl = new StringValues("no-cache");
 27224                            }
 27225                        }
 27226                    });
 27227
 27228                    mainApp.UseRobotsRedirection();
 27229                }
 27230
 27231                mainApp.UseStaticFiles();
 27232                mainApp.UseAuthentication();
 27233                mainApp.UseJellyfinApiSwagger(_serverConfigurationManager);
 27234                mainApp.UseQueryStringDecoding();
 27235                mainApp.UseRouting();
 27236                mainApp.UseAuthorization();
 27237
 27238                mainApp.UseIPBasedAccessValidation();
 27239                mainApp.UseWebSocketHandler();
 27240                mainApp.UseServerStartupMessage();
 27241
 27242                if (_serverConfigurationManager.Configuration.EnableMetrics)
 27243                {
 27244                    // Must be registered after any middleware that could change HTTP response codes or the data will be
 27245                    mainApp.UseHttpMetrics();
 27246                }
 27247
 27248                mainApp.UseEndpoints(endpoints =>
 27249                {
 27250                    endpoints.MapControllers();
 27251                    if (_serverConfigurationManager.Configuration.EnableMetrics)
 27252                    {
 27253                        endpoints.MapMetrics();
 27254                    }
 27255
 27256                    endpoints.MapHealthChecks("/health");
 27257                });
 27258            });
 27259        }
 260    }
 261}