Remove developer exception page in production

- Replace it with an ErrorMessage payload
- Adjust the client to account for this
This commit is contained in:
Jordan Brown
2020-01-09 20:29:14 -05:00
parent 9ca39c9ad0
commit b53562a667
4 changed files with 48 additions and 15 deletions
+5 -1
View File
@@ -112,7 +112,11 @@ namespace Tgstation.Server.Client
throw new MethodNotSupportedException();
case HttpStatusCode.InternalServerError:
// response json is html
throw new ServerErrorException(json);
throw new ServerErrorException(errorMessage ?? new ErrorMessage
{
Message = "An internal server error occurred!",
SeverApiVersion = null
}, response.StatusCode);
case (HttpStatusCode)429:
// rate limited
response.Headers.TryGetValues("Retry-After", out var values);
@@ -9,27 +9,18 @@ namespace Tgstation.Server.Client
/// </summary>
public sealed class ServerErrorException : ClientException
{
/// <summary>
/// The raw HTML of the error
/// </summary>
public string Html { get; }
/// <summary>
/// Construct an <see cref="ServerErrorException"/>
/// </summary>
public ServerErrorException() { }
/// <summary>
/// Construct an <see cref="ServerErrorException"/> with <paramref name="html"/>
/// Construct an <see cref="ServerErrorException"/> with a given <paramref name="errorMessage"/>
/// </summary>
/// <param name="html">The raw HTML response of the <see cref="ServerErrorException"/></param>
public ServerErrorException(string html) : base(new ErrorMessage
/// <param name="errorMessage">The <see cref="ErrorMessage"/> for the <see cref="ClientException"/></param>
/// <param name="statusCode">The <see cref="HttpStatusCode"/> for the <see cref="ClientException"/></param>
public ServerErrorException(ErrorMessage errorMessage, HttpStatusCode statusCode) : base(errorMessage, statusCode)
{
Message = "An internal server error occurred!",
SeverApiVersion = null
}, HttpStatusCode.InternalServerError)
{
Html = html;
}
/// <summary>
@@ -351,9 +351,12 @@ namespace Tgstation.Server.Host.Core
ChangeToken.OnChange(configuration.GetReloadToken, () => serverControl.Restart());
// setup the HTTP request pipeline
// Final point where we wrap exceptions in a 500 (ErrorMessage) response
applicationBuilder.UseServerErrorHandling();
// should anything after this throw an exception, catch it and display a detailed html page
applicationBuilder.UseDeveloperExceptionPage(); // it is not worth it to limit this, you should only ever get it if you're an authorized user
if(hostingEnvironment.IsDevelopment())
applicationBuilder.UseDeveloperExceptionPage(); // it is not worth it to limit this, you should only ever get it if you're an authorized user
// suppress OperationCancelledExceptions, they are just aborted HTTP requests
applicationBuilder.UseCancelledRequestSuppression();
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Globalization;
using System.Net;
using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Host.Core
@@ -69,5 +70,39 @@ namespace Tgstation.Server.Host.Core
}
});
}
/// <summary>
/// Suppress all in flight exceptions with error 500.
/// </summary>
/// <param name="applicationBuilder">The <see cref="IApplicationBuilder"/> to configure</param>
public static void UseServerErrorHandling(this IApplicationBuilder applicationBuilder)
{
if (applicationBuilder == null)
throw new ArgumentNullException(nameof(applicationBuilder));
applicationBuilder.Use(async (context, next) =>
{
var logger = GetLogger(context);
try
{
await next().ConfigureAwait(false);
}
catch (Exception e)
{
logger.LogError("Failed request: {0}", e);
await new ObjectResult(
new ErrorMessage
{
Message = $"A unhandled exception has occurred: {e}"
})
{
StatusCode = (int)HttpStatusCode.InternalServerError
}
.ExecuteResultAsync(new ActionContext
{
HttpContext = context
}).ConfigureAwait(false);
}
});
}
}
}