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

Aldaviva / Unfucked / 41068530179

30 Oct 2026 02:03PM UTC coverage: 46.159% (+0.1%) from 46.063%
41068530179

push

github

Aldaviva
HTTP: revert making all MessageBodyReaders take lots of arguments and not have access to the HttpResponseMessage or HttpContent just so they would always be forced to use the PartiallyBufferedStream, because most readers don't sniff body prefixes (only XML and JSON object mapping readers do), and it prevents the rest of them from using the optimized methods on HttpContent to read the body as a byte array or string. Solved by making a richer type hierarchy where the prefix sniffing lives in an abstract superclass that implements MessageBodyReader, and WebTarget is aware of it and can call it only when it's actually trying to detect prefixes. This has the added benefit that non-prefix-aware readers are skipped if they've already mismatched and won't be re-asked if they can handle the response when in the second phase prefix sniffing pass of deserialization.

838 of 2337 branches covered (35.86%)

44 of 67 new or added lines in 9 files covered. (65.67%)

2 existing lines in 2 files now uncovered.

1454 of 3150 relevant lines covered (46.16%)

151.49 hits per line

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

89.61
/HTTP/Serialization/GenericBodyReader.cs
1
using System.Collections.Concurrent;
2
using System.Net.Http.Headers;
3
using System.Reflection;
4
using System.Runtime.Serialization;
5
using System.Text;
6
using Unfucked.HTTP.Config;
7
using ConstructorMethod =
8
#if NET8_0_OR_GREATER
9
    System.Reflection.ConstructorInvoker
10
#else
11
    System.Reflection.ConstructorInfo
12
#endif
13
    ;
14

15
namespace Unfucked.HTTP.Serialization;
16

17
/// <summary>Can parse types like <see cref="Version"/> or <see cref="Uri"/> from strings</summary>
18
public sealed class GenericBodyReader(StringBodyReader stringBodyReader): AbstractMessageBodyReader {
8 ✔
19

20
    private static readonly Lazy<ConcurrentDictionary<Type, ConstructorMethod?>> CONSTRUCTOR_CACHE     = new(LazyThreadSafetyMode.PublicationOnly);
1 ✔
21
    private static readonly Lazy<ConcurrentDictionary<Type, object?>>            PARSE_METHOD_CACHE    = new(LazyThreadSafetyMode.PublicationOnly); // type of value is ParseString<T>?
1 ✔
22
    private static readonly Lazy<ConcurrentDictionary<Type, object?>>            TRYPARSE_METHOD_CACHE = new(LazyThreadSafetyMode.PublicationOnly); // type of value is TryParseString<T>?
1 ✔
23

24
#if NET8_0_OR_GREATER
25
    private delegate T ParseUtf8Span<out T>(ReadOnlySpan<byte> serialized, IFormatProvider? formatProvider);
26

27
    private static readonly Lazy<ConcurrentDictionary<Type, object?>> UTF8_SPAN_PARSER_CACHE = new(LazyThreadSafetyMode.PublicationOnly); // type of value is ParseUtf8Span<T>
1 ✔
28
#endif
29

30
#if NET7_0_OR_GREATER
31
    private delegate T ParseStringWithFormat<out T>(string serialized, IFormatProvider? formatProvider);
32

33
    private static readonly Lazy<ConcurrentDictionary<Type, object?>> STRING_PARSER_CACHE = new(LazyThreadSafetyMode.PublicationOnly); // type of value is ParseStringWithFormat<T>?
1 ✔
34
#endif
35

36
    private delegate T ParseString<out T>(string serialized);
37

38
    private delegate bool TryParseString<T>(string serialized, out T? parsed);
39

40
    /// <inheritdoc />
41
    public override bool CanRead<T>(MediaTypeHeaderValue? contentType) =>
42
#if NET8_0_OR_GREATER
43
        ((contentType?.CharSet?.Replace("-", string.Empty).Equals(Encoding.UTF8.BodyName, StringComparison.OrdinalIgnoreCase) ?? true) &&
6 !
44
            UTF8_SPAN_PARSER_CACHE.Value.GetOrAdd(typeof(T), _ => FindUtf8SpanParser<T>()) != null) ||
4 ✔
45
#endif
6 ✔
46
#if NET7_0_OR_GREATER
6 ✔
47
        STRING_PARSER_CACHE.Value.GetOrAdd(typeof(T), _ => FindStringParser<T>()) != null ||
4 ✔
48
#endif
6 ✔
49
        CONSTRUCTOR_CACHE.Value.GetOrAdd(typeof(T), FindConstructor) != null ||
6 !
50
        PARSE_METHOD_CACHE.Value.GetOrAdd(typeof(T), _ => FindParseMethod<T>()) != null ||
2 ✔
51
        TRYPARSE_METHOD_CACHE.Value.GetOrAdd(typeof(T), _ => FindTryParseMethod<T>()) != null;
7 ✔
52

53
    /// <inheritdoc />
54
    /// <exception cref="SerializationException"></exception>
55
    public override async Task<T> Read<T>(HttpResponseMessage response, Encoding? responseEncoding, Configurable? clientConfig, CancellationToken cancellationToken) {
56
#if NET8_0_OR_GREATER
57
        if (((responseEncoding?.Equals(Encoding.UTF8) ?? true) || responseEncoding.Equals(Encoding.ASCII)) &&
4 !
58
            UTF8_SPAN_PARSER_CACHE.Value.GetOrAdd(typeof(T), _ => FindUtf8SpanParser<T>()) is ParseUtf8Span<T> utf8SpanParser) {
4 ✔
59
            Stream       bodyStream = await GetBodyStream(response, cancellationToken);
1 ✔
60
            MemoryStream bodyBuffer = new();
1 ✔
61
            await bodyStream.CopyToAsync(bodyBuffer, int.MaxValue, cancellationToken).ConfigureAwait(false);
1 ✔
62
            ReadOnlySpan<byte> bodySpan = bodyBuffer.GetBuffer().AsSpan(0, (int) bodyBuffer.Length);
1 ✔
63
            return utf8SpanParser(bodySpan, null);
1 ✔
64
        }
65
#endif
66

67
#if NET7_0_OR_GREATER
68
        if (STRING_PARSER_CACHE.Value.GetOrAdd(typeof(T), _ => FindStringParser<T>()) is ParseStringWithFormat<T> stringParser) {
3 ✔
69
            string stringBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
1 ✔
70
            return stringParser(stringBody, null);
1 ✔
71
        }
72
#endif
73

74
        if (CONSTRUCTOR_CACHE.Value.GetOrAdd(typeof(T), FindConstructor) is {} constructor) {
2 !
75
            string stringBody = await response.Content.ReadAsStringAsync(
1 ✔
76
#if NET5_0_OR_GREATER
1 ✔
77
                cancellationToken
1 ✔
78
#endif
1 ✔
79
            ).ConfigureAwait(false);
1 ✔
80

81
            return (T)
1 ✔
82
#if NET8_0_OR_GREATER
1 ✔
83
                constructor.Invoke(stringBody);
1 ✔
84
#else
85
                constructor.Invoke([stringBody]);
86
#endif
87
        }
88

89
        if (PARSE_METHOD_CACHE.Value.GetOrAdd(typeof(T), _ => FindParseMethod<T>()) is ParseString<T> parseMethod) {
1 !
90
            string stringBody = await response.Content.ReadAsStringAsync(
1 ✔
91
#if NET5_0_OR_GREATER
1 ✔
92
                cancellationToken
1 ✔
93
#endif
1 ✔
94
            ).ConfigureAwait(false);
1 ✔
95

96
            return parseMethod(stringBody);
1 ✔
97
        }
98

99
        if (TRYPARSE_METHOD_CACHE.Value.GetOrAdd(typeof(T), _ => FindTryParseMethod<T>()) is TryParseString<T> tryParseMethod) {
×
NEW
100
            string stringBody = await response.Content.ReadAsStringAsync(
×
NEW
101
#if NET5_0_OR_GREATER
×
NEW
102
                cancellationToken
×
NEW
103
#endif
×
NEW
104
            ).ConfigureAwait(false);
×
105

NEW
106
            return tryParseMethod(stringBody, out T? parsed) ? parsed! : throw new SerializationException($"{typeof(T).FullName}.TryParse failed to deserialize '{stringBody}'");
×
107
        }
108

109
        throw new SerializationException($"{typeof(T).FullName} can be deserialized with neither IUtf8SpanParsable.Parse nor IParsable.Parse nor new(string) nor static Parse(string)");
×
110
    }
4 ✔
111

112
#if NET8_0_OR_GREATER
113
    private static ParseUtf8Span<T>? FindUtf8SpanParser<T>() {
114
        Type type = typeof(T);
4 ✔
115
        try {
116
            type.IsAssignableTo(typeof(IUtf8SpanParsable<>).MakeGenericType(type));
4 ✔
117
        } catch (ArgumentException) {
4 ✔
118
            return null;
3 ✔
119
        }
120
        return type.GetMethod($"System.IUtf8SpanParsable<{type.FullName}>.Parse",
1 !
121
                BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
1 ✔
122
                [typeof(ReadOnlySpan<byte>), typeof(IFormatProvider)])?
1 ✔
123
            .CreateDelegate<ParseUtf8Span<T>>();
1 ✔
124
    }
3 ✔
125

126
#endif
127

128
#if NET7_0_OR_GREATER
129
    private static ParseStringWithFormat<T>? FindStringParser<T>() {
130
        Type type = typeof(T);
4 ✔
131
        try {
132
            type.IsAssignableTo(typeof(IParsable<>).MakeGenericType(type));
4 ✔
133
        } catch (ArgumentException) {
4 ✔
134
            return null;
3 ✔
135
        }
136
        return type.GetMethod($"System.IParsable<{type.FullName}>.Parse",
1 !
137
            BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic,
1 ✔
138
            [typeof(string), typeof(IFormatProvider)])?.CreateDelegate<ParseStringWithFormat<T>>();
1 ✔
139
    }
3 ✔
140

141
#endif
142

143
    private static ConstructorMethod? FindConstructor(Type type) {
144
        var constructor = type.GetConstructor([typeof(string)]);
3 ✔
145
        return
3 ✔
146
#if NET8_0_OR_GREATER
3 ✔
147
            constructor != null ? ConstructorMethod.Create(constructor) : null;
3 ✔
148
#else
149
            constructor;
150
#endif
151
    }
152

153
    private static ParseString<T>? FindParseMethod<T>() =>
154
        typeof(T).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, [typeof(string)], null)?.CreateDelegate
2 ✔
155
#if NET5_0_OR_GREATER
2 ✔
156
            <ParseString<T>>();
2 ✔
157
#else
158
            (typeof(ParseString<T>)) as ParseString<T>;
159
#endif
160

161
    private static TryParseString<T>? FindTryParseMethod<T>() =>
162
        typeof(T).GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, [typeof(string), typeof(T).MakeByRefType()], null)?.CreateDelegate
1 !
163
#if NET5_0_OR_GREATER
1 ✔
164
            <TryParseString<T>>();
1 ✔
165
#else
166
            (typeof(TryParseString<T>)) as TryParseString<T>;
167
#endif
168

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

© 2026 Coveralls, Inc