Пример #1
0
        public async Task ReadsShouldUnblockWrites()
        {
            var p      = new BufferedPipe(70);
            var input  = new byte[70];
            var input2 = new byte[50];
            var output = new byte[60];

            for (var i = 0; i < 70; i++)
            {
                input[i] = (byte)i;
            }

            // Fill the complete buffer
            await p.WriteAsync(new ArraySegment <byte>(input));

            var writeMoreTask = p.WriteAsync(new ArraySegment <byte>(input2));
            // Read in the background to unblock
            var readTask = Task.Run(async() =>
            {
                await Task.Delay(10);
                return(await p.ReadAsync(new ArraySegment <byte>(output)).AsTask());
            });
            // The next line would deadlock without the reader in the background
            await writeMoreTask;
            var   res = await readTask;

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(60, res.BytesRead);
            for (var i = 0; i < 60; i++)
            {
                Assert.Equal(i, output[i]);
            }
        }
Пример #2
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");
        }
Пример #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();
        }
        public async Task ServerShouldCloseTheConnectionIfCorrectPrefaceIsNotReceived()
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, inPipe, outPipe);

            var b = new byte[ClientPreface.Length];

            // Initialize with non-preface data
            for (var i = 0; i < b.Length; i++)
            {
                b[i] = 10;
            }
            await inPipe.WriteAsync(new ArraySegment <byte>(b));

            // Wait for the response - a settings frame is expected first
            // But as there's a race condition the connection could be closed
            // before or after the settings frame was fully received
            try
            {
                await outPipe.ReadAndDiscardSettings();

                var hdrBuf = new byte[FrameHeader.HeaderSize + 50];
                var header = await FrameHeader.ReceiveAsync(outPipe, hdrBuf);

                Assert.Equal(FrameType.GoAway, header.Type);
            }
            catch (Exception e)
            {
                Assert.IsType <System.IO.EndOfStreamException>(e);
            }
        }
Пример #5
0
        public async Task WritesShouldUnblockReads()
        {
            var p      = new BufferedPipe(128);
            var input  = new byte[70];
            var output = new byte[50];

            for (var i = 0; i < 70; i++)
            {
                input[i] = (byte)i;
            }
            // Start read first
            var task = p.ReadAsync(new ArraySegment <byte>(output)).AsTask();
            // Schedule write
            var writeTask = Task.Run(async() =>
            {
                await Task.Delay(10);
                await p.WriteAsync(new ArraySegment <byte>(input));
            });
            // And wait for read to unblock
            var res = await task;

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(50, res.BytesRead);
            for (var i = 0; i < 50; i++)
            {
                Assert.Equal(i, output[i]);
            }
            // The writeTask should also finish
            await writeTask;
        }
Пример #6
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);
        }
Пример #7
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();
        }
Пример #8
0
 public async Task ShouldNotErrorIfPrefaceWasReceivedWithinTimeout()
 {
     var timeout = 200;
     var pipe    = new BufferedPipe(50);
     var _       = Task.Run(async() =>
     {
         await pipe.WriteAsync(new ArraySegment <byte>(ClientPreface.Bytes));
     });
     await ClientPreface.ReadAsync(pipe, timeout);
 }
Пример #9
0
        public async Task WritesShouldBlockIfBufferIsFull()
        {
            var p      = new BufferedPipe(128);
            var input  = new byte[50];
            var output = new byte[50];
            // Fill pipe with two writes
            await p.WriteAsync(new ArraySegment <byte>(input));

            await p.WriteAsync(new ArraySegment <byte>(input));

            // Try to write more data from the pipe which is full
            var writeTask = Task.Run(async() => await p.WriteAsync(new ArraySegment <byte>(input)));
            // Start a timer in parallel
            var timerTask = Task.Delay(20);

            var finishedTask = await Task.WhenAny(writeTask, timerTask);

            Assert.Equal(timerTask, finishedTask);
            Assert.Equal(false, writeTask.IsCompleted);
        }
        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();
        }
Пример #11
0
        public async Task ServerShouldCloseTheConnectionIfNoPrefaceIsSent(
            int nrDummyPrefaceData)
        {
            var inPipe   = new BufferedPipe(1024);
            var outPipe  = new BufferedPipe(1024);
            var http2Con = BuildConnection(true, inPipe, outPipe);

            // Write some dummy data
            // All this data is not long enough to be a preface, so the
            // preface reception should time out
            if (nrDummyPrefaceData != 0)
            {
                var b = new byte[nrDummyPrefaceData];
                for (var i = 0; i < b.Length; i++)
                {
                    b[i] = 10;
                }
                await inPipe.WriteAsync(new ArraySegment <byte>(b));
            }

            // Settings will be sent by connection before the preface is
            // checked - so they must be discarded
            await outPipe.ReadAndDiscardSettings();

            // Wait for the stream to end within 400ms.
            // This is longer than the timeout in the connection waiting for the
            // preface

            var buf          = new byte[1];
            var readTask     = outPipe.ReadAsync(new ArraySegment <byte>(buf)).AsTask();
            var timeoutTask  = Task.Delay(400);
            var finishedTask = await Task.WhenAny(
                new Task[] { readTask, timeoutTask });

            if (ReferenceEquals(finishedTask, readTask))
            {
                var res = readTask.Result;
                Assert.Equal(true, res.EndOfStream);
                Assert.Equal(0, res.BytesRead);
                // Received end of stream
                return;
            }
            Assert.True(false,
                        "Expected connection to close outgoing stream. " +
                        "Got timeout");
        }
Пример #12
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);
        }
Пример #13
0
        public async Task WritingOnOneEndShallYieldInDataOnTheOtherEnd()
        {
            var p      = new BufferedPipe(128);
            var input  = new byte[70];
            var output = new byte[50];

            for (var i = 0; i < 70; i++)
            {
                input[i] = (byte)i;
            }

            await p.WriteAsync(new ArraySegment <byte>(input));

            var res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(50, res.BytesRead);
            for (var i = 0; i < 50; i++)
            {
                Assert.Equal(i, output[i]);
            }

            await p.CloseAsync();

            res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(20, res.BytesRead);
            for (var i = 0; i < 20; i++)
            {
                Assert.Equal(50 + i, output[i]);
            }

            await p.CloseAsync();

            res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(true, res.EndOfStream);
            Assert.Equal(0, res.BytesRead);
        }
Пример #14
0
        public async Task ReadsShouldBlockIfNoDataIsAvailable()
        {
            var p      = new BufferedPipe(128);
            var input  = new byte[30];
            var output = new byte[50];
            // Fill some data first - first try should succeed
            await p.WriteAsync(new ArraySegment <byte>(input));

            var res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(30, res.BytesRead);

            // Try to read more data from the pipe which wil never get available
            var readTask = Task.Run(async() => await p.ReadAsync(new ArraySegment <byte>(output)));
            // Start a timer in parallel
            var timerTask = Task.Delay(20);

            var finishedTask = await Task.WhenAny(readTask, timerTask);

            Assert.Equal(timerTask, finishedTask);
            Assert.Equal(false, readTask.IsCompleted);
        }
Пример #15
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();
        }
Пример #16
0
        public async Task CloseShouldAllowRemainingDataToBeReadBeforeSignalClose()
        {
            var p      = new BufferedPipe(128);
            var input  = new byte[20];
            var output = new byte[10];

            for (var i = 0; i < 20; i++)
            {
                input[i] = (byte)i;
            }
            await p.WriteAsync(new ArraySegment <byte>(input));

            await p.CloseAsync();

            var res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(10, res.BytesRead);
            for (var i = 0; i < 10; i++)
            {
                Assert.Equal(i, output[i]);
            }

            res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(false, res.EndOfStream);
            Assert.Equal(10, res.BytesRead);
            for (var i = 0; i < 10; i++)
            {
                Assert.Equal(i + 10, output[i]);
            }

            res = await p.ReadAsync(new ArraySegment <byte>(output));

            Assert.Equal(true, res.EndOfStream);
            Assert.Equal(0, res.BytesRead);
        }
Пример #17
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();
        }
        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();
        }
Пример #19
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");
        }
Пример #20
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");
        }
Пример #21
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();
        }
Пример #22
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);
        }