Skip to content

API Suggestion: Add HttpSys wrapper interface for HttpQueryRequestProperty Windows API #63181

@markalward

Description

@markalward

Background and Motivation

Windows Http.sys supports an HttpQueryRequestProperty API that provides access to various details about the HTTP request and connection. This is currently used in the ASP.NET HttpSys server to make the TLS ClientHello and TLS SNI hostname available to the user.

It would be useful to expose the HttpQueryRequestProperty API through a generic interface, allowing direct access to all the information it provides. The benefits are:

  • Future-proofing: If Windows ships new telemetry that is available through this API, we'll be able to consume it without needing code changes in ASP.NET Core. For the TLS ClientHello and SNI hostname features, the support was added in a piecemeal fashion, requiring a feature ask, implementation, and backporting. The generic API would make it possible to consume HttpSys features more easily and with a shorter turnaround time.
  • Existing telemetry: Some information that is already available through this API - such as TCP statistics - is useful for debugging and network monitoring.

This API would be similar to IHttpSysRequestInfoFeature in that it provides raw data to the user, who must then parse it themselves using the http.h header as a reference.

Proposed API

namespace Microsoft.AspNetCore.Server.HttpSys;

public interface IHttpSysRequestPropertyFeature
{
    bool TryGetTlsClientHello(Span<byte> tlsClientHelloBytesDestination, out int bytesReturned);

+    ValueTask<bool> TryGetRequestPropertyAsync(int propertyId, ReadOnlyMemory<byte> qualifier, Memory<byte> output, out int bytesReturned);
}
  • The method returns true on success and fills the user-provided output buffer with the value of the requested property. bytesReturned returns the number of bytes written to the buffer.
  • The method returns false if the buffer is too small. In this case, bytesReturned returns the required buffer size.
  • For any other error, the method throws an exception.
  • Both qualifier and output can be set to an empty Memory<byte>. The user would set qualifier to empty for property IDs that don't use a qualifier (this must be mapped to null when calling the underlying HttpQueryRequestProperty API, since the API will return ERROR_INVALID_PARAMETER for any other pointer value). The user would set output to empty to query for the required buffer size.

The method is asynchronous since the HttpQueryRequestProperty Windows API supports async completion. The docs suggest that most properties are fetched synchronously, but that async completion is possible:

While you can provide an OVERLAPPED structure for asynchronous operation, setting this parameter is not a guarantee that the API will run asynchronously; most operations on this API are always synchronous.

Usage Examples

Example of retrieving the HttpRequestPropertyStreamError property using this API:

[StructLayout(LayoutKind.Sequential)]
struct HTTP_REQUEST_PROPERTY_STREAM_ERROR
{
    public uint ErrorCode;
}

async ValueTask<uint> GetStreamErrorAsync(HttpContext context)
{
    const int HttpRequestPropertyStreamError = 5;

    var feature = context.Features.Get<IHttpSysRequestPropertyFeature>();

    int bufferSize = Marshal.SizeOf<HTTP_REQUEST_PROPERTY_STREAM_ERROR>();
    byte[] pooledArray = ArrayPool<byte>.Shared.Rent(bufferSize);
    try
    {
        var buffer = pooledArray.AsMemory(0, bufferSize);

        // error handling omitted..
        await feature.TryGetRequestPropertyAsync(
            HttpRequestPropertyStreamError,
            default,
            buffer,
            out int _);

        var streamError = MemoryMarshal.AsRef<HTTP_REQUEST_PROPERTY_STREAM_ERROR>(buffer.Span);
        return streamError.ErrorCode;
    }
    finally
    {
        ArrayPool<byte>.Shared.Return(pooledArray);
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractionsfeature-httpsys

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions