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(); } }