public async ValueTask <long> TryReadStreamIdAsync() { while (true) { var result = await ReadApplicationInputAsync(); var readableBuffer = result.Buffer; var consumed = readableBuffer.Start; var examined = readableBuffer.End; try { if (!readableBuffer.IsEmpty) { var id = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out examined); if (id != -1) { return(id); } } if (result.IsCompleted) { return(-1); } } finally { Pair.Application.Input.AdvanceTo(consumed, examined); } } }
private async ValueTask <long> TryReadStreamHeaderAsync() { // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-6.2 while (_isClosed == 0) { var result = await Input.ReadAsync(); var readableBuffer = result.Buffer; var consumed = readableBuffer.Start; var examined = readableBuffer.End; try { if (!readableBuffer.IsEmpty) { var id = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out examined); if (id != -1) { return(id); } } if (result.IsCompleted) { return(-1); } } finally { Input.AdvanceTo(consumed, examined); } } return(-1); }
internal async ValueTask <Dictionary <long, long> > ExpectSettingsAsync() { var http3WithPayload = await ReceiveFrameAsync(); Http3InMemory.AssertFrameType(http3WithPayload.Type, Http3FrameType.Settings); var payload = http3WithPayload.PayloadSequence; var settings = new Dictionary <long, long>(); while (true) { var id = VariableLengthIntegerHelper.GetInteger(payload, out var consumed, out _); if (id == -1) { break; } payload = payload.Slice(consumed); var value = VariableLengthIntegerHelper.GetInteger(payload, out consumed, out _); if (value == -1) { break; } payload = payload.Slice(consumed); settings.Add(id, value); } return(settings); }
internal void VerifyGoAway(Http3FrameWithPayload frame, long expectedLastStreamId, Http3ErrorCode expectedErrorCode) { Assert.Equal(Http3FrameType.GoAway, frame.Type); var payload = frame.Payload; Assert.True(VariableLengthIntegerHelper.TryRead(payload.Span, out var streamId, out var _)); Assert.Equal(expectedLastStreamId, streamId); }
internal async Task SendGoAwayAsync(long streamId, bool endStream = false) { var data = new byte[VariableLengthIntegerHelper.GetByteCount(streamId)]; VariableLengthIntegerHelper.WriteInteger(data, streamId); await SendFrameAsync(Http3FrameType.GoAway, data, endStream); }
public void TryWrite_BufferNotEmpty_OneByteLimit(long longToEncode) { Span <byte> span = new Span <byte>(new byte[1]); bool isSuccess = VariableLengthIntegerHelper.TryWrite(span, longToEncode, out int bytesWritten); Assert.True(isSuccess); Assert.Equal(1, bytesWritten); Assert.Equal(longToEncode, span[0]); }
public void TryWrite_BufferEmpty() { Span <byte> span = new Span <byte>(); long longToEncode = 1; bool isSuccess = VariableLengthIntegerHelper.TryWrite(span, longToEncode, out int bytesWritten); Assert.False(isSuccess); Assert.Equal(0, bytesWritten); }
public void TryRead_FromReadOnlySpan_BufferEmpty() { ReadOnlySpan <byte> readOnlySpan = new ReadOnlySpan <byte>(); bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan, out long value, out int bytesRead); Assert.False(isSuccess); Assert.Equal(0, value); Assert.Equal(0, bytesRead); }
public void TryWrite_BufferNotSizedCorrectly_EightByteLimit() { long longToEncode = 1073741824; Span <byte> span = new Span <byte>(new byte[1]); bool isSuccess = VariableLengthIntegerHelper.TryWrite(span, longToEncode, out int bytesWritten); Assert.False(isSuccess); Assert.Equal(0, bytesWritten); }
public void TryWrite_BufferNotEmpty_EightByteLimit(long longToEncode, byte[] expected) { Span <byte> span = new Span <byte>(new byte[8]); bool isSuccess = VariableLengthIntegerHelper.TryWrite(span, longToEncode, out int bytesWritten); Assert.True(isSuccess); Assert.Equal(8, bytesWritten); Assert.Equal(expected, span.ToArray()); }
public void CheckEncoding(long input, byte[] expected) { var outputBuffer = new Span <byte>(new byte[8]); var encodedLength = VariableLengthIntegerHelper.WriteInteger(outputBuffer, input); Assert.Equal(expected.Length, encodedLength); for (var i = 0; i < expected.Length; i++) { Assert.Equal(expected[i], outputBuffer[i]); } }
internal static void WriteSettings(List <Http3PeerSetting> settings, Span <byte> destination) { foreach (var setting in settings) { var parameterLength = VariableLengthIntegerHelper.WriteInteger(destination, (long)setting.Parameter); destination = destination.Slice(parameterLength); var valueLength = VariableLengthIntegerHelper.WriteInteger(destination, (long)setting.Value); destination = destination.Slice(valueLength); } }
internal static int CalculateSettingsSize(List <Http3PeerSetting> settings) { var length = 0; foreach (var setting in settings) { length += VariableLengthIntegerHelper.GetByteCount((long)setting.Parameter); length += VariableLengthIntegerHelper.GetByteCount(setting.Value); } return(length); }
public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialFourByteLengthMask_TryReadNotUInt32BigEndian() { ReadOnlySpan <byte> readOnlySpan = new ReadOnlySpan <byte>(new byte[] { 128 }); bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan, out long value, out int bytesRead); Assert.False(isSuccess); Assert.Equal(0, value); Assert.Equal(0, bytesRead); }
public void GetInteger_NotValidSegmentedSequence() { MemorySegment <byte> memorySegment1 = new MemorySegment <byte>(new byte[] { 192 }); MemorySegment <byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 2 }); ReadOnlySequence <byte> readOnlySequence = new ReadOnlySequence <byte>( memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length); long result = VariableLengthIntegerHelper.GetInteger(readOnlySequence, out SequencePosition consumed, out SequencePosition examined); Assert.Equal(-1, result); Assert.Equal(0, consumed.GetInteger()); Assert.Equal(6, examined.GetInteger()); }
public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialOneByteLengthMask() { ReadOnlySpan <byte> readOnlySpan = new ReadOnlySpan <byte>(new byte[] { 1 }); bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan, out long value, out int bytesRead); Assert.True(isSuccess); Assert.Equal(1, value); Assert.Equal(1, bytesRead); }
internal void VerifyGoAway(Http3FrameWithPayload frame, long expectedLastStreamId) { Http3InMemory.AssertFrameType(frame.Type, Http3FrameType.GoAway); var payload = frame.Payload; if (!VariableLengthIntegerHelper.TryRead(payload.Span, out var streamId, out var _)) { throw new InvalidOperationException("Failed to read GO_AWAY stream ID."); } if (streamId != expectedLastStreamId) { throw new InvalidOperationException($"Expected stream ID {expectedLastStreamId}, got {streamId}."); } }
public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialEightByteLengthMask_TryReadUInt64BigEndian() { ReadOnlySpan <byte> readOnlySpan = new ReadOnlySpan <byte>( new byte[] { 192, 0, 0, 0, 0, 0, 0, 4 }); bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan, out long value, out int bytesRead); Assert.True(isSuccess); Assert.Equal(4, value); Assert.Equal(8, bytesRead); }
public async Task WriteStreamIdAsync(int id) { var writableBuffer = Pair.Application.Output; void WriteSpan(PipeWriter pw) { var buffer = pw.GetSpan(sizeHint: 8); var lengthWritten = VariableLengthIntegerHelper.WriteInteger(buffer, id); pw.Advance(lengthWritten); } WriteSpan(writableBuffer); await FlushAsync(writableBuffer); }
/* https://quicwg.org/base-drafts/draft-ietf-quic-http.html#frame-layout * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length (i) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Frame Payload (*) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ internal static bool TryReadFrame(ref ReadOnlySequence <byte> readableBuffer, Http3RawFrame frame, out ReadOnlySequence <byte> framePayload) { framePayload = ReadOnlySequence <byte> .Empty; SequencePosition consumed; SequencePosition examined; var type = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out examined); if (type == -1) { return(false); } var firstLengthBuffer = readableBuffer.Slice(consumed); var length = VariableLengthIntegerHelper.GetInteger(firstLengthBuffer, out consumed, out examined); // Make sure the whole frame is buffered if (length == -1) { return(false); } var startOfFramePayload = readableBuffer.Slice(consumed); if (startOfFramePayload.Length < length) { return(false); } frame.Length = length; frame.Type = (Http3FrameType)type; // The remaining payload minus the extra fields framePayload = startOfFramePayload.Slice(0, length); readableBuffer = readableBuffer.Slice(framePayload.End); return(true); }
public void GetByteCountTest(long longToEncode, int expectedLimit) { int result = VariableLengthIntegerHelper.GetByteCount(longToEncode); Assert.Equal(expectedLimit, result); }
public void CheckDecoding(long expected, byte[] input) { var decoded = VariableLengthIntegerHelper.GetInteger(new ReadOnlySequence <byte>(input), out _, out _); Assert.Equal(expected, decoded); }
public async ValueTask <long> ReadNextStreamHeaderAsync(Http3StreamContext context, long streamId, Http3StreamType?advanceOn) { var Input = context.Transport.Input; var advance = false; SequencePosition consumed = default; SequencePosition start = default; try { while (!_isClosed) { var result = await Input.ReadAsync(); if (result.IsCanceled) { throw new Exception(); } var readableBuffer = result.Buffer; consumed = readableBuffer.Start; start = readableBuffer.Start; if (!readableBuffer.IsEmpty) { var value = VariableLengthIntegerHelper.GetInteger(readableBuffer, out consumed, out _); if (value != -1) { if (!advanceOn.HasValue || value == (long)advanceOn) { advance = true; } return(value); } } if (result.IsCompleted) { return(-1L); } } } catch (Exception) { throw new Http3PendingStreamException(CoreStrings.AttemptedToReadHeaderOnAbortedStream, streamId, _abortedException); } finally { if (!_isClosed) { if (advance) { Input.AdvanceTo(consumed); } else { Input.AdvanceTo(start); } } StreamTimeoutTicks = default; } return(-1L); }