Skip to content

Commit 31c76a0

Browse files
committed
Clean up error handling. Check for control frame fragmentation.
1 parent 7d11034 commit 31c76a0

File tree

2 files changed

+41
-39
lines changed

2 files changed

+41
-39
lines changed

src/Microsoft.AspNet.WebSockets.Protocol/CommonWebSocket.cs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,7 @@ public async override Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byt
221221
{
222222
if (!_firstDataOpCode.HasValue)
223223
{
224-
if (State == WebSocketState.Open)
225-
{
226-
await CloseOutputAsync(WebSocketCloseStatus.ProtocolError, "Invalid continuation frame", cancellationToken);
227-
Abort();
228-
}
229-
throw new InvalidOperationException("A continuation can't be the first frame"); // TODO: WebSocketException
224+
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Invalid continuation frame", cancellationToken);
230225
}
231226
opCode = _firstDataOpCode.Value;
232227
}
@@ -261,12 +256,7 @@ public async override Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byt
261256
if (messageType == WebSocketMessageType.Text
262257
&& !Utilities.TryValidateUtf8(new ArraySegment<byte>(buffer.Array, buffer.Offset, bytesToCopy), _frameInProgress.Fin, _incomingUtf8MessageState))
263258
{
264-
if (State == WebSocketState.Open)
265-
{
266-
await CloseOutputAsync(WebSocketCloseStatus.InvalidPayloadData, "Invalid UTF-8", cancellationToken);
267-
Abort();
268-
}
269-
throw new InvalidOperationException("An invalid UTF-8 payload was received."); // TODO: WebSocketException
259+
await SendErrorAbortAndThrow(WebSocketCloseStatus.InvalidPayloadData, "Invalid UTF-8", cancellationToken);
270260
}
271261

272262
if (bytesToCopy == _frameBytesRemaining)
@@ -303,47 +293,41 @@ private async Task ReadNextFrameAsync(CancellationToken cancellationToken)
303293

304294
if (_frameInProgress.AreReservedSet())
305295
{
306-
if (State == WebSocketState.Open)
307-
{
308-
await CloseOutputAsync(WebSocketCloseStatus.ProtocolError, "Unexpected reserved bits set", cancellationToken);
309-
Abort();
310-
}
311-
throw new InvalidOperationException("Unexpected reserved bits are set."); // TODO: WebSocketException
296+
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Unexpected reserved bits set", cancellationToken);
312297
}
313298

314299
if (_unmaskInput != _frameInProgress.Masked)
315300
{
316-
if (State == WebSocketState.Open)
317-
{
318-
await CloseOutputAsync(WebSocketCloseStatus.ProtocolError, "Incorrect masking", cancellationToken);
319-
Abort();
320-
}
321-
throw new InvalidOperationException("Unmasking settings out of sync with data."); // TODO: WebSocketException
301+
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Incorrect masking", cancellationToken);
322302
}
323303

324-
if (_frameInProgress.OpCode == Constants.OpCodes.PingFrame || _frameInProgress.OpCode == Constants.OpCodes.PongFrame)
304+
if (_frameInProgress.IsControlFrame)
325305
{
326306
if (_frameBytesRemaining > 125)
327307
{
328-
if (State == WebSocketState.Open)
329-
{
330-
await CloseOutputAsync(WebSocketCloseStatus.ProtocolError, "Invalid control frame size", cancellationToken);
331-
Abort();
332-
}
333-
throw new InvalidOperationException("Control frame too large."); // TODO: WebSocketException
308+
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Invalid control frame size", cancellationToken);
334309
}
335-
// Drain it, should be less than 125 bytes
336-
await EnsureDataAvailableOrReadAsync((int)_frameBytesRemaining, cancellationToken);
337310

338-
if (_frameInProgress.OpCode == Constants.OpCodes.PingFrame)
311+
if (!_frameInProgress.Fin)
339312
{
340-
await SendPongReplyAsync(cancellationToken);
313+
await SendErrorAbortAndThrow(WebSocketCloseStatus.ProtocolError, "Fragmented control frame", cancellationToken);
341314
}
342315

343-
_receiveBufferOffset += (int)_frameBytesRemaining;
344-
_receiveBufferBytes -= (int)_frameBytesRemaining;
345-
_frameBytesRemaining = 0;
346-
_frameInProgress = null;
316+
if (_frameInProgress.OpCode == Constants.OpCodes.PingFrame || _frameInProgress.OpCode == Constants.OpCodes.PongFrame)
317+
{
318+
// Drain it, should be less than 125 bytes
319+
await EnsureDataAvailableOrReadAsync((int)_frameBytesRemaining, cancellationToken);
320+
321+
if (_frameInProgress.OpCode == Constants.OpCodes.PingFrame)
322+
{
323+
await SendPongReplyAsync(cancellationToken);
324+
}
325+
326+
_receiveBufferOffset += (int)_frameBytesRemaining;
327+
_receiveBufferBytes -= (int)_frameBytesRemaining;
328+
_frameBytesRemaining = 0;
329+
_frameInProgress = null;
330+
}
347331
}
348332
}
349333

@@ -587,5 +571,15 @@ private void ValidateSegment(ArraySegment<byte> buffer)
587571
throw new ArgumentOutOfRangeException("buffer.Count", buffer.Count, string.Empty);
588572
}
589573
}
574+
575+
private async Task SendErrorAbortAndThrow(WebSocketCloseStatus error, string message, CancellationToken cancellationToken)
576+
{
577+
if (State == WebSocketState.Open)
578+
{
579+
await CloseOutputAsync(error, message, cancellationToken);
580+
}
581+
Abort();
582+
throw new InvalidOperationException(message); // TODO: WebSocketException
583+
}
590584
}
591585
}

src/Microsoft.AspNet.WebSockets.Protocol/FrameHeader.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,14 @@ public ArraySegment<byte> Buffer
209209
}
210210
}
211211

212+
public bool IsControlFrame
213+
{
214+
get
215+
{
216+
return OpCode >= Constants.OpCodes.CloseFrame;
217+
}
218+
}
219+
212220
// bits 1-3.
213221
internal bool AreReservedSet()
214222
{

0 commit comments

Comments
 (0)