/// <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); }
/// <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); }
/// <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"); } } }
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); } } }
/// <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"); } } }
private void Reset() { headerSize = 0; state = State.ReadHeaderRepresentation; indexType = HpackUtil.IndexType.None; }
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"); } }
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; } }
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(); } }