예제 #1
0
        // Called when we have complete header with name and value.
        private void OnHeaderComplete(HeaderCallback onHeader, object onHeaderState, ReadOnlySpan <byte> headerName, ReadOnlySpan <byte> headerValue)
        {
            // Call provided callback.
            onHeader(onHeaderState, headerName, headerValue);

            if (_index)
            {
                _dynamicTable.Insert(headerName, headerValue);
            }
        }
예제 #2
0
        public void Decode(ReadOnlySpan <byte> data, HeaderCallback onHeader, object onHeaderState)
        {
            for (int i = 0; i < data.Length; i++)
            {
                byte b = data[i];

                switch (_state)
                {
                case State.Ready:
                    // TODO: Instead of masking and comparing each prefix value,
                    // consider doing a 16-way switch on the first four bits (which is the max prefix size).
                    // Look at this once we have more concrete perf data.
                    if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation)
                    {
                        int val = b & ~IndexedHeaderFieldMask;

                        if (_integerDecoder.StartDecode((byte)val, IndexedHeaderFieldPrefix))
                        {
                            OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState);
                        }
                        else
                        {
                            _state = State.HeaderFieldIndex;
                        }
                    }
                    else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation)
                    {
                        _index = true;
                        int val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask;

                        if (val == 0)
                        {
                            _state = State.HeaderNameLength;
                        }
                        else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix))
                        {
                            OnIndexedHeaderName(_integerDecoder.Value);
                        }
                        else
                        {
                            _state = State.HeaderNameIndex;
                        }
                    }
                    else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation)
                    {
                        _index = false;
                        int val = b & ~LiteralHeaderFieldWithoutIndexingMask;

                        if (val == 0)
                        {
                            _state = State.HeaderNameLength;
                        }
                        else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix))
                        {
                            OnIndexedHeaderName(_integerDecoder.Value);
                        }
                        else
                        {
                            _state = State.HeaderNameIndex;
                        }
                    }
                    else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation)
                    {
                        _index = false;
                        int val = b & ~LiteralHeaderFieldNeverIndexedMask;

                        if (val == 0)
                        {
                            _state = State.HeaderNameLength;
                        }
                        else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix))
                        {
                            OnIndexedHeaderName(_integerDecoder.Value);
                        }
                        else
                        {
                            _state = State.HeaderNameIndex;
                        }
                    }
                    else if ((b & DynamicTableSizeUpdateMask) == DynamicTableSizeUpdateRepresentation)
                    {
                        if (_integerDecoder.StartDecode((byte)(b & ~DynamicTableSizeUpdateMask), DynamicTableSizeUpdatePrefix))
                        {
                            // TODO: validate that it's less than what's defined via SETTINGS
                            _dynamicTable.Resize(_integerDecoder.Value);
                        }
                        else
                        {
                            _state = State.DynamicTableSizeUpdate;
                        }
                    }
                    else
                    {
                        // Can't happen
                        Debug.Fail("Unreachable code");
                        throw new InternalException();
                    }

                    break;

                case State.HeaderFieldIndex:
                    if (_integerDecoder.Decode(b))
                    {
                        OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState);
                    }

                    break;

                case State.HeaderNameIndex:
                    if (_integerDecoder.Decode(b))
                    {
                        OnIndexedHeaderName(_integerDecoder.Value);
                    }

                    break;

                case State.HeaderNameLength:
                    _huffman = (b & HuffmanMask) != 0;

                    if (_integerDecoder.StartDecode((byte)(b & ~HuffmanMask), StringLengthPrefix))
                    {
                        OnStringLength(_integerDecoder.Value, nextState: State.HeaderName);
                    }
                    else
                    {
                        _state = State.HeaderNameLengthContinue;
                    }

                    break;

                case State.HeaderNameLengthContinue:
                    if (_integerDecoder.Decode(b))
                    {
                        OnStringLength(_integerDecoder.Value, nextState: State.HeaderName);
                    }

                    break;

                case State.HeaderName:
                    _stringOctets[_stringIndex++] = b;

                    if (_stringIndex == _stringLength)
                    {
                        OnString(nextState: State.HeaderValueLength);
                    }

                    break;

                case State.HeaderValueLength:
                    _huffman = (b & HuffmanMask) != 0;

                    if (_integerDecoder.StartDecode((byte)(b & ~HuffmanMask), StringLengthPrefix))
                    {
                        OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue);
                    }
                    else
                    {
                        _state = State.HeaderValueLengthContinue;
                    }

                    break;

                case State.HeaderValueLengthContinue:
                    if (_integerDecoder.Decode(b))
                    {
                        OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue);
                    }

                    break;

                case State.HeaderValue:
                    _stringOctets[_stringIndex++] = b;

                    if (_stringIndex == _stringLength)
                    {
                        OnString(nextState: State.Ready);

                        var headerNameSpan  = new ReadOnlySpan <byte>(_headerName, 0, _headerNameLength);
                        var headerValueSpan = new ReadOnlySpan <byte>(_headerValueOctets, 0, _headerValueLength);

                        onHeader(onHeaderState, headerNameSpan, headerValueSpan);

                        if (_index)
                        {
                            _dynamicTable.Insert(headerNameSpan, headerValueSpan);
                        }
                    }

                    break;

                case State.DynamicTableSizeUpdate:
                    if (_integerDecoder.Decode(b))
                    {
                        if (_integerDecoder.Value > _maxDynamicTableSize)
                        {
                            // Dynamic table size update is too large.
                            throw new HPackDecodingException();
                        }

                        _dynamicTable.Resize(_integerDecoder.Value);
                        _state = State.Ready;
                    }

                    break;

                default:
                    // Can't happen
                    Debug.Fail("HPACK decoder reach an invalid state");
                    throw new InternalException(_state);
                }
            }
        }