Added stricter SSE message type parsing (#410)

This commit is contained in:
Mikael Mengistu 2017-04-28 11:58:10 -07:00 committed by GitHub
parent 15afda7abf
commit db868af8d8
2 changed files with 22 additions and 9 deletions

View File

@ -23,6 +23,8 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
private static byte[] _sseLineEnding = Encoding.UTF8.GetBytes("\r\n");
private static byte[] _newLine = Encoding.UTF8.GetBytes(Environment.NewLine);
private readonly static int _messageTypeLineLength = "data: X\r\n".Length;
private InternalParseState _internalParserState = InternalParseState.ReadMessageType;
private List<byte[]> _data = new List<byte[]>();
private MessageType _messageType = MessageType.Text;
@ -94,7 +96,10 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
switch (_internalParserState)
{
case InternalParseState.ReadMessageType:
_messageType = GetMessageType(line);
EnsureStartsWithDataPrefix(line);
_messageType = ParseMessageType(line);
_internalParserState = InternalParseState.ReadMessagePayload;
@ -102,6 +107,8 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
consumed = lineEnd;
break;
case InternalParseState.ReadMessagePayload:
EnsureStartsWithDataPrefix(line);
// Slice away the 'data: '
var payloadLength = line.Length - (_dataPrefix.Length + _sseLineEnding.Length);
var newData = line.Slice(_dataPrefix.Length, payloadLength).ToArray();
@ -198,9 +205,12 @@ namespace Microsoft.AspNetCore.Sockets.Internal.Formatters
return line.Length == _sseLineEnding.Length && line.SequenceEqual(_sseLineEnding);
}
private MessageType GetMessageType(ReadOnlySpan<byte> line)
private MessageType ParseMessageType(ReadOnlySpan<byte> line)
{
EnsureStartsWithDataPrefix(line);
if (line.Length != _messageTypeLineLength)
{
throw new FormatException("Expected a data format message of the form 'data: <MesssageType>'");
}
// Skip the "data: " part of the line
var type = line[_dataPrefix.Length];

View File

@ -48,19 +48,20 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
[InlineData("data: X\r\n", "Unknown message type: 'X'")]
[InlineData("data: T\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data: X\r\n\r\n", "Unknown message type: 'X'")]
[InlineData("data: Not the message type\r\n\r\n", "Unknown message type: 'N'")]
[InlineData("data: Not the message type\r\n\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: T\r\ndata: Hello, World\r\r\n\n", "There was an error in the frame format")]
[InlineData("data: Not the message type\r\r\n", "Unknown message type: 'N'")]
[InlineData("data: Not the message type\r\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: T\r\ndata: Hello, World\n\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data: T\r\nfoo: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("foo: T\r\ndata: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("food: T\r\ndata: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("data: T\r\ndata: Hello, World\r\n\n", "There was an error in the frame format")]
[InlineData("data: T\r\ndata: Hello\n, World\r\n\r\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data: data: \r\n", "Unknown message type: 'd'")]
[InlineData("data: data: \r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: T\r\ndata: Hello, World\r\n\r\\", "Expected a \\r\\n frame ending")]
[InlineData("data: T\r\ndata: Major\r\ndata: Key\rndata: Alert\r\n\r\\", "Expected a \\r\\n frame ending")]
[InlineData("data: T\r\ndata: Major\r\ndata: Key\r\ndata: Alert\r\n\r\\", "Expected a \\r\\n frame ending")]
[InlineData("data: This is not a message type\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: B\r\n SGVsbG8sIFdvcmxk\r\n\r\n", "Expected the message prefix 'data: '")]
public void ParseSSEMessageFailureCases(string encodedMessage, string expectedExceptionMessage)
{
@ -155,18 +156,20 @@ namespace Microsoft.AspNetCore.Sockets.Common.Tests.Internal.Formatters
[InlineData("data: ", "X\r\n", "Unknown message type: 'X'")]
[InlineData("data: T", "\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data: ", "X\r\n\r\n", "Unknown message type: 'X'")]
[InlineData("data: ", "Not the message type\r\n\r\n", "Unknown message type: 'N'")]
[InlineData("data: ", "Not the message type\r\n\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: T\r\n", "data: Hello, World\r\r\n\n", "There was an error in the frame format")]
[InlineData("data:", " Not the message type\r\r\n", "Unknown message type: 'N'")]
[InlineData("data:", " Not the message type\r\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: T\r\n", "data: Hello, World\n\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data: T\r\nf", "oo: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("foo", ": T\r\ndata: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("food:", " T\r\ndata: Hello, World\r\n\r\n", "Expected the message prefix 'data: '")]
[InlineData("data: T\r\ndata: Hello, W", "orld\r\n\n", "There was an error in the frame format")]
[InlineData("data: T\r\nda", "ta: Hello\n, World\r\n\r\n", "Unexpected '\n' in message. A '\n' character can only be used as part of the newline sequence '\r\n'")]
[InlineData("data:", " data: \r\n", "Unknown message type: 'd'")]
[InlineData("data:", " data: \r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: ", "T\r\ndata: Major\r\ndata: Key\r\ndata: Alert\r\n\r\\", "Expected a \\r\\n frame ending")]
[InlineData("data: ", "This is not a message type\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
[InlineData("data: B\r\ndata: SGVs", "bG8sIFdvcmxk\r\n\n\n", "There was an error in the frame format")]
[InlineData("data: T", "his is not a message type\r\n", "Expected a data format message of the form 'data: <MesssageType>'")]
public async Task ParseMessageAcrossMultipleReadsFailure(string encodedMessagePart1, string encodedMessagePart2, string expectedMessage)
{
using (var pipeFactory = new PipeFactory())