Skip to content

Add API for Kestrel named pipes transport #44612

Closed
@JamesNK

Description

@JamesNK

Background and Motivation

Public API for named pipes transport - #44426

The transport is still work-in-progress. This API issue reflects its ideal final API shape, not the PR's current state.

Proposed API

Feature to get the server stream of the name pipe connection. Used to access methods like GetImpersonatedUser and RunAs from the pipe. Similar to IConnectionSocketFeature.

namespace Microsoft.AspNetCore.Connections.Features;

/// <summary>
/// Provides access to the connection's underlying <see cref="NamedPipeServerStream"/>.
/// </summary>
public interface IConnectionNamedPipeFeature
{
    /// <summary>
    /// Gets the underlying <see cref="NamedPipeServerStream"/>.
    /// </summary>
    NamedPipeServerStream NamedPipe { get; }
}

Options type for named pipes transport. Similar to SocketTransportOptions.

namespace Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;

/// <summary>
/// Options for named pipe based transports.
/// </summary>
public sealed class NamedPipeTransportOptions
{
    /// <summary>
    /// The maximum length of the pending connection queue.
    /// </summary>
    /// <remarks>
    /// Defaults to 512 pending connections.
    /// </remarks>
    public int Backlog { get; set; } = 512;

    /// <summary>
    /// Gets or sets the maximum unconsumed incoming bytes the transport will buffer.
    /// <para>
    /// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering.
    /// Unlimited server buffering is a security risk given untrusted clients.
    /// </para>
    /// </summary>
    /// <remarks>
    /// Defaults to 1 MiB.
    /// </remarks>
    public long? MaxReadBufferSize { get; set; } = 1024 * 1024;

    /// <summary>
    /// Gets or sets the maximum outgoing bytes the transport will buffer before applying write backpressure.
    /// <para>
    /// A value of <see langword="null"/> or 0 disables backpressure entirely allowing unlimited buffering.
    /// Unlimited server buffering is a security risk given untrusted clients.
    /// </para>
    /// </summary>
    /// <remarks>
    /// Defaults to 64 KiB.
    /// </remarks>
    public long? MaxWriteBufferSize { get; set; } = 64 * 1024;

    /// <summary>
    /// Gets or sets a value that indicates that the pipe can only be connected to by a client created by
    /// the same user account.
    /// <para>
    /// On Windows, a value of true verifies both the user account and elevation level.
    /// </para>
    /// </summary>
    /// <remarks>
    /// Defaults to true.
    /// </remarks>
    public bool CurrentUserOnly { get; set; } = true;

    /// <summary>
    /// Gets or sets the security information that determines the access control and audit security for pipes.
    /// </summary>
    public PipeSecurity? PipeSecurity { get; set; }
}

Extension methods to register named pipes services and/or customize options.

namespace Microsoft.AspNetCore.Hosting;

/// <summary>
/// <see cref="IWebHostBuilder" /> extension methods to configure the Named Pipes transport to be used by Kestrel.
/// </summary>
public static class WebHostBuilderNamedPipeExtensions
{
    /// <summary>
    /// Specify Named Pipes as the transport to be used by Kestrel.
    /// </summary>
    /// <param name="hostBuilder">
    /// The <see cref="IWebHostBuilder" /> to configure.
    /// </param>
    /// <returns>
    /// The <see cref="IWebHostBuilder" />.
    /// </returns>
    public static IWebHostBuilder UseNamedPipes(this IWebHostBuilder hostBuilder)
    {
        return hostBuilder.ConfigureServices(services =>
        {
            services.AddSingleton<IConnectionListenerFactory, NamedPipeTransportFactory>();
        });
    }

    /// <summary>
    /// Specify Named Pipes as the transport to be used by Kestrel.
    /// </summary>
    /// <param name="hostBuilder">
    /// The <see cref="IWebHostBuilder" /> to configure.
    /// </param>
    /// <param name="configureOptions">
    /// A callback to configure transport options.
    /// </param>
    /// <returns>
    /// The <see cref="IWebHostBuilder" />.
    /// </returns>
    public static IWebHostBuilder UseNamedPipes(this IWebHostBuilder hostBuilder, Action<NamedPipeTransportOptions> configureOptions)
    {
        return hostBuilder.UseNamedPipes().ConfigureServices(services =>
        {
            services.Configure(configureOptions);
        });
    }
}

New methods on KestrelServerOptions to register listener. There isn't a public NamedPipeEndPoint to pass to Listen(EndPoint) so these methods will be the only way to listen for a named pipe.

namespace Microsoft.AspNetCore.Server.Kestrel.Core;

public class KestrelServerOptions
{
    /// <summary>
    /// Bind to given named pipe.
    /// </summary>
    public void ListenNamedPipe(string pipeName);

    /// <summary>
    /// Bind to given named pipe.
    /// Specify callback to configure endpoint-specific settings.
    /// </summary>
    public void ListenNamedPipe(string pipeName, Action<ListenOptions> configure);
}

Usage Examples

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseNamedPipes(); // note: may be registered by default in .NET 8
builder.WebHost.UseKestrel(o =>
{
    o.ListenNamedPipe("MyCoolPipe");
});

var app = builder.Build();

app.MapGet("/", (HttpContext context) =>
{
    var pipe = context.Features.Get<IConnectionNamedPipeFeature>().NamedPipe;
    return $"Hello {pipe.GetImpersonationUserName()}";
});

app.Run();

Alternative Designs

Risks

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions