public async Task CanSendAndReceiveCompressedData()
    {
        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            using var webSocket = await context.WebSockets.AcceptWebSocketAsync(new WebSocketAcceptContext()
            {
                DangerousEnableCompression = true,
                ServerMaxWindowBits = 13
            });

            var serverBuffer = new byte[1024];
            while (true)
            {
                var result = await webSocket.ReceiveAsync(serverBuffer, CancellationToken.None);
                if (result.MessageType == WebSocketMessageType.Close)
                {
                    break;
                }
                await webSocket.SendAsync(serverBuffer.AsMemory(0, result.Count), result.MessageType, result.EndOfMessage, default);
            }
            await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
        }))
        {
            using (var client = new ClientWebSocket())
            {
                client.Options.DangerousDeflateOptions = new WebSocketDeflateOptions()
                {
                    ServerMaxWindowBits = 12,
                    ClientMaxWindowBits = 11,
                };
                await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);

                var sendCount  = 8193;
                var clientBuf  = new byte[sendCount];
                var receiveBuf = new byte[sendCount];
                Random.Shared.NextBytes(clientBuf);
                await client.SendAsync(clientBuf.AsMemory(0, sendCount), WebSocketMessageType.Binary, true, default);

                var totalRecv = 0;
                while (totalRecv < sendCount)
                {
                    var result = await client.ReceiveAsync(receiveBuf.AsMemory(totalRecv), default);

                    totalRecv += result.Count;
                    if (result.EndOfMessage)
                    {
                        Assert.Equal(sendCount, totalRecv);
                        for (var i = 0; i < sendCount; ++i)
                        {
                            Assert.True(clientBuf[i] == receiveBuf[i], $"offset {i} not equal: {clientBuf[i]} == {receiveBuf[i]}");
                        }
                    }
                }

                await client.CloseAsync(WebSocketCloseStatus.NormalClosure, null, default);
            }
        }
    }
    public async Task SendFragmentedData_Success()
    {
        var orriginalData = Encoding.UTF8.GetBytes("Hello World");
        var tcs           = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            var serverBuffer = new byte[orriginalData.Length];
            var result = await webSocket.ReceiveAsync(new ArraySegment <byte>(serverBuffer), CancellationToken.None);
            Assert.False(result.EndOfMessage);
            Assert.Equal(2, result.Count);
            int totalReceived = result.Count;
            Assert.Equal(WebSocketMessageType.Binary, result.MessageType);
            tcs.SetResult();

            result = await webSocket.ReceiveAsync(
                new ArraySegment <byte>(serverBuffer, totalReceived, serverBuffer.Length - totalReceived), CancellationToken.None);
            Assert.False(result.EndOfMessage);
            Assert.Equal(2, result.Count);
            totalReceived += result.Count;
            Assert.Equal(WebSocketMessageType.Binary, result.MessageType);
            tcs.SetResult();

            result = await webSocket.ReceiveAsync(
                new ArraySegment <byte>(serverBuffer, totalReceived, serverBuffer.Length - totalReceived), CancellationToken.None);
            Assert.True(result.EndOfMessage);
            Assert.Equal(7, result.Count);
            totalReceived += result.Count;
            Assert.Equal(WebSocketMessageType.Binary, result.MessageType);

            Assert.Equal(orriginalData, serverBuffer);
        }))
        {
            using (var client = new ClientWebSocket())
            {
                await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);

                await client.SendAsync(new ArraySegment <byte>(orriginalData, 0, 2), WebSocketMessageType.Binary, false, CancellationToken.None);

                await tcs.Task;
                tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
                await client.SendAsync(new ArraySegment <byte>(orriginalData, 2, 2), WebSocketMessageType.Binary, false, CancellationToken.None);

                await tcs.Task;
                tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
                await client.SendAsync(new ArraySegment <byte>(orriginalData, 4, 7), WebSocketMessageType.Binary, true, CancellationToken.None);
            }
        }
    }
 public async Task Connect_Success()
 {
     await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
     {
         Assert.True(context.WebSockets.IsWebSocketRequest);
         var webSocket = await context.WebSockets.AcceptWebSocketAsync();
     }))
     {
         using (var client = new ClientWebSocket())
         {
             await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);
         }
     }
 }
    public async Task CommonHeadersAreSetToInternedStrings()
    {
        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            // Use ReferenceEquals and test against the constants
            Assert.Same(HeaderNames.Upgrade, context.Request.Headers.Connection.ToString());
            Assert.Same(Constants.Headers.UpgradeWebSocket, context.Request.Headers.Upgrade.ToString());
            Assert.Same(Constants.Headers.SupportedVersion, context.Request.Headers.SecWebSocketVersion.ToString());
        }))
        {
            using (var client = new ClientWebSocket())
            {
                await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);
            }
        }
    }
    public async Task OriginIsValidatedForWebSocketRequests(HttpStatusCode expectedCode, params string[] origins)
    {
        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            return(Task.CompletedTask);
        },
                                                                       o =>
        {
            if (origins != null)
            {
                foreach (var origin in origins)
                {
                    o.AllowedOrigins.Add(origin);
                }
            }
        }))
        {
            using (var client = new HttpClient())
            {
                var uri = new UriBuilder(new Uri($"ws://127.0.0.1:{port}/"));
                uri.Scheme = "http";

                // Craft a valid WebSocket Upgrade request
                using (var request = new HttpRequestMessage(HttpMethod.Get, uri.ToString()))
                {
                    request.Headers.Connection.Clear();
                    request.Headers.Connection.Add("Upgrade");
                    request.Headers.Upgrade.Add(new System.Net.Http.Headers.ProductHeaderValue("websocket"));
                    request.Headers.Add(HeaderNames.SecWebSocketVersion, "13");
                    // SecWebSocketKey required to be 16 bytes
                    request.Headers.Add(HeaderNames.SecWebSocketKey, Convert.ToBase64String(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, Base64FormattingOptions.None));

                    request.Headers.Add(HeaderNames.Origin, "http://example.com");

                    var response = await client.SendAsync(request);

                    Assert.Equal(expectedCode, response.StatusCode);
                }
            }
        }
    }
    public async Task CloseFromCloseReceived_Success()
    {
        string closeDescription = "Test Closed";

        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, closeDescription, CancellationToken.None);

            var serverBuffer = new byte[1024];
            var result = await webSocket.ReceiveAsync(new ArraySegment <byte>(serverBuffer), CancellationToken.None);
            Assert.True(result.EndOfMessage);
            Assert.Equal(0, result.Count);
            Assert.Equal(WebSocketMessageType.Close, result.MessageType);
            Assert.Equal(WebSocketCloseStatus.NormalClosure, result.CloseStatus);
            Assert.Equal(closeDescription, result.CloseStatusDescription);
        }))
        {
            using (var client = new ClientWebSocket())
            {
                await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);

                var clientBuffer = new byte[1024];
                var result       = await client.ReceiveAsync(new ArraySegment <byte>(clientBuffer), CancellationToken.None);

                Assert.True(result.EndOfMessage);
                Assert.Equal(0, result.Count);
                Assert.Equal(WebSocketMessageType.Close, result.MessageType);
                Assert.Equal(WebSocketCloseStatus.NormalClosure, result.CloseStatus);
                Assert.Equal(closeDescription, result.CloseStatusDescription);

                Assert.Equal(WebSocketState.CloseReceived, client.State);

                await client.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);

                Assert.Equal(WebSocketState.Closed, client.State);
            }
        }
    }
    public async Task SendEmptyData_Success()
    {
        await using (var server = KestrelWebSocketHelpers.CreateServer(LoggerFactory, out var port, async context =>
        {
            Assert.True(context.WebSockets.IsWebSocketRequest);
            var webSocket = await context.WebSockets.AcceptWebSocketAsync();

            var serverBuffer = new byte[0];
            var result = await webSocket.ReceiveAsync(new ArraySegment <byte>(serverBuffer), CancellationToken.None);
            Assert.True(result.EndOfMessage);
            Assert.Equal(0, result.Count);
            Assert.Equal(WebSocketMessageType.Binary, result.MessageType);
        }))
        {
            using (var client = new ClientWebSocket())
            {
                await client.ConnectAsync(new Uri($"ws://127.0.0.1:{port}/"), CancellationToken.None);

                var orriginalData = new byte[0];
                await client.SendAsync(new ArraySegment <byte>(orriginalData), WebSocketMessageType.Binary, true, CancellationToken.None);
            }
        }
    }