Skip to content

Commit

Permalink
Extended payload length bug. #229
Browse files Browse the repository at this point in the history
  • Loading branch information
chronoxor committed Oct 26, 2022
1 parent 9fe246c commit 6824ee2
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 53 deletions.
3 changes: 2 additions & 1 deletion source/NetCoreServer/IWebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ void OnWsReceived(byte[] buffer, long offset, long size) {}
/// <param name="buffer">Received buffer</param>
/// <param name="offset">Received buffer offset</param>
/// <param name="size">Received buffer size</param>
void OnWsClose(byte[] buffer, long offset, long size) {}
/// <param name="status">WebSocket close status (default is 1000)</param>
void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) {}

/// <summary>
/// Handle WebSocket ping notification
Expand Down
2 changes: 1 addition & 1 deletion source/NetCoreServer/NetCoreServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>6.6.0.0</Version>
<Version>6.7.0.0</Version>
<Authors>Ivan Shynkarenka</Authors>
<Copyright>Copyright (c) 2019-2022 Ivan Shynkarenka</Copyright>
<RepositoryUrl>https://github.com/chronoxor/NetCoreServer</RepositoryUrl>
Expand Down
4 changes: 2 additions & 2 deletions source/NetCoreServer/UdpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public virtual long Send(EndPoint endpoint, ReadOnlySpan<byte> buffer)
try
{
// Sent datagram to the server
int sent = Socket.SendTo(buffer, SocketFlags.None, endpoint);
long sent = Socket.SendTo(buffer, SocketFlags.None, endpoint);
if (sent > 0)
{
// Update statistic
Expand Down Expand Up @@ -632,7 +632,7 @@ public virtual long Receive(ref EndPoint endpoint, byte[] buffer, long offset, l
try
{
// Receive datagram from the server
int received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint);
long received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint);

// Update statistic
DatagramsReceived++;
Expand Down
4 changes: 2 additions & 2 deletions source/NetCoreServer/UdpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ public virtual long Send(EndPoint endpoint, ReadOnlySpan<byte> buffer)
try
{
// Sent datagram to the client
int sent = Socket.SendTo(buffer, SocketFlags.None, endpoint);
long sent = Socket.SendTo(buffer, SocketFlags.None, endpoint);
if (sent > 0)
{
// Update statistic
Expand Down Expand Up @@ -610,7 +610,7 @@ public virtual long Receive(ref EndPoint endpoint, byte[] buffer, long offset, l
try
{
// Receive datagram from the client
int received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint);
long received = Socket.ReceiveFrom(buffer, (int)offset, (int)size, SocketFlags.None, ref endpoint);

// Update statistic
DatagramsReceived++;
Expand Down
74 changes: 47 additions & 27 deletions source/NetCoreServer/WebSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ public bool PerformServerUpgrade(HttpRequest request, HttpResponse response)
/// <param name="status">WebSocket status (default is 0)</param>
public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan<byte> buffer, int status = 0)
{
int size = buffer.Length;
long size = (((opcode & WS_CLOSE) == WS_CLOSE) && (buffer.Length > 0)) ? (buffer.Length + 2) : buffer.Length;

// Clear the previous WebSocket send buffer
WsSendBuffer.Clear();
Expand All @@ -263,7 +263,7 @@ public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan<byte> buffer,

// Append WebSocket frame size
if (size <= 125)
WsSendBuffer.Append((byte)((size & 0xFF) | (mask ? 0x80 : 0)));
WsSendBuffer.Append((byte)(((int)size & 0xFF) | (mask ? 0x80 : 0)));
else if (size <= 65535)
{
WsSendBuffer.Append((byte)(126 | (mask ? 0x80 : 0)));
Expand All @@ -284,11 +284,21 @@ public void PrepareSendFrame(byte opcode, bool mask, ReadOnlySpan<byte> buffer,
}

// Resize WebSocket frame buffer
int offset = (int)WsSendBuffer.Size;
long offset = WsSendBuffer.Size;
WsSendBuffer.Resize(WsSendBuffer.Size + size);

int index = 0;

// Append WebSocket close status
if (((opcode & WS_CLOSE) == WS_CLOSE) && (buffer.Length > 0))
{
index += 2;
WsSendBuffer.Append((byte)((status >> 8) & 0xFF));
WsSendBuffer.Append((byte)(status & 0xFF));
}

// Mask WebSocket frame content
for (int i = 0; i < size; i++)
for (int i = index; i < size; i++)
WsSendBuffer.Data[offset + i] = (byte)(buffer[i] ^ WsSendMask[i % 4]);
}

Expand All @@ -302,7 +312,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
{
lock (WsReceiveLock)
{
var index = 0;
int index = 0;

// Clear received data after WebSocket frame was processed
if (WsFrameReceived)
Expand Down Expand Up @@ -339,7 +349,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
// Prepare WebSocket frame opcode and mask flag
if (WsReceiveFrameBuffer.Size < 2)
{
for (int i = 0; i < 2; i++, index++, size--)
for (long i = 0; i < 2; i++, index++, size--)
{
if (size == 0)
return;
Expand All @@ -350,7 +360,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
byte opcode = (byte)(WsReceiveFrameBuffer[0] & 0x0F);
bool fin = ((WsReceiveFrameBuffer[0] >> 7) & 0x01) != 0;
bool mask = ((WsReceiveFrameBuffer[1] >> 7) & 0x01) != 0;
int payload = WsReceiveFrameBuffer[1] & (~0x80);
long payload = WsReceiveFrameBuffer[1] & (~0x80);

// Prepare WebSocket opcode
WsOpcode = (opcode != 0) ? opcode : WsOpcode;
Expand All @@ -365,7 +375,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
{
if (WsReceiveFrameBuffer.Size < 4)
{
for (int i = 0; i < 2; i++, index++, size--)
for (long i = 0; i < 2; i++, index++, size--)
{
if (size == 0)
return;
Expand All @@ -381,7 +391,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
{
if (WsReceiveFrameBuffer.Size < 10)
{
for (int i = 0; i < 8; i++, index++, size--)
for (long i = 0; i < 8; i++, index++, size--)
{
if (size == 0)
return;
Expand All @@ -399,7 +409,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
{
if (WsReceiveFrameBuffer.Size < WsHeaderSize)
{
for (int i = 0; i < 4; i++, index++, size--)
for (long i = 0; i < 4; i++, index++, size--)
{
if (size == 0)
return;
Expand All @@ -409,12 +419,12 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
}
}

int total = WsHeaderSize + WsPayloadSize;
int length = Math.Min(total - (int)WsReceiveFrameBuffer.Size, (int)size);
long total = WsHeaderSize + WsPayloadSize;
long length = Math.Min(total - WsReceiveFrameBuffer.Size, size);

// Prepare WebSocket frame payload
WsReceiveFrameBuffer.Append(buffer[((int)offset + index)..((int)offset + index + length)]);
index += length;
WsReceiveFrameBuffer.Append(buffer[((int)offset + index)..((int)offset + index + (int)length)]);
index += (int)length;
size -= length;

// Process WebSocket frame
Expand All @@ -423,11 +433,11 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
// Unmask WebSocket frame content
if (mask)
{
for (int i = 0; i < WsPayloadSize; i++)
for (long i = 0; i < WsPayloadSize; i++)
WsReceiveFinalBuffer.Append((byte)(WsReceiveFrameBuffer[WsHeaderSize + i] ^ WsReceiveMask[i % 4]));
}
else
WsReceiveFinalBuffer.Append(WsReceiveFrameBuffer.AsSpan().Slice(WsHeaderSize, WsPayloadSize));
WsReceiveFinalBuffer.Append(WsReceiveFrameBuffer.AsSpan().Slice((int)WsHeaderSize, (int)WsPayloadSize));

WsFrameReceived = true;

Expand All @@ -452,8 +462,18 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
}
case WS_CLOSE:
{
int sindex = 0;
int status = 1000;

// Read WebSocket close status
if (WsReceiveFinalBuffer.Size > 2)
{
sindex += 2;
status = ((WsReceiveFinalBuffer[0] << 8) | (WsReceiveFinalBuffer[1] << 0));
}

// Call the WebSocket close handler
_wsHandler.OnWsClose(WsReceiveFinalBuffer.Data, 0, WsReceiveFinalBuffer.Size);
_wsHandler.OnWsClose(WsReceiveFinalBuffer.Data, sindex, WsReceiveFinalBuffer.Size - sindex, status);
break;
}
case WS_BINARY:
Expand All @@ -473,7 +493,7 @@ public void PrepareReceiveFrame(byte[] buffer, long offset, long size)
/// <summary>
/// Required WebSocket receive frame size
/// </summary>
public int RequiredReceiveFrameSize()
public long RequiredReceiveFrameSize()
{
lock (WsReceiveLock)
{
Expand All @@ -482,23 +502,23 @@ public int RequiredReceiveFrameSize()

// Required WebSocket frame opcode and mask flag
if (WsReceiveFrameBuffer.Size < 2)
return 2 - (int)WsReceiveFrameBuffer.Size;
return 2 - WsReceiveFrameBuffer.Size;

bool mask = ((WsReceiveFrameBuffer[1] >> 7) & 0x01) != 0;
int payload = WsReceiveFrameBuffer[1] & (~0x80);
long payload = WsReceiveFrameBuffer[1] & (~0x80);

// Required WebSocket frame size
if ((payload == 126) && (WsReceiveFrameBuffer.Size < 4))
return 4 - (int)WsReceiveFrameBuffer.Size;
return 4 - WsReceiveFrameBuffer.Size;
if ((payload == 127) && (WsReceiveFrameBuffer.Size < 10))
return 10 - (int)WsReceiveFrameBuffer.Size;
return 10 - WsReceiveFrameBuffer.Size;

// Required WebSocket frame mask
if ((mask) && (WsReceiveFrameBuffer.Size < WsHeaderSize))
return WsHeaderSize - (int)WsReceiveFrameBuffer.Size;
return WsHeaderSize - WsReceiveFrameBuffer.Size;

// Required WebSocket frame payload
return WsHeaderSize + WsPayloadSize - (int)WsReceiveFrameBuffer.Size;
return WsHeaderSize + WsPayloadSize - WsReceiveFrameBuffer.Size;
}
}

Expand Down Expand Up @@ -561,15 +581,15 @@ public void ClearWsBuffers()
/// <summary>
/// Received frame opcode
/// </summary>
internal int WsOpcode;
internal byte WsOpcode;
/// <summary>
/// Received frame header size
/// </summary>
internal int WsHeaderSize;
internal long WsHeaderSize;
/// <summary>
/// Received frame payload size
/// </summary>
internal int WsPayloadSize;
internal long WsPayloadSize;

/// <summary>
/// Receive buffer lock
Expand Down
10 changes: 5 additions & 5 deletions source/NetCoreServer/WsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ public string ReceiveText()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = base.Receive(cache.Data, 0, required);
if (received != required)
return result.ExtractString(0, result.Data.Length);
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -251,9 +251,9 @@ public Buffer ReceiveBinary()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = base.Receive(cache.Data, 0, required);
if (received != required)
return result;
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -378,7 +378,7 @@ public virtual void OnWsConnected(HttpRequest request) {}
public virtual void OnWsDisconnecting() {}
public virtual void OnWsDisconnected() {}
public virtual void OnWsReceived(byte[] buffer, long offset, long size) {}
public virtual void OnWsClose(byte[] buffer, long offset, long size) { CloseAsync(1000); }
public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { CloseAsync(status); }
public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); }
public virtual void OnWsPong(byte[] buffer, long offset, long size) {}
public virtual void OnWsError(string error) { OnError(SocketError.SocketError); }
Expand Down
10 changes: 5 additions & 5 deletions source/NetCoreServer/WsSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ public string ReceiveText()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = base.Receive(cache.Data, 0, required);
if (received != required)
return result.ExtractString(0, result.Data.Length);
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -218,9 +218,9 @@ public Buffer ReceiveBinary()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = base.Receive(cache.Data, 0, required);
if (received != required)
return result;
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -330,7 +330,7 @@ public virtual void OnWsConnected(HttpRequest request) {}
public virtual void OnWsDisconnecting() {}
public virtual void OnWsDisconnected() {}
public virtual void OnWsReceived(byte[] buffer, long offset, long size) {}
public virtual void OnWsClose(byte[] buffer, long offset, long size) { Close(1000); }
public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { Close(status); }
public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); }
public virtual void OnWsPong(byte[] buffer, long offset, long size) {}
public virtual void OnWsError(string error) { OnError(SocketError.SocketError); }
Expand Down
10 changes: 5 additions & 5 deletions source/NetCoreServer/WssClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ public string ReceiveText()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = (int)base.Receive(cache.Data, 0, required);
if (received != required)
return result.ExtractString(0, result.Data.Length);
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -255,9 +255,9 @@ public Buffer ReceiveBinary()
{
while (!WebSocket.WsFrameReceived)
{
int required = WebSocket.RequiredReceiveFrameSize();
long required = WebSocket.RequiredReceiveFrameSize();
cache.Resize(required);
int received = (int)base.Receive(cache.Data, 0, required);
long received = (int)base.Receive(cache.Data, 0, required);
if (received != required)
return result;
WebSocket.PrepareReceiveFrame(cache.Data, 0, received);
Expand Down Expand Up @@ -382,7 +382,7 @@ public virtual void OnWsConnected(HttpRequest request) {}
public virtual void OnWsDisconnecting() {}
public virtual void OnWsDisconnected() {}
public virtual void OnWsReceived(byte[] buffer, long offset, long size) {}
public virtual void OnWsClose(byte[] buffer, long offset, long size) { CloseAsync(1000); }
public virtual void OnWsClose(byte[] buffer, long offset, long size, int status = 1000) { CloseAsync(status); }
public virtual void OnWsPing(byte[] buffer, long offset, long size) { SendPongAsync(buffer, offset, size); }
public virtual void OnWsPong(byte[] buffer, long offset, long size) {}
public virtual void OnWsError(string error) { OnError(SocketError.SocketError); }
Expand Down
Loading

0 comments on commit 6824ee2

Please sign in to comment.