Exemplo n.º 1
0
        public async Task StreamWindowUpdatesShouldRespectBufferState()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            // Lower the initial window size so that stream window updates are
            // sent earlier than connection window updates
            var settings = Settings.Default;

            settings.InitialWindowSize = 16000;
            settings.MaxFrameSize      = 1000000;
            var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe,
                localSettings : settings);

            // Write 12k of data. Buffer amount: 12k. Remaining window: 4k
            await inPipe.WriteData(1u, 12000);

            // Read 5k of data. Buffer amount: 7k
            await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000]));

            // This should not trigger a window update
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();

            // Read 5k of data. Buffer amount: 2k
            await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000]));

            // Expect a window update of 10k. Remaining window: 14k
            await outPipe.AssertWindowUpdate(1u, 10000);

            // Read 2k of data - buffer is now drained
            await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[2000]));

            // This should not trigger a window update
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();

            // Write 4k of data. Buffer amount: 4k. Remaining window: 10k
            await inPipe.WriteData(1u, 4000);

            // Read 4k of data. Buffer amount: 0k
            await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[4000]));

            // This should not trigger a window update
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();

            // Write 8k of data. Buffer amount: 8k. Remaining window: 2k
            await inPipe.WriteData(1u, 8000);

            // Read 5k of data. Buffer amount: 3k
            await res.stream.ReadAllWithTimeout(new ArraySegment <byte>(new byte[5000]));

            // Expect a window update of 11k. Remaining window: 13k
            await outPipe.AssertWindowUpdate(1u, 11000);
        }
Exemplo n.º 2
0
        public async Task ReceivingDataDirectlyAfterInformationalHeadersShouldBeAnError()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe);

            // Send informational headers to the client
            var infoHeaders = new HeaderField[]
            {
                new HeaderField {
                    Name = ":status", Value = "100"
                },
                new HeaderField {
                    Name = "extension-field", Value = "bar"
                },
            };
            await inPipe.WriteHeaders(res.hEncoder, 1u, false, infoHeaders);

            var recvdHeaders = await res.stream.ReadHeadersAsync();

            Assert.True(infoHeaders.SequenceEqual(recvdHeaders));

            // Try to send data
            await inPipe.WriteData(1u, 100, null, true);

            // Expect to receive an error
            await outPipe.AssertResetStreamReception(1u, ErrorCode.ProtocolError);

            Assert.Equal(StreamState.Reset, res.stream.State);

            await Assert.ThrowsAsync <StreamResetException>(
                () => res.stream.ReadHeadersAsync());
        }
Exemplo n.º 3
0
        public async Task ADataFrameOnAnUnknownStreamIdShouldTriggerAStreamReset(
            bool isServer, uint streamId)
        {
            // TODO: Add test cases for clients
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            Func <IStream, bool> listener = (s) => true;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider, listener);

            // Establish a high stream ID, which means all below are invalid
            var hEncoder        = new Encoder();
            var createdStreamId = 111u;

            if (!isServer)
            {
                throw new Exception("For clients the stream must be created from connection");
            }
            await inPipe.WriteHeaders(
                hEncoder, createdStreamId, false, DefaultGetHeaders);

            await inPipe.WriteData(streamId, 0);

            await outPipe.AssertResetStreamReception(streamId, ErrorCode.StreamClosed);
        }
Exemplo n.º 4
0
        public async Task ReceivingHeadersOrDataOnAClosedStreamShouldTriggerAStreamReset(
            StreamState streamState,
            bool sendHeaders, bool sendData, bool sendTrailers)
        {
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var localCloseDone = new SemaphoreSlim(0);

            var res = await StreamCreator.CreateConnectionAndStream(
                streamState, loggerProvider, inPipe, outPipe);

            if (sendHeaders)
            {
                await inPipe.WriteHeaders(res.hEncoder, 1, false, DefaultGetHeaders);
            }
            if (sendData)
            {
                await inPipe.WriteData(1u, 0);
            }
            if (sendTrailers)
            {
                await inPipe.WriteHeaders(res.hEncoder, 1, true, DefaultGetHeaders);
            }

            await outPipe.AssertResetStreamReception(1u, ErrorCode.StreamClosed);
            var expectedState =
                streamState == StreamState.Closed
                ? StreamState.Closed
                : StreamState.Reset;
            Assert.Equal(expectedState, res.stream.State);
        }
Exemplo n.º 5
0
        public async Task ClientUpgradeRequestShouldYieldStream1()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var upgrade = new ClientUpgradeRequestBuilder().Build();
            var config  = new ConnectionConfigurationBuilder(false)
                          .Build();

            var conn = new Connection(
                config, inPipe, outPipe,
                new Connection.Options
            {
                Logger = loggerProvider.CreateLogger("http2Con"),
                ClientUpgradeRequest = upgrade,
            });

            await conn.PerformHandshakes(inPipe, outPipe);

            var stream = await upgrade.UpgradeRequestStream;

            Assert.Equal(1u, stream.Id);
            Assert.Equal(1, conn.ActiveStreamCount);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);

            var readHeadersTask = stream.ReadHeadersAsync();

            Assert.False(readHeadersTask.IsCompleted);

            var hEncoder = new Http2.Hpack.Encoder();
            await inPipe.WriteHeaders(hEncoder, 1u, false, DefaultStatusHeaders);

            Assert.True(
                await Task.WhenAny(
                    readHeadersTask,
                    Task.Delay(ReadableStreamTestExtensions.ReadTimeout))
                == readHeadersTask,
                "Expected to read headers, got timeout");
            var headers = await readHeadersTask;

            Assert.True(headers.SequenceEqual(DefaultStatusHeaders));
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);

            await inPipe.WriteData(1u, 100, 5, true);

            var data = await stream.ReadAllToArrayWithTimeout();

            Assert.True(data.Length == 100);
            Assert.Equal(StreamState.Closed, stream.State);
            Assert.Equal(0, conn.ActiveStreamCount);
        }
Exemplo n.º 6
0
        public async Task ADataFrameOnAnIdleStreamIdShouldTriggerAGoAway(
            bool isServer, uint streamId)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            Func <IStream, bool> listener = (s) => true;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider, listener);

            await inPipe.WriteData(streamId, 0);

            await outPipe.AssertGoAwayReception(ErrorCode.StreamClosed, 0u);
        }
Exemplo n.º 7
0
        public async Task ReceivingEmptyDataFramesShouldBePossibleIfStreamWindowIsDrained(
            bool emptyFrameIsEndOfStream)
        {
            var inPipe        = new BufferedPipe(1024);
            var outPipe       = new BufferedPipe(1024);
            var localSettings = Settings.Default;

            localSettings.InitialWindowSize = 10;
            var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe,
                localSettings : localSettings);

            // Consume the complete stream flow control window
            await inPipe.WriteData(1u, 10);

            // Send a 0byte data frame
            await inPipe.WriteData(1u, 0, endOfStream : emptyFrameIsEndOfStream);

            // Check if we are still alive
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 8
0
        public async Task SendingLargeAmountOfDataShouldTriggerWindowUpdates(
            int[] dataLength,
            int[] expectedStreamWindowUpdates,
            int[] expectedConnWindowUpdates)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            // Lower the initial window size so that stream window updates are
            // sent earlier than connection window updates
            var settings = Settings.Default;

            settings.InitialWindowSize = 16000;
            var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe,
                localSettings : settings);

            // Consume all data on reader side
            var readTask = Task.Run(async() =>
            {
                await res.stream.ReadHeadersAsync();
                var data = await res.stream.ReadAllToArrayWithTimeout();
            });

            for (var i = 0; i < dataLength.Length; i++)
            {
                var toSend        = dataLength[i];
                var isEndOfStream = i == (dataLength.Length - 1);
                await inPipe.WriteData(1u, toSend, endOfStream : isEndOfStream);

                // Wait for a short amount of time between DATA frames
                if (!isEndOfStream)
                {
                    await Task.Delay(5);
                }
                // Check if window updates were received if required
                if (expectedConnWindowUpdates[i] != 0)
                {
                    await outPipe.AssertWindowUpdate(0, expectedConnWindowUpdates[i]);
                }
                if (expectedStreamWindowUpdates[i] != 0)
                {
                    await outPipe.AssertWindowUpdate(1, expectedStreamWindowUpdates[i]);
                }
            }
        }
Exemplo n.º 9
0
        public async Task ReceivingDataBeforeHeadersShouldYieldAResetException()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var res = await StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider,
                inPipe, outPipe);

            await inPipe.WriteData(1u, 1);

            await outPipe.AssertResetStreamReception(1u, ErrorCode.ProtocolError);

            var ex = await Assert.ThrowsAsync <AggregateException>(
                () => res.stream.ReadWithTimeout(new ArraySegment <byte>(
                                                     new byte[1])));

            Assert.IsType <StreamResetException>(ex.InnerException);
            Assert.Equal(StreamState.Reset, res.stream.State);
        }
Exemplo n.º 10
0
        public async Task EmptyDataFramesShouldBeValidSeperatorsBeforeTrailers(
            bool isServer)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await StreamCreator.CreateConnectionAndStream(
                isServer, loggerProvider, inPipe, outPipe);

            // Send a 0byte data frame
            await inPipe.WriteData(1u, 0);

            // Send trailers
            await inPipe.WriteHeaders(res.hEncoder, 1u, true,
                                      DefaultTrailingHeaders);

            // Check for no stream error
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 11
0
        public async Task HeadersWithContentLengthShouldForceDataLengthValidation(
            int contentLen, int[] dataLength, bool useTrailers, bool shouldError)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            Func <IStream, bool> listener = (s) => true;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener);

            var headers = TestHeaders.DefaultGetHeaders.Append(
                new HeaderField {
                Name  = "content-length",
                Value = contentLen.ToString()
            });

            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, false, headers);

            for (var i = 0; i < dataLength.Length; i++)
            {
                var isEos = i == (dataLength.Length - 1) && !useTrailers;
                await inPipe.WriteData(1u, dataLength[i], endOfStream : isEos);
            }

            if (useTrailers)
            {
                await inPipe.WriteHeaders(hEncoder, 1, true, new HeaderField[0]);
            }

            if (shouldError)
            {
                await outPipe.AssertResetStreamReception(1u, ErrorCode.ProtocolError);
            }
            else
            {
                await inPipe.WritePing(new byte[8], false);

                await outPipe.ReadAndDiscardPong();
            }
        }
Exemplo n.º 12
0
        public async Task EmptyDataFramesShouldNotWakeupPendingReads(
            bool isServer)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await StreamCreator.CreateConnectionAndStream(
                isServer, loggerProvider, inPipe, outPipe);

            // Send a 0byte data frame
            await inPipe.WriteData(1u, 0);

            // Try to read - this should not unblock
            var readTask = res.stream.ReadAsync(
                new ArraySegment <byte>(new byte[1])).AsTask();

            var doneTask = await Task.WhenAny(readTask, Task.Delay(100));

            Assert.True(
                doneTask != readTask,
                "Expected read timeout but read finished");
        }
Exemplo n.º 13
0
        public async Task ReceivingHeadersOrDataOnAResetStreamShouldProduceAClosedStreamError(
            bool sendHeaders, bool sendData, bool sendTrailers)
        {
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var r = await StreamCreator.CreateConnectionAndStream(
                StreamState.Reset, loggerProvider, inPipe, outPipe);

            if (sendHeaders)
            {
                await inPipe.WriteHeaders(r.hEncoder, 1, false, DefaultGetHeaders);
            }
            if (sendData)
            {
                await inPipe.WriteData(1u, 0);
            }
            if (sendTrailers)
            {
                await inPipe.WriteHeaders(r.hEncoder, 1, true, DefaultGetHeaders);
            }
            await outPipe.AssertResetStreamReception(1, ErrorCode.StreamClosed);
        }
Exemplo n.º 14
0
        public async Task ViolationsOfTheStreamFlowControlWindowShouldBeDetected(
            int?padLen, int streamWindowSize, int dataAmount, bool isError)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            // Use a smaller flow control window for streams so that the stream
            // window errors.
            var settings = Settings.Default;

            settings.InitialWindowSize = (uint)streamWindowSize;
            settings.MaxFrameSize      = 1024 * 1024;
            // The test values for the amount of data to be sent on the stream
            // are tuned small enough that no connection window
            // updates will be sent, which would fail the expected output.

            var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe,
                localSettings : settings);

            // Write more data than the stream allows
            await inPipe.WriteData(1u, dataAmount, padLen : padLen);

            if (isError)
            {
                // Expect that the stream got reset
                await outPipe.AssertResetStreamReception(1u, ErrorCode.FlowControlError);

                Assert.Equal(StreamState.Reset, res.stream.State);
            }

            // Send a ping afterwards, which should be processed in all cases
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 15
0
        public async Task ViolationsOfTheConnectionFlowControlWindowShouldBeDetected(
            int?padLen, uint streamId, int dataAmount, bool isError)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            // Use a bigger flow control window for streams so that the connection
            // window errors and streams dont send window updates.
            // Also update maxFrameSize, otherwise the connection will send
            // window updates faster than we can violate the contract
            var settings = Settings.Default;

            settings.InitialWindowSize = 256 * 1024;
            settings.MaxFrameSize      = 1024 * 1024;

            var res = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe,
                localSettings : settings);

            // Open an additional stream, so that streamId 3 is not in the IDLE
            // range, which causes a connection error
            await inPipe.WriteHeaders(
                res.hEncoder, 555u, false, DefaultGetHeaders);

            // Try to send the data
            // This might fail, if the connection goes away before
            // everything is read
            try
            {
                await inPipe.WriteData(streamId, dataAmount, padLen : padLen);
            }
            catch (Exception e)
            {
                if (!isError || !(e is TimeoutException))
                {
                    throw;
                }
            }

            if (isError)
            {
                await outPipe.AssertGoAwayReception(ErrorCode.FlowControlError, 555u);

                await outPipe.AssertStreamEnd();

                await res.conn.Done;
                Assert.Equal(StreamState.Reset, res.stream.State);
            }
            else
            {
                // Expect the connection to be alive
                await outPipe.AssertWindowUpdate(0u, 65535);

                if (streamId != 1)
                {
                    // We expect a reset for the unknown stream on which data
                    // was transmitted
                    await outPipe.AssertResetStreamReception(streamId, ErrorCode.StreamClosed);
                }
                await inPipe.WritePing(new byte[8], false);

                await outPipe.ReadAndDiscardPong();

                Assert.Equal(StreamState.Open, res.stream.State);
            }
        }
Exemplo n.º 16
0
        public async Task TheNextOutgoingStreamAfterUpgradeShouldUseId3()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var upgrade = new ClientUpgradeRequestBuilder().Build();
            var config  = new ConnectionConfigurationBuilder(false)
                          .Build();

            var conn = new Connection(
                config, inPipe, outPipe,
                new Connection.Options
            {
                Logger = loggerProvider.CreateLogger("http2Con"),
                ClientUpgradeRequest = upgrade,
            });

            await conn.PerformHandshakes(inPipe, outPipe);

            var stream = await upgrade.UpgradeRequestStream;

            Assert.Equal(1u, stream.Id);

            var readHeadersTask = stream.ReadHeadersAsync();

            Assert.False(readHeadersTask.IsCompleted);

            var nextStream = await conn.CreateStreamAsync(DefaultGetHeaders);

            await outPipe.ReadAndDiscardHeaders(3u, false);

            Assert.Equal(3u, nextStream.Id);
            Assert.True(stream != nextStream);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(StreamState.Open, nextStream.State);

            var hEncoder = new Http2.Hpack.Encoder();
            await inPipe.WriteHeaders(hEncoder, 3u, true, DefaultStatusHeaders);

            var nextStreamHeaders = await nextStream.ReadHeadersAsync();

            Assert.True(nextStreamHeaders.SequenceEqual(DefaultStatusHeaders));
            Assert.False(readHeadersTask.IsCompleted);
            Assert.Equal(StreamState.HalfClosedRemote, nextStream.State);
            Assert.Equal(StreamState.HalfClosedLocal, stream.State);
            Assert.Equal(2, conn.ActiveStreamCount);

            await nextStream.WriteAsync(new ArraySegment <byte>(new byte[0]), true);

            await outPipe.ReadAndDiscardData(3u, true, 0);

            Assert.Equal(StreamState.Closed, nextStream.State);
            Assert.Equal(1, conn.ActiveStreamCount);

            var headers2 = DefaultStatusHeaders.Append(
                new HeaderField()
            {
                Name = "hh", Value = "vv"
            });
            await inPipe.WriteHeaders(hEncoder, 1u, false, headers2);

            var streamHeaders = await readHeadersTask;

            Assert.True(streamHeaders.SequenceEqual(headers2));
            await inPipe.WriteData(1u, 10, 0, true);

            var data = await stream.ReadAllToArrayWithTimeout();

            Assert.True(data.Length == 10);
            Assert.Equal(StreamState.Closed, stream.State);
            Assert.Equal(0, conn.ActiveStreamCount);
        }