Exemplo n.º 1
0
        public async Task ReceivingAnInformationalHeaderAfterANormalHeaderShouldBeAnError()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe);

            await inPipe.WriteHeaders(res.hEncoder, 1u, false, DefaultStatusHeaders);

            // Expect to receive the status headers
            var recvdHeaders = await res.stream.ReadHeadersAsync();

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

            // 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);

            // 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.º 2
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.º 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);
        }
Exemplo n.º 4
0
        public async Task ClientsShouldBeAbleToReceiveInformationalHeaders()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var res     = await StreamCreator.CreateConnectionAndStream(
                StreamState.Open, loggerProvider, inPipe, outPipe);

            // Send and receive first set of informational headers
            var readInfoHeaders1Task = res.stream.ReadHeadersAsync();

            Assert.False(readInfoHeaders1Task.IsCompleted);

            var infoHeaders1 = new HeaderField[]
            {
                new HeaderField {
                    Name = ":status", Value = "100"
                },
                new HeaderField {
                    Name = "extension-field", Value = "bar"
                },
            };
            await inPipe.WriteHeaders(res.hEncoder, 1u, false, infoHeaders1);

            var recvdInfoHeaders1 = await readInfoHeaders1Task;

            Assert.True(infoHeaders1.SequenceEqual(recvdInfoHeaders1));

            // Send and receive second set of informational headers
            var readInfoHeaders2Task = res.stream.ReadHeadersAsync();

            Assert.False(readInfoHeaders2Task.IsCompleted);

            var infoHeaders2 = new HeaderField[]
            {
                new HeaderField {
                    Name = ":status", Value = "108"
                },
                new HeaderField {
                    Name = "extension-field-b", Value = "bar2"
                },
            };
            await inPipe.WriteHeaders(res.hEncoder, 1u, false, infoHeaders2);

            var recvdInfoHeaders2 = await readInfoHeaders2Task;

            Assert.True(infoHeaders2.SequenceEqual(recvdInfoHeaders2));

            // Send and receive final headers
            var recvHeadersTask = res.stream.ReadHeadersAsync();

            Assert.False(recvHeadersTask.IsCompleted);
            await inPipe.WriteHeaders(res.hEncoder, 1u, true, DefaultStatusHeaders);

            var recvdHeaders = await recvHeadersTask;

            Assert.True(DefaultStatusHeaders.SequenceEqual(recvdHeaders));
        }
Exemplo n.º 5
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.º 6
0
        public async Task ReceivingHeadersWithEndOfStreamShouldAllowToReadEndOfStream()
        {
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            var handlerDone = new SemaphoreSlim(0);
            var gotEos = false;
            var streamStateOk = false;

            Func<IStream, bool> listener = (s) =>
            {
                Task.Run(async () =>
                {
                    await s.ReadHeadersAsync();
                    var buf = new byte[1024];
                    var res = await s.ReadAsync(new ArraySegment<byte>(buf));
                    gotEos = res.EndOfStream && res.BytesRead == 0;
                    streamStateOk = s.State == StreamState.HalfClosedRemote;
                    handlerDone.Release();
                });
                return true;
            };
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener);

            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, true, DefaultGetHeaders);
            var requestDone = await handlerDone.WaitAsync(ReadableStreamTestExtensions.ReadTimeout);
            Assert.True(requestDone, "Expected handler to complete within timeout");
            Assert.True(gotEos);
            Assert.True(streamStateOk);
        }
        public async Task ConnectionShouldIgnoreResetsforUnknownStreams()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            var hEncoder = new Encoder();

            var streamId = 7u;
            await inPipe.WriteHeaders(
                hEncoder, streamId, false, TestHeaders.DefaultGetHeaders);

            await inPipe.WriteResetStream(streamId - 2, ErrorCode.RefusedStream);

            await inPipe.WriteResetStream(streamId - 4, ErrorCode.Cancel);

            // Send a ping afterwards
            // If we get a response the reset frame in between was ignored
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 8
0
        public async Task IfSettingsDecreaseHeaderTableNextOutgoingHeadersShouldContainAnUpdate()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            Func <IStream, bool> listener = (s) =>
            {
                Task.Run(() =>
                {
                    var res = new HeaderField[]
                    {
                        new HeaderField {
                            Name = ":status", Value = "200"
                        },
                    };
                    s.WriteHeadersAsync(res, false);
                });
                return(true);
            };

            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener);

            // Change remote settings 2 times
            var settings = Settings.Default;

            settings.HeaderTableSize = 8;
            await inPipe.WriteSettings(settings);

            await outPipe.AssertSettingsAck();

            settings.HeaderTableSize = 30;
            await inPipe.WriteSettings(settings);

            await outPipe.AssertSettingsAck();

            // Establish a stream
            // When we send a response through it we should observe the size udpate
            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, false, DefaultGetHeaders);

            // Wait for the incoming status headers with header update
            var fh = await outPipe.ReadFrameHeaderWithTimeout();

            Assert.Equal(FrameType.Headers, fh.Type);
            Assert.Equal((byte)(HeadersFrameFlags.EndOfHeaders), fh.Flags);
            Assert.Equal(1u, fh.StreamId);

            Assert.Equal(3, fh.Length);
            var data = new byte[fh.Length];
            await outPipe.ReadAllWithTimeout(new ArraySegment <byte>(data));

            Assert.Equal(0x28, data[0]); // Size Update to 8
            Assert.Equal(0x3e, data[1]); // Size Update to 30
            Assert.Equal(0x88, data[2]); // :status 200
        }
Exemplo n.º 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);
        }
Exemplo n.º 10
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.º 11
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.º 12
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.º 13
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);
        }
Exemplo n.º 14
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);
        }
Exemplo n.º 15
0
        public async Task HeadersOnStreamId0ShouldTriggerAGoAway(
            bool isServer)
        {
            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, 0, false, DefaultGetHeaders);

            await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 0);

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 16
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);
        }
Exemplo n.º 17
0
        public async Task ReceivingHeadersShouldCreateNewStreamsAndAllowToReadTheHeaders()
        {
            const int nrStreams = 10;
            var inPipe = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);
            int nrAcceptedStreams = 0;
            var handlerDone = new SemaphoreSlim(0);
            uint streamId = 1;
            var headersOk = false;
            var streamIdOk = false;
            var streamStateOk = false;

            Func<IStream, bool> listener = (s) =>
            {
                Interlocked.Increment(ref nrAcceptedStreams);
                Task.Run(async () =>
                {
                    var rcvdHeaders = await s.ReadHeadersAsync();
                    headersOk = DefaultGetHeaders.SequenceEqual(rcvdHeaders);
                    streamIdOk = s.Id == streamId;
                    streamStateOk = s.State == StreamState.Open;
                    handlerDone.Release();
                });
                return true;
            };
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener);

            var hEncoder = new Encoder();
            for (var i = 0; i < nrStreams; i++)
            {
                headersOk = false;
                streamIdOk = false;
                streamStateOk = false;
                await inPipe.WriteHeaders(hEncoder, streamId, false, DefaultGetHeaders);
                var requestDone = await handlerDone.WaitAsync(ReadableStreamTestExtensions.ReadTimeout);
                Assert.True(requestDone, "Expected handler to complete within timeout");
                Assert.True(headersOk);
                Assert.True(streamIdOk);
                Assert.True(streamStateOk);
                streamId += 2;
            }
            Assert.Equal(nrStreams, nrAcceptedStreams);
        }
Exemplo n.º 18
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);
        }
Exemplo n.º 19
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.º 20
0
        public async Task ShouldAllowToSetTheMaxPossibleStreamFlowControlWindowSize()
        {
            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);

            var amount = int.MaxValue - 65535;
            await inPipe.WriteWindowUpdate(1, amount);

            // Check aliveness with ping/pong
            await inPipe.WritePing(new byte[8], false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 21
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);
        }
Exemplo n.º 22
0
        public async Task ReceivingTrailersShouldUnblockDataReceptionAndPresentThem(
            bool isServer)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            var readDataTask = res.stream.ReadAllToArrayWithTimeout();

            var fh = new FrameHeader
            {
                Type     = FrameType.Data,
                Length   = 4,
                StreamId = 1,
                Flags    = (byte)0,
            };
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(
                new ArraySegment <byte>(
                    System.Text.Encoding.ASCII.GetBytes("ABCD")));

            var trailers = new HeaderField[] {
                new HeaderField {
                    Name = "trai", Value = "ler"
                },
            };
            await inPipe.WriteHeaders(res.hEncoder, 1, true, trailers);

            var bytes = await readDataTask;

            Assert.Equal(4, bytes.Length);
            Assert.Equal("ABCD", System.Text.Encoding.ASCII.GetString(bytes));
            Assert.Equal(StreamState.HalfClosedRemote, res.stream.State);
            var rcvdTrailers = await res.stream.ReadTrailersAsync();

            Assert.Equal(trailers, rcvdTrailers);
        }
Exemplo n.º 23
0
        public async Task InvalidContinuationFramesShouldLeadToGoAway(
            uint contStreamId, int?contLength, FrameType contFrameType)
        {
            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();
            // Send a valid HEADERS frame
            await inPipe.WriteHeaders(
                hEncoder, 1, false,
                DefaultGetHeaders.Take(2), false);

            // Followed by an invalid continuation frame
            var outBuf = new byte[Settings.Default.MaxFrameSize];
            var result = hEncoder.EncodeInto(
                new ArraySegment <byte>(outBuf),
                DefaultGetHeaders.Skip(2));

            var length = contLength ?? result.UsedBytes;
            var fh     = new FrameHeader
            {
                Type     = contFrameType,
                StreamId = contStreamId,
                Length   = length,
                Flags    = 0,
            };
            await inPipe.WriteFrameHeader(fh);

            await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 0u);

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 24
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);
            }
        }
Exemplo n.º 25
0
        public async Task MaxHeaderListSizeViolationsShouldBeDetected(
            uint maxHeaderListSize,
            int headersInFirstFrame,
            int headersInContFrame,
            bool shouldError)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            Func <IStream, bool> listener = (s) => true;
            var settings = Settings.Default;

            settings.MaxHeaderListSize = maxHeaderListSize;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener,
                localSettings : settings,
                huffmanStrategy : HuffmanStrategy.Never);

            var hEncoder = new Encoder();
            var headers  = new List <HeaderField>();

            // Add the default headers
            // These take 123 bytes in store and 3 bytes in transmission
            headers.AddRange(new HeaderField[]
            {
                new HeaderField {
                    Name = ":method", Value = "GET"
                },
                new HeaderField {
                    Name = ":path", Value = "/"
                },
                new HeaderField {
                    Name = ":scheme", Value = "http"
                },
            });
            var currentHeadersLength = headers
                                       .Select(hf => hf.Name.Length + hf.Value.Length + 32)
                                       .Sum();
            // Create a header which takes 34 bytes in store and 5 bytes in transmission
            var extraHeader = new HeaderField
            {
                Name = "a", Value = "b", Sensitive = true
            };

            while (currentHeadersLength < headersInFirstFrame)
            {
                headers.Add(extraHeader);
                currentHeadersLength += 1 + 1 + 32;
            }

            await inPipe.WriteHeaders(
                hEncoder, 1, false,
                headers, headersInContFrame == 0);

            if (headersInContFrame != 0)
            {
                headers.Clear();
                currentHeadersLength = 0;
                while (currentHeadersLength < headersInContFrame)
                {
                    headers.Add(extraHeader);
                    currentHeadersLength += 1 + 1 + 32;
                }
                await inPipe.WriteContinuation(
                    hEncoder, 1,
                    headers, true);
            }

            if (shouldError)
            {
                // TODO: The spec says actually the remote should answer with
                // an HTTP431 error - but that happens on another layer
                await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 0u);

                await outPipe.AssertStreamEnd();
            }
            else
            {
                await inPipe.WritePing(new byte[8], false);

                await outPipe.ReadAndDiscardPong();
            }
        }
Exemplo n.º 26
0
        public async Task ContinuationFrameHeadersShouldBeAddedToTotalHeaders(
            int[] nrHeadersInFrame)
        {
            var     inPipe  = new BufferedPipe(1024);
            var     outPipe = new BufferedPipe(1024);
            IStream stream  = null;
            IEnumerable <HeaderField> receivedHeaders = null;
            SemaphoreSlim             handlerDone     = new SemaphoreSlim(0);

            Func <IStream, bool> listener = (s) =>
            {
                stream = s;
                Task.Run(async() =>
                {
                    receivedHeaders = await s.ReadHeadersAsync();
                    handlerDone.Release();
                });
                return(true);
            };
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener);

            var hEncoder       = new Encoder();
            var totalHeaders   = DefaultGetHeaders;
            var isContinuation = false;
            var toSkip         = 0;
            var isEndOfHeaders = false;

            for (var frameNr = 0; frameNr <= nrHeadersInFrame.Length; frameNr++)
            {
                var headersToSend = totalHeaders.Skip(toSkip);
                if (frameNr != nrHeadersInFrame.Length)
                {
                    var toSend = nrHeadersInFrame[frameNr];
                    headersToSend = headersToSend.Take(toSend);
                    toSkip       += toSend;
                }
                else
                {
                    // send remaining headers
                    isEndOfHeaders = true;
                }
                if (!isContinuation)
                {
                    await inPipe.WriteHeaders(
                        hEncoder, 1, false, headersToSend, isEndOfHeaders);

                    isContinuation = true;
                }
                else
                {
                    await inPipe.WriteContinuation(
                        hEncoder, 1, headersToSend, isEndOfHeaders);
                }
            }
            var handlerCompleted = await handlerDone.WaitAsync(
                ReadableStreamTestExtensions.ReadTimeout);

            Assert.True(handlerCompleted, "Expected stream handler to complete");
            Assert.True(
                totalHeaders.SequenceEqual(receivedHeaders),
                "Expected to receive all sent headers");
        }
Exemplo n.º 27
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);
        }
Exemplo n.º 28
0
        public async Task TheRemoteHeaderTableSizeShouldOnlyBeUsedUpToConfiguredLimit()
        {
            var inPipe      = new BufferedPipe(1024);
            var outPipe     = new BufferedPipe(1024);
            var handlerDone = new SemaphoreSlim(0);

            Func <IStream, bool> listener = (s) =>
            {
                Task.Run(() =>
                {
                    var res = new HeaderField[]
                    {
                        new HeaderField {
                            Name = ":status", Value = "200"
                        },
                    };
                    s.WriteHeadersAsync(res, false);
                });
                handlerDone.Release();
                return(true);
            };

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

            localSettings.HeaderTableSize = 20000;
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider, listener,
                localSettings : localSettings);

            // Change remote settings, which grants us a giant header table
            var settings = Settings.Default;

            settings.HeaderTableSize = 50 * 1024 * 1024;
            await inPipe.WriteSettings(settings);

            await outPipe.AssertSettingsAck();

            // Establish a stream
            // When we send a response through it we should observe the size udpate
            var hEncoder = new Encoder();
            await inPipe.WriteHeaders(hEncoder, 1, false, DefaultGetHeaders);

            var ok = await handlerDone.WaitAsync(
                ReadableStreamTestExtensions.ReadTimeout);

            if (!ok)
            {
                throw new Exception("Stream was not created");
            }

            // Wait for the incoming status headers with header update
            var fh = await outPipe.ReadFrameHeaderWithTimeout();

            Assert.Equal(FrameType.Headers, fh.Type);
            Assert.Equal((byte)(HeadersFrameFlags.EndOfHeaders), fh.Flags);
            Assert.Equal(1u, fh.StreamId);

            // Observe headers with status update
            // We should update the header table to 20000
            Assert.Equal(5, fh.Length);
            var data = new byte[fh.Length];
            await outPipe.ReadAllWithTimeout(new ArraySegment <byte>(data));

            Assert.Equal(0x3f, data[0]); // Size Update to 20000 => 20000 - 31 = 19969
            Assert.Equal(0x81, data[1]); // 19969 % 128 + 128 = 0x81, 19969 / 128 = 156
            Assert.Equal(0x9c, data[2]); // 156 % 128 + 128 = 0x9c, 156 / 128 = 1
            Assert.Equal(0x01, data[3]); // 1
            Assert.Equal(0x88, data[4]); // :status 200
        }
Exemplo n.º 29
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);
            }
        }