/// <summary>
        /// Encode literal header field according to Section 6.2.
        /// </summary>
        /// <param name="output">Output.</param>
        /// <param name="name">Name.</param>
        /// <param name="value">Value.</param>
        /// <param name="indexType">Index type.</param>
        /// <param name="nameIndex">Name index.</param>
        private void encodeLiteral(BinaryWriter output, string name, string value, HpackUtil.IndexType indexType,
                                   int nameIndex)
        {
            int mask;
            int prefixBits;

            switch (indexType)
            {
            case HpackUtil.IndexType.Incremental:
                mask       = 0x40;
                prefixBits = 6;
                break;

            case HpackUtil.IndexType.None:
                mask       = 0x00;
                prefixBits = 4;
                break;

            case HpackUtil.IndexType.Never:
                mask       = 0x10;
                prefixBits = 4;
                break;

            default:
                throw new Exception("should not reach here");
            }

            encodeInteger(output, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex);
            if (nameIndex == -1)
            {
                encodeStringLiteral(output, name);
            }

            encodeStringLiteral(output, value);
        }
Exemple #2
0
        /// <summary>
        /// Encode literal header field according to Section 6.2.
        /// </summary>
        /// <param name="output"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <param name="indexType"></param>
        /// <param name="nameIndex"></param>
        void EncodeLiteral(IByteBuffer output, ICharSequence name, ICharSequence value, HpackUtil.IndexType indexType, int nameIndex)
        {
            bool nameIndexValid = nameIndex != -1;

            switch (indexType)
            {
            case HpackUtil.IndexType.Incremental:
                EncodeInteger(output, 0x40, 6, nameIndexValid ? nameIndex : 0);
                break;

            case HpackUtil.IndexType.None:
                EncodeInteger(output, 0x00, 4, nameIndexValid ? nameIndex : 0);
                break;

            case HpackUtil.IndexType.Never:
                EncodeInteger(output, 0x10, 4, nameIndexValid ? nameIndex : 0);
                break;

            default:
                ThrowHelper.ThrowException_ShouldNotReachHere();
                break;
            }

            if (!nameIndexValid)
            {
                EncodeStringLiteral(output, name);
            }

            EncodeStringLiteral(output, value);
        }
Exemple #3
0
        /// <summary>
        /// Decode the header block into header fields.
        /// </summary>
        /// <param name="input">Input.</param>
        /// <param name="headerListener">Header listener.</param>
        public void Decode(BinaryReader input, IHeaderListener headerListener)
        {
            while(input.BaseStream.Length - input.BaseStream.Position > 0) {
                switch(this.state) {
                    case State.READ_HEADER_REPRESENTATION:
                        var b = input.ReadSByte();
                        if (maxDynamicTableSizeChangeRequired && (b & 0xE0) != 0x20) {
                            // Encoder MUST signal maximum dynamic table size change
                            throw new IOException("max dynamic table size change required");
                        }
                        if (b < 0) {
                            // Indexed Header Field
                            this.index = b & 0x7F;
                            if (this.index == 0) {
                                throw new IOException("illegal index value (" + this.index + ")");
                            } else if (this.index == 0x7F) {
                                    this.state = State.READ_INDEXED_HEADER;
                                } else {
                                    this.IndexHeader(this.index, headerListener);
                                }
                        } else if ((b & 0x40) == 0x40) {
                                // Literal Header Field with Incremental Indexing
                                this.indexType = HpackUtil.IndexType.INCREMENTAL;
                                this.index = b & 0x3F;
                                if (this.index == 0) {
                                    this.state = State.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                                } else if (this.index == 0x3F) {
                                        this.state = State.READ_INDEXED_HEADER_NAME;
                                    } else {
                                        // Index was stored as the prefix
                                        this.ReadName(this.index);
                                        this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                                    }
                            } else if ((b & 0x20) == 0x20) {
                                    // Dynamic Table Size Update
                                    this.index = b & 0x1F;
                                    if (this.index == 0x1F) {
                                        this.state = State.READ_MAX_DYNAMIC_TABLE_SIZE;
                                    } else {
                                        this.SetDynamicTableSize(index);
                                        this.state = State.READ_HEADER_REPRESENTATION;
                                    }
                                } else {
                                    // Literal Header Field without Indexing / never Indexed
                                    this.indexType = ((b & 0x10) == 0x10) ? HpackUtil.IndexType.NEVER : HpackUtil.IndexType.NONE;
                                    this.index = b & 0x0F;
                                    if (this.index == 0) {
                                        this.state = State.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                                    } else if (this.index == 0x0F) {
                                            this.state = State.READ_INDEXED_HEADER_NAME;
                                        } else {
                                            // Index was stored as the prefix
                                            this.ReadName(this.index);
                                            this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                                        }
                                }
                        break;

                    case State.READ_MAX_DYNAMIC_TABLE_SIZE:
                        var maxSize = Decoder.DecodeULE128(input);
                        if (maxSize == -1) {
                            return;
                        }

                        // Check for numerical overflow
                        if (maxSize > int.MaxValue - this.index) {
                            throw new IOException("decompression failure");
                        }

                        this.SetDynamicTableSize(this.index + maxSize);
                        this.state = State.READ_HEADER_REPRESENTATION;
                        break;

                    case State.READ_INDEXED_HEADER:
                        var headerIndex = Decoder.DecodeULE128(input);
                        if (headerIndex == -1) {
                            return;
                        }

                        // Check for numerical overflow
                        if (headerIndex > int.MaxValue - this.index) {
                            throw new IOException("decompression failure");
                        }

                        this.IndexHeader(this.index + headerIndex, headerListener);
                        this.state = State.READ_HEADER_REPRESENTATION;
                        break;

                    case State.READ_INDEXED_HEADER_NAME:
                        // Header Name matches an entry in the Header Table
                        var nameIndex = Decoder.DecodeULE128(input);
                        if (nameIndex == -1) {
                            return;
                        }

                        // Check for numerical overflow
                        if (nameIndex > int.MaxValue - this.index) {
                            throw new IOException("decompression failure");
                        }

                        this.ReadName(this.index + nameIndex);
                        this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        break;

                    case State.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX:
                        b = input.ReadSByte();
                        this.huffmanEncoded = (b & 0x80) == 0x80;
                        this.index = b & 0x7F;
                        if (this.index == 0x7f) {
                            this.state = State.READ_LITERAL_HEADER_NAME_LENGTH;
                        } else {
                            this.nameLength = this.index;

                            // Disallow empty names -- they cannot be represented in HTTP/1.x
                            if (this.nameLength == 0) {
                                throw new IOException("decompression failure");
                            }

                            // Check name length against max header size
                            if (this.ExceedsMaxHeaderSize(this.nameLength)) {
                                if (this.indexType == HpackUtil.IndexType.NONE) {
                                    // Name is unused so skip bytes
                                    this.name = EMPTY;
                                    this.skipLength = this.nameLength;
                                    this.state = State.SKIP_LITERAL_HEADER_NAME;
                                    break;
                                }

                                // Check name length against max dynamic table size
                                if (this.nameLength + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity) {
                                    this.dynamicTable.Clear();
                                    this.name = EMPTY;
                                    this.skipLength = this.nameLength;
                                    this.state = State.SKIP_LITERAL_HEADER_NAME;
                                    break;
                                }
                            }
                            this.state = State.READ_LITERAL_HEADER_NAME;
                        }
                        break;

                    case State.READ_LITERAL_HEADER_NAME_LENGTH:
                        // Header Name is a Literal String
                        this.nameLength = Decoder.DecodeULE128(input);
                        if (this.nameLength == -1) {
                            return;
                        }

                        // Check for numerical overflow
                        if (this.nameLength > int.MaxValue - this.index) {
                            throw new IOException("decompression failure");
                        }
                        this.nameLength += this.index;

                        // Check name length against max header size
                        if (this.ExceedsMaxHeaderSize(this.nameLength)) {
                            if (this.indexType == HpackUtil.IndexType.NONE) {
                                // Name is unused so skip bytes
                                this.name = EMPTY;
                                this.skipLength = this.nameLength;
                                this.state = State.SKIP_LITERAL_HEADER_NAME;
                                break;
                            }

                            // Check name length against max dynamic table size
                            if (this.nameLength + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity) {
                                this.dynamicTable.Clear();
                                this.name = EMPTY;
                                this.skipLength = this.nameLength;
                                this.state = State.SKIP_LITERAL_HEADER_NAME;
                                break;
                            }
                        }
                        this.state = State.READ_LITERAL_HEADER_NAME;
                        break;

                    case State.READ_LITERAL_HEADER_NAME:
                        // Wait until entire name is readable
                        if (input.BaseStream.Length - input.BaseStream.Position < this.nameLength) {
                            return;
                        }

                        this.name = this.ReadStringLiteral(input, this.nameLength);
                        this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        break;

                    case State.SKIP_LITERAL_HEADER_NAME:

                        this.skipLength -= (int)input.BaseStream.Seek(this.skipLength, SeekOrigin.Current);
                        if (this.skipLength < 0) {
                            this.skipLength = 0;
                        }
                        if (this.skipLength == 0) {
                            this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        }
                        break;

                    case State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX:
                        b = input.ReadSByte();
                        this.huffmanEncoded = (b & 0x80) == 0x80;
                        this.index = b & 0x7F;
                        if (this.index == 0x7f) {
                            this.state = State.READ_LITERAL_HEADER_VALUE_LENGTH;
                        } else {
                            this.valueLength = this.index;

                            // Check new header size against max header size
                            var newHeaderSize1 = (long)((long)this.nameLength + (long)this.valueLength);
                            if (this.ExceedsMaxHeaderSize(newHeaderSize1)) {
                                // truncation will be reported during endHeaderBlock
                                this.headerSize = this.maxHeaderSize + 1;

                                if (this.indexType == HpackUtil.IndexType.NONE) {
                                    // Value is unused so skip bytes
                                    this.state = State.SKIP_LITERAL_HEADER_VALUE;
                                    break;
                                }

                                // Check new header size against max dynamic table size
                                if (newHeaderSize1 + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity) {
                                    this.dynamicTable.Clear();
                                    this.state = State.SKIP_LITERAL_HEADER_VALUE;
                                    break;
                                }
                            }

                            if (this.valueLength == 0) {
                                this.InsertHeader(headerListener, this.name, EMPTY, this.indexType);
                                this.state = State.READ_HEADER_REPRESENTATION;
                            } else {
                                this.state = State.READ_LITERAL_HEADER_VALUE;
                            }
                        }
                        break;

                    case State.READ_LITERAL_HEADER_VALUE_LENGTH:
                        // Header Value is a Literal String
                        this.valueLength = Decoder.DecodeULE128(input);
                        if (this.valueLength == -1) {
                            return;
                        }

                        // Check for numerical overflow
                        if (this.valueLength > int.MaxValue - this.index) {
                            throw new IOException("decompression failure");
                        }
                        this.valueLength += this.index;

                        // Check new header size against max header size
                        var newHeaderSize2 = (long)((long)this.nameLength + (long)this.valueLength);
                        if (newHeaderSize2 + this.headerSize > this.maxHeaderSize) {
                            // truncation will be reported during endHeaderBlock
                            this.headerSize = this.maxHeaderSize + 1;

                            if (this.indexType == HpackUtil.IndexType.NONE) {
                                // Value is unused so skip bytes
                                this.state = State.SKIP_LITERAL_HEADER_VALUE;
                                break;
                            }

                            // Check new header size against max dynamic table size
                            if (newHeaderSize2 + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity) {
                                this.dynamicTable.Clear();
                                this.state = State.SKIP_LITERAL_HEADER_VALUE;
                                break;
                            }
                        }
                        this.state = State.READ_LITERAL_HEADER_VALUE;
                        break;

                    case State.READ_LITERAL_HEADER_VALUE:
                        // Wait until entire value is readable
                        if (input.BaseStream.Length - input.BaseStream.Position < this.valueLength) {
                            return;
                        }

                        var value = this.ReadStringLiteral(input, this.valueLength);
                        this.InsertHeader(headerListener, this.name, value, this.indexType);
                        this.state = State.READ_HEADER_REPRESENTATION;
                        break;

                    case State.SKIP_LITERAL_HEADER_VALUE:
                        this.valueLength -= (int)input.BaseStream.Seek(this.valueLength, SeekOrigin.Current);
                        if (this.valueLength < 0) {
                            this.valueLength = 0;
                        }
                        if (this.valueLength == 0) {
                            this.state = State.READ_HEADER_REPRESENTATION;
                        }
                        break;

                    default:
                        throw new Exception("should not reach here");
                }
            }
        }
Exemple #4
0
 private void Reset()
 {
     this.headerSize = 0;
     this.state = State.READ_HEADER_REPRESENTATION;
     this.indexType = HpackUtil.IndexType.NONE;
 }
        /// <summary>
        /// Encode the header field into the header block.
        /// </summary>
        /// <param name="output">Output.</param>
        /// <param name="name">Name.</param>
        /// <param name="value">Value.</param>
        /// <param name="sensitive">If set to <c>true</c> sensitive.</param>
        /// <param name="indexType">Index type.</param>
        /// <param name="useStaticName">Use static name.</param>
        public void EncodeHeader(BinaryWriter output, string name, string value, bool sensitive = false, HpackUtil.IndexType indexType = HpackUtil.IndexType.Incremental, bool useStaticName = true)
        {
            // If the header value is sensitive then it must never be indexed
            if (sensitive)
            {
                int nameIndex = getNameIndex(name);
                encodeLiteral(output, name, value, HpackUtil.IndexType.Never, nameIndex);
                return;
            }

            // If the peer will only use the static table
            if (MaxHeaderTableSize == 0)
            {
                int staticTableIndex = StaticTable.GetIndex(name, value);
                if (staticTableIndex == -1)
                {
                    int nameIndex = StaticTable.GetIndex(name);
                    encodeLiteral(output, name, value, HpackUtil.IndexType.None, nameIndex);
                }
                else
                {
                    encodeInteger(output, 0x80, 7, staticTableIndex);
                }

                return;
            }

            int headerSize = HttpHeader.SizeOf(name, value);

            // If the headerSize is greater than the max table size then it must be encoded literally
            if (headerSize > MaxHeaderTableSize)
            {
                int nameIndex = getNameIndex(name);
                encodeLiteral(output, name, value, HpackUtil.IndexType.None, nameIndex);
                return;
            }

            var headerField = getEntry(name, value);

            if (headerField != null)
            {
                int index = getIndex(headerField.Index) + StaticTable.Length;

                // Section 6.1. Indexed Header Field Representation
                encodeInteger(output, 0x80, 7, index);
            }
            else
            {
                int staticTableIndex = StaticTable.GetIndex(name, value);
                if (staticTableIndex != -1)
                {
                    // Section 6.1. Indexed Header Field Representation
                    encodeInteger(output, 0x80, 7, staticTableIndex);
                }
                else
                {
                    int nameIndex = useStaticName ? getNameIndex(name) : -1;
                    ensureCapacity(headerSize);

                    encodeLiteral(output, name, value, indexType, nameIndex);
                    add(name, value);
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Decode the header block into header fields.
        /// </summary>
        /// <param name="input">Input.</param>
        /// <param name="headerListener">Header listener.</param>
        public void Decode(BinaryReader input, IHeaderListener headerListener)
        {
            while (input.BaseStream.Length - input.BaseStream.Position > 0)
            {
                switch (state)
                {
                case State.ReadHeaderRepresentation:
                    sbyte b = input.ReadSByte();
                    if (maxDynamicTableSizeChangeRequired && (b & 0xE0) != 0x20)
                    {
                        // Encoder MUST signal maximum dynamic table size change
                        throw new IOException("max dynamic table size change required");
                    }

                    if (b < 0)
                    {
                        // Indexed Header Field
                        index = b & 0x7F;
                        if (index == 0)
                        {
                            throw new IOException("illegal index value (" + index + ")");
                        }
                        else if (index == 0x7F)
                        {
                            state = State.ReadIndexedHeader;
                        }
                        else
                        {
                            IndexHeader(index, headerListener);
                        }
                    }
                    else if ((b & 0x40) == 0x40)
                    {
                        // Literal Header Field with Incremental Indexing
                        indexType = HpackUtil.IndexType.Incremental;
                        index     = b & 0x3F;
                        if (index == 0)
                        {
                            state = State.ReadLiteralHeaderNameLengthPrefix;
                        }
                        else if (index == 0x3F)
                        {
                            state = State.ReadIndexedHeaderName;
                        }
                        else
                        {
                            // Index was stored as the prefix
                            ReadName(index);
                            state = State.ReadLiteralHeaderValueLengthPrefix;
                        }
                    }
                    else if ((b & 0x20) == 0x20)
                    {
                        // Dynamic Table Size Update
                        index = b & 0x1F;
                        if (index == 0x1F)
                        {
                            state = State.ReadMaxDynamicTableSize;
                        }
                        else
                        {
                            SetDynamicTableSize(index);
                            state = State.ReadHeaderRepresentation;
                        }
                    }
                    else
                    {
                        // Literal Header Field without Indexing / never Indexed
                        indexType = ((b & 0x10) == 0x10) ? HpackUtil.IndexType.Never : HpackUtil.IndexType.None;
                        index     = b & 0x0F;
                        if (index == 0)
                        {
                            state = State.ReadLiteralHeaderNameLengthPrefix;
                        }
                        else if (index == 0x0F)
                        {
                            state = State.ReadIndexedHeaderName;
                        }
                        else
                        {
                            // Index was stored as the prefix
                            ReadName(index);
                            state = State.ReadLiteralHeaderValueLengthPrefix;
                        }
                    }

                    break;

                case State.ReadMaxDynamicTableSize:
                    int maxSize = decodeULE128(input);
                    if (maxSize == -1)
                    {
                        return;
                    }

                    // Check for numerical overflow
                    if (maxSize > int.MaxValue - index)
                    {
                        throw new IOException("decompression failure");
                    }

                    SetDynamicTableSize(index + maxSize);
                    state = State.ReadHeaderRepresentation;
                    break;

                case State.ReadIndexedHeader:
                    int headerIndex = decodeULE128(input);
                    if (headerIndex == -1)
                    {
                        return;
                    }

                    // Check for numerical overflow
                    if (headerIndex > int.MaxValue - index)
                    {
                        throw new IOException("decompression failure");
                    }

                    IndexHeader(index + headerIndex, headerListener);
                    state = State.ReadHeaderRepresentation;
                    break;

                case State.ReadIndexedHeaderName:
                    // Header Name matches an entry in the Header Table
                    int nameIndex = decodeULE128(input);
                    if (nameIndex == -1)
                    {
                        return;
                    }

                    // Check for numerical overflow
                    if (nameIndex > int.MaxValue - index)
                    {
                        throw new IOException("decompression failure");
                    }

                    ReadName(index + nameIndex);
                    state = State.ReadLiteralHeaderValueLengthPrefix;
                    break;

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

                        // Disallow empty names -- they cannot be represented in HTTP/1.x
                        if (nameLength == 0)
                        {
                            throw new IOException("decompression failure");
                        }

                        // Check name length against max header size
                        if (ExceedsMaxHeaderSize(nameLength))
                        {
                            if (indexType == HpackUtil.IndexType.None)
                            {
                                // Name is unused so skip bytes
                                name       = string.Empty;
                                skipLength = nameLength;
                                state      = State.SkipLiteralHeaderName;
                                break;
                            }

                            // Check name length against max dynamic table size
                            if (nameLength + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
                            {
                                dynamicTable.Clear();
                                name       = string.Empty;
                                skipLength = nameLength;
                                state      = State.SkipLiteralHeaderName;
                                break;
                            }
                        }

                        state = State.ReadLiteralHeaderName;
                    }

                    break;

                case State.ReadLiteralHeaderNameLength:
                    // Header Name is a Literal String
                    nameLength = decodeULE128(input);
                    if (nameLength == -1)
                    {
                        return;
                    }

                    // Check for numerical overflow
                    if (nameLength > int.MaxValue - index)
                    {
                        throw new IOException("decompression failure");
                    }

                    nameLength += index;

                    // Check name length against max header size
                    if (ExceedsMaxHeaderSize(nameLength))
                    {
                        if (indexType == HpackUtil.IndexType.None)
                        {
                            // Name is unused so skip bytes
                            name       = string.Empty;
                            skipLength = nameLength;
                            state      = State.SkipLiteralHeaderName;
                            break;
                        }

                        // Check name length against max dynamic table size
                        if (nameLength + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
                        {
                            dynamicTable.Clear();
                            name       = string.Empty;
                            skipLength = nameLength;
                            state      = State.SkipLiteralHeaderName;
                            break;
                        }
                    }

                    state = State.ReadLiteralHeaderName;
                    break;

                case State.ReadLiteralHeaderName:
                    // Wait until entire name is readable
                    if (input.BaseStream.Length - input.BaseStream.Position < nameLength)
                    {
                        return;
                    }

                    name  = ReadStringLiteral(input, nameLength);
                    state = State.ReadLiteralHeaderValueLengthPrefix;
                    break;

                case State.SkipLiteralHeaderName:

                    skipLength -= (int)input.BaseStream.Seek(skipLength, SeekOrigin.Current);
                    if (skipLength < 0)
                    {
                        skipLength = 0;
                    }

                    if (skipLength == 0)
                    {
                        state = State.ReadLiteralHeaderValueLengthPrefix;
                    }

                    break;

                case State.ReadLiteralHeaderValueLengthPrefix:
                    b = input.ReadSByte();
                    huffmanEncoded = (b & 0x80) == 0x80;
                    index          = b & 0x7F;
                    if (index == 0x7f)
                    {
                        state = State.ReadLiteralHeaderValueLength;
                    }
                    else
                    {
                        valueLength = index;

                        // Check new header size against max header size
                        long newHeaderSize1 = (long)nameLength + valueLength;
                        if (ExceedsMaxHeaderSize(newHeaderSize1))
                        {
                            // truncation will be reported during endHeaderBlock
                            headerSize = maxHeaderSize + 1;

                            if (indexType == HpackUtil.IndexType.None)
                            {
                                // Value is unused so skip bytes
                                state = State.SkipLiteralHeaderValue;
                                break;
                            }

                            // Check new header size against max dynamic table size
                            if (newHeaderSize1 + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
                            {
                                dynamicTable.Clear();
                                state = State.SkipLiteralHeaderValue;
                                break;
                            }
                        }

                        if (valueLength == 0)
                        {
                            InsertHeader(headerListener, name, string.Empty, indexType);
                            state = State.ReadHeaderRepresentation;
                        }
                        else
                        {
                            state = State.ReadLiteralHeaderValue;
                        }
                    }

                    break;

                case State.ReadLiteralHeaderValueLength:
                    // Header Value is a Literal String
                    valueLength = decodeULE128(input);
                    if (valueLength == -1)
                    {
                        return;
                    }

                    // Check for numerical overflow
                    if (valueLength > int.MaxValue - index)
                    {
                        throw new IOException("decompression failure");
                    }

                    valueLength += index;

                    // Check new header size against max header size
                    long newHeaderSize2 = (long)nameLength + valueLength;
                    if (newHeaderSize2 + headerSize > maxHeaderSize)
                    {
                        // truncation will be reported during endHeaderBlock
                        headerSize = maxHeaderSize + 1;

                        if (indexType == HpackUtil.IndexType.None)
                        {
                            // Value is unused so skip bytes
                            state = State.SkipLiteralHeaderValue;
                            break;
                        }

                        // Check new header size against max dynamic table size
                        if (newHeaderSize2 + HttpHeader.HttpHeaderOverhead > dynamicTable.Capacity)
                        {
                            dynamicTable.Clear();
                            state = State.SkipLiteralHeaderValue;
                            break;
                        }
                    }

                    state = State.ReadLiteralHeaderValue;
                    break;

                case State.ReadLiteralHeaderValue:
                    // Wait until entire value is readable
                    if (input.BaseStream.Length - input.BaseStream.Position < valueLength)
                    {
                        return;
                    }

                    var value = ReadStringLiteral(input, valueLength);
                    InsertHeader(headerListener, name, value, indexType);
                    state = State.ReadHeaderRepresentation;
                    break;

                case State.SkipLiteralHeaderValue:
                    valueLength -= (int)input.BaseStream.Seek(valueLength, SeekOrigin.Current);
                    if (valueLength < 0)
                    {
                        valueLength = 0;
                    }

                    if (valueLength == 0)
                    {
                        state = State.ReadHeaderRepresentation;
                    }

                    break;

                default:
                    throw new Exception("should not reach here");
                }
            }
        }
Exemple #7
0
 private void Reset()
 {
     headerSize = 0;
     state      = State.ReadHeaderRepresentation;
     indexType  = HpackUtil.IndexType.None;
 }
Exemple #8
0
        private void InsertHeader(IHeaderListener headerListener, string name, string value, HpackUtil.IndexType indexType)
        {
            AddHeader(headerListener, name, value, indexType == HpackUtil.IndexType.Never);

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

            case HpackUtil.IndexType.Incremental:
                dynamicTable.Add(new HttpHeader(name, value));
                break;

            default:
                throw new Exception("should not reach here");
            }
        }
Exemple #9
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;
            }
        }
Exemple #10
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();
            }
        }