fix: use byte-length for close message truncation, add exception-safe disposal
- CreateCloseMessage now operates on UTF-8 byte length (matching Go's len(body) behavior) instead of character length, with proper UTF-8 boundary detection during truncation - WsCompression.Compress now uses try/finally for exception-safe disposal of DeflateStream and MemoryStream
This commit is contained in:
@@ -22,19 +22,24 @@ public static class WsCompression
|
|||||||
{
|
{
|
||||||
var output = new MemoryStream();
|
var output = new MemoryStream();
|
||||||
var deflate = new DeflateStream(output, CompressionLevel.Fastest, leaveOpen: true);
|
var deflate = new DeflateStream(output, CompressionLevel.Fastest, leaveOpen: true);
|
||||||
deflate.Write(data);
|
try
|
||||||
deflate.Flush();
|
{
|
||||||
|
deflate.Write(data);
|
||||||
|
deflate.Flush();
|
||||||
|
|
||||||
var compressed = output.ToArray();
|
var compressed = output.ToArray();
|
||||||
|
|
||||||
deflate.Dispose();
|
// Remove trailing 4-byte sync marker (0x00 0x00 0xff 0xff) per RFC 7692
|
||||||
output.Dispose();
|
if (compressed.Length >= 4)
|
||||||
|
return compressed[..^4];
|
||||||
|
|
||||||
// Remove trailing 4-byte sync marker (0x00 0x00 0xff 0xff) per RFC 7692
|
return compressed;
|
||||||
if (compressed.Length >= 4)
|
}
|
||||||
return compressed[..^4];
|
finally
|
||||||
|
{
|
||||||
return compressed;
|
deflate.Dispose();
|
||||||
|
output.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -102,16 +102,27 @@ public static class WsFrameWriter
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] CreateCloseMessage(int status, string body)
|
public static byte[] CreateCloseMessage(int status, string body)
|
||||||
{
|
{
|
||||||
if (body.Length > WsConstants.MaxControlPayloadSize - WsConstants.CloseStatusSize)
|
var bodyBytes = Encoding.UTF8.GetBytes(body);
|
||||||
|
int maxBody = WsConstants.MaxControlPayloadSize - WsConstants.CloseStatusSize;
|
||||||
|
|
||||||
|
if (bodyBytes.Length > maxBody)
|
||||||
{
|
{
|
||||||
body = body[..(WsConstants.MaxControlPayloadSize - WsConstants.CloseStatusSize - 3)] + "...";
|
var suffix = "..."u8;
|
||||||
|
int truncLen = maxBody - suffix.Length;
|
||||||
|
// Find a valid UTF-8 boundary by walking back from truncation point
|
||||||
|
while (truncLen > 0 && (bodyBytes[truncLen] & 0xC0) == 0x80)
|
||||||
|
truncLen--;
|
||||||
|
var buf = new byte[WsConstants.CloseStatusSize + truncLen + suffix.Length];
|
||||||
|
BinaryPrimitives.WriteUInt16BigEndian(buf, (ushort)status);
|
||||||
|
bodyBytes.AsSpan(0, truncLen).CopyTo(buf.AsSpan(WsConstants.CloseStatusSize));
|
||||||
|
suffix.CopyTo(buf.AsSpan(WsConstants.CloseStatusSize + truncLen));
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bodyBytes = Encoding.UTF8.GetBytes(body);
|
var result = new byte[WsConstants.CloseStatusSize + bodyBytes.Length];
|
||||||
var buf = new byte[WsConstants.CloseStatusSize + bodyBytes.Length];
|
BinaryPrimitives.WriteUInt16BigEndian(result, (ushort)status);
|
||||||
BinaryPrimitives.WriteUInt16BigEndian(buf, (ushort)status);
|
bodyBytes.CopyTo(result.AsSpan(WsConstants.CloseStatusSize));
|
||||||
bodyBytes.CopyTo(buf.AsSpan(WsConstants.CloseStatusSize));
|
return result;
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user