예제 #1
0
        /// <summary>
        /// Returns the index value for the given header field in the static table. Returns -1 if the
        /// header field is not in the static table.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal static int GetIndexInsensitive(ICharSequence name, ICharSequence value)
        {
            int index = GetIndex(name);

            if ((uint)index > SharedConstants.TooBigOrNegative /* == -1*/)
            {
                return(-1);
            }

            uint uLength = (uint)Length;

            // Note this assumes all entries for a given header field are sequential.
            while ((uint)index <= uLength)
            {
                HpackHeaderField entry = GetEntry(index);
                if (HpackUtil.EqualsVariableTime(name, entry._name) && HpackUtil.EqualsVariableTime(value, entry._value))
                {
                    return(index);
                }

                index++;
            }

            return(-1);
        }
예제 #2
0
        public void AppendToHeaderList(ICharSequence name, ICharSequence value)
        {
            _headersLength     += HpackHeaderField.SizeOf(name, value);
            _exceededMaxLength |= _headersLength > _maxHeaderListSize;

            if (_exceededMaxLength || _validationException is object)
            {
                // We don't store the header since we've already failed validation requirements.
                return;
            }

            if (_validate)
            {
                try
                {
                    _previousType = HpackDecoder.Validate(_streamId, name, _previousType);
                }
                catch (Http2Exception ex)
                {
                    _validationException = ex;
                    return;
                }
            }

            _ = _headers.Add(name, value);
        }
예제 #3
0
        /// <summary>
        /// create a map CharSequenceMap header name to index value to allow quick lookup
        /// </summary>
        static CharSequenceMap <int> CreateMap()
        {
            int length = StaticTable.Length;
            CharSequenceMap <int> ret = new CharSequenceMap <int>(true, UnsupportedValueConverter <int> .Instance, length);

            // Iterate through the static table in reverse order to
            // save the smallest index for a given name in the map.
            for (int index = length; index > 0; index--)
            {
                HpackHeaderField entry = GetEntry(index);
                ICharSequence    name  = entry._name;
                _ = ret.Set(name, index);
            }

            return(ret);
        }
예제 #4
0
        private ICharSequence ReadName(int index)
        {
            if ((uint)index <= (uint)HpackStaticTable.Length)
            {
                HpackHeaderField hpackHeaderField = HpackStaticTable.GetEntry(index);
                return(hpackHeaderField._name);
            }

            if ((uint)(index - HpackStaticTable.Length) <= (uint)_hpackDynamicTable.Length())
            {
                HpackHeaderField hpackHeaderField = _hpackDynamicTable.GetEntry(index - HpackStaticTable.Length);
                return(hpackHeaderField._name);
            }

            ThrowHelper.ThrowHttp2Exception_ReadNameIllegalIndexValue(); return(null);
        }
예제 #5
0
        void EncodeHeadersEnforceMaxHeaderListSize(int streamId, IByteBuffer output, IHttp2Headers headers, ISensitivityDetector sensitivityDetector)
        {
            long headerSize = 0;

            // To ensure we stay consistent with our peer check the size is valid before we potentially modify HPACK state.
            foreach (HeaderEntry <ICharSequence, ICharSequence> header in headers)
            {
                ICharSequence name  = header.Key;
                ICharSequence value = header.Value;
                // OK to increment now and check for bounds after because this value is limited to unsigned int and will not
                // overflow.
                headerSize += HpackHeaderField.SizeOf(name, value);
                if (headerSize > _maxHeaderListSize)
                {
                    Http2CodecUtil.HeaderListSizeExceeded(streamId, _maxHeaderListSize, false);
                }
            }

            EncodeHeadersIgnoreMaxHeaderListSize(@output, headers, sensitivityDetector);
        }
예제 #6
0
 void EncodeHeadersIgnoreMaxHeaderListSize(IByteBuffer output, IHttp2Headers headers, ISensitivityDetector sensitivityDetector)
 {
     foreach (HeaderEntry <ICharSequence, ICharSequence> header in headers)
     {
         ICharSequence name  = header.Key;
         ICharSequence value = header.Value;
         EncodeHeader(output, name, value, sensitivityDetector.IsSensitive(name, value), HpackHeaderField.SizeOf(name, value));
     }
 }
예제 #7
0
 public bool EqualsForTest(HpackHeaderField other)
 {
     return(HpackUtil.EqualsVariableTime(_name, other._name) && HpackUtil.EqualsVariableTime(_value, other._value));
 }
예제 #8
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();
            }
        }