• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Aldaviva / Unfucked / 23378203323

21 Mar 2026 10:59AM UTC coverage: 35.442% (-11.7%) from 47.183%
23378203323

push

github

Aldaviva
Seal all possible classes for allegedly higher performance, since they weren't actually subclassable anyway due to C# not making methods virtual by default. If this change does more harm than good, blame Stephen Toub.

573 of 1629 branches covered (35.17%)

14 of 72 new or added lines in 15 files covered. (19.44%)

488 existing lines in 30 files now uncovered.

975 of 2751 relevant lines covered (35.44%)

162.06 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/HTTP/Exceptions/HttpException.cs
1
using System.Net;
2
using System.Net.Http.Headers;
3
using System.Text;
4

5
namespace Unfucked.HTTP.Exceptions;
6

7
#pragma warning disable CS9113 // Parameter is unread. - the superclass constructor overload that reads it only exists in .NET 6, not .NET Standard 2.0
8
/// <summary>
9
/// Base exception class for all network, filtering, deserialization, and HTTP status code errors
10
/// </summary>
11
public abstract class HttpException(HttpStatusCode? status, string message, Exception? cause, HttpExceptionParams exceptionParams): HttpRequestException(MessageChain(message, cause), cause
×
12
#if !NETSTANDARD2_0
×
13
    , status
×
14
#endif
×
15
) {
×
16

17
#pragma warning restore CS9113 // Parameter is unread.
18

19
    protected readonly HttpExceptionParams HttpExceptionParams = exceptionParams;
×
20

21
    public Uri? RequestUrl => HttpExceptionParams.RequestUrl;
×
22
    public HttpMethod Verb => HttpExceptionParams.Verb;
×
23
    public IDictionary<string, object?>? RequestProperties => HttpExceptionParams.RequestProperties;
×
24
#if NET5_0_OR_GREATER
UNCOV
25
    public HttpRequestOptions? RequestOptions => HttpExceptionParams.RequestOptions;
×
26
#endif
27

28
    private static string MessageChain(string outerMessage, Exception? cause) {
29
        StringBuilder chain = new(outerMessage);
×
30
        while (cause != null) {
×
31
            chain.Append(": ").Append(cause.Message);
×
32
            cause = cause.InnerException is var inner && cause != inner ? inner : null;
×
33
        }
34
        return chain.ToString();
×
35
    }
36

37
}
38

39
#pragma warning disable CS0618 // Type or member is obsolete - it's not obsolete in .NET Standard 2.0, which this library targets
NEW
40
public sealed record HttpExceptionParams(
×
41
    HttpMethod Verb,
×
42
    Uri? RequestUrl,
×
43
    HttpResponseHeaders? ResponseHeaders = null,
×
44
    ReadOnlyMemory<byte>? ResponseBody = null,
×
45
    IDictionary<string, object?>? RequestProperties = null
×
46
#if NET5_0_OR_GREATER
×
47
    ,
×
48
    HttpRequestOptions? RequestOptions = null
×
49
#endif
×
50
) {
×
51

52
    public static HttpExceptionParams FromRequest(HttpRequestMessage request) => new(request.Method, request.RequestUri, null, null, request.Properties
×
53
#if NET5_0_OR_GREATER
×
54
        , request.Options
×
55
#endif
×
56
    );
×
57

58
    public static async Task<HttpExceptionParams> FromResponse(HttpResponseMessage response, CancellationToken cancellationToken = default) {
59
        HttpRequestMessage? request = response.RequestMessage;
×
60

61
        ReadOnlyMemory<byte>? responseBody = null;
×
62
        try {
63
            await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
×
64
            Task<byte[]> readAsByteArrayAsync =
×
65
#if NET5_0_OR_GREATER
×
66
                response.Content.ReadAsByteArrayAsync(cancellationToken);
×
67
#else
68
                response.Content.ReadAsByteArrayAsync();
69
#endif
70
            responseBody = (await readAsByteArrayAsync.ConfigureAwait(false)).AsMemory();
×
71
        } catch (InvalidOperationException) {
×
72
            // leave responseBody null
73
        }
×
74

75
        return new HttpExceptionParams(request?.Method ?? HttpMethod.Get, request?.RequestUri, response.Headers, responseBody, request?.Properties
×
76
#if NET5_0_OR_GREATER
×
77
            , request?.Options
×
78
#endif
×
79
        );
×
80
    }
×
81

82
}
83
#pragma warning restore CS0618 // Type or member is obsolete
84

85
/// <summary>
86
/// Unsuccessful HTTP status code
87
/// </summary>
88
public class WebApplicationException(HttpStatusCode status, string reasonPhrase, HttpExceptionParams exceptionParams)
89
    : HttpException(status, $"{(int) status} {reasonPhrase} from {exceptionParams.RequestUrl}", null, exceptionParams) {
×
90

91
    public string ReasonPhrase => reasonPhrase;
×
92
    public HttpResponseHeaders ResponseHeaders => HttpExceptionParams.ResponseHeaders!;
×
93
    public ReadOnlyMemory<byte>? ResponseBody => HttpExceptionParams.ResponseBody;
×
94

95
    public
96
#if NET5_0_OR_GREATER
97
        new
98
#endif
99
        HttpStatusCode StatusCode => status;
×
100

101
}
102

103
/// <summary>400–499</summary>
104
public class ClientErrorException(HttpStatusCode status, string reasonPhrase, HttpExceptionParams exceptionParams): WebApplicationException(status, reasonPhrase, exceptionParams);
×
105

106
/// <summary>400</summary>
NEW
107
public sealed class BadRequestException(string? reasonPhrase, HttpExceptionParams exceptionParams): ClientErrorException(HttpStatusCode.BadRequest, reasonPhrase ?? "Bad Request", exceptionParams);
×
108

109
/// <summary>401</summary>
110
public sealed class NotAuthorizedException(string? reasonPhrase, HttpExceptionParams exceptionParams)
NEW
111
    : ClientErrorException(HttpStatusCode.Unauthorized, reasonPhrase ?? "Unauthorized", exceptionParams);
×
112

113
/// <summary>403</summary>
NEW
114
public sealed class ForbiddenException(string? reasonPhrase, HttpExceptionParams exceptionParams): ClientErrorException(HttpStatusCode.Forbidden, reasonPhrase ?? "Forbidden", exceptionParams);
×
115

116
/// <summary>404</summary>
NEW
117
public sealed class NotFoundException(string? reasonPhrase, HttpExceptionParams exceptionParams): ClientErrorException(HttpStatusCode.NotFound, reasonPhrase ?? "Not Found", exceptionParams);
×
118

119
/// <summary>405</summary>
120
public sealed class NotAllowedException(string? reasonPhrase, HttpExceptionParams exceptionParams)
121
    : ClientErrorException(HttpStatusCode.MethodNotAllowed, reasonPhrase ?? "Method Not Allowed", exceptionParams);
×
122

123
/// <summary>406</summary>
124
public sealed class NotAcceptableException(string? reasonPhrase, HttpExceptionParams exceptionParams)
NEW
125
    : ClientErrorException(HttpStatusCode.NotAcceptable, reasonPhrase ?? "Not Acceptable", exceptionParams);
×
126

127
/// <summary>415</summary>
128
public sealed class NotSupportedException(string? reasonPhrase, HttpExceptionParams exceptionParams)
129
    : ClientErrorException(HttpStatusCode.UnsupportedMediaType, reasonPhrase ?? "Unsupported Media Type", exceptionParams);
×
130

131
/// <summary>500–599</summary>
132
public class ServerErrorException(HttpStatusCode statusCode, string reasonPhrase, HttpExceptionParams exceptionParams): WebApplicationException(statusCode, reasonPhrase, exceptionParams);
×
133

134
/// <summary>500</summary>
135
public sealed class InternalServerErrorException(string? reasonPhrase, HttpExceptionParams exceptionParams)
136
    : ServerErrorException(HttpStatusCode.InternalServerError, reasonPhrase ?? "Internal Server Error", exceptionParams);
×
137

138
/// <summary>503</summary>
139
public sealed class ServiceUnavailableException(string? reasonPhrase, HttpExceptionParams exceptionParams)
140
    : ServerErrorException(HttpStatusCode.ServiceUnavailable, reasonPhrase ?? "Service Unavailable", exceptionParams);
×
141

142
/// <summary>300–399</summary>
143
public sealed class RedirectionException(HttpStatusCode statusCode, Uri? destination, string reasonPhrase, HttpExceptionParams exceptionParams)
144
    : WebApplicationException(statusCode, reasonPhrase, exceptionParams) {
×
145

146
    public Uri? Destination { get; } = destination;
×
147

148
}
149

150
/// <summary>Network, filter, or deserialization error</summary>
NEW
151
public sealed class ProcessingException(Exception cause, HttpExceptionParams exceptionParams): HttpException(null,
×
152
    $"Network, filter, or deserialization error during HTTP {exceptionParams.Verb} request to {exceptionParams.RequestUrl?.AbsoluteUri}", cause, exceptionParams) {
×
153

154
#if NET5_0_OR_GREATER
155
    // ReSharper disable once MemberCanBeMadeStatic.Global - unhides parent property, defeating the purpose of hiding it
156
    [Obsolete(
157
        $"{nameof(ProcessingException)}s never have status codes, so this property always returns null. They represent failures in network I/O or response deserialization (such as timeouts, refused connections, or malformed JSON), rather than non-200-class status codes, which are instead represented by {nameof(WebApplicationException)}.")]
UNCOV
158
    public new HttpStatusCode? StatusCode => null;
×
159
#endif
160

161
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc