Пример #1
0
        /// <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, byte[] name, byte[] 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");
            }
            Encoder.EncodeInteger(output, mask, prefixBits, nameIndex == -1 ? 0 : nameIndex);
            if (nameIndex == -1)
            {
                this.EncodeStringLiteral(output, name);
            }
            this.EncodeStringLiteral(output, value);
        }
Пример #2
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, AddHeaderDelegate addHeaderDelegate)
        {
            while(input.BaseStream.Length - input.BaseStream.Position > 0) {
                switch(this.state) {
                case State.READ_HEADER_REPRESENTATION:
                    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.READ_INDEXED_HEADER;
                        } else {
                            this.IndexHeader(index, addHeaderDelegate);
                        }
                    } else if ((b & 0x40) == 0x40) {
                        // Literal Header Field with Incremental Indexing
                        indexType = HPackUtil.IndexType.INCREMENTAL;
                        index = b & 0x3F;
                        if (index == 0) {
                            state = State.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                        } else if (index == 0x3F) {
                            state = State.READ_INDEXED_HEADER_NAME;
                        } else {
                            // Index was stored as the prefix
                            this.ReadName(index);
                            state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        }
                    } else if ((b & 0x20) == 0x20) {
                        // Dynamic Table Size Update
                        index = b & 0x1F;
                        if (index == 0x1F) {
                            state = State.READ_MAX_DYNAMIC_TABLE_SIZE;
                        } else {
                            this.SetDynamicTableSize(index);
                            state = State.READ_HEADER_REPRESENTATION;
                        }
                    } 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.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                        } else if (index == 0x0F) {
                            state = State.READ_INDEXED_HEADER_NAME;
                        } else {
                            // Index was stored as the prefix
                            this.ReadName(index);
                            state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        }
                    }
                    break;

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

                    // Check for numerical overflow
                    if (maxSize > int.MaxValue - index) {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

                    // Check for numerical overflow
                    if (headerIndex > int.MaxValue - index) {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

                    // Check for numerical overflow
                    if (nameIndex > int.MaxValue - index) {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

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

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

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

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

                    // Check for numerical overflow
                    if (nameLength > int.MaxValue - index) {
                        throw DECOMPRESSION_EXCEPTION;
                    }
                    nameLength += index;

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

                        // Check name length against max dynamic table size
                        if (nameLength + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity) {
                            this.dynamicTable.Clear();
                            name = EMPTY;
                            this.skipLength = nameLength;
                            state = State.SKIP_LITERAL_HEADER_NAME;
                            break;
                        }
                    }
                    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 < nameLength) {
                        return;
                    }

                    name = this.ReadStringLiteral(input, nameLength);
                    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) {
                        state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                    }
                    break;

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

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

                            if (indexType == HPackUtil.IndexType.NONE) {
                                // Value is unused so skip bytes
                                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();
                                state = State.SKIP_LITERAL_HEADER_VALUE;
                                break;
                            }
                        }

                        if (this.valueLength == 0) {
                            this.InsertHeader(addHeaderDelegate, name, EMPTY, indexType);
                            state = State.READ_HEADER_REPRESENTATION;
                        } else {
                            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 - index) {
                        throw DECOMPRESSION_EXCEPTION;
                    }
                    this.valueLength += index;

                    // Check new header size against max header size
                    long newHeaderSize2 = (long)nameLength + (long)this.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.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();
                            state = State.SKIP_LITERAL_HEADER_VALUE;
                            break;
                        }
                    }
                    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;
                    }

                    byte[] value = this.ReadStringLiteral(input, this.valueLength);
                    this.InsertHeader(addHeaderDelegate, name, value, indexType);
                    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) {
                        state = State.READ_HEADER_REPRESENTATION;
                    }
                    break;

                default:
                    throw new Exception("should not reach here");
                }
            }
        }
Пример #3
0
 private void Reset()
 {
     this.headerSize = 0;
     this.state = State.READ_HEADER_REPRESENTATION;
     this.indexType = HPackUtil.IndexType.NONE;
 }
Пример #4
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, AddHeaderDelegate addHeaderDelegate)
        {
            while (input.BaseStream.Length - input.BaseStream.Position > 0)
            {
                switch (this.state)
                {
                case State.READ_HEADER_REPRESENTATION:
                    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.READ_INDEXED_HEADER;
                        }
                        else
                        {
                            this.IndexHeader(index, addHeaderDelegate);
                        }
                    }
                    else if ((b & 0x40) == 0x40)
                    {
                        // Literal Header Field with Incremental Indexing
                        indexType = HPackUtil.IndexType.INCREMENTAL;
                        index     = b & 0x3F;
                        if (index == 0)
                        {
                            state = State.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                        }
                        else if (index == 0x3F)
                        {
                            state = State.READ_INDEXED_HEADER_NAME;
                        }
                        else
                        {
                            // Index was stored as the prefix
                            this.ReadName(index);
                            state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        }
                    }
                    else if ((b & 0x20) == 0x20)
                    {
                        // Dynamic Table Size Update
                        index = b & 0x1F;
                        if (index == 0x1F)
                        {
                            state = State.READ_MAX_DYNAMIC_TABLE_SIZE;
                        }
                        else
                        {
                            this.SetDynamicTableSize(index);
                            state = State.READ_HEADER_REPRESENTATION;
                        }
                    }
                    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.READ_LITERAL_HEADER_NAME_LENGTH_PREFIX;
                        }
                        else if (index == 0x0F)
                        {
                            state = State.READ_INDEXED_HEADER_NAME;
                        }
                        else
                        {
                            // Index was stored as the prefix
                            this.ReadName(index);
                            state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                        }
                    }
                    break;

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

                    // Check for numerical overflow
                    if (maxSize > int.MaxValue - index)
                    {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

                    // Check for numerical overflow
                    if (headerIndex > int.MaxValue - index)
                    {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

                    // Check for numerical overflow
                    if (nameIndex > int.MaxValue - index)
                    {
                        throw DECOMPRESSION_EXCEPTION;
                    }

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

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

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

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

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

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

                    // Check for numerical overflow
                    if (nameLength > int.MaxValue - index)
                    {
                        throw DECOMPRESSION_EXCEPTION;
                    }
                    nameLength += index;

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

                        // Check name length against max dynamic table size
                        if (nameLength + HeaderField.HEADER_ENTRY_OVERHEAD > this.dynamicTable.Capacity)
                        {
                            this.dynamicTable.Clear();
                            name            = EMPTY;
                            this.skipLength = nameLength;
                            state           = State.SKIP_LITERAL_HEADER_NAME;
                            break;
                        }
                    }
                    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 < nameLength)
                    {
                        return;
                    }

                    name  = this.ReadStringLiteral(input, nameLength);
                    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)
                    {
                        state = State.READ_LITERAL_HEADER_VALUE_LENGTH_PREFIX;
                    }
                    break;

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

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

                            if (indexType == HPackUtil.IndexType.NONE)
                            {
                                // Value is unused so skip bytes
                                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();
                                state = State.SKIP_LITERAL_HEADER_VALUE;
                                break;
                            }
                        }

                        if (this.valueLength == 0)
                        {
                            this.InsertHeader(addHeaderDelegate, name, EMPTY, indexType);
                            state = State.READ_HEADER_REPRESENTATION;
                        }
                        else
                        {
                            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 - index)
                    {
                        throw DECOMPRESSION_EXCEPTION;
                    }
                    this.valueLength += index;

                    // Check new header size against max header size
                    long newHeaderSize2 = (long)nameLength + (long)this.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.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();
                            state = State.SKIP_LITERAL_HEADER_VALUE;
                            break;
                        }
                    }
                    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;
                    }

                    byte[] value = this.ReadStringLiteral(input, this.valueLength);
                    this.InsertHeader(addHeaderDelegate, name, value, indexType);
                    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)
                    {
                        state = State.READ_HEADER_REPRESENTATION;
                    }
                    break;

                default:
                    throw new Exception("should not reach here");
                }
            }
        }
Пример #5
0
 private void Reset()
 {
     this.headerSize = 0;
     this.state      = State.READ_HEADER_REPRESENTATION;
     this.indexType  = HPackUtil.IndexType.NONE;
 }
Пример #6
0
        private void InsertHeader(AddHeaderDelegate addHeaderDelegate, byte[] name, byte[] value, HPackUtil.IndexType indexType)
        {
            this.AddHeader(addHeaderDelegate, name, value, indexType == HPackUtil.IndexType.NEVER);

            switch (indexType)
            {
            case HPackUtil.IndexType.NONE:
            case HPackUtil.IndexType.NEVER:
                break;

            case HPackUtil.IndexType.INCREMENTAL:
                this.dynamicTable.Add(new HeaderField(name, value));
                break;

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