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