| File: Rpc\NativeRpcFrameProtocol.cs | Web Access |
| Project: src\src\Aspire.Hosting.Native.Server\Aspire.Hosting.Native.Server.csproj (Aspire.Hosting.Native.Server) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; using System.Text; namespace Aspire.Hosting.Native.Rpc; /// <summary>Validates LSP-style header bytes independently of stream buffering.</summary> internal static class NativeRpcFrameProtocol { public const int MaximumHeaderBytes = 8192; public static int ReadContentLength(ReadOnlySpan<byte> headers, int maximumRequestBytes) { // Content-Length: 42\r\nContent-Type: application/vscode-jsonrpc; charset=utf-8 // Header names are ASCII case-insensitive; lengths count UTF-8 body bytes. // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#headerPart int? contentLength = null; foreach (var range in headers.Split("\r\n"u8)) { var line = headers[range]; var separator = line.IndexOf((byte)':'); if (separator <= 0) { throw new InvalidDataException("The JSON-RPC frame header is malformed."); } var name = line[..separator]; if (Ascii.EqualsIgnoreCase(name, "Content-Length"u8)) { var value = line[(separator + 1)..]; while (!value.IsEmpty && char.IsWhiteSpace((char)value[0])) { value = value[1..]; } while (!value.IsEmpty && char.IsWhiteSpace((char)value[^1])) { value = value[..^1]; } if (contentLength is not null || !int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var length) || length > maximumRequestBytes) { throw new InvalidDataException("The JSON-RPC frame length is invalid."); } contentLength = length; } else if (!Ascii.EqualsIgnoreCase(name, "Content-Type"u8)) { throw new InvalidDataException("The JSON-RPC frame header is not supported."); } } return contentLength ?? throw new InvalidDataException("The JSON-RPC frame has no content length."); } }