Beispiel #1
0
        private void InsertHeader(ISink sink, ICharSequence name, ICharSequence value, HpackUtil.IndexType indexType)
        {
            sink.AppendToHeaderList(name, value);

            switch (indexType)
            {
            case HpackUtil.IndexType.None:
            case HpackUtil.IndexType.Never:
                break;

            case HpackUtil.IndexType.Incremental:
                _hpackDynamicTable.Add(new HpackHeaderField(name, value));
                break;

            default:
                ThrowHelper.ThrowException_ShouldNotReachHere();
                break;
            }
        }
Beispiel #2
0
        public void Decode(IByteBuffer input, ISink sink)
        {
            int           index          = 0;
            int           nameLength     = 0;
            int           valueLength    = 0;
            byte          state          = ReadHeaderRepresentation;
            bool          huffmanEncoded = false;
            ICharSequence name           = null;

            HpackUtil.IndexType indexType = HpackUtil.IndexType.None;
            while (input.IsReadable())
            {
                switch (state)
                {
                case ReadHeaderRepresentation:
                    byte b = input.ReadByte();
                    if (_maxDynamicTableSizeChangeRequired && (b & 0xE0) != 0x20)
                    {
                        // HpackEncoder MUST signal maximum dynamic table size change
                        ThrowHelper.ThrowHttp2Exception_MaxDynamicTableSizeChangeRequired();
                    }

                    if (b > 127)
                    {
                        // Indexed Header Field
                        index = b & 0x7F;
                        switch (index)
                        {
                        case 0:
                            ThrowHelper.ThrowHttp2Exception_DecodeIllegalIndexValue();
                            break;

                        case 0x7F:
                            state = ReadIndexedHeader;
                            break;

                        default:
                            HpackHeaderField idxHeader = GetIndexedHeader(index);
                            sink.AppendToHeaderList(idxHeader._name, idxHeader._value);
                            break;
                        }
                    }
                    else if ((b & 0x40) == 0x40)
                    {
                        // Literal Header Field with Incremental Indexing
                        indexType = HpackUtil.IndexType.Incremental;
                        index     = b & 0x3F;
                        switch (index)
                        {
                        case 0:
                            state = ReadLiteralHeaderNameLengthPrefix;
                            break;

                        case 0x3F:
                            state = ReadIndexedHeaderName;
                            break;

                        default:
                            // Index was stored as the prefix
                            name       = ReadName(index);
                            nameLength = name.Count;
                            state      = ReadLiteralHeaderValueLengthPrefix;
                            break;
                        }
                    }
                    else if ((b & 0x20) == 0x20)
                    {
                        // Dynamic Table Size Update
                        index = b & 0x1F;
                        if (index == 0x1F)
                        {
                            state = ReadMaxDynamicTableSize;
                        }
                        else
                        {
                            SetDynamicTableSize(index);
                            state = ReadHeaderRepresentation;
                        }
                    }
                    else
                    {
                        // Literal Header Field without Indexing / never Indexed
                        indexType = ((b & 0x10) == 0x10) ? HpackUtil.IndexType.Never : HpackUtil.IndexType.None;
                        index     = b & 0x0F;
                        switch (index)
                        {
                        case 0:
                            state = ReadLiteralHeaderNameLengthPrefix;
                            break;

                        case 0x0F:
                            state = ReadIndexedHeaderName;
                            break;

                        default:
                            // Index was stored as the prefix
                            name       = ReadName(index);
                            nameLength = name.Count;
                            state      = ReadLiteralHeaderValueLengthPrefix;
                            break;
                        }
                    }

                    break;

                case ReadMaxDynamicTableSize:
                    SetDynamicTableSize(DecodeULE128(input, (long)index));
                    state = ReadHeaderRepresentation;
                    break;

                case ReadIndexedHeader:
                    HpackHeaderField indexedHeader = GetIndexedHeader(DecodeULE128(input, index));
                    sink.AppendToHeaderList(indexedHeader._name, indexedHeader._value);
                    state = ReadHeaderRepresentation;
                    break;

                case ReadIndexedHeaderName:
                    // Header Name matches an entry in the Header Table
                    name       = ReadName(DecodeULE128(input, index));
                    nameLength = name.Count;
                    state      = ReadLiteralHeaderValueLengthPrefix;
                    break;

                case ReadLiteralHeaderNameLengthPrefix:
                    b = input.ReadByte();
                    huffmanEncoded = (b & 0x80) == 0x80;
                    index          = b & 0x7F;
                    if (index == 0x7f)
                    {
                        state = ReadLiteralHeaderNameLength;
                    }
                    else
                    {
                        nameLength = index;
                        state      = ReadLiteralHeaderName;
                    }

                    break;

                case ReadLiteralHeaderNameLength:
                    // Header Name is a Literal String
                    nameLength = DecodeULE128(input, index);
                    state      = ReadLiteralHeaderName;
                    break;

                case ReadLiteralHeaderName:
                    // Wait until entire name is readable
                    if (input.ReadableBytes < nameLength)
                    {
                        ThrowHelper.ThrowArgumentException_NotEnoughData(input);
                    }

                    name = ReadStringLiteral(input, nameLength, huffmanEncoded);

                    state = ReadLiteralHeaderValueLengthPrefix;
                    break;

                case ReadLiteralHeaderValueLengthPrefix:
                    b = input.ReadByte();
                    huffmanEncoded = (b & 0x80) == 0x80;
                    index          = b & 0x7F;
                    switch (index)
                    {
                    case 0x7f:
                        state = ReadLiteralHeaderValueLength;
                        break;

                    case 0:
                        InsertHeader(sink, name, AsciiString.Empty, indexType);
                        state = ReadHeaderRepresentation;
                        break;

                    default:
                        valueLength = index;
                        state       = ReadLiteralHeaderValue;
                        break;
                    }

                    break;

                case ReadLiteralHeaderValueLength:
                    // Header Value is a Literal String
                    valueLength = DecodeULE128(input, index);
                    state       = ReadLiteralHeaderValue;
                    break;

                case ReadLiteralHeaderValue:
                    // Wait until entire value is readable
                    if (input.ReadableBytes < valueLength)
                    {
                        ThrowHelper.ThrowArgumentException_NotEnoughData(input);
                    }

                    ICharSequence value = ReadStringLiteral(input, valueLength, huffmanEncoded);
                    InsertHeader(sink, name, value, indexType);
                    state = ReadHeaderRepresentation;
                    break;

                default:
                    ThrowHelper.ThrowException_ShouldNotReachHere(state);
                    break;
                }
            }

            if (state != ReadHeaderRepresentation)
            {
                ThrowHelper.ThrowConnectionError_IncompleteHeaderBlockFragment();
            }
        }