Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 08fd68b

Browse files
authored
Fix WebSockets receiving messages in chunks does not detect correct message size (#28325)
* change the fix not to introduce public api, and add test * changer per feedback * address feedback
1 parent 67a34c7 commit 08fd68b

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ internal class WebSocketBuffer : IDisposable
3939
private readonly ArraySegment<byte> _propertyBuffer;
4040
private readonly int _sendBufferSize;
4141
private volatile int _payloadOffset;
42-
private volatile WebSocketReceiveResult _bufferedPayloadReceiveResult;
42+
private volatile PayloadReceiveResult _bufferedPayloadReceiveResult;
4343
private long _pinnedSendBufferStartAddress;
4444
private long _pinnedSendBufferEndAddress;
4545
private ArraySegment<byte> _pinnedSendBuffer;
@@ -305,7 +305,7 @@ internal void BufferPayload(ArraySegment<byte> payload,
305305
Debug.Assert(_payloadOffset == 0,
306306
"'m_PayloadOffset' MUST be '0' at this point.");
307307
Debug.Assert(_bufferedPayloadReceiveResult == null || _bufferedPayloadReceiveResult.Count == 0,
308-
"'m_BufferedPayloadReceiveResult.Count' MUST be '0' at this point.");
308+
"'_bufferedPayloadReceiveResult.Count' MUST be '0' at this point.");
309309

310310
Buffer.BlockCopy(payload.Array,
311311
payload.Offset + unconsumedDataOffset,
@@ -314,7 +314,7 @@ internal void BufferPayload(ArraySegment<byte> payload,
314314
bytesBuffered);
315315

316316
_bufferedPayloadReceiveResult =
317-
new WebSocketReceiveResult(bytesBuffered, messageType, endOfMessage);
317+
new PayloadReceiveResult(bytesBuffered, messageType, endOfMessage);
318318

319319
this.ValidateBufferedPayload();
320320
}
@@ -326,12 +326,12 @@ internal bool ReceiveFromBufferedPayload(ArraySegment<byte> buffer, out WebSocke
326326

327327
int bytesTransferred = Math.Min(buffer.Count, _bufferedPayloadReceiveResult.Count);
328328

329+
_bufferedPayloadReceiveResult.Count -= bytesTransferred;
330+
329331
receiveResult = new WebSocketReceiveResult(
330332
bytesTransferred,
331333
_bufferedPayloadReceiveResult.MessageType,
332-
bytesTransferred == 0 && _bufferedPayloadReceiveResult.EndOfMessage,
333-
_bufferedPayloadReceiveResult.CloseStatus,
334-
_bufferedPayloadReceiveResult.CloseStatusDescription);
334+
_bufferedPayloadReceiveResult.Count == 0 && _bufferedPayloadReceiveResult.EndOfMessage);
335335

336336
Buffer.BlockCopy(_payloadBuffer.Array,
337337
_payloadBuffer.Offset + _payloadOffset,
@@ -558,9 +558,9 @@ private void ThrowIfDisposed()
558558
private void ValidateBufferedPayload()
559559
{
560560
Debug.Assert(_bufferedPayloadReceiveResult != null,
561-
"'m_BufferedPayloadReceiveResult' MUST NOT be NULL.");
561+
"'_bufferedPayloadReceiveResult' MUST NOT be NULL.");
562562
Debug.Assert(_bufferedPayloadReceiveResult.Count >= 0,
563-
"'m_BufferedPayloadReceiveResult.Count' MUST NOT be negative.");
563+
"'_bufferedPayloadReceiveResult.Count' MUST NOT be negative.");
564564
Debug.Assert(_payloadOffset >= 0, "'m_PayloadOffset' MUST NOT be smaller than 0.");
565565
Debug.Assert(_payloadOffset <= _payloadBuffer.Count,
566566
"'m_PayloadOffset' MUST NOT be bigger than 'm_PayloadBuffer.Count'.");
@@ -685,5 +685,24 @@ private static class SendBufferState
685685
public const int None = 0;
686686
public const int SendPayloadSpecified = 1;
687687
}
688+
689+
private class PayloadReceiveResult
690+
{
691+
public int Count { get; set; }
692+
public bool EndOfMessage { get; }
693+
public WebSocketMessageType MessageType { get; }
694+
695+
public PayloadReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage)
696+
{
697+
if (count < 0)
698+
{
699+
throw new ArgumentOutOfRangeException(nameof(count));
700+
}
701+
702+
Count = count;
703+
EndOfMessage = endOfMessage;
704+
MessageType = messageType;
705+
}
706+
}
688707
}
689-
}
708+
}

src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,40 @@ public async Task ReceiveAsync_ReadWholeBuffer_Success(WebSocketMessageType mess
112112
Assert.Equal(Text, Encoding.ASCII.GetString(receivedBytes));
113113
}
114114

115+
[ConditionalTheory(nameof(IsNotWindows7))]
116+
[InlineData(300)]
117+
[InlineData(500)]
118+
[InlineData(1000)]
119+
[InlineData(1300)]
120+
public async Task ReceiveAsync_DetectEndOfMessage_Success(int bufferSize)
121+
{
122+
const int StringLength = 1000;
123+
string sendString = new string('A', StringLength);
124+
byte[] sentBytes = Encoding.ASCII.GetBytes(sendString);
125+
126+
HttpListenerWebSocketContext context = await GetWebSocketContext();
127+
await ClientConnectTask;
128+
129+
await Client.SendAsync(new ArraySegment<byte>(sentBytes), WebSocketMessageType.Text, true, new CancellationToken());
130+
131+
byte[] receivedBytes = new byte[bufferSize];
132+
List<byte> compoundBuffer = new List<byte>();
133+
134+
WebSocketReceiveResult result = new WebSocketReceiveResult(0, WebSocketMessageType.Close, false);
135+
while (!result.EndOfMessage)
136+
{
137+
result = await (context.WebSocket).ReceiveAsync(new ArraySegment<byte>(receivedBytes), new CancellationToken());
138+
139+
byte[] readBytes = new byte[result.Count];
140+
Array.Copy(receivedBytes, readBytes, result.Count);
141+
compoundBuffer.AddRange(readBytes);
142+
}
143+
144+
Assert.True(result.EndOfMessage);
145+
string msg = Encoding.UTF8.GetString(compoundBuffer.ToArray());
146+
Assert.Equal(sendString, msg);
147+
}
148+
115149
[ConditionalFact(nameof(IsNotWindows7))]
116150
public async Task ReceiveAsync_NoInnerBuffer_ThrowsArgumentNullException()
117151
{

0 commit comments

Comments
 (0)