Пример #1
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());
        }
Пример #2
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);
        }
Пример #3
0
        public async Task SendingInvalidTrailersShouldTriggerAStreamReset()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var headers = new HeaderField[]
            {
                new HeaderField {
                    Name = ":method", Value = "GET"
                },
                new HeaderField {
                    Name = ":scheme", Value = "http"
                },
                new HeaderField {
                    Name = ":path", Value = "/"
                },
            };
            var trailers = new HeaderField[]
            {
                new HeaderField {
                    Name = ":method", Value = "GET"
                },
            };

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

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

            await inPipe.WriteHeaders(hEncoder, 1, true, trailers);

            await outPipe.AssertResetStreamReception(1, ErrorCode.ProtocolError);
        }
Пример #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);
        }
Пример #5
0
        public async Task CancellingAStreamShouldSendAResetFrame(
            bool isServer)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            r.stream.Cancel();
            await outPipe.AssertResetStreamReception(1, ErrorCode.Cancel);

            Assert.Equal(StreamState.Reset, r.stream.State);
        }
Пример #6
0
        public async Task HeadersOnStreamIdWhichCanNotBeRemoteInitiatedShouldTriggerAStreamReset(
            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);

            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, streamId, false, DefaultGetHeaders);

            await outPipe.AssertResetStreamReception(streamId, ErrorCode.StreamClosed);
        }
Пример #7
0
        public async Task ReceivingHeadersWithNoAttachedListenerOrRefusingListenerShouldTriggerStreamReset(
            bool noListener)
        {
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, false, DefaultGetHeaders);
            await outPipe.AssertResetStreamReception(1, ErrorCode.RefusedStream);
        }
Пример #8
0
        public async Task ShouldResetStreamWhenStreamFlowControlWindowIsOverloaded(
            int amount)
        {
            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 hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, false, DefaultGetHeaders);

            await inPipe.WriteWindowUpdate(1, amount);

            await outPipe.AssertResetStreamReception(1, ErrorCode.FlowControlError);
        }
Пример #9
0
        public async Task ReceivingHeadersWithATooSmallStreamIdShouldTriggerAStreamReset(
            bool noListener)
        {
            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 hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 33, false, DefaultGetHeaders);
            await inPipe.WriteHeaders(hEncoder, 31, false, DefaultGetHeaders);
            // Remark: The specification actually wants a connection error / GOAWAY
            // to be emitted. However as the implementation can not safely determine
            // if that stream ID was never used and valid we send and check for
            // a stream reset.
            await outPipe.AssertResetStreamReception(31, ErrorCode.StreamClosed);
        }
Пример #10
0
        public async Task ReceivingHeaders2TimesShouldTriggerAStreamReset(
            bool isServer, bool headersAreEndOfStream)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            // Establish open streams, which means headers are sent in both
            // directions
            var res = await StreamCreator.CreateConnectionAndStream(
                isServer, loggerProvider, inPipe, outPipe);

            // Write a second header
            await inPipe.WriteHeaders(
                res.hEncoder, 1, headersAreEndOfStream, DefaultGetHeaders);

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

            Assert.Equal(StreamState.Reset, res.stream.State);
        }
Пример #11
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);
        }
Пример #12
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();
            }
        }
Пример #13
0
        public async Task NewStreamsAfterGoAwayShouldBeRejected()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            // Start the GoAway process
            await res.conn.GoAwayAsync(ErrorCode.NoError, false);

            // Expect the GoAway message
            await outPipe.AssertGoAwayReception(ErrorCode.NoError, 1u);

            // Try to establish a new stream
            var hEncoder = new Http2.Hpack.Encoder();
            await inPipe.WriteHeaders(hEncoder, 3, true, TestHeaders.DefaultGetHeaders);

            // Expect a stream rejection
            await outPipe.AssertResetStreamReception(3u, ErrorCode.RefusedStream);
        }
Пример #14
0
        public async Task ReceivingWindowUpdatesWith0AmountShouldTriggerGoAwayOrReset(
            uint streamId)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await ServerStreamTests.StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe);

            await inPipe.WriteWindowUpdate(streamId, 0);

            if (streamId == 0)
            {
                await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 1);

                await outPipe.AssertStreamEnd();
            }
            else
            {
                await outPipe.AssertResetStreamReception(1u, ErrorCode.ProtocolError);
            }
        }
Пример #15
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);
        }
Пример #16
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();
        }
Пример #17
0
        public async Task IncomingStreamsAfterMaxConcurrentStreamsShouldBeRejected(
            int maxConcurrentStreams)
        {
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var acceptedStreams = new List<IStream>();

            Func<IStream, bool> listener = (s) =>
            {
                lock (acceptedStreams)
                {
                    acceptedStreams.Add(s);
                }
                return true;
            };
            var settings = Settings.Default;
            settings.MaxConcurrentStreams = (uint)maxConcurrentStreams;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener,
                localSettings: settings);

            var hEncoder = new Encoder();
            // Open maxConcurrentStreams
            var streamId = 1u;
            for (var i = 0; i < maxConcurrentStreams; i++)
            {
                await inPipe.WriteHeaders(hEncoder, streamId, false, DefaultGetHeaders);
                streamId += 2;
            }
            // Assert no rejection and response so far
            await inPipe.WritePing(new byte[8], false);
            await outPipe.ReadAndDiscardPong();
            lock (acceptedStreams)
            {
                Assert.Equal(maxConcurrentStreams, acceptedStreams.Count);
            }
            // Try to open an additional stream
            await inPipe.WriteHeaders(hEncoder, streamId, false, DefaultGetHeaders);
            // This one should be rejected
            await outPipe.AssertResetStreamReception(streamId, ErrorCode.RefusedStream);
            lock (acceptedStreams)
            {
                Assert.Equal(maxConcurrentStreams, acceptedStreams.Count);
            }

            // Once a stream is closed a new one should be acceptable
            await inPipe.WriteResetStream(streamId-2, ErrorCode.Cancel);
            streamId += 2;
            await inPipe.WriteHeaders(hEncoder, streamId, false, DefaultGetHeaders);
            // Assert no error response
            await inPipe.WritePing(new byte[8], false);
            await outPipe.ReadAndDiscardPong();
            lock (acceptedStreams)
            {
                // +1 because the dead stream isn't removed
                Assert.Equal(maxConcurrentStreams+1, acceptedStreams.Count);
                // Check if the reset worked
                Assert.Equal(
                    StreamState.Reset,
                    acceptedStreams[acceptedStreams.Count-2].State);
            }
        }
Пример #18
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);
            }
        }