Пример #1
0
        public async Task SSEWritesMessages()
        {
            using (StartVerifiableLog())
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
                var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
                var context    = new DefaultHttpContext();

                var ms = new MemoryStream();
                context.Response.Body = ms;
                var sse = new ServerSentEventsServerTransport(connection.Application.Input, connectionId: string.Empty, LoggerFactory);

                var task = sse.ProcessRequestAsync(context, context.RequestAborted);

                await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes("Hello"));

                connection.Transport.Output.Complete();
                await task.OrTimeout();

                Assert.Equal(":\r\ndata: Hello\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
            }
        }
Пример #2
0
        public async Task ClientJoinedPacketSent()
        {
            var manager     = new ChatRoomManager();
            var roomId      = manager.CreateChatRoom();
            var room        = manager.GetChatRoom(roomId);
            var duplexPipe1 = new DuplexPipe();
            var connection1 = new Connection(duplexPipe1, null, null);
            var client1     = new ChatClient(connection1, manager);

            room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", "128450673"));
            room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Alice", "94371960"));

            var authenticationPacket1 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };
            await duplexPipe1.ReceivePipe.Writer.WriteAsync(authenticationPacket1);

            await duplexPipe1.ReceivePipe.Writer.FlushAsync();

            var duplexPipe2           = new DuplexPipe();
            var connection2           = new Connection(duplexPipe2, null, null);
            var client2               = new ChatClient(connection2, manager);
            var authenticationPacket2 = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xC5, 0xFB, 0x98, 0xCB, 0xFE, 0x92, 0xCA, 0xFF, 0xAB, 0xFC };
            await duplexPipe2.ReceivePipe.Writer.WriteAsync(authenticationPacket2);

            await duplexPipe2.ReceivePipe.Writer.FlushAsync();

            var expectedPacket = new byte[]
            {
                0xC1, 0x0F, 0x01, 0x00, 0x01, 0x41, 0x6C, 0x69, 0x63, 0x65, 0, 0, 0, 0, 0,
            };

            var readResult = await duplexPipe1.SendPipe.Reader.ReadAsync();

            var result = readResult.Buffer.ToArray().TakeLast(expectedPacket.Length).ToArray();

            Assert.That(result, Is.EquivalentTo(expectedPacket));
            Assert.That(client1.Nickname, Is.EqualTo("Bob"));
            Assert.That(client2.Nickname, Is.EqualTo("Alice"));
        }
Пример #3
0
        public async Task TransportFailsOnTimeoutWithErrorWhenApplicationFailsAndClientDoesNotSendCloseFrame()
        {
            using (StartVerifiableLog())
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
                {
                    Transport   = pair.Transport,
                    Application = pair.Application,
                };

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

                    var connectionContext = new HttpConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsServerTransport(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);
                }
            }
        }
Пример #4
0
        public async Task SSETransportStopsWithErrorIfServerSendsIncompleteResults()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();

                var mockStream = new Mock <Stream>();
                mockStream
                .Setup(s => s.CopyToAsync(It.IsAny <Stream>(), It.IsAny <int>(), It.IsAny <CancellationToken>()))
                .Returns <Stream, int, CancellationToken>(async(stream, bufferSize, t) =>
                {
                    var buffer = Encoding.ASCII.GetBytes("data: 3:a");
                    await stream.WriteAsync(buffer, 0, buffer.Length);
                });
                mockStream.Setup(s => s.CanRead).Returns(true);

                return(new HttpResponseMessage {
                    Content = new StreamContent(mockStream.Object)
                });
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var sseTransport = new ServerSentEventsTransport(httpClient);

                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                await sseTransport.StartAsync(
                    new Uri("http://fakeuri.org"), pair.Application, TransferMode.Text, connection : Mock.Of <IConnection>()).OrTimeout();

                var exception = await Assert.ThrowsAsync <FormatException>(() => sseTransport.Running.OrTimeout());

                Assert.Equal("Incomplete message.", exception.Message);
            }
        }
Пример #5
0
        public async Task ServerGracefullyClosesWhenClientSendsCloseFrameThenApplicationEnds()
        {
            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();

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

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

                    _ = await client.OrTimeout();

                    await transport.OrTimeout();

                    Assert.Equal(WebSocketCloseStatus.NormalClosure, serverSocket.CloseStatus);
                }
            }
        }
Пример #6
0
        public async Task TransportClosesOnCloseTimeoutIfClientDoesNotSendCloseFrame()
        {
            using (StartVerifiableLog())
            {
                var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var connection = new HttpConnectionContext("foo", connectionToken: null, LoggerFactory.CreateLogger(nameof(HttpConnectionContext)))
                {
                    Transport   = pair.Transport,
                    Application = pair.Application,
                };

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

                    var connectionContext = new HttpConnectionContext(string.Empty, null, null);
                    var ws = new WebSocketsServerTransport(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();
                }
            }
        }
        public void GlobalSetup()
        {
            var serviceCollection = new ServiceCollection();
            serviceCollection.AddSignalRCore();

            var provider = serviceCollection.BuildServiceProvider();

            var serviceScopeFactory = provider.GetService<IServiceScopeFactory>();

            _dispatcher = new DefaultHubDispatcher<TestHub>(
                serviceScopeFactory,
                new HubContext<TestHub>(new DefaultHubLifetimeManager<TestHub>(NullLogger<DefaultHubLifetimeManager<TestHub>>.Instance)),
                Options.Create(new HubOptions<TestHub>()),
                Options.Create(new HubOptions()),
                new Logger<DefaultHubDispatcher<TestHub>>(NullLoggerFactory.Instance));

            var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
            var connection = new DefaultConnectionContext(Guid.NewGuid().ToString(), pair.Application, pair.Transport);

            _connectionContext = new NoErrorHubConnectionContext(connection, TimeSpan.Zero, NullLoggerFactory.Instance);

            _connectionContext.Protocol = new FakeHubProtocol();
        }
Пример #8
0
        public HttpConnectionTests()
        {
            _memoryPool = KestrelMemoryPool.Create();
            var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _httpConnectionContext = new HttpConnectionContext
            {
                ConnectionId       = "0123456789",
                ConnectionAdapters = new List <IConnectionAdapter>(),
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _memoryPool,
                HttpConnectionId   = long.MinValue,
                Application        = pair.Application,
                Transport          = pair.Transport,
                ServiceContext     = new TestServiceContext
                {
                    SystemClock = new SystemClock()
                }
            };

            _httpConnection = new HttpConnection(_httpConnectionContext);
        }
        public HttpProtocolFeatureCollectionTests()
        {
            _memoryPool = KestrelMemoryPool.Create();
            var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
            var pair    = DuplexPipe.CreateConnectionPair(options, options);

            _transport   = pair.Transport;
            _application = pair.Application;

            _serviceContext         = new TestServiceContext();
            _http1ConnectionContext = new HttpConnectionContext
            {
                ServiceContext     = _serviceContext,
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _memoryPool,
                TimeoutControl     = Mock.Of <ITimeoutControl>(),
                Transport          = pair.Transport
            };

            _http1Connection = new TestHttp1Connection(_http1ConnectionContext);
            _http1Connection.Reset();
            _collection = _http1Connection;
        }
Пример #10
0
        public async Task SSEWritesVeryLargeMessages()
        {
            var pair       = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
            var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
            var context    = new DefaultHttpContext();

            var ms = new MemoryStream();

            context.Response.Body = ms;
            var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory: new LoggerFactory());

            var task = sse.ProcessRequestAsync(context, context.RequestAborted);

            string hText = new string('H', 60000);
            string wText = new string('W', 60000);

            await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes(hText + wText));

            connection.Transport.Output.Complete();
            await task.OrTimeout();

            Assert.Equal(":\r\ndata: " + hText + wText + "\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
        }
Пример #11
0
        private async ValueTask TestException(Action <InvalidPacketHeaderException> check)
        {
            bool thrown     = false;
            var  duplexPipe = new DuplexPipe();

            using var connection = new Connection(duplexPipe, null, new Xor.PipelinedXor32Encryptor(duplexPipe.Output), new NullLogger <Connection>());
            _ = connection.BeginReceive();
            try
            {
                await duplexPipe.ReceivePipe.Writer.WriteAsync(this.malformedData);
            }
            catch (InvalidPacketHeaderException e)
            {
                thrown = true;
                check(e);
            }
            catch (Exception e)
            {
                Assert.Fail($"Wrong exception type {e}", e);
            }

            Assert.That(thrown);
        }
    public void InitialDictionaryIsEmpty()
    {
        using (var memoryPool = PinnedBlockMemoryPoolFactory.Create())
        {
            var options = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
            var pair    = DuplexPipe.CreateConnectionPair(options, options);
            var http1ConnectionContext = TestContextFactory.CreateHttpConnectionContext(
                serviceContext: new TestServiceContext(),
                connectionContext: Mock.Of <ConnectionContext>(),
                transport: pair.Transport,
                memoryPool: memoryPool,
                connectionFeatures: new FeatureCollection());

            var http1Connection = new Http1Connection(http1ConnectionContext);

            http1Connection.Reset();

            IDictionary <string, StringValues> headers = http1Connection.ResponseHeaders;

            Assert.Equal(0, headers.Count);
            Assert.False(headers.IsReadOnly);
        }
    }
Пример #13
0
        public Http1ConnectionTests()
        {
            _pipelineFactory = new MemoryPool();
            var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory);

            _transport   = pair.Transport;
            _application = pair.Application;

            _serviceContext         = new TestServiceContext();
            _timeoutControl         = new Mock <ITimeoutControl>();
            _http1ConnectionContext = new Http1ConnectionContext
            {
                ServiceContext     = _serviceContext,
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _pipelineFactory,
                TimeoutControl     = _timeoutControl.Object,
                Application        = pair.Application,
                Transport          = pair.Transport
            };

            _http1Connection = new TestHttp1Connection(_http1ConnectionContext);
            _http1Connection.Reset();
        }
Пример #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));
                }
            }
        }
Пример #15
0
        public PipeSocket(Socket socket,
                          MemoryPool <byte> memoryPool,
                          PipeScheduler scheduler,
                          long?maxReadBufferSize  = null,
                          long?maxWriteBufferSize = null,
                          bool waitForData        = true)
        {
            _socket      = socket;
            MemoryPool   = memoryPool;
            _waitForData = waitForData;
            // On *nix platforms, Sockets already dispatches to the ThreadPool.
            // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
            // https://github.com/aspnet/KestrelHttpServer/issues/2573
            // var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;

            maxReadBufferSize ??= 0;
            maxWriteBufferSize ??= 0;

            var inputOptions  = new PipeOptions(MemoryPool, PipeScheduler.ThreadPool, scheduler, maxReadBufferSize.Value, maxReadBufferSize.Value / 2, useSynchronizationContext: false);
            var outputOptions = new PipeOptions(MemoryPool, scheduler, PipeScheduler.ThreadPool, maxWriteBufferSize.Value, maxWriteBufferSize.Value / 2, useSynchronizationContext: false);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);


            Transport   = pair.Transport;
            Application = pair.Application;



            var awaiterScheduler = IsWindows ? scheduler : PipeScheduler.Inline;

            _receiver = new SocketReceiver(_socket, awaiterScheduler);
            _sender   = new SocketSender(_socket, awaiterScheduler);

            maxReadBufferSize ??= 0;
            maxWriteBufferSize ??= 0;
        }
Пример #16
0
    public async Task ExistingPipe_Send_Accept_Recv_Send()
    {
        var packets = new byte[][]
        {
            new byte[] { 1, 2, 3 },
            new byte[] { 4, 5, 6 },
            new byte[] { 7, 8, 9 },
        };

        var channel2OutboundPipe = new Pipe();
        var channel2InboundPipe  = new Pipe();
        var channel2Stream       = new DuplexPipe(channel2InboundPipe.Reader, channel2OutboundPipe.Writer).AsStream();
        var channel2Options      = new MultiplexingStream.ChannelOptions {
            ExistingPipe = new DuplexPipe(channel2OutboundPipe.Reader, channel2InboundPipe.Writer)
        };

        // Create the channel and transmit before it is accepted.
        var channel1       = this.mx1.CreateChannel();
        var channel1Stream = channel1.AsStream();
        await channel1Stream.WriteAsync(packets[0], 0, packets[0].Length, this.TimeoutToken);

        await channel1Stream.FlushAsync(this.TimeoutToken);

        // Accept the channel and read the bytes
        await this.WaitForEphemeralChannelOfferToPropagate();

        var channel2 = this.mx2.AcceptChannel(channel1.Id, channel2Options);

        await this.VerifyReceivedDataAsync(channel2Stream, packets[0]);

        // Verify we can transmit via the ExistingPipe.
        await this.TransmitAndVerifyAsync(channel2Stream, channel1Stream, packets[1]);

        // Verify we can receive more bytes via the ExistingPipe.
        // MANUALLY VERIFY with debugger that received bytes are read DIRECTLY into channel2InboundPipe.Writer (no intermediary buffer copying).
        await this.TransmitAndVerifyAsync(channel1Stream, channel2Stream, packets[2]);
    }
Пример #17
0
        internal SocketConnection(Socket socket,
                                  MemoryPool <byte> memoryPool,
                                  PipeScheduler transportScheduler,
                                  ISocketsTrace trace,
                                  SocketSenderPool socketSenderPool,
                                  PipeOptions inputOptions,
                                  PipeOptions outputOptions,
                                  bool waitForData = true)
        {
            Debug.Assert(socket != null);
            Debug.Assert(memoryPool != null);
            Debug.Assert(trace != null);

            _socket           = socket;
            MemoryPool        = memoryPool;
            _trace            = trace;
            _waitForData      = waitForData;
            _socketSenderPool = socketSenderPool;

            LocalEndPoint  = _socket.LocalEndPoint;
            RemoteEndPoint = _socket.RemoteEndPoint;

            ConnectionClosed = _connectionClosedTokenSource.Token;

            // On *nix platforms, Sockets already dispatches to the ThreadPool.
            // Yes, the IOQueues are still used for the PipeSchedulers. This is intentional.
            // https://github.com/aspnet/KestrelHttpServer/issues/2573
            var awaiterScheduler = OperatingSystem.IsWindows() ? transportScheduler : PipeScheduler.Inline;

            _receiver = new SocketReceiver(awaiterScheduler);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);

            // Set the transport and connection id
            Transport   = _originalTransport = pair.Transport;
            Application = pair.Application;
        }
Пример #18
0
        public async Task LongPollingTransportStopsWhenSendRequestFails()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                var statusCode = request.Method == HttpMethod.Post
                        ? HttpStatusCode.InternalServerError
                        : HttpStatusCode.OK;
                return(ResponseUtils.CreateResponse(statusCode));
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var longPollingTransport = new LongPollingTransport(httpClient);
                try
                {
                    var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                    await longPollingTransport.StartAsync(new Uri("http://fakeuri.org"), pair.Application, TransferFormat.Binary, connection : new TestConnection());

                    await pair.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));

                    await Assert.ThrowsAsync <HttpRequestException>(async() => await longPollingTransport.Running.OrTimeout());

                    var exception = await Assert.ThrowsAsync <HttpRequestException>(async() => await pair.Transport.Input.ReadAllAsync().OrTimeout());

                    Assert.Contains(" 500 ", exception.Message);
                }
                finally
                {
                    await longPollingTransport.StopAsync();
                }
            }
        }
    public HttpProtocolFeatureCollection()
    {
        var memoryPool = PinnedBlockMemoryPoolFactory.Create();
        var options    = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
        var pair       = DuplexPipe.CreateConnectionPair(options, options);

        var serviceContext = TestContextFactory.CreateServiceContext(
            serverOptions: new KestrelServerOptions(),
            httpParser: new HttpParser <Http1ParsingHandler>(),
            dateHeaderValueManager: new DateHeaderValueManager());

        var connectionContext = TestContextFactory.CreateHttpConnectionContext(
            serviceContext: serviceContext,
            connectionContext: null,
            transport: pair.Transport,
            memoryPool: memoryPool,
            connectionFeatures: new FeatureCollection());

        var http1Connection = new Http1Connection(connectionContext);

        http1Connection.Reset();

        _collection = http1Connection;
    }
Пример #20
0
        public async Task SSETransportDoesNotSupportBinary()
        {
            var mockHttpHandler = new Mock <HttpMessageHandler>();

            mockHttpHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .Returns <HttpRequestMessage, CancellationToken>(async(request, cancellationToken) =>
            {
                await Task.Yield();
                return(new HttpResponseMessage {
                    Content = new StringContent(string.Empty)
                });
            });

            using (var httpClient = new HttpClient(mockHttpHandler.Object))
            {
                var sseTransport = new ServerSentEventsTransport(httpClient);

                var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
                var ex   = await Assert.ThrowsAsync <ArgumentException>(() => sseTransport.StartAsync(new Uri("http://fakeuri.org"), pair.Application, TransferFormat.Binary, connection : Mock.Of <IConnection>()).OrTimeout());

                Assert.Equal($"The 'Binary' transfer format is not supported by this transport.{Environment.NewLine}Parameter name: transferFormat", ex.Message);
            }
        }
    public virtual void GlobalSetup()
    {
        _memoryPool = PinnedBlockMemoryPoolFactory.Create();
        _httpFrame  = new Http2Frame();

        var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);

        _connectionPair = DuplexPipe.CreateConnectionPair(options, options);

        _httpRequestHeaders = new HttpRequestHeaders();
        _httpRequestHeaders[HeaderNames.Method]    = new StringValues("GET");
        _httpRequestHeaders[HeaderNames.Path]      = new StringValues("/");
        _httpRequestHeaders[HeaderNames.Scheme]    = new StringValues("http");
        _httpRequestHeaders[HeaderNames.Authority] = new StringValues("localhost:80");

        _headersBuffer = new byte[1024 * 16];
        _hpackEncoder  = new DynamicHPackEncoder();

        var serviceContext = TestContextFactory.CreateServiceContext(
            serverOptions: new KestrelServerOptions(),
            dateHeaderValueManager: new DateHeaderValueManager(),
            systemClock: new MockSystemClock());

        serviceContext.DateHeaderValueManager.OnHeartbeat(default);
Пример #22
0
        public void Setup()
        {
            var memoryPool = SlabMemoryPoolFactory.Create();
            var options    = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
            var pair       = DuplexPipe.CreateConnectionPair(options, options);

            var serviceContext = TestContextFactory.CreateServiceContext(
                serverOptions: new KestrelServerOptions(),
                httpParser: new HttpParser <Http1ParsingHandler>());

            var connectionContext = TestContextFactory.CreateHttpConnectionContext(
                serviceContext: serviceContext,
                connectionContext: null,
                transport: pair.Transport,
                timeoutControl: new TimeoutControl(timeoutHandler: null),
                memoryPool: memoryPool,
                connectionFeatures: new FeatureCollection());

            var http1Connection = new Http1Connection(connectionContext);

            http1Connection.Reset();

            Connection = http1Connection;
        }
Пример #23
0
    public async Task ReaderOnly()
    {
        var pipe   = new Pipe();
        var duplex = new DuplexPipe(pipe.Reader);

        // Our assert strategy is to verify our no-op writer behaves the same way as a completed writer.
        pipe.Writer.Complete();
        Assert.Throws <InvalidOperationException>(() => pipe.Writer.GetMemory());
        Assert.Throws <InvalidOperationException>(() => duplex.Output.GetMemory());

        Assert.Throws <InvalidOperationException>(() => pipe.Writer.GetSpan());
        Assert.Throws <InvalidOperationException>(() => duplex.Output.GetSpan());

        // System.IO.Pipelines stopped throwing when Advance(0) is called after completion,
        // But we still feel it's useful to throw since it's a read-only pipe.
        pipe.Writer.Advance(0);
        Assert.Throws <InvalidOperationException>(() => duplex.Output.Advance(0));

        FlushResult flushResult = await pipe.Writer.FlushAsync();

        Assert.False(flushResult.IsCompleted);
        flushResult = await duplex.Output.FlushAsync();

        Assert.False(flushResult.IsCompleted);

        pipe.Writer.CancelPendingFlush();
        duplex.Output.CancelPendingFlush();

#pragma warning disable CS0618 // Type or member is obsolete
        pipe.Writer.OnReaderCompleted((ex, s) => { }, null);
        duplex.Output.OnReaderCompleted((ex, s) => { }, null);
#pragma warning restore CS0618 // Type or member is obsolete

        pipe.Writer.Complete();
        duplex.Output.Complete();
    }
Пример #24
0
        public async Task RoomClientListSentAfterJoin()
        {
            var manager    = new ChatRoomManager();
            var roomId     = manager.CreateChatRoom();
            var room       = manager.GetChatRoom(roomId);
            var duplexPipe = new DuplexPipe();
            var connection = new Connection(duplexPipe, null, null);
            var client     = new ChatClient(connection, manager);

            room.RegisterClient(new ChatServerAuthenticationInfo(room.GetNextClientIndex(), roomId, "Bob", "128450673"));

            var authenticationPacket = new byte[] { 0xC1, 0x10, 0x00, 0x00, (byte)roomId, (byte)(roomId >> 8), 0xCD, 0xFD, 0x93, 0xC8, 0xFA, 0x9B, 0xCA, 0xF8, 0x98, 0xFC };

            duplexPipe.ReceivePipe.Writer.Write(authenticationPacket);
            await duplexPipe.ReceivePipe.Writer.FlushAsync();

            var expectedPacket = new byte[] { 0xC2, 0x00, 0x13, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x42, 0x6F, 0x62, 0, 0, 0, 0, 0, 0, 0 };
            var readResult     = await duplexPipe.SendPipe.Reader.ReadAsync();

            var result = readResult.Buffer.ToArray();

            Assert.That(result, Is.EquivalentTo(expectedPacket));
            Assert.That(client.Nickname, Is.EqualTo("Bob"));
        }
Пример #25
0
        internal async Task <(ConnectionLoop, ConnectionLoop)> ConnectTo(TestNode other)
        {
            var pipe = DuplexPipe.CreateConnection(PipeOptions.Default, PipeOptions.Default);

            var(conn, descriptor)   = this.CreateConnection(pipe.Application);
            var(conn2, descriptor2) = other.CreateConnection(pipe.Transport);
            // manually start outbound connection from node A.
            var initialSend = PeerManager.NewOutboundConnection(descriptor, other.NodeConfig.KeysManager.GetNodeSecret().PubKey.ToBytes());
            await pipe.Application.Output.WriteAsync(initialSend);

            var flushResult = pipe.Application.Output.FlushAsync();

            if (!flushResult.IsCompleted)
            {
                await flushResult.ConfigureAwait(false);
            }

            // manually start inbound connection for node B.
            other.PeerManager.NewInboundConnection(descriptor2);

            conn.Start();
            conn2.Start();
            return(conn, conn2);
        }
        private Http1OutputProducer CreateOutputProducer(PipeOptions pipeOptions, CancellationTokenSource cts = null)
        {
            var pair = DuplexPipe.CreateConnectionPair(pipeOptions, pipeOptions);

            var logger         = new TestApplicationErrorLogger();
            var serviceContext = new TestServiceContext
            {
                Log        = new TestKestrelTrace(logger),
                ThreadPool = new InlineLoggingThreadPool(new TestKestrelTrace(logger))
            };
            var transportContext = new TestLibuvTransportContext {
                Log = new LibuvTrace(logger)
            };

            var socket   = new MockSocket(_mockLibuv, _libuvThread.Loop.ThreadId, transportContext.Log);
            var consumer = new LibuvOutputConsumer(pair.Application.Input, _libuvThread, socket, "0", transportContext.Log);

            var http1Connection = new Http1Connection(new Http1ConnectionContext
            {
                ServiceContext     = serviceContext,
                ConnectionFeatures = new FeatureCollection(),
                MemoryPool         = _memoryPool,
                TimeoutControl     = Mock.Of <ITimeoutControl>(),
                Application        = pair.Application,
                Transport          = pair.Transport
            });

            if (cts != null)
            {
                http1Connection.RequestAborted.Register(cts.Cancel);
            }

            var ignore = WriteOutputAsync(consumer, pair.Application.Input, http1Connection);

            return((Http1OutputProducer)http1Connection.Output);
        }
Пример #27
0
        public void OnConnection(IFeatureCollection features)
        {
            var connectionContext = new DefaultConnectionContext(features);

            var transportFeature = connectionContext.Features.Get <IConnectionTransportFeature>();

            // REVIEW: Unfortunately, we still need to use the service context to create the pipes since the settings
            // for the scheduler and limits are specified here
            var inputOptions  = GetInputPipeOptions(_serviceContext, transportFeature.MemoryPool, transportFeature.InputWriterScheduler);
            var outputOptions = GetOutputPipeOptions(_serviceContext, transportFeature.MemoryPool, transportFeature.OutputReaderScheduler);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);

            // Set the transport and connection id
            connectionContext.ConnectionId = CorrelationIdGenerator.GetNextId();
            connectionContext.Transport    = pair.Transport;

            // This *must* be set before returning from OnConnection
            transportFeature.Application = pair.Application;

            // REVIEW: This task should be tracked by the server for graceful shutdown
            // Today it's handled specifically for http but not for aribitrary middleware
            _ = Execute(connectionContext);
        }
Пример #28
0
        public void Launch(string url, string username)
        {
            if (Running)
            {
                Destroy();
                isClosing = false;
            }

            lastUrl      = url;
            lastUsername = username;

            try{
                currentPipe         = DuplexPipe.CreateServer();
                currentPipe.DataIn += currentPipe_DataIn;

                if ((currentProcess = Process.Start(new ProcessStartInfo {
                    FileName = Path.Combine(Program.ProgramPath, "TweetDuck.Video.exe"),
                    Arguments = $"{owner.Handle} {Program.UserConfig.VideoPlayerVolume} \"{url}\" \"{currentPipe.GenerateToken()}\"",
                    UseShellExecute = false,
                    RedirectStandardOutput = true
                })) != null)
                {
                    currentProcess.EnableRaisingEvents = true;
                    currentProcess.Exited += process_Exited;

                    #if DEBUG
                    currentProcess.BeginOutputReadLine();
                    currentProcess.OutputDataReceived += (sender, args) => Debug.WriteLine("VideoPlayer: " + args.Data);
                    #endif
                }

                currentPipe.DisposeToken();
            }catch (Exception e) {
                Program.Reporter.HandleException("Video Playback Error", "Error launching video player.", true, e);
            }
        }
Пример #29
0
        public async Task CopyToAsyncDoesNotCopyBlocks()
        {
            var writeCount      = 0;
            var writeTcs        = new TaskCompletionSource <(byte[], int, int)>();
            var mockDestination = new Mock <Stream>()
            {
                CallBase = true
            };

            mockDestination
            .Setup(m => m.WriteAsync(It.IsAny <byte[]>(), It.IsAny <int>(), It.IsAny <int>(), CancellationToken.None))
            .Callback((byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
            {
                writeTcs.SetResult((buffer, offset, count));
                writeCount++;
            })
            .Returns(Task.CompletedTask);

            using (var memoryPool = KestrelMemoryPool.Create())
            {
                var options                = new PipeOptions(pool: memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
                var pair                   = DuplexPipe.CreateConnectionPair(options, options);
                var transport              = pair.Transport;
                var application            = pair.Application;
                var http1ConnectionContext = new Http1ConnectionContext
                {
                    ServiceContext     = new TestServiceContext(),
                    ConnectionFeatures = new FeatureCollection(),
                    Application        = application,
                    Transport          = transport,
                    MemoryPool         = memoryPool,
                    TimeoutControl     = Mock.Of <ITimeoutControl>()
                };
                var http1Connection = new Http1Connection(http1ConnectionContext)
                {
                    HasStartedConsumingRequestBody = true
                };

                var headers = new HttpRequestHeaders {
                    HeaderContentLength = "12"
                };
                var body = Http1MessageBody.For(HttpVersion.Http11, headers, http1Connection);

                var copyToAsyncTask = body.CopyToAsync(mockDestination.Object);

                var bytes  = Encoding.ASCII.GetBytes("Hello ");
                var buffer = http1Connection.RequestBodyPipe.Writer.GetMemory(2048);
                ArraySegment <byte> segment;
                Assert.True(MemoryMarshal.TryGetArray(buffer, out segment));
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length);
                http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length);
                await http1Connection.RequestBodyPipe.Writer.FlushAsync();

                // Verify the block passed to Stream.WriteAsync() is the same one incoming data was written into.
                Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task);

                // Verify the again when GetMemory returns the tail space of the same block.
                writeTcs = new TaskCompletionSource <(byte[], int, int)>();
                bytes    = Encoding.ASCII.GetBytes("World!");
                buffer   = http1Connection.RequestBodyPipe.Writer.GetMemory(2048);
                Assert.True(MemoryMarshal.TryGetArray(buffer, out segment));
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, bytes.Length);
                http1Connection.RequestBodyPipe.Writer.Advance(bytes.Length);
                await http1Connection.RequestBodyPipe.Writer.FlushAsync();

                Assert.Equal((segment.Array, segment.Offset, bytes.Length), await writeTcs.Task);

                http1Connection.RequestBodyPipe.Writer.Complete();

                await copyToAsyncTask;

                Assert.Equal(2, writeCount);

                // Don't call body.StopAsync() because PumpAsync() was never called.
                http1Connection.RequestBodyPipe.Reader.Complete();
            }
        }
Пример #30
0
        internal async Task ConnectInternalAsync(Func <WebSocketTransport, Task> connectFunc, CancellationToken cancellationToken)
        {
            CheckDisposed();

            TimerAwaitable timer     = null;
            Task           timerTask = null;

            try
            {
                // Pipes
                _duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                // Transport
                var transport = new WebSocketTransport(_duplexPipePair.Application, _logger);

                // Application
                _transportHandler = new TransportHandler(_duplexPipePair.Transport, _logger);

                // Session
                _session = new StreamingSession(_requestHandler, _transportHandler, _logger, cancellationToken);

                // Set up cancellation
                _disconnectCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                // Start transport and application
                var transportTask   = connectFunc(transport);
                var applicationTask = _transportHandler.ListenAsync(_disconnectCts.Token);
                var combinedTask    = Task.WhenAll(transportTask, applicationTask);

                Log.ClientStarted(_logger, _url ?? string.Empty);

                // Periodic task: keep alive
                // Disposed with `timer.Stop()` in the finally block below
                if (_keepAlive.HasValue)
                {
                    timer     = new TimerAwaitable(_keepAlive.Value, _keepAlive.Value);
                    timerTask = TimerLoopAsync(timer);
                }

                // We are connected!
                IsConnected = true;

                // Block until transport or application ends.
                await combinedTask.ConfigureAwait(false);

                // Signal that we're done
                _disconnectCts.Cancel();
                Log.ClientTransportApplicationCompleted(_logger, _url);
            }
            finally
            {
                timer?.Stop();

                if (timerTask != null)
                {
                    await timerTask.ConfigureAwait(false);
                }
            }

            Log.ClientCompleted(_logger, _url ?? string.Empty);
        }