using System; using System.Net; using System.Runtime.ExceptionServices; using System.Net.Http; using System.Threading.Tasks; using System.Web; using EmbedIO.Utilities; using Swan.Logging; namespace EmbedIO { /// /// Provides standard handlers for HTTP exceptions at both module and server level. /// /// /// Where applicable, HTTP exception handlers defined in this class /// use the and /// properties to customize /// their behavior. /// /// /// public static class HttpExceptionHandler { /// /// Gets the default handler used by . /// This is the same as . /// public static HttpExceptionHandlerCallback Default { get; } = HtmlResponse; /// /// Sends an empty response. /// /// An interface representing the context of the request. /// The HTTP exception. /// A representing the ongoing operation. #pragma warning disable CA1801 // Unused parameter public static Task EmptyResponse(IHttpContext context, IHttpException httpException) #pragma warning restore CA1801 => Task.CompletedTask; /// /// Sends a HTTP exception's Message property /// as a plain text response. /// This handler does not use the DataObject property. /// /// An interface representing the context of the request. /// The HTTP exception. /// A representing the ongoing operation. public static Task PlainTextResponse(IHttpContext context, IHttpException httpException) => context.SendStringAsync(httpException.Message ?? string.Empty, MimeType.PlainText, WebServer.DefaultEncoding); /// /// Sends a response with a HTML payload /// briefly describing the error, including contact information and/or a stack trace /// if specified via the /// and properties, respectively. /// This handler does not use the DataObject property. /// /// An interface representing the context of the request. /// The HTTP exception. /// A representing the ongoing operation. public static Task HtmlResponse(IHttpContext context, IHttpException httpException) => context.SendStandardHtmlAsync( httpException.StatusCode, text => { text.Write( "

Exception type: {0}

Message: {1}", WebUtility.HtmlEncode(httpException.GetType().FullName ?? ""), WebUtility.HtmlEncode(httpException.Message)); text.Write("


If this error is completely unexpected to you, and you think you should not seeing this page, please contact the server administrator"); if (!string.IsNullOrEmpty(ExceptionHandler.ContactInformation)) text.Write(" ({0})", WebUtility.HtmlEncode(ExceptionHandler.ContactInformation)); text.Write(", informing them of the time this error occurred and the action(s) you performed that resulted in this error.

"); if (ExceptionHandler.IncludeStackTraces) { text.Write( "

Stack trace:


{0}
", WebUtility.HtmlEncode(httpException.StackTrace)); } }); /// /// Gets a that will serialize a HTTP exception's /// DataObject property and send it as a JSON response. /// /// A used to serialize data and send it to the client. /// A . /// is . public static HttpExceptionHandlerCallback DataResponse(ResponseSerializerCallback serializerCallback) { Validate.NotNull(nameof(serializerCallback), serializerCallback); return (context, httpException) => serializerCallback(context, httpException.DataObject); } /// /// Gets a that will serialize a HTTP exception's /// Message and DataObject properties /// and send them as a JSON response. /// The response will be a JSON object with a message property and a data property. /// /// A used to serialize data and send it to the client. /// A . /// is . public static HttpExceptionHandlerCallback FullDataResponse(ResponseSerializerCallback serializerCallback) { Validate.NotNull(nameof(serializerCallback), serializerCallback); return (context, httpException) => serializerCallback(context, new { message = httpException.Message, data = httpException.DataObject, }); } internal static async Task Handle(string logSource, IHttpContext context, Exception exception, HttpExceptionHandlerCallback? handler) { if (handler == null || !(exception is IHttpException httpException)) { ExceptionDispatchInfo.Capture(exception).Throw(); return; } exception.Log(logSource, $"[{context.Id}] HTTP exception {httpException.StatusCode}"); try { context.Response.SetEmptyResponse(httpException.StatusCode); context.Response.DisableCaching(); httpException.PrepareResponse(context); await handler(context, httpException) .ConfigureAwait(false); } catch (OperationCanceledException) when (context.CancellationToken.IsCancellationRequested) { throw; } catch (HttpListenerException) { throw; } catch (Exception exception2) { exception2.Log(logSource, $"[{context.Id}] Unhandled exception while handling HTTP exception {httpException.StatusCode}"); } } } }