< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
FuzzTarget(...)0%220%
Test(System.Net.Http.Headers.HttpHeaders,System.String,System.String)0%12120%

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{
 011    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
 015    private static readonly string[] s_knownHeaderNames = [
 016        ":status", "Accept", "Accept-Charset", "Accept-Encoding", "Accept-Language", "Accept-Patch",
 017        "Accept-Ranges", "Access-Control-Allow-Credentials", "Access-Control-Allow-Headers",
 018        "Access-Control-Allow-Methods", "Access-Control-Allow-Origin", "Access-Control-Expose-Headers",
 019        "Access-Control-Max-Age", "Age", "Allow", "Alt-Svc", "Alt-Used", "Authorization", "Cache-Control",
 020        "Connection", "Content-Disposition", "Content-Encoding", "Content-Language", "Content-Length",
 021        "Content-Location", "Content-MD5", "Content-Range", "Content-Security-Policy", "Content-Type",
 022        "Cookie", "Cookie2", "Date", "ETag", "Expect", "Expect-CT", "Expires", "From", "grpc-encoding",
 023        "grpc-message", "grpc-status", "Host", "If-Match", "If-Modified-Since", "If-None-Match",
 024        "If-Range", "If-Unmodified-Since", "Keep-Alive", "Last-Modified", "Link", "Location",
 025        "Max-Forwards", "Origin", "P3P", "Pragma", "Proxy-Authenticate", "Proxy-Authorization",
 026        "Proxy-Connection", "Proxy-Support", "Public-Key-Pins", "Range", "Referer", "Referrer-Policy",
 027        "Refresh", "Retry-After", "Sec-WebSocket-Accept", "Sec-WebSocket-Extensions", "Sec-WebSocket-Key",
 028        "Sec-WebSocket-Protocol", "Sec-WebSocket-Version", "Server", "Server-Timing", "Set-Cookie",
 029        "Set-Cookie2", "Strict-Transport-Security", "TE", "TSV", "Trailer", "Transfer-Encoding",
 030        "Upgrade", "Upgrade-Insecure-Requests", "User-Agent", "Vary", "Via", "WWW-Authenticate",
 031        "Warning", "X-AspNet-Version", "X-Cache", "X-Content-Duration", "X-Content-Type-Options",
 032        "X-Frame-Options", "X-MSEdge-Ref", "X-Powered-By", "X-Request-ID", "X-UA-Compatible", "X-XSS-Protection"
 033    ];
 34
 035    private static readonly HttpRequestHeaders s_requestHeaders = new HttpRequestMessage().Headers;
 036    private static readonly HttpContentHeaders s_contentHeaders = new ByteArrayContent([]).Headers;
 037    private static readonly HttpResponseHeaders s_responseHeaders = new HttpResponseMessage().Headers;
 38
 39    public void FuzzTarget(ReadOnlySpan<byte> bytes)
 040    {
 041        if (bytes.Length < 2)
 042        {
 043            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.
 049        string name = s_knownHeaderNames[bytes[0] % s_knownHeaderNames.Length];
 050        string value = MemoryMarshal.Cast<byte, char>(bytes.Slice(2)).ToString();
 51
 052        Test(s_requestHeaders, name, value);
 053        Test(s_contentHeaders, name, value);
 054        Test(s_responseHeaders, name, value);
 55
 56        static void Test(HttpHeaders headers, string name, string value)
 057        {
 058            headers.Clear();
 59
 060            if (headers.TryAddWithoutValidation(name, value))
 061            {
 62                // Enumerating the header collection should never throw,
 63                // even if invalid values were added without validation.
 064                foreach (var _ in headers) { }
 65
 066                headers.Clear();
 67
 68                // If the value is invalid, we should only throw FormatException.
 69                try
 070                {
 071                    headers.Add(name, value);
 072                    headers.Add(name, value);
 073                }
 074                catch (FormatException) { }
 75
 76                // If values were added with validation, they should not contain CR or LF characters.
 077                foreach ((_, HeaderStringValues values) in headers.NonValidated)
 078                {
 079                    foreach (string headerValue in values)
 080                    {
 081                        Assert.False(headerValue.ContainsAny('\r', '\n', '\0'));
 082                    }
 083                }
 84
 085                foreach ((_, IEnumerable<string> values) in headers)
 086                {
 087                    foreach (string headerValue in values)
 088                    {
 089                        Assert.False(headerValue.ContainsAny('\r', '\n', '\0'));
 090                    }
 091                }
 092            }
 093        }
 094    }
 95}