Exemplo n.º 1
0
        public async Task ConnectionShouldGoAwayOnInvalidGoAwayFrameLength(
            bool isServer, int frameLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            var fh = new FrameHeader
            {
                Type     = FrameType.GoAway,
                Flags    = 0,
                Length   = frameLength,
                StreamId = 0,
            };
            await inPipe.WriteFrameHeader(fh);

            var expectedErr = frameLength > 65535
                ? ErrorCode.FrameSizeError
                : ErrorCode.ProtocolError;

            await outPipe.AssertGoAwayReception(expectedErr, 0);

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 2
0
        public async Task ClientShouldGoAwayIfFirstFrameIsNotSettings()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(false, Settings.Default, inPipe, outPipe);
            var fh       = new FrameHeader
            {
                Type     = FrameType.Headers,
                Length   = 0,
                Flags    = 0,
                StreamId = 2
            };
            await inPipe.WriteFrameHeader(fh);

            var expected = Settings.Default;

            expected.EnablePush = false;
            await outPipe.ReadAndDiscardPreface();

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 3
0
        public async Task ConnectionShouldGoAwayOnInvalidSettingsFrameLength()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            var settings     = Settings.Default;
            var settingsData = new byte[settings.RequiredSize + 1]; // 1 byte extra
            var fh           = new FrameHeader
            {
                Type     = FrameType.Settings,
                Length   = settingsData.Length,
                Flags    = 0,
                StreamId = 0,
            };

            settings.EncodeInto(new ArraySegment <byte>(
                                    settingsData, 0, settingsData.Length - 1));
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(new ArraySegment <byte>(settingsData));

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 4
0
        public async Task ConnectionShouldGoAwayOnSettingsAckWithNonZeroLength(
            int frameLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            await inPipe.WriteSettings(Settings.Default);

            // Wait for remote settings
            await outPipe.ReadAndDiscardSettings();

            // Wait for ack to our settings
            await outPipe.AssertSettingsAck();

            var fh = new FrameHeader
            {
                Type     = FrameType.Settings,
                Flags    = (byte)SettingsFrameFlags.Ack,
                StreamId = 0,
                Length   = frameLength,
            };
            await inPipe.WriteFrameHeader(fh);

            // Wait for GoAway due to wrong stream ID
            await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 0);

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 5
0
        public async Task PingAsyncShouldSendPingAndWaitForAssociatedAck()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider);

            // Request ping
            var pingTask = http2Con.PingAsync();
            // Expect ping emission
            var fh = await outPipe.ReadFrameHeaderWithTimeout();

            Assert.Equal(FrameType.Ping, fh.Type);
            Assert.Equal(8, fh.Length);
            Assert.Equal(0, fh.Flags);
            Assert.Equal(0u, fh.StreamId);
            var pingData = new ArraySegment <byte>(new byte[8]);
            await outPipe.ReadAllWithTimeout(pingData);

            // Respond with pong
            fh.Flags = (byte)PingFrameFlags.Ack;
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(pingData);

            // Await ping task to finish
            Assert.True(
                pingTask == await Task.WhenAny(pingTask, Task.Delay(200)),
                "Expected pingTask to finish");
        }
        public async Task ConnectionShouldCloseAndSignalDoneInCaseOfAProtocolError(bool isServer)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            // Cause a protocol error
            var fh = new FrameHeader
            {
                Type     = FrameType.Data,
                StreamId = 0u,
                Flags    = 0,
                Length   = 0,
            };
            await inPipe.WriteFrameHeader(fh);

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

            await outPipe.AssertStreamEnd();

            await inPipe.CloseAsync();

            // Expect the connection to close within timeout
            var closed = http2Con.Done;

            Assert.True(
                closed == await Task.WhenAny(closed, Task.Delay(1000)),
                "Expected connection to close");
        }
Exemplo n.º 7
0
        public async Task PaddingViolationsOnStreamsShouldLeadToGoAway(
            bool onKnownStream, int frameLength, byte?padData)
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

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

            var fh = new FrameHeader
            {
                Type     = FrameType.Data,
                StreamId = onKnownStream ? 1u : 2u,
                Flags    = (byte)DataFrameFlags.Padded,
                Length   = frameLength,
            };
            await inPipe.WriteFrameHeader(fh);

            if (frameLength > 0)
            {
                var data = new byte[frameLength];
                data[0] = padData.Value;
                await inPipe.WriteAsync(new ArraySegment <byte>(data));
            }
            await outPipe.AssertGoAwayReception(ErrorCode.ProtocolError, 1u);
        }
Exemplo n.º 8
0
        public async Task ConnectionShouldGoAwayOnInvalidWindowSizeSettingWithFlowControlError()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            var settings = Settings.Default;

            settings.InitialWindowSize = (uint)int.MaxValue + 1u; // Invalid
            var settingsData = new byte[settings.RequiredSize];
            var fh           = new FrameHeader
            {
                Type     = FrameType.Settings,
                Length   = settingsData.Length,
                Flags    = 0,
                StreamId = 0,
            };

            settings.EncodeInto(new ArraySegment <byte>(settingsData));
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(new ArraySegment <byte>(settingsData));

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
        public async Task ConnectionShouldGoAwayOnPushPromiseWithInvalidLength(
            bool isServer, int?padLen)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            // This test is set up in a way where the payload length is 1 byte
            // too small for the transferred content
            var requiredLen = 4;
            var flags       = (byte)PushPromiseFrameFlags.EndOfHeaders;

            if (padLen != null)
            {
                flags       |= (byte)PushPromiseFrameFlags.Padded;
                requiredLen += 1 + padLen.Value;
            }
            var actualLen = requiredLen - 1;
            var fh        = new FrameHeader
            {
                Type     = FrameType.PushPromise,
                Flags    = flags,
                Length   = actualLen,
                StreamId = 1,
            };
            await inPipe.WriteFrameHeader(fh);

            var content = new byte[actualLen];
            var offset  = 0;

            if (padLen != null)
            {
                content[offset] = (byte)padLen.Value;
                offset++;
            }
            // Set promised stream Id
            content[offset + 0] = content[offset + 1] = content[offset + 2] = 0;
            if (offset + 3 <= content.Length - 1)
            {
                content[offset + 3] = 1;
            }
            offset += 4;
            await inPipe.WriteAsync(new ArraySegment <byte>(content));

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 10
0
        public async Task ConnectionShouldGoAwayOnInvalidPingFrameLength(int pingFrameLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider);

            var pingHeader = new FrameHeader
            {
                Type     = FrameType.Ping,
                Flags    = 0,
                Length   = pingFrameLength,
                StreamId = 0,
            };
            await inPipe.WriteFrameHeader(pingHeader);

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

            await outPipe.AssertStreamEnd();
        }
        public async Task ConnectionShouldGoAwayOnPushPromiseWithInvalidStreamId(
            bool isServer)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            var fh = new FrameHeader
            {
                Type     = FrameType.PushPromise,
                Flags    = (byte)PushPromiseFrameFlags.EndOfHeaders,
                Length   = 128,
                StreamId = 1,
            };
            await inPipe.WriteFrameHeader(fh);

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

            await outPipe.AssertStreamEnd();
        }
        public async Task ConnectionShouldGoAwayOnPushPromise(
            bool isServer, uint streamId, int payloadLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            var fh = new FrameHeader
            {
                Type     = FrameType.PushPromise,
                Flags    = 0,
                Length   = payloadLength,
                StreamId = streamId,
            };
            await inPipe.WriteFrameHeader(fh);

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

            await outPipe.AssertStreamEnd();
        }
        public async Task ConnectionShouldGoAwayOnInvalidResetStreamFrameLength(
            bool isServer, int resetFrameLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            var rstStreamHeader = new FrameHeader
            {
                Type     = FrameType.ResetStream,
                Flags    = 0,
                Length   = resetFrameLength,
                StreamId = 1,
            };
            await inPipe.WriteFrameHeader(rstStreamHeader);

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 14
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.º 15
0
        public async Task ConnectionShouldGoAwayOnInvalidSettingsMaxLengthExceeded()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            var fh = new FrameHeader
            {
                Type     = FrameType.Settings,
                Length   = (int)Settings.Default.MaxFrameSize + 1,
                Flags    = 0,
                StreamId = 0,
            };
            await inPipe.WriteFrameHeader(fh);

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 16
0
        public async Task ConnectionShouldGoAwayOnSettingsStreamIdNonZero()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            var fh = new FrameHeader
            {
                Type     = FrameType.Settings,
                Length   = Settings.Default.RequiredSize,
                Flags    = 0,
                StreamId = 1,
            };
            await inPipe.WriteFrameHeader(fh);

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 17
0
        public async Task ServersShouldGoAwayIfFirstFrameIsNotSettings()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);
            await ClientPreface.WriteAsync(inPipe);

            var fh = new FrameHeader
            {
                Type     = FrameType.Headers,
                Length   = 0,
                Flags    = 0,
                StreamId = 2,
            };
            await inPipe.WriteFrameHeader(fh);

            await outPipe.ReadAndDiscardSettings();

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 18
0
        public async Task ConnectionShouldIgnoreAndAcknowledgeUnknownSettings()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, Settings.Default, inPipe, outPipe);

            await ClientPreface.WriteAsync(inPipe);

            await outPipe.ReadAndDiscardSettings();

            var settings = Settings.Default;
            // Create a buffer for normal settings plus 3 unknown ones
            var settingsBuffer = new byte[settings.RequiredSize + 18];

            settings.EncodeInto(new ArraySegment <byte>(
                                    settingsBuffer, 0, settings.RequiredSize));
            // Use some unknown settings IDs
            settingsBuffer[settings.RequiredSize]      = 0;
            settingsBuffer[settings.RequiredSize + 1]  = 10;
            settingsBuffer[settings.RequiredSize + 6]  = 10;
            settingsBuffer[settings.RequiredSize + 7]  = 20;
            settingsBuffer[settings.RequiredSize + 12] = 0xFF;
            settingsBuffer[settings.RequiredSize + 13] = 0xFF;
            var settingsHeader = new FrameHeader
            {
                Type     = FrameType.Settings,
                StreamId = 0,
                Flags    = 0,
                Length   = settingsBuffer.Length,
            };
            await inPipe.WriteFrameHeader(settingsHeader);

            await inPipe.WriteAsync(new ArraySegment <byte>(settingsBuffer));

            // Check if the connection ACKs these settings
            await outPipe.AssertSettingsAck();
        }
Exemplo n.º 19
0
        public async Task ConnectionShouldGoAwayOnInvalidGoAwayStreamId(
            bool isServer)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            var goAwayData = new GoAwayFrameData
            {
                Reason = new GoAwayReason
                {
                    LastStreamId = 0u,
                    ErrorCode    = ErrorCode.NoError,
                    DebugData    = new ArraySegment <byte>(new byte[0]),
                },
            };

            var fh = new FrameHeader
            {
                Type     = FrameType.GoAway,
                Flags    = 0,
                StreamId = 1,
                Length   = goAwayData.RequiredSize,
            };

            var dataBytes = new byte[goAwayData.RequiredSize];

            goAwayData.EncodeInto(new ArraySegment <byte>(dataBytes));
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(new ArraySegment <byte>(dataBytes));

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

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 20
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();
        }
        public async Task ConnectionShouldIgnoreUnknownFrames(
            bool isServer, int payloadLength)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                isServer, inPipe, outPipe, loggerProvider);

            // send an undefined frame type
            var fh = new FrameHeader
            {
                Type     = (FrameType)100,
                Flags    = 33,
                Length   = payloadLength,
                StreamId = 0,
            };
            await inPipe.WriteFrameHeader(fh);

            if (payloadLength != 0)
            {
                var payload = new byte[payloadLength];
                await inPipe.WriteAsync(new ArraySegment <byte>(payload));
            }

            // Send a ping afterwards
            // If we get a response the unknown frame in between was ignored
            var pingData = new byte[8];

            for (var i = 0; i < 8; i++)
            {
                pingData[i] = (byte)i;
            }
            await inPipe.WritePing(pingData, false);

            await outPipe.ReadAndDiscardPong();
        }
Exemplo n.º 22
0
        public async Task PingAsyncShouldNotCompleteWhenWrongPingResponseIsReceived()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = await ConnectionUtils.BuildEstablishedConnection(
                true, inPipe, outPipe, loggerProvider);

            // Request ping
            var pingTask = http2Con.PingAsync();
            // Expect ping emission
            var fh = await outPipe.ReadFrameHeaderWithTimeout();

            Assert.Equal(FrameType.Ping, fh.Type);
            Assert.Equal(8, fh.Length);
            Assert.Equal(0, fh.Flags);
            Assert.Equal(0u, fh.StreamId);
            var pingData = new ArraySegment <byte>(new byte[8]);
            await outPipe.ReadAllWithTimeout(pingData);

            // Respond with pong and manipulated data
            fh.Flags = (byte)PingFrameFlags.Ack;
            for (var i = 0; i < pingData.Count; i++)
            {
                pingData.Array[i] = 0xFF;
            }
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(pingData);

            // Await ping not to finish
            var timeoutTask = Task.Delay(200);

            Assert.True(
                timeoutTask == await Task.WhenAny(pingTask, timeoutTask),
                "Expected pingTask not to finish");
        }
Exemplo n.º 23
0
        public async Task ContinuationsWherePartsDontContainFullHeaderMustBeSupported(
            int nrContinuations)
        {
            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();
            // Construct a proper set of header here, where a single headerfield could
            // by splitted over more than 1 fragment
            var totalHeaders = DefaultGetHeaders.TakeWhile(
                h => h.Name.StartsWith(":"));

            totalHeaders = totalHeaders.Append(
                new HeaderField {
                Name = "longname", Value = "longvalue"
            });
            totalHeaders = totalHeaders.Append(
                new HeaderField {
                Name = "abc", Value = "xyz"
            });

            // Encode all headers in a single header block
            var hBuf      = new byte[32 * 1024];
            var encodeRes =
                hEncoder.EncodeInto(new ArraySegment <byte>(hBuf), totalHeaders);

            Assert.Equal(totalHeaders.Count(), encodeRes.FieldCount);
            Assert.True(
                encodeRes.UsedBytes >= 5,
                "Test must encode headers with at least 5 bytes to work properly");

            // Write the first 3 bytes in a header frame
            // These cover all pseudoheaders, which wouldn't be affected by
            // possible bugs anyway
            var fh = new FrameHeader
            {
                Type     = FrameType.Headers,
                Length   = 3,
                StreamId = 1u,
                Flags    = (byte)0,
            };
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(new ArraySegment <byte>(hBuf, 0, 3));

            var offset = 3;
            var length = encodeRes.UsedBytes - 3;

            for (var i = 0; i < nrContinuations; i++)
            {
                var isLast     = i == nrContinuations - 1;
                var dataLength = isLast ? length : 1;
                fh = new FrameHeader
                {
                    Type     = FrameType.Continuation,
                    Length   = dataLength,
                    StreamId = 1u,
                    Flags    = (byte)(isLast ? ContinuationFrameFlags.EndOfHeaders : 0),
                };
                await inPipe.WriteFrameHeader(fh);

                await inPipe.WriteAsync(new ArraySegment <byte>(hBuf, offset, dataLength));

                offset += dataLength;
                length -= dataLength;
            }

            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.º 24
0
        public async Task IncompleteHeaderBlocksShouldBeDetected(
            int nrContinuations)
        {
            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();
            // Construct a proper set of header here, where a single headerfield could
            // by splitted over more than 1 fragment
            var totalHeaders = DefaultGetHeaders.TakeWhile(
                h => h.Name.StartsWith(":"));

            totalHeaders = totalHeaders.Append(
                new HeaderField {
                Name = "longname", Value = "longvalue"
            });
            totalHeaders = totalHeaders.Append(
                new HeaderField {
                Name = "abc", Value = "xyz"
            });

            // Encode all headers in a single header block
            var hBuf      = new byte[32 * 1024];
            var encodeRes =
                hEncoder.EncodeInto(new ArraySegment <byte>(hBuf), totalHeaders);

            Assert.Equal(totalHeaders.Count(), encodeRes.FieldCount);
            Assert.True(
                encodeRes.UsedBytes >= 5,
                "Test must encode headers with at least 5 bytes to work properly");

            // Write header data in multiple parts
            // The last part will miss one byte
            var offset = 0;
            var length = encodeRes.UsedBytes;

            var isLast     = nrContinuations == 0;
            var dataLength = isLast ? (length - 1) : 3;
            var fh         = new FrameHeader
            {
                Type     = FrameType.Headers,
                Length   = dataLength,
                StreamId = 1u,
                Flags    = (byte)(isLast ? HeadersFrameFlags.EndOfHeaders : 0),
            };
            await inPipe.WriteFrameHeader(fh);

            await inPipe.WriteAsync(new ArraySegment <byte>(hBuf, offset, dataLength));

            offset += dataLength;
            length -= dataLength;

            for (var i = 0; i < nrContinuations; i++)
            {
                isLast     = i == nrContinuations - 1;
                dataLength = isLast ? (length - 1) : 1;
                fh         = new FrameHeader
                {
                    Type     = FrameType.Continuation,
                    Length   = dataLength,
                    StreamId = 1u,
                    Flags    = (byte)(isLast ? ContinuationFrameFlags.EndOfHeaders : 0),
                };
                await inPipe.WriteFrameHeader(fh);

                await inPipe.WriteAsync(new ArraySegment <byte>(hBuf, offset, dataLength));

                offset += dataLength;
                length -= dataLength;
            }

            Assert.True(1 == length, "Expected to send all but 1 byte");

            // Expect a GoAway as reaction to incomplete headers
            await outPipe.AssertGoAwayReception(ErrorCode.CompressionError, 0u);

            await outPipe.AssertStreamEnd();
        }
Exemplo n.º 25
0
        public async Task ReceivingHeadersWithPaddingAndPriorityShouldBeSupported(
            int?numPadding, bool hasPrio)
        {
            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();
            var outBuf   = new byte[Settings.Default.MaxFrameSize];

            for (var i = 0; i < nrStreams; i++)
            {
                headersOk     = false;
                streamIdOk    = false;
                streamStateOk = false;

                var headerOffset = 0;
                if (numPadding != null)
                {
                    outBuf[0]     = (byte)numPadding;
                    headerOffset += 1;
                }
                if (hasPrio)
                {
                    // TODO: Initialize the priority data in this test properly
                    // if priority data checking gets inserted later on
                    headerOffset += 5;
                }
                var result = hEncoder.EncodeInto(
                    new ArraySegment <byte>(outBuf, headerOffset, outBuf.Length - headerOffset),
                    DefaultGetHeaders);
                var totalLength = headerOffset + result.UsedBytes;
                if (numPadding != null)
                {
                    totalLength += numPadding.Value;
                }

                var flags = (byte)HeadersFrameFlags.EndOfHeaders;
                if (numPadding != null)
                {
                    flags |= (byte)HeadersFrameFlags.Padded;
                }
                if (hasPrio)
                {
                    flags |= (byte)HeadersFrameFlags.Priority;
                }

                var fh = new FrameHeader
                {
                    Type     = FrameType.Headers,
                    Length   = totalLength,
                    Flags    = (byte)flags,
                    StreamId = streamId,
                };
                await inPipe.WriteFrameHeader(fh);

                await inPipe.WriteAsync(new ArraySegment <byte>(outBuf, 0, totalLength));

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