< Summary

Information
Class: DotnetFuzzing.Fuzzers.HttpHeadersFuzzer
Assembly: DotnetFuzzing
File(s): D:\runner\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\HttpHeadersFuzzer.cs
Line coverage
98%
Covered lines: 60
Uncovered lines: 1
Coverable lines: 61
Total lines: 95
Line coverage: 98.3%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
FuzzTarget(...)100%22100%
Test(System.Net.Http.Headers.HttpHeaders,System.String,System.String)100%1212100%

File(s)

D:\runner\runtime\src\libraries\Fuzzing\DotnetFuzzing\Fuzzers\HttpHeadersFuzzer.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Net.Http.Headers;
 5using System.Runtime.InteropServices;
 6
 7namespace DotnetFuzzing.Fuzzers;
 8
 9internal sealed class HttpHeadersFuzzer : IFuzzer
 10{
 111    public string[] TargetAssemblies { get; } = ["System.Net.Http"];
 012    public string[] TargetCoreLibPrefixes => [];
 13
 14    // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeader
 115    private static readonly string[] s_knownHeaderNames = [
 116        ":status", "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Accept-Patch",
 117        "Accept-Ranges", "Access-Control-Allow-Credentials", "Access-Control-Allow-Headers",
 118        "Access-Control-Allow-Methods", "Access-Control-Allow-Origin", "Access-Control-Expose-Headers",
 119        "Access-Control-Max-Age", "Age", "Allow", "Alt-Svc", "Alt-Used", "Authorization", "Cache-Control",
 120        "Connection", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length",
 121        "Content-Location", "Content-MD5", "Content-Range", "Content-Security-Policy", "Content-Type",
 122        "Cookie", "Cookie2", "Date", "ETag", "Expect", "Expect-CT", "Expires", "From", "grpc-encoding",
 123        "grpc-message", "grpc-status", "Host", "If-Match", "If-Modified-Since", "If-None-Match",
 124        "If-Range", "If-Unmodified-Since", "Keep-Alive", "Last-Modified", "Link", "Location",
 125        "Max-Forwards", "Origin", "P3P", "Pragma", "Proxy-Authenticate", "Proxy-Authorization",
 126        "Proxy-Connection", "Proxy-Support", "Public-Key-Pins", "Range", "Referer", "Referrer-Policy",
 127        "Refresh", "Retry-After", "Sec-WebSocket-Accept", "Sec-WebSocket-Extensions", "Sec-WebSocket-Key",
 128        "Sec-WebSocket-Protocol", "Sec-WebSocket-Version", "Server", "Server-Timing", "Set-Cookie",
 129        "Set-Cookie2", "Strict-Transport-Security", "TE", "TSV", "Trailer", "Transfer-Encoding",
 130        "Upgrade", "Upgrade-Insecure-Requests", "User-Agent", "Vary", "Via", "WWW-Authenticate",
 131        "Warning", "X-AspNet-Version", "X-Cache", "X-Content-Duration", "X-Content-Type-Options",
 132        "X-Frame-Options", "X-MSEdge-Ref", "X-Powered-By", "X-Request-ID", "X-UA-Compatible", "X-XSS-Protection"
 133    ];
 34
 135    private static readonly HttpRequestHeaders s_requestHeaders = new HttpRequestMessage().Headers;
 136    private static readonly HttpContentHeaders s_contentHeaders = new ByteArrayContent([]).Headers;
 137    private static readonly HttpResponseHeaders s_responseHeaders = new HttpResponseMessage().Headers;
 38
 39    public void FuzzTarget(ReadOnlySpan<byte> bytes)
 490040    {
 490041        if (bytes.Length < 2)
 442        {
 443            return;
 44        }
 45
 46        // We use the first byte to select a known header name.
 47        // The rest of the input is used as the UTF-16 header value.
 48        // The second byte is skipped to keep the value chars 2-byte aligned.
 489649        string name = s_knownHeaderNames[bytes[0] % s_knownHeaderNames.Length];
 489650        string value = MemoryMarshal.Cast<byte, char>(bytes.Slice(2)).ToString();
 51
 489652        Test(s_requestHeaders, name, value);
 489653        Test(s_contentHeaders, name, value);
 489654        Test(s_responseHeaders, name, value);
 55
 56        static void Test(HttpHeaders headers, string name, string value)
 1468857        {
 1468858            headers.Clear();
 59
 1468860            if (headers.TryAddWithoutValidation(name, value))
 986561            {
 62                // Enumerating the header collection should never throw,
 63                // even if invalid values were added without validation.
 6905564                foreach (var _ in headers) { }
 65
 986566                headers.Clear();
 67
 68                // If the value is invalid, we should only throw FormatException.
 69                try
 986570                {
 986571                    headers.Add(name, value);
 570172                    headers.Add(name, value);
 562773                }
 1271474                catch (FormatException) { }
 75
 76                // If values were added with validation, they should not contain CR or LF characters.
 4077177                foreach ((_, HeaderStringValues values) in headers.NonValidated)
 558878                {
 14872879                    foreach (string headerValue in values)
 6598280                    {
 6598281                        Assert.False(headerValue.ContainsAny('\r', '\n', '\0'));
 6598282                    }
 558883                }
 84
 4077185                foreach ((_, IEnumerable<string> values) in headers)
 558886                {
 14872887                    foreach (string headerValue in values)
 6598288                    {
 6598289                        Assert.False(headerValue.ContainsAny('\r', '\n', '\0'));
 6598290                    }
 558891                }
 986592            }
 1468893        }
 490094    }
 95}