Skip to content

Commit

Permalink
introduce Stream.ReadExactly extension methods
Browse files Browse the repository at this point in the history
fixes Frame.FromStream messing up when stream read less than requested
  • Loading branch information
luca-schlecker committed May 4, 2024
1 parent c43cc39 commit f13d43f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
24 changes: 4 additions & 20 deletions src/Frame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ public byte[] ToArray()
}
public static async Task<Frame> FromStream(Stream stream, CancellationToken token)
{
var header = new byte[2];
var read = await stream.ReadAsync(header, token);
if (read == 0) throw new EndOfStreamException();
var header = await stream.ReadExactly(2, token);
var isMasked = (header[1] & 0x80) == 0x80;
var isFinal = (header[0] & 0x80) == 0x80;
var opCode = (FrameOpCode)(header[0] & 0x0F);
Expand All @@ -49,29 +47,15 @@ public static async Task<Frame> FromStream(Stream stream, CancellationToken toke
127 => new byte[8],
_ => new byte[0],
};
if (payloadLength.Length != 0)
{
read = await stream.ReadAsync(payloadLength, token);
if (read == 0) throw new EndOfStreamException();
}
await stream.ReadExactly(payloadLength, token);
var realLength = payloadLength.Length switch
{
2 => BitConverter.ToUInt16(payloadLength),
8 => BitConverter.ToUInt64(payloadLength),
_ => (ulong)(header[1] & 0x7F),
};
var maskingKey = isMasked ? new byte[4] : null;
if (maskingKey != null)
{
read = await stream.ReadAsync(maskingKey, token);
if (read == 0) throw new EndOfStreamException();
}
var payload = new byte[realLength];
if (realLength != 0)
{
read = await stream.ReadAsync(payload, token);
if (read == 0) throw new EndOfStreamException();
}
var maskingKey = isMasked ? await stream.ReadExactly(4, token) : null;
var payload = await stream.ReadExactly((int)realLength, token);
return new Frame(isFinal, opCode, maskingKey, payload);
}

Expand Down
32 changes: 32 additions & 0 deletions src/StreamHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace SwebSocket;

internal static class StreamHelper
{
public static async Task ReadExactly(this Stream stream, byte[] buffer, CancellationToken token)
{
if (buffer.Length == 0) return;

int alreadyRead = 0;
int toBeRead = buffer.Length;

while (alreadyRead != toBeRead)
{
var actuallyRead = await stream.ReadAsync(buffer, alreadyRead, toBeRead - alreadyRead, token);
if (actuallyRead == 0) throw new EndOfStreamException();
alreadyRead += actuallyRead;
}
}

public static async Task<byte[]> ReadExactly(this Stream stream, int bytes, CancellationToken token)
{
var buffer = new byte[bytes];
await ReadExactly(stream, buffer, token);

return buffer;
}
}

0 comments on commit f13d43f

Please sign in to comment.