示例#1
0
        public void CreatingAConnectionWithInvalidUpgradeShouldThrow()
        {
            var inPipe  = new BufferedPipe(1024);
            var outPipe = new BufferedPipe(1024);

            var config = new ConnectionConfigurationBuilder(true)
                         .UseStreamListener(s => false)
                         .Build();

            var builder = new ServerUpgradeRequestBuilder();

            builder.SetHeaders(DefaultGetHeaders.ToList());
            builder.SetHttp2Settings("!");
            var upgrade = builder.Build();

            Assert.False(upgrade.IsValid);

            var ex = Assert.Throws <ArgumentException>(() =>
            {
                var conn = new Connection(
                    config, inPipe, outPipe,
                    new Connection.Options
                {
                    Logger = loggerProvider.CreateLogger(""),
                    ServerUpgradeRequest = upgrade,
                });
            });

            Assert.Equal(
                "The ServerUpgradeRequest is invalid.\n" +
                "Invalid upgrade requests must be denied by the HTTP/1 handler",
                ex.Message);
        }
示例#2
0
        public void UpgradesWithPayloadMustHaveMatchingContentLength(
            int?contentLength, int?payloadLength, bool isOk)
        {
            var builder = new ServerUpgradeRequestBuilder();

            builder.SetHttp2Settings("");
            var headers = DefaultGetHeaders.ToList();

            if (contentLength != null)
            {
                headers.Add(new HeaderField()
                {
                    Name  = "content-length",
                    Value = contentLength.ToString()
                });
            }
            builder.SetHeaders(headers);

            if (payloadLength != null)
            {
                const int padding = 3;
                var       pl      = new byte[padding + payloadLength.Value];
                builder.SetPayload(new ArraySegment <byte>(pl, padding, payloadLength.Value));
            }

            var upgrade = builder.Build();

            Assert.Equal(isOk, upgrade.IsValid);
        }
示例#3
0
        public void UpgradesWithInvalidEncodedHttp2SettingsStringShouldBeInvalid(
            string encodedSettings)
        {
            var builder = new ServerUpgradeRequestBuilder();

            builder.SetHeaders(DefaultGetHeaders.ToList());
            builder.SetHttp2Settings(encodedSettings);
            var upgrade = builder.Build();

            Assert.False(upgrade.IsValid);
        }
示例#4
0
        public void ValidHttp2SettingsShouldBeAccepted(
            byte[] payload)
        {
            var builder = new ServerUpgradeRequestBuilder();

            builder.SetHeaders(DefaultGetHeaders.ToList());
            var base64 = Convert.ToBase64String(payload);

            base64 = base64.Replace('/', '_');
            base64 = base64.Replace('+', '-');
            builder.SetHttp2Settings(base64);
            var upgrade = builder.Build();

            Assert.True(upgrade.IsValid);
        }
示例#5
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);
        }
示例#6
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();
        }
示例#7
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);
        }
示例#8
0
        public async Task ServerUpgradeRequestsShouldDispatchStream1(
            int payloadLength)
        {
            var     inPipe            = new BufferedPipe(1024);
            var     outPipe           = new BufferedPipe(1024);
            int     nrAcceptedStreams = 0;
            IStream stream            = null;
            var     handlerDone       = new SemaphoreSlim(0);

            Func <IStream, bool> listener = (s) =>
            {
                Interlocked.Increment(ref nrAcceptedStreams);
                Task.Run(() =>
                {
                    stream = s;
                    handlerDone.Release();
                });
                return(true);
            };

            var startOfPayload = 44;

            byte[] payload = new byte[payloadLength];
            for (var i = 0; i < payloadLength; i++)
            {
                payload[i] = (byte)(startOfPayload + i);
            }

            var builder = new ServerUpgradeRequestBuilder();
            var headers = DefaultGetHeaders.ToList();

            if (payloadLength != 0)
            {
                builder.SetPayload(new ArraySegment <byte>(payload));
                headers.Add(new HeaderField()
                {
                    Name  = "content-length",
                    Value = payloadLength.ToString()
                });
            }
            builder.SetHeaders(headers);
            builder.SetHttp2Settings("");
            var upgrade = builder.Build();

            var config = new ConnectionConfigurationBuilder(true)
                         .UseStreamListener(listener)
                         .Build();

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

            await conn.PerformHandshakes(inPipe, outPipe);

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

            Assert.True(requestDone, "Expected handler to complete within timeout");

            Assert.Equal(1u, stream.Id);
            Assert.Equal(StreamState.HalfClosedRemote, stream.State);
            var rcvdHeaders = await stream.ReadHeadersAsync();

            Assert.True(headers.SequenceEqual(rcvdHeaders));
            var allData = await stream.ReadAllToArrayWithTimeout();

            Assert.Equal(payloadLength, allData.Length);
            Assert.Equal(payload, allData);

            Assert.Equal(1, nrAcceptedStreams);
        }
示例#9
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();
        }
示例#10
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");
        }