Esempio n. 1
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");
            }
        }
Esempio n. 2
0
        private void AddHeader(IHeaderListener headerListener, string name, string value, bool sensitive)
        {
            if (name.Length == 0)
            {
                throw new ArgumentException("name is empty");
            }

            long newSize = headerSize + name.Length + value.Length;

            if (newSize <= maxHeaderSize)
            {
                headerListener.AddHeader(name, value, sensitive);
                headerSize = (int)newSize;
            }
            else
            {
                // truncation will be reported during endHeaderBlock
                headerSize = maxHeaderSize + 1;
            }
        }
Esempio n. 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");
                }
            }
        }
Esempio n. 4
0
        private void InsertHeader(IHeaderListener headerListener, byte[] name, byte[] value, HpackUtil.IndexType indexType)
        {
            this.AddHeader(headerListener, 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");
            }
        }
Esempio n. 5
0
 private void IndexHeader(int index, IHeaderListener headerListener)
 {
     if (index <= StaticTable.Length) {
         var headerField = StaticTable.GetEntry(index);
         this.AddHeader(headerListener, headerField.Name, headerField.Value, false);
     } else if (index - StaticTable.Length <= this.dynamicTable.Length()) {
             var headerField = this.dynamicTable.GetEntry(index - StaticTable.Length);
             this.AddHeader(headerListener, headerField.Name, headerField.Value, false);
         } else {
             throw new IOException("illegal index value (" + index + ")");
         }
 }
Esempio n. 6
0
 private void AddHeader(IHeaderListener headerListener, byte[] name, byte[] value, bool sensitive)
 {
     if (name.Length == 0) {
         throw new ArgumentException("name is empty");
     }
     var newSize = (long)(this.headerSize + name.Length + value.Length);
     if (newSize <= this.maxHeaderSize) {
         headerListener.AddHeader(name, value, sensitive);
         this.headerSize = (int)newSize;
     } else {
         // truncation will be reported during endHeaderBlock
         this.headerSize = this.maxHeaderSize + 1;
     }
 }
Esempio n. 7
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");
                }
            }
        }
Esempio n. 8
0
        private void IndexHeader(int index, IHeaderListener headerListener)
        {
            var headerField = GetHeaderField(index);

            AddHeader(headerListener, headerField.Name, headerField.Value, false);
        }
Esempio n. 9
0
 public void SetUp()
 {
     this.decoder = new Decoder(MAX_HEADER_SIZE, MAX_HEADER_TABLE_SIZE);
     //this.mockListener = mock(HeaderListener.class);
     this.mockListener = new HeaderListener();
 }