diff options
| author | Cody Robibero <cody@robibe.ro> | 2020-04-29 07:38:18 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-29 07:38:18 -0600 |
| commit | d491b1b45fc813cb3bd1fe87918f693897621555 (patch) | |
| tree | 4bb52a35e9cd7cd0326c6c89d80b5349b3dfee0a /Jellyfin.Server/Middleware/ExceptionMiddleware.cs | |
| parent | 068368df6352cfad4e69df599c364b3f05b367ba (diff) | |
| parent | 2cb0f6f1263cabee288ab30109b55c57e24c7ed0 (diff) | |
Merge branch 'api-migration' into redoc
Diffstat (limited to 'Jellyfin.Server/Middleware/ExceptionMiddleware.cs')
| -rw-r--r-- | Jellyfin.Server/Middleware/ExceptionMiddleware.cs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/Jellyfin.Server/Middleware/ExceptionMiddleware.cs b/Jellyfin.Server/Middleware/ExceptionMiddleware.cs new file mode 100644 index 000000000..0d79bbfaf --- /dev/null +++ b/Jellyfin.Server/Middleware/ExceptionMiddleware.cs @@ -0,0 +1,145 @@ +using System; +using System.IO; +using System.Net.Mime; +using System.Net.Sockets; +using System.Threading.Tasks; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Authentication; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Middleware +{ + /// <summary> + /// Exception Middleware. + /// </summary> + public class ExceptionMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger<ExceptionMiddleware> _logger; + private readonly IServerConfigurationManager _configuration; + + /// <summary> + /// Initializes a new instance of the <see cref="ExceptionMiddleware"/> class. + /// </summary> + /// <param name="next">Next request delegate.</param> + /// <param name="logger">Instance of the <see cref="ILogger{ExceptionMiddleware}"/> interface.</param> + /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> + public ExceptionMiddleware( + RequestDelegate next, + ILogger<ExceptionMiddleware> logger, + IServerConfigurationManager serverConfigurationManager) + { + _next = next; + _logger = logger; + _configuration = serverConfigurationManager; + } + + /// <summary> + /// Invoke request. + /// </summary> + /// <param name="context">Request context.</param> + /// <returns>Task.</returns> + public async Task Invoke(HttpContext context) + { + try + { + await _next(context).ConfigureAwait(false); + } + catch (Exception ex) + { + if (context.Response.HasStarted) + { + _logger.LogWarning("The response has already started, the exception middleware will not be executed."); + throw; + } + + ex = GetActualException(ex); + + bool ignoreStackTrace = + ex is SocketException + || ex is IOException + || ex is OperationCanceledException + || ex is SecurityException + || ex is AuthenticationException + || ex is FileNotFoundException; + + if (ignoreStackTrace) + { + _logger.LogError( + "Error processing request: {ExceptionMessage}. URL {Method} {Url}.", + ex.Message.TrimEnd('.'), + context.Request.Method, + context.Request.Path); + } + else + { + _logger.LogError( + ex, + "Error processing request. URL {Method} {Url}.", + context.Request.Method, + context.Request.Path); + } + + context.Response.StatusCode = GetStatusCode(ex); + context.Response.ContentType = MediaTypeNames.Text.Plain; + var errorContent = NormalizeExceptionMessage(ex.Message); + await context.Response.WriteAsync(errorContent).ConfigureAwait(false); + } + } + + private static Exception GetActualException(Exception ex) + { + if (ex is AggregateException agg) + { + var inner = agg.InnerException; + if (inner != null) + { + return GetActualException(inner); + } + + var inners = agg.InnerExceptions; + if (inners.Count > 0) + { + return GetActualException(inners[0]); + } + } + + return ex; + } + + private static int GetStatusCode(Exception ex) + { + switch (ex) + { + case ArgumentException _: return StatusCodes.Status400BadRequest; + case SecurityException _: return StatusCodes.Status401Unauthorized; + case DirectoryNotFoundException _: + case FileNotFoundException _: + case ResourceNotFoundException _: return StatusCodes.Status404NotFound; + case MethodNotAllowedException _: return StatusCodes.Status405MethodNotAllowed; + default: return StatusCodes.Status500InternalServerError; + } + } + + private string NormalizeExceptionMessage(string msg) + { + if (msg == null) + { + return string.Empty; + } + + // Strip any information we don't want to reveal + return msg.Replace( + _configuration.ApplicationPaths.ProgramSystemPath, + string.Empty, + StringComparison.OrdinalIgnoreCase) + .Replace( + _configuration.ApplicationPaths.ProgramDataPath, + string.Empty, + StringComparison.OrdinalIgnoreCase); + } + } +} |
