- Convert WsReadInfo from mutable struct to class (prevents silent copy bugs) - Add handshake timeout enforcement via CancellationToken in WsUpgrade - Use buffered reading (512 bytes) in ReadHttpRequestAsync instead of byte-at-a-time - Add IAsyncDisposable to WsConnection for proper async cleanup - Simplify redundant mask bit check in WsReadInfo - Remove unused WsGuid and CompressLastBlock dead code from WsConstants - Document single-reader assumption on WsConnection read-side state
73 lines
2.8 KiB
C#
73 lines
2.8 KiB
C#
namespace NATS.Server.WebSocket;
|
|
|
|
/// <summary>
|
|
/// WebSocket protocol constants (RFC 6455).
|
|
/// Ported from golang/nats-server/server/websocket.go lines 41-106.
|
|
/// </summary>
|
|
public static class WsConstants
|
|
{
|
|
// Opcodes (RFC 6455 Section 5.2)
|
|
public const int TextMessage = 1;
|
|
public const int BinaryMessage = 2;
|
|
public const int CloseMessage = 8;
|
|
public const int PingMessage = 9;
|
|
public const int PongMessage = 10;
|
|
public const int ContinuationFrame = 0;
|
|
|
|
// Frame header bits
|
|
public const byte FinalBit = 0x80; // 1 << 7
|
|
public const byte Rsv1Bit = 0x40; // 1 << 6 (compression, RFC 7692)
|
|
public const byte Rsv2Bit = 0x20; // 1 << 5
|
|
public const byte Rsv3Bit = 0x10; // 1 << 4
|
|
public const byte MaskBit = 0x80; // 1 << 7 (in second byte)
|
|
|
|
// Frame size limits
|
|
public const int MaxFrameHeaderSize = 14;
|
|
public const int MaxControlPayloadSize = 125;
|
|
public const int FrameSizeForBrowsers = 4096;
|
|
public const int CompressThreshold = 64;
|
|
public const int CloseStatusSize = 2;
|
|
|
|
// Close status codes (RFC 6455 Section 11.7)
|
|
public const int CloseStatusNormalClosure = 1000;
|
|
public const int CloseStatusGoingAway = 1001;
|
|
public const int CloseStatusProtocolError = 1002;
|
|
public const int CloseStatusUnsupportedData = 1003;
|
|
public const int CloseStatusNoStatusReceived = 1005;
|
|
public const int CloseStatusInvalidPayloadData = 1007;
|
|
public const int CloseStatusPolicyViolation = 1008;
|
|
public const int CloseStatusMessageTooBig = 1009;
|
|
public const int CloseStatusInternalSrvError = 1011;
|
|
public const int CloseStatusTlsHandshake = 1015;
|
|
|
|
// Compression constants (RFC 7692)
|
|
public const string PmcExtension = "permessage-deflate";
|
|
public const string PmcSrvNoCtx = "server_no_context_takeover";
|
|
public const string PmcCliNoCtx = "client_no_context_takeover";
|
|
public static readonly string PmcReqHeaderValue = $"{PmcExtension}; {PmcSrvNoCtx}; {PmcCliNoCtx}";
|
|
public static readonly string PmcFullResponse = $"Sec-WebSocket-Extensions: {PmcExtension}; {PmcSrvNoCtx}; {PmcCliNoCtx}\r\n";
|
|
|
|
// Header names
|
|
public const string NoMaskingHeader = "Nats-No-Masking";
|
|
public const string NoMaskingValue = "true";
|
|
public static readonly string NoMaskingFullResponse = $"{NoMaskingHeader}: {NoMaskingValue}\r\n";
|
|
public const string XForwardedForHeader = "X-Forwarded-For";
|
|
|
|
// Path routing
|
|
public const string ClientPath = "/";
|
|
public const string LeafNodePath = "/leafnode";
|
|
public const string MqttPath = "/mqtt";
|
|
|
|
// Decompression trailer appended before decompressing (RFC 7692 Section 7.2.2)
|
|
public static readonly byte[] DecompressTrailer = [0x00, 0x00, 0xff, 0xff];
|
|
|
|
public static bool IsControlFrame(int opcode) => opcode >= CloseMessage;
|
|
}
|
|
|
|
public enum WsClientKind
|
|
{
|
|
Client,
|
|
Leaf,
|
|
Mqtt,
|
|
}
|