< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Client.KrHttpClientFactory
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Client/KrHttpClientFactory.cs
Tag: Kestrun/Kestrun@5f1d2b981c9d7292c11fd448428c6ab6c811c5de
Line coverage
54%
Covered lines: 39
Uncovered lines: 33
Coverable lines: 72
Total lines: 176
Line coverage: 54.1%
Branch coverage
58%
Covered branches: 14
Total branches: 24
Branch coverage: 58.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 11/19/2025 - 17:40:50 Line coverage: 0% (0/72) Branch coverage: 0% (0/24) Total lines: 176 Tag: Kestrun/Kestrun@fcf33342333cef0516fe0d0912a86709874fd02603/26/2026 - 03:54:59 Line coverage: 54.1% (39/72) Branch coverage: 58.3% (14/24) Total lines: 176 Tag: Kestrun/Kestrun@844b5179fb0492dc6b1182bae3ff65fa7365521d 11/19/2025 - 17:40:50 Line coverage: 0% (0/72) Branch coverage: 0% (0/24) Total lines: 176 Tag: Kestrun/Kestrun@fcf33342333cef0516fe0d0912a86709874fd02603/26/2026 - 03:54:59 Line coverage: 54.1% (39/72) Branch coverage: 58.3% (14/24) Total lines: 176 Tag: Kestrun/Kestrun@844b5179fb0492dc6b1182bae3ff65fa7365521d

Coverage delta

Coverage delta 59 -59

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
CreateHandler(...)40%401033.33%
CreateBasicHandler(...)75%88100%
MakeClient(...)100%22100%
CreateNamedPipeClient(...)100%210%
CreateNamedPipeClient(...)100%210%
CreateNamedPipeClient(...)50%4220%
CreateUnixSocketClient(...)100%210%
CreateUnixSocketClient(...)100%210%
CreateUnixSocketClient(...)50%4220%
CreateTcpClient(...)100%210%
CreateTcpClient(...)100%210%
CreateTcpClient(...)100%11100%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Client/KrHttpClientFactory.cs

#LineLine coverage
 1// src/CSharp/Kestrun.Net/KrHttp.cs
 2using System.IO.Pipes;
 3using System.Net;
 4using System.Net.Security;
 5using System.Net.Sockets;
 6
 7namespace Kestrun.Client;
 8
 9/// <summary>
 10/// Factory methods to create HttpClient instances for different transport types.
 11/// </summary>
 12public static class KrHttpClientFactory
 13{
 14    // ---- Internal helper ----------------------------------------------------
 15    private static SocketsHttpHandler CreateHandler(KrHttpClientOptions opts)
 16    {
 217        var handler = CreateBasicHandler(opts);
 18
 19        // Proxy auth wiring if provided
 220        if (opts.Proxy is not null)
 21        {
 022            if (opts.ProxyUseDefaultCredentials)
 23            {
 024                opts.Proxy.Credentials = CredentialCache.DefaultCredentials;
 25            }
 026            else if (opts.Proxy.Credentials is null && opts.Credentials is not null)
 27            {
 28                // If caller didn't set proxy creds explicitly but provided server creds,
 29                // reuse them for the proxy (common IWR behavior).
 030                opts.Proxy.Credentials = opts.Credentials;
 31            }
 32        }
 33
 234        if (opts.IgnoreCertErrors)
 35        {
 036            handler.SslOptions = new SslClientAuthenticationOptions
 037            {
 038                RemoteCertificateValidationCallback = static (sender, certificate, chain, errors) => true
 039            };
 40        }
 41
 242        return handler;
 43    }
 44
 45    /// <summary>
 46    /// Creates a basic SocketsHttpHandler with common options applied.
 47    /// </summary>
 48    /// <param name="opts">The HTTP client options.</param>
 49    /// <returns>A configured SocketsHttpHandler instance.</returns>
 50    private static SocketsHttpHandler CreateBasicHandler(KrHttpClientOptions opts)
 51    {
 252        var effectiveTimeout = (opts.Timeout <= TimeSpan.Zero) ? TimeSpan.FromSeconds(100) : opts.Timeout;
 53
 254        return new SocketsHttpHandler
 255        {
 256            AutomaticDecompression = opts.Decompression,
 257            ConnectTimeout = effectiveTimeout,
 258
 259            // Redirects
 260            AllowAutoRedirect = opts.AllowAutoRedirect,
 261            MaxAutomaticRedirections = Math.Max(1, opts.MaxAutomaticRedirections),
 262
 263            // Cookies/session
 264            UseCookies = opts.Cookies is not null,
 265            CookieContainer = opts.Cookies ?? new CookieContainer(),
 266
 267            // Proxy
 268            UseProxy = opts.UseProxy && opts.Proxy is not null,
 269            Proxy = opts.Proxy,
 270
 271            // Server auth
 272            Credentials = opts.UseDefaultCredentials
 273                    ? CredentialCache.DefaultCredentials
 274                    : opts.Credentials
 275        };
 76    }
 77
 78    /// <summary>
 79    /// Creates an HttpClient with the specified handler, base address, and timeout.
 80    /// </summary>
 81    /// <param name="handler">The HTTP message handler.</param>
 82    /// <param name="baseAddress">The base address for the HTTP client.</param>
 83    /// <param name="timeout">The timeout for HTTP requests.</param>
 84    /// <returns>A configured HttpClient instance.</returns>
 85    private static HttpClient MakeClient(HttpMessageHandler handler, Uri baseAddress, TimeSpan timeout)
 286        => new(handler)
 287        {
 288            Timeout = (timeout <= TimeSpan.Zero) ? TimeSpan.FromSeconds(100) : timeout,
 289            BaseAddress = baseAddress
 290        };
 91
 92    // ---- Named Pipe ---------------------------------------------------------
 93    /// <summary>Create an HttpClient that talks HTTP over a Windows Named Pipe.</summary>
 94    public static HttpClient CreateNamedPipeClient(string pipeName, TimeSpan timeout)
 095        => CreateNamedPipeClient(pipeName, timeout, ignoreCertErrors: false);
 96
 97    /// <summary>Create an HttpClient that talks HTTP over a Windows Named Pipe (legacy overload).</summary>
 98    public static HttpClient CreateNamedPipeClient(string pipeName, TimeSpan timeout, bool ignoreCertErrors)
 99    {
 0100        var opts = new KrHttpClientOptions { Timeout = timeout, IgnoreCertErrors = ignoreCertErrors };
 0101        return CreateNamedPipeClient(pipeName, opts);
 102    }
 103
 104    /// <summary>Create an HttpClient that talks HTTP over a Windows Named Pipe (full options).</summary>
 105    public static HttpClient CreateNamedPipeClient(string pipeName, KrHttpClientOptions opts)
 106    {
 1107        if (string.IsNullOrWhiteSpace(pipeName))
 108        {
 1109            throw new ArgumentNullException(nameof(pipeName));
 110        }
 111
 0112        var h = CreateHandler(opts);
 113
 114        // capture pipeName in the lambda (works on .NET 6/7/8)
 0115        h.ConnectCallback = (ctx, ct) =>
 0116        {
 0117            var stream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
 0118            stream.Connect();
 0119            return new ValueTask<Stream>(stream);
 0120        };
 121
 0122        return MakeClient(h, new Uri("http://localhost"), opts.Timeout);
 123    }
 124
 125    // ---- Unix Domain Socket -------------------------------------------------
 126    /// <summary>Create an HttpClient that talks HTTP over a Unix Domain Socket.</summary>
 127    public static HttpClient CreateUnixSocketClient(string socketPath, TimeSpan timeout)
 0128        => CreateUnixSocketClient(socketPath, timeout, ignoreCertErrors: false);
 129
 130    /// <summary>Create an HttpClient that talks HTTP over a Unix Domain Socket (legacy overload).</summary>
 131    public static HttpClient CreateUnixSocketClient(string socketPath, TimeSpan timeout, bool ignoreCertErrors)
 132    {
 0133        var opts = new KrHttpClientOptions { Timeout = timeout, IgnoreCertErrors = ignoreCertErrors };
 0134        return CreateUnixSocketClient(socketPath, opts);
 135    }
 136
 137    /// <summary>Create an HttpClient that talks HTTP over a Unix Domain Socket (full options).</summary>
 138    public static HttpClient CreateUnixSocketClient(string socketPath, KrHttpClientOptions opts)
 139    {
 1140        if (string.IsNullOrWhiteSpace(socketPath))
 141        {
 1142            throw new ArgumentNullException(nameof(socketPath));
 143        }
 144
 0145        var h = CreateHandler(opts);
 146
 0147        h.ConnectCallback = (ctx, ct) =>
 0148        {
 0149            var sock = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
 0150            sock.Connect(new UnixDomainSocketEndPoint(socketPath));
 0151            return new ValueTask<Stream>(new NetworkStream(sock, ownsSocket: true));
 0152        };
 153
 0154        return MakeClient(h, new Uri("http://localhost"), opts.Timeout);
 155    }
 156
 157    // ---- TCP (HTTP/HTTPS) ---------------------------------------------------
 158    /// <summary>Classic TCP HttpClient (normal HTTP/S).</summary>
 159    public static HttpClient CreateTcpClient(Uri baseUri, TimeSpan timeout)
 0160        => CreateTcpClient(baseUri, timeout, ignoreCertErrors: false);
 161
 162    /// <summary>Classic TCP HttpClient (normal HTTP/S, legacy overload).</summary>
 163    public static HttpClient CreateTcpClient(Uri baseUri, TimeSpan timeout, bool ignoreCertErrors)
 164    {
 0165        var opts = new KrHttpClientOptions { Timeout = timeout, IgnoreCertErrors = ignoreCertErrors };
 0166        return CreateTcpClient(baseUri, opts);
 167    }
 168
 169    /// <summary>Classic TCP HttpClient (normal HTTP/S, full options).</summary>
 170    public static HttpClient CreateTcpClient(Uri baseUri, KrHttpClientOptions opts)
 171    {
 2172        ArgumentNullException.ThrowIfNull(baseUri);
 2173        var h = CreateHandler(opts);
 2174        return MakeClient(h, baseUri, opts.Timeout);
 175    }
 176}