示例#1
0
        private void OnIndexedHeaderField(int index, HeaderCallback onHeader)
        {
            HeaderField header = GetHeader(index);

            onHeader(new Span <byte>(header.Name), new Span <byte>(header.Value));
            _state = State.Ready;
        }
示例#2
0
        private void OnIndexedHeaderField(int index, HeaderCallback onHeader, object onHeaderState)
        {
            HeaderField header = GetHeader(index);

            onHeader(onHeaderState, new ReadOnlySpan <byte>(header.Name), new ReadOnlySpan <byte>(header.Value));
            _state = State.Ready;
        }
示例#3
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);
            }
        }
示例#4
0
        private static void readHeader <T>(BinaryReader reader, IList <T> items, HeaderCallback <T> readCallback)
        {
            // Count
            int count = BinaryReaderTools.ReadNumber(reader);

            // Items)
            for (int i = 0; i < count; i++)
            {
                string itemAsText = BinaryReaderTools.ReadString(reader);
                T      item       = readCallback(itemAsText);
                items.Add(item);
            }
        }
示例#5
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);
                }
            }
        }
示例#6
0
        public void Decode(ReadOnlySpan <byte> data, bool endHeaders, 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)
                    {
                        _headersObserved = true;

                        int val = b & ~IndexedHeaderFieldMask;

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

                        _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)
                    {
                        _headersObserved = true;

                        _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)
                    {
                        _headersObserved = true;

                        _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)
                    {
                        // https://tools.ietf.org/html/rfc7541#section-4.2
                        // This dynamic table size
                        // update MUST occur at the beginning of the first header block
                        // following the change to the dynamic table size.
                        if (_headersObserved)
                        {
                            throw new HPackDecodingException(SR.net_http_hpack_late_dynamic_table_size_update);
                        }

                        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))
                    {
                        if (_integerDecoder.Value > 0)
                        {
                            OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue);
                        }
                        else
                        {
                            OnStringLength(_integerDecoder.Value, nextState: State.Ready);
                            OnHeaderComplete(onHeader, onHeaderState, new ReadOnlySpan <byte>(_headerName, 0, _headerNameLength), new ReadOnlySpan <byte>());
                        }
                    }
                    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);

                        OnHeaderComplete(onHeader, onHeaderState, 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);
                }
            }

            if (endHeaders)
            {
                if (_state != State.Ready)
                {
                    throw new HPackDecodingException(SR.net_http_hpack_incomplete_header_block);
                }

                _headersObserved = false;
            }
        }
        private static void ReadHeader <T>(BinaryReader reader, ICollection <T> items, HeaderCallback <T> readCallback)
        {
            // Count
            var count = BinaryReaderTools.ReadNumber(reader);

            // Items
            for (var i = 0; i < count; i++)
            {
                var itemAsText = BinaryReaderTools.ReadString(reader);
                var item       = readCallback(itemAsText);
                items.Add(item);
            }
        }