aspnetcore/test/Microsoft.Extensions.WebSoc.../WebSocketConnectionTests.Ut...

227 lines
12 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO.Pipelines;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.Extensions.WebSockets.Internal.Tests
{
public partial class WebSocketConnectionTests
{
public class Utf8Validation
{
[Theory]
[InlineData(new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }, "Hello")]
[InlineData(new byte[] { 0xC2, 0xA7, 0x31, 0x2C, 0x20, 0x39, 0x35, 0xC2, 0xA2 }, "§1, 95¢")]
[InlineData(new byte[] { 0xE0, 0xA0, 0x80, 0xE0, 0xA4, 0x80 }, "\u0800\u0900")]
[InlineData(new byte[] { 0xF0, 0x90, 0x80, 0x80 }, "\U00010000")]
public async Task ValidSingleFramePayloads(byte[] payload, string decoded)
{
using (var pair = WebSocketPair.Create())
{
var timeoutToken = TestUtil.CreateTimeoutToken();
using (timeoutToken.Register(() => pair.Dispose()))
{
var server = pair.ServerSocket.ExecuteAndCaptureFramesAsync();
var client = pair.ClientSocket.ExecuteAndCaptureFramesAsync();
var frame = new WebSocketFrame(
endOfMessage: true,
opcode: WebSocketOpcode.Text,
payload: ReadableBuffer.Create(payload));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
await pair.ClientSocket.CloseAsync(WebSocketCloseStatus.NormalClosure).OrTimeout();
var serverSummary = await server.OrTimeout();
await pair.ServerSocket.CloseAsync(WebSocketCloseStatus.NormalClosure).OrTimeout();
var clientSummary = await client.OrTimeout();
Assert.Equal(0, clientSummary.Received.Count);
Assert.Equal(1, serverSummary.Received.Count);
Assert.True(serverSummary.Received[0].EndOfMessage);
Assert.Equal(WebSocketOpcode.Text, serverSummary.Received[0].Opcode);
Assert.Equal(decoded, Encoding.UTF8.GetString(serverSummary.Received[0].Payload.ToArray()));
}
}
}
[Theory]
[InlineData(new byte[] { 0x48, 0x65 }, new byte[] { 0x6C, 0x6C, 0x6F }, "Hello")]
[InlineData(new byte[0], new byte[] { 0xC2, 0xA7 }, "§")]
[InlineData(new byte[] { 0xC2 }, new byte[] { 0xA7 }, "§")]
[InlineData(new byte[] { 0xC2, 0xA7 }, new byte[0], "§")]
[InlineData(new byte[0], new byte[] { 0xC2, 0xA2 }, "¢")]
[InlineData(new byte[] { 0xC2 }, new byte[] { 0xA2 }, "¢")]
[InlineData(new byte[] { 0xC2, 0xA2 }, new byte[0], "¢")]
[InlineData(new byte[0], new byte[] { 0xE0, 0xA0, 0x80 }, "\u0800")]
[InlineData(new byte[] { 0xE0 }, new byte[] { 0xA0, 0x80 }, "\u0800")]
[InlineData(new byte[] { 0xE0, 0xA0 }, new byte[] { 0x80 }, "\u0800")]
[InlineData(new byte[] { 0xE0, 0xA0, 0x80 }, new byte[0], "\u0800")]
[InlineData(new byte[0], new byte[] { 0xE0, 0xA4, 0x80 }, "\u0900")]
[InlineData(new byte[] { 0xE0 }, new byte[] { 0xA4, 0x80 }, "\u0900")]
[InlineData(new byte[] { 0xE0, 0xA4 }, new byte[] { 0x80 }, "\u0900")]
[InlineData(new byte[] { 0xE0, 0xA4, 0x80 }, new byte[0], "\u0900")]
[InlineData(new byte[0], new byte[] { 0xF0, 0x90, 0x80, 0x80 }, "\U00010000")]
[InlineData(new byte[] { 0xF0 }, new byte[] { 0x90, 0x80, 0x80 }, "\U00010000")]
[InlineData(new byte[] { 0xF0, 0x90 }, new byte[] { 0x80, 0x80 }, "\U00010000")]
[InlineData(new byte[] { 0xF0, 0x90, 0x80 }, new byte[] { 0x80 }, "\U00010000")]
[InlineData(new byte[] { 0xF0, 0x90, 0x80, 0x80 }, new byte[0], "\U00010000")]
public async Task ValidMultiFramePayloads(byte[] payload1, byte[] payload2, string decoded)
{
using (var pair = WebSocketPair.Create())
{
var server = pair.ServerSocket.ExecuteAndCaptureFramesAsync();
var client = pair.ClientSocket.ExecuteAndCaptureFramesAsync();
var frame = new WebSocketFrame(
endOfMessage: false,
opcode: WebSocketOpcode.Text,
payload: ReadableBuffer.Create(payload1));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
frame = new WebSocketFrame(
endOfMessage: true,
opcode: WebSocketOpcode.Continuation,
payload: ReadableBuffer.Create(payload2));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
await pair.ClientSocket.CloseAsync(WebSocketCloseStatus.NormalClosure).OrTimeout();
var serverSummary = await server.OrTimeout();
await pair.ServerSocket.CloseAsync(WebSocketCloseStatus.NormalClosure).OrTimeout();
var clientSummary = await client.OrTimeout();
Assert.Equal(0, clientSummary.Received.Count);
Assert.Equal(2, serverSummary.Received.Count);
Assert.False(serverSummary.Received[0].EndOfMessage);
Assert.Equal(WebSocketOpcode.Text, serverSummary.Received[0].Opcode);
Assert.True(serverSummary.Received[1].EndOfMessage);
Assert.Equal(WebSocketOpcode.Continuation, serverSummary.Received[1].Opcode);
var finalPayload = serverSummary.Received.SelectMany(f => f.Payload.ToArray()).ToArray();
Assert.Equal(decoded, Encoding.UTF8.GetString(finalPayload));
}
}
[Theory]
// Continuation byte as first byte of code point
[InlineData(new byte[] { 0x48, 0x65, 0x80, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65, 0x99, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65, 0xAB, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65, 0xB0, 0x6C, 0x6F })]
// Incomplete Code Point
[InlineData(new byte[] { 0xC2 })]
[InlineData(new byte[] { 0xE0 })]
[InlineData(new byte[] { 0xE0, 0xA0 })]
[InlineData(new byte[] { 0xE0, 0xA4 })]
[InlineData(new byte[] { 0xF0, 0x90, 0x80 })]
// Overlong Encoding
// 'H' (1 byte char) encoded with 2, 3 and 4 bytes
[InlineData(new byte[] { 0xC1, 0x88 })]
[InlineData(new byte[] { 0xE0, 0x81, 0x88 })]
[InlineData(new byte[] { 0xF0, 0x80, 0x81, 0x88 })]
// '§' (2 byte char) encoded with 3 and 4 bytes
[InlineData(new byte[] { 0xE0, 0x82, 0xA7 })]
[InlineData(new byte[] { 0xF0, 0x80, 0x82, 0xA7 })]
// '\u0800' (3 byte char) encoded with 4 bytes
[InlineData(new byte[] { 0xF0, 0x80, 0xA0, 0x80 })]
public async Task InvalidSingleFramePayloads(byte[] payload)
{
using (var pair = WebSocketPair.Create())
{
var server = pair.ServerSocket.ExecuteAndCaptureFramesAsync();
var client = pair.ClientSocket.ExecuteAndCaptureFramesAsync();
var frame = new WebSocketFrame(
endOfMessage: true,
opcode: WebSocketOpcode.Text,
payload: ReadableBuffer.Create(payload));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
var clientSummary = await client.OrTimeout();
var serverSummary = await server.OrTimeout();
Assert.Equal(0, serverSummary.Received.Count);
Assert.Equal(0, clientSummary.Received.Count);
Assert.Equal(WebSocketCloseStatus.InvalidPayloadData, clientSummary.CloseResult.Status);
Assert.Equal("An invalid Text frame payload was received", clientSummary.CloseResult.Description);
}
}
[Theory]
// Continuation byte as first byte of code point
[InlineData(new byte[] { 0x48, 0x65 }, new byte[] { 0x80, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65 }, new byte[] { 0x99, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65 }, new byte[] { 0xAB, 0x6C, 0x6F })]
[InlineData(new byte[] { 0x48, 0x65 }, new byte[] { 0xB0, 0x6C, 0x6F })]
// Incomplete Code Point
[InlineData(new byte[] { 0xC2 }, new byte[0])]
[InlineData(new byte[] { 0xE0 }, new byte[0])]
[InlineData(new byte[] { 0xE0, 0xA0 }, new byte[0])]
[InlineData(new byte[] { 0xE0, 0xA4 }, new byte[0])]
[InlineData(new byte[] { 0xF0, 0x90, 0x80 }, new byte[0])]
// Overlong Encoding
// 'H' (1 byte char) encoded with 2, 3 and 4 bytes
[InlineData(new byte[] { 0xC1 }, new byte[] { 0x88 })]
[InlineData(new byte[] { 0xE0 }, new byte[] { 0x81, 0x88 })]
[InlineData(new byte[] { 0xF0 }, new byte[] { 0x80, 0x81, 0x88 })]
// '§' (2 byte char) encoded with 3 and 4 bytes
[InlineData(new byte[] { 0xE0, 0x82 }, new byte[] { 0xA7 })]
[InlineData(new byte[] { 0xF0, 0x80 }, new byte[] { 0x82, 0xA7 })]
// '\u0800' (3 byte char) encoded with 4 bytes
[InlineData(new byte[] { 0xF0, 0x80 }, new byte[] { 0xA0, 0x80 })]
public async Task InvalidMultiFramePayloads(byte[] payload1, byte[] payload2)
{
using (var pair = WebSocketPair.Create())
{
var timeoutToken = TestUtil.CreateTimeoutToken();
using (timeoutToken.Register(() => pair.Dispose()))
{
var server = pair.ServerSocket.ExecuteAndCaptureFramesAsync();
var client = pair.ClientSocket.ExecuteAndCaptureFramesAsync();
var frame = new WebSocketFrame(
endOfMessage: false,
opcode: WebSocketOpcode.Text,
payload: ReadableBuffer.Create(payload1));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
frame = new WebSocketFrame(
endOfMessage: true,
opcode: WebSocketOpcode.Continuation,
payload: ReadableBuffer.Create(payload2));
await pair.ClientSocket.SendAsync(frame).OrTimeout();
var clientSummary = await client.OrTimeout();
var serverSummary = await server.OrTimeout();
Assert.Equal(1, serverSummary.Received.Count);
Assert.False(serverSummary.Received[0].EndOfMessage);
Assert.Equal(WebSocketOpcode.Text, serverSummary.Received[0].Opcode);
Assert.Equal(payload1, serverSummary.Received[0].Payload.ToArray());
Assert.Equal(0, clientSummary.Received.Count);
Assert.Equal(WebSocketCloseStatus.InvalidPayloadData, clientSummary.CloseResult.Status);
Assert.Equal("An invalid Text frame payload was received", clientSummary.CloseResult.Description);
}
}
}
}
}
}