using System.Diagnostics; using System.Globalization; using System.Threading.Tasks; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Middleware; /// /// Response time middleware. /// public class ResponseTimeMiddleware { private const string ResponseHeaderResponseTime = "X-Response-Time-ms"; private readonly RequestDelegate _next; private readonly ILogger _logger; /// /// Initializes a new instance of the class. /// /// Next request delegate. /// Instance of the interface. public ResponseTimeMiddleware( RequestDelegate next, ILogger logger) { _next = next; _logger = logger; } /// /// Invoke request. /// /// Request context. /// Instance of the interface. /// Task. public async Task Invoke(HttpContext context, IServerConfigurationManager serverConfigurationManager) { var startTimestamp = Stopwatch.GetTimestamp(); var enableWarning = serverConfigurationManager.Configuration.EnableSlowResponseWarning; var warningThreshold = serverConfigurationManager.Configuration.SlowResponseThresholdMs; context.Response.OnStarting(() => { var responseTime = Stopwatch.GetElapsedTime(startTimestamp); var responseTimeMs = responseTime.TotalMilliseconds; if (enableWarning && responseTimeMs > warningThreshold && _logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug( "Slow HTTP Response from {Url} to {RemoteIP} in {Elapsed:g} with Status Code {StatusCode}", context.Request.GetDisplayUrl(), context.GetNormalizedRemoteIP(), responseTime, context.Response.StatusCode); } context.Response.Headers[ResponseHeaderResponseTime] = responseTimeMs.ToString(CultureInfo.InvariantCulture); return Task.CompletedTask; }); // Call the next delegate/middleware in the pipeline await this._next(context).ConfigureAwait(false); } }