Esempio n. 1
0
        public async Task TransportClosesOnCloseTimeoutIfClientDoesNotSendCloseFrame()
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var options = new WebSocketOptions()
                    {
                        CloseTimeout = TimeSpan.FromSeconds(1)
                    };

                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(options, connection.Application, connectionContext, loggerFactory);

                    var serverSocket = await feature.AcceptAsync();

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(serverSocket);

                    // End the app
                    connection.Transport.Output.Complete();

                    await transport.OrTimeout(TimeSpan.FromSeconds(10));

                    // Now we're closed
                    Assert.Equal(WebSocketState.Aborted, serverSocket.State);

                    serverSocket.Dispose();
                }
            }
        }
Esempio n. 2
0
        public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientDoesNotSendCloseFrame()
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var options = new WebSocketOptions
                    {
                        CloseTimeout = TimeSpan.FromSeconds(1)
                    };

                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(options, connection.Application, connectionContext, loggerFactory);

                    var serverSocket = await feature.AcceptAsync();

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(serverSocket);

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // fail the client to server channel
                    connection.Transport.Output.Complete(new Exception());

                    await transport.OrTimeout();

                    Assert.Equal(WebSocketState.Aborted, serverSocket.State);
                }
            }
        }
Esempio n. 3
0
        public async Task ClientReceivesInternalServerErrorWhenTheApplicationFails()
        {
            using (StartLog(out var loggerFactory))
            {
                var transportToApplication = Channel.CreateUnbounded <byte[]>();
                var applicationToTransport = Channel.CreateUnbounded <byte[]>();

                using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                    using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                        using (var feature = new TestWebSocketConnectionFeature())
                        {
                            var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                            var ws = new WebSocketsTransport(new WebSocketOptions(), transportSide, connectionContext, loggerFactory);

                            // Give the server socket to the transport and run it
                            var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                            // Run the client socket
                            var client = feature.Client.ExecuteAndCaptureFramesAsync();

                            // Fail in the app
                            Assert.True(applicationSide.Writer.TryComplete(new InvalidOperationException("Catastrophic failure.")));
                            var clientSummary = await client.OrTimeout();

                            Assert.Equal(WebSocketCloseStatus.InternalServerError, clientSummary.CloseResult.CloseStatus);

                            // Close from the client
                            await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                            var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => transport.OrTimeout());

                            Assert.Equal("Catastrophic failure.", ex.Message);
                        }
            }
        }
Esempio n. 4
0
        public async Task ClientReceivesInternalServerErrorWhenTheApplicationFails()
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // Fail in the app
                    connection.Transport.Output.Complete(new InvalidOperationException("Catastrophic failure."));
                    var clientSummary = await client.OrTimeout();

                    Assert.Equal(WebSocketCloseStatus.InternalServerError, clientSummary.CloseResult.CloseStatus);

                    // Close from the client
                    await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                    await transport.OrTimeout();
                }
            }
        }
Esempio n. 5
0
        public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientDoesNotSendCloseFrame()
        {
            var transportToApplication = Channel.CreateUnbounded <byte[]>();
            var applicationToTransport = Channel.CreateUnbounded <byte[]>();

            using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                    using (var feature = new TestWebSocketConnectionFeature())
                    {
                        var options = new WebSocketOptions
                        {
                            CloseTimeout = TimeSpan.FromSeconds(1)
                        };

                        var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                        var ws = new WebSocketsTransport(options, transportSide, connectionContext, loggerFactory: new LoggerFactory());

                        var serverSocket = await feature.AcceptAsync();

                        // Give the server socket to the transport and run it
                        var transport = ws.ProcessSocketAsync(serverSocket);

                        // Run the client socket
                        var client = feature.Client.ExecuteAndCaptureFramesAsync();

                        // fail the client to server channel
                        applicationToTransport.Out.TryComplete(new Exception());

                        await Assert.ThrowsAsync <Exception>(() => transport).OrTimeout();

                        Assert.Equal(WebSocketState.Aborted, serverSocket.State);
                    }
        }
Esempio n. 6
0
        public async Task TransportClosesOnCloseTimeoutIfClientDoesNotSendCloseFrame()
        {
            var transportToApplication = Channel.CreateUnbounded <byte[]>();
            var applicationToTransport = Channel.CreateUnbounded <byte[]>();

            using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                    using (var feature = new TestWebSocketConnectionFeature())
                    {
                        var options = new WebSocketOptions()
                        {
                            CloseTimeout = TimeSpan.FromSeconds(1)
                        };

                        var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                        var ws = new WebSocketsTransport(options, transportSide, connectionContext, loggerFactory: new LoggerFactory());

                        var serverSocket = await feature.AcceptAsync();

                        // Give the server socket to the transport and run it
                        var transport = ws.ProcessSocketAsync(serverSocket);

                        // End the app
                        applicationSide.Dispose();

                        await transport.OrTimeout(TimeSpan.FromSeconds(10));

                        // Now we're closed
                        Assert.Equal(WebSocketState.Aborted, serverSocket.State);

                        serverSocket.Dispose();
                    }
        }
Esempio n. 7
0
        public async Task TransportCommunicatesErrorToApplicationWhenClientDisconnectsAbnormally()
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    async Task CompleteApplicationAfterTransportCompletes()
                    {
                        try
                        {
                            // Wait until the transport completes so that we can end the application
                            var result = await connection.Transport.Input.ReadAsync();

                            connection.Transport.Input.AdvanceTo(result.Buffer.End);
                        }
                        catch (Exception ex)
                        {
                            Assert.IsType <WebSocketError>(ex);
                        }
                        finally
                        {
                            // Complete the application so that the connection unwinds without aborting
                            connection.Transport.Output.Complete();
                        }
                    }

                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // When the close frame is received, we complete the application so the send
                    // loop unwinds
                    _ = CompleteApplicationAfterTransportCompletes();

                    // Terminate the client to server channel with an exception
                    feature.Client.SendAbort();

                    // Wait for the transport
                    await transport.OrTimeout();

                    await client.OrTimeout();
                }
            }
        }
Esempio n. 8
0
        public async Task ReceivedFramesAreWrittenToChannel(WebSocketMessageType webSocketMessageType)
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // Send a frame, then close
                    await feature.Client.SendAsync(
                        buffer : new ArraySegment <byte>(Encoding.UTF8.GetBytes("Hello")),
                        messageType : webSocketMessageType,
                        endOfMessage : true,
                        cancellationToken : CancellationToken.None);

                    await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                    var result = await connection.Transport.Input.ReadAsync();

                    var buffer = result.Buffer;
                    Assert.Equal("Hello", Encoding.UTF8.GetString(buffer.ToArray()));
                    connection.Transport.Input.AdvanceTo(buffer.End);

                    connection.Transport.Output.Complete();

                    // The transport should finish now
                    await transport;

                    // The connection should close after this, which means the client will get a close frame.
                    var clientSummary = await client;

                    Assert.Equal(WebSocketCloseStatus.NormalClosure, clientSummary.CloseResult.CloseStatus);
                }
            }
        }
Esempio n. 9
0
        public async Task ReceivedFramesAreWrittenToChannel(WebSocketMessageType webSocketMessageType)
        {
            using (StartLog(out var loggerFactory))
            {
                var transportToApplication = Channel.CreateUnbounded <byte[]>();
                var applicationToTransport = Channel.CreateUnbounded <byte[]>();

                using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                    using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                        using (var feature = new TestWebSocketConnectionFeature())
                        {
                            var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                            var ws = new WebSocketsTransport(new WebSocketOptions(), transportSide, connectionContext, loggerFactory);

                            // Give the server socket to the transport and run it
                            var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                            // Run the client socket
                            var client = feature.Client.ExecuteAndCaptureFramesAsync();

                            // Send a frame, then close
                            await feature.Client.SendAsync(
                                buffer : new ArraySegment <byte>(Encoding.UTF8.GetBytes("Hello")),
                                messageType : webSocketMessageType,
                                endOfMessage : true,
                                cancellationToken : CancellationToken.None);

                            await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                            var buffer = await applicationSide.Reader.ReadAsync();

                            Assert.Equal("Hello", Encoding.UTF8.GetString(buffer));

                            Assert.True(applicationSide.Writer.TryComplete());

                            // The transport should finish now
                            await transport;

                            // The connection should close after this, which means the client will get a close frame.
                            var clientSummary = await client;

                            Assert.Equal(WebSocketCloseStatus.NormalClosure, clientSummary.CloseResult.CloseStatus);
                        }
            }
        }
Esempio n. 10
0
        public async Task TransportFailsWhenClientDisconnectsAbnormally()
        {
            using (StartLog(out var loggerFactory))
            {
                var transportToApplication = Channel.CreateUnbounded <byte[]>();
                var applicationToTransport = Channel.CreateUnbounded <byte[]>();

                using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                    using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                        using (var feature = new TestWebSocketConnectionFeature())
                        {
                            async Task CompleteApplicationAfterTransportCompletes()
                            {
                                // Wait until the transport completes so that we can end the application
                                await applicationSide.Reader.WaitToReadAsync();

                                // Complete the application so that the connection unwinds without aborting
                                applicationSide.Writer.TryComplete();
                            }

                            var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                            var ws = new WebSocketsTransport(new WebSocketOptions(), transportSide, connectionContext, loggerFactory);

                            // Give the server socket to the transport and run it
                            var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                            // Run the client socket
                            var client = feature.Client.ExecuteAndCaptureFramesAsync();

                            // When the close frame is received, we complete the application so the send
                            // loop unwinds
                            _ = CompleteApplicationAfterTransportCompletes();

                            // Terminate the client to server channel with an exception
                            feature.Client.SendAbort();

                            // Wait for the transport
                            await Assert.ThrowsAsync <WebSocketException>(() => transport).OrTimeout();

                            var summary = await client.OrTimeout();

                            Assert.Equal(WebSocketCloseStatus.InternalServerError, summary.CloseResult.CloseStatus);
                        }
            }
        }
Esempio n. 11
0
        public async Task WebSocketTransportSetsMessageTypeBasedOnTransferModeFeature(TransferMode transferMode, WebSocketMessageType expectedMessageType)
        {
            using (StartLog(out var loggerFactory))
            {
                var transportToApplication = Channel.CreateUnbounded <byte[]>();
                var applicationToTransport = Channel.CreateUnbounded <byte[]>();

                using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                    using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                        using (var feature = new TestWebSocketConnectionFeature())
                        {
                            var connectionContext = new DefaultConnectionContext(string.Empty, null, null)
                            {
                                TransferMode = transferMode
                            };
                            var ws = new WebSocketsTransport(new WebSocketOptions(), transportSide, connectionContext, loggerFactory);

                            // Give the server socket to the transport and run it
                            var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                            // Run the client socket
                            var client = feature.Client.ExecuteAndCaptureFramesAsync();

                            // Write to the output channel, and then complete it
                            await applicationSide.Writer.WriteAsync(Encoding.UTF8.GetBytes("Hello"));

                            Assert.True(applicationSide.Writer.TryComplete());

                            // The client should finish now, as should the server
                            var clientSummary = await client;
                            await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                            await transport;

                            Assert.Equal(1, clientSummary.Received.Count);
                            Assert.True(clientSummary.Received[0].EndOfMessage);
                            Assert.Equal(expectedMessageType, clientSummary.Received[0].MessageType);
                            Assert.Equal("Hello", Encoding.UTF8.GetString(clientSummary.Received[0].Buffer));
                        }
            }
        }
Esempio n. 12
0
        public async Task ServerGracefullyClosesWhenApplicationEndsThenClientSendsCloseFrame()
        {
            using (StartLog(out var loggerFactory))
            {
                var transportToApplication = Channel.CreateUnbounded <byte[]>();
                var applicationToTransport = Channel.CreateUnbounded <byte[]>();

                using (var transportSide = ChannelConnection.Create <byte[]>(applicationToTransport, transportToApplication))
                    using (var applicationSide = ChannelConnection.Create <byte[]>(transportToApplication, applicationToTransport))
                        using (var feature = new TestWebSocketConnectionFeature())
                        {
                            var options = new WebSocketOptions
                            {
                                // We want to verify behavior without timeout affecting it
                                CloseTimeout = TimeSpan.FromSeconds(20)
                            };

                            var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                            var ws = new WebSocketsTransport(options, transportSide, connectionContext, loggerFactory);

                            var serverSocket = await feature.AcceptAsync();

                            // Give the server socket to the transport and run it
                            var transport = ws.ProcessSocketAsync(serverSocket);

                            // Run the client socket
                            var client = feature.Client.ExecuteAndCaptureFramesAsync();

                            // close the client to server channel
                            applicationToTransport.Writer.TryComplete();

                            _ = await client.OrTimeout();

                            await feature.Client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None).OrTimeout();

                            await transport.OrTimeout();

                            Assert.Equal(WebSocketCloseStatus.NormalClosure, serverSocket.CloseStatus);
                        }
            }
        }
Esempio n. 13
0
        public async Task ServerGracefullyClosesWhenApplicationEndsThenClientSendsCloseFrame()
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var options = new WebSocketOptions
                    {
                        // We want to verify behavior without timeout affecting it
                        CloseTimeout = TimeSpan.FromSeconds(20)
                    };

                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsTransport(options, connection.Application, connectionContext, loggerFactory);

                    var serverSocket = await feature.AcceptAsync();

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(serverSocket);

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // close the client to server channel
                    connection.Transport.Output.Complete();

                    _ = await client.OrTimeout();

                    await feature.Client.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None).OrTimeout();

                    await transport.OrTimeout();

                    Assert.Equal(WebSocketCloseStatus.NormalClosure, serverSocket.CloseStatus);
                }
            }
        }
Esempio n. 14
0
        public async Task WebSocketTransportSetsMessageTypeBasedOnTransferFormatFeature(TransferFormat transferFormat, WebSocketMessageType expectedMessageType)
        {
            using (StartLog(out var loggerFactory, LogLevel.Debug))
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);

                using (var feature = new TestWebSocketConnectionFeature())
                {
                    var connectionContext = new DefaultConnectionContext(string.Empty, null, null);
                    connectionContext.ActiveFormat = transferFormat;
                    var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);

                    // Give the server socket to the transport and run it
                    var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());

                    // Run the client socket
                    var client = feature.Client.ExecuteAndCaptureFramesAsync();

                    // Write to the output channel, and then complete it
                    await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello"));

                    connection.Transport.Output.Complete();

                    // The client should finish now, as should the server
                    var clientSummary = await client;
                    await feature.Client.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

                    await transport;

                    Assert.Equal(1, clientSummary.Received.Count);
                    Assert.True(clientSummary.Received[0].EndOfMessage);
                    Assert.Equal(expectedMessageType, clientSummary.Received[0].MessageType);
                    Assert.Equal("Hello", Encoding.UTF8.GetString(clientSummary.Received[0].Buffer));
                }
            }
        }