1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
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.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.Middleware;
/// <summary>
/// Exception Middleware.
/// </summary>
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionMiddleware> _logger;
private readonly IServerConfigurationManager _configuration;
private readonly IWebHostEnvironment _hostEnvironment;
/// <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>
/// <param name="hostEnvironment">Instance of the <see cref="IWebHostEnvironment"/> interface.</param>
public ExceptionMiddleware(
RequestDelegate next,
ILogger<ExceptionMiddleware> logger,
IServerConfigurationManager serverConfigurationManager,
IWebHostEnvironment hostEnvironment)
{
_next = next;
_logger = logger;
_configuration = serverConfigurationManager;
_hostEnvironment = hostEnvironment;
}
/// <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;
// Don't send exception unless the server is in a Development environment
var errorContent = _hostEnvironment.IsDevelopment()
? NormalizeExceptionMessage(ex.Message)
: "Error processing request.";
await context.Response.WriteAsync(errorContent).ConfigureAwait(false);
}
}
private static Exception GetActualException(Exception ex)
{
if (ex is AggregateException agg)
{
var inner = agg.InnerException;
if (inner is not null)
{
return GetActualException(inner);
}
var inners = agg.InnerExceptions;
if (inners.Count > 0)
{
return GetActualException(inners[0]);
}
}
return ex;
}
private static int GetStatusCode(Exception ex)
{
return ex switch
{
ArgumentException => StatusCodes.Status400BadRequest,
AuthenticationException => StatusCodes.Status401Unauthorized,
SecurityException => StatusCodes.Status403Forbidden,
DirectoryNotFoundException => StatusCodes.Status404NotFound,
FileNotFoundException => StatusCodes.Status404NotFound,
ResourceNotFoundException => StatusCodes.Status404NotFound,
MethodNotAllowedException => StatusCodes.Status405MethodNotAllowed,
_ => StatusCodes.Status500InternalServerError
};
}
private string NormalizeExceptionMessage(string msg)
{
// 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);
}
}
|