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