|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Buffers;
using System.Net.Http.HPack;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http3.QPack;
internal sealed class DecoderStreamReader
{
private enum State
{
Ready,
HeaderAckowledgement,
StreamCancellation,
InsertCountIncrement
}
//0 1 2 3 4 5 6 7
//+---+---+---+---+---+---+---+---+
//| 1 | Stream ID(7+) |
//+---+---------------------------+
private const byte HeaderAcknowledgementMask = 0x80;
private const byte HeaderAcknowledgementRepresentation = 0x80;
private const byte HeaderAcknowledgementPrefixMask = 0x7F;
private const int HeaderAcknowledgementPrefix = 7;
//0 1 2 3 4 5 6 7
//+---+---+---+---+---+---+---+---+
//| 0 | 1 | Stream ID(6+) |
//+---+---+-----------------------+
private const byte StreamCancellationMask = 0xC0;
private const byte StreamCancellationRepresentation = 0x40;
private const byte StreamCancellationPrefixMask = 0x3F;
private const int StreamCancellationPrefix = 6;
//0 1 2 3 4 5 6 7
//+---+---+---+---+---+---+---+---+
//| 0 | 0 | Increment(6+) |
//+---+---+-----------------------+
private const byte InsertCountIncrementMask = 0xC0;
private const byte InsertCountIncrementRepresentation = 0x00;
private const byte InsertCountIncrementPrefixMask = 0x3F;
private const int InsertCountIncrementPrefix = 6;
private IntegerDecoder _integerDecoder;
private State _state;
public DecoderStreamReader()
{
}
public void Read(ReadOnlySequence<byte> data)
{
foreach (var segment in data)
{
var span = segment.Span;
for (var i = 0; i < span.Length; i++)
{
OnByte(span[i]);
}
}
}
private void OnByte(byte b)
{
int intResult;
int prefixInt;
switch (_state)
{
case State.Ready:
if ((b & HeaderAcknowledgementMask) == HeaderAcknowledgementRepresentation)
{
prefixInt = HeaderAcknowledgementPrefixMask & b;
if (_integerDecoder.BeginTryDecode((byte)prefixInt, HeaderAcknowledgementPrefix, out intResult))
{
OnHeaderAcknowledgement(intResult);
}
else
{
_state = State.HeaderAckowledgement;
}
}
else if ((b & StreamCancellationMask) == StreamCancellationRepresentation)
{
prefixInt = StreamCancellationPrefixMask & b;
if (_integerDecoder.BeginTryDecode((byte)prefixInt, StreamCancellationPrefix, out intResult))
{
OnStreamCancellation(intResult);
}
else
{
_state = State.StreamCancellation;
}
}
else if ((b & InsertCountIncrementMask) == InsertCountIncrementRepresentation)
{
prefixInt = InsertCountIncrementPrefixMask & b;
if (_integerDecoder.BeginTryDecode((byte)prefixInt, InsertCountIncrementPrefix, out intResult))
{
OnInsertCountIncrement(intResult);
}
else
{
_state = State.InsertCountIncrement;
}
}
break;
}
}
private void OnInsertCountIncrement(int intResult)
{
// increment some count.
_state = State.Ready;
}
private void OnStreamCancellation(int streamId)
{
// Remove stream?
_state = State.Ready;
}
private void OnHeaderAcknowledgement(int intResult)
{
// Acknowledge header somehow
_state = State.Ready;
}
}
|