private void OnIndexedHeaderField(int index, IProtoHeadersHandler handler) { var header = GetHeader(index); handler.OnHeader(new Span <byte>(header.Name), new Span <byte>(header.Value)); _state = State.Ready; }
private void ProcessHeaderValue(IProtoHeadersHandler handler) { OnString(nextState: State.Ready); var headerNameSpan = new Span <byte>(_headerName, 0, _headerNameLength); var headerValueSpan = new Span <byte>(_headerValueOctets, 0, _headerValueLength); handler.OnHeader(headerNameSpan, headerValueSpan); if (_index) { _dynamicTable.Insert(headerNameSpan, headerValueSpan); } }
public void Decode(ReadOnlySequence <byte> data, bool endHeaders, IProtoHeadersHandler handler) { foreach (var segment in data) { var span = segment.Span; for (var i = 0; i < span.Length; i++) { OnByte(span[i], handler); } } if (endHeaders) { if (_state != State.Ready) { throw new HPackDecodingException(CoreStrings.HPackErrorIncompleteHeaderBlock); } _headersObserved = false; } }
private void OnByte(byte b, IProtoHeadersHandler handler) { int intResult; switch (_state) { case State.Ready: if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation) { _headersObserved = true; var val = b & ~IndexedHeaderFieldMask; if (_integerDecoder.BeginTryDecode((byte)val, IndexedHeaderFieldPrefix, out intResult)) { OnIndexedHeaderField(intResult, handler); } else { _state = State.HeaderFieldIndex; } } else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation) { _headersObserved = true; _index = true; var val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix, out intResult)) { OnIndexedHeaderName(intResult); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation) { _headersObserved = true; _index = false; var val = b & ~LiteralHeaderFieldWithoutIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix, out intResult)) { OnIndexedHeaderName(intResult); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation) { _headersObserved = true; _index = false; var val = b & ~LiteralHeaderFieldNeverIndexedMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix, out intResult)) { OnIndexedHeaderName(intResult); } else { _state = State.HeaderNameIndex; } } else if ((b & DynamicTableSizeUpdateMask) == DynamicTableSizeUpdateRepresentation) { // https://tools.ietf.org/html/rfc7541#section-4.2 // This dynamic table size // update MUST occur at the beginning of the first header block // following the change to the dynamic table size. if (_headersObserved) { throw new HPackDecodingException(CoreStrings.HPackErrorDynamicTableSizeUpdateNotAtBeginningOfHeaderBlock); } if (_integerDecoder.BeginTryDecode((byte)(b & ~DynamicTableSizeUpdateMask), DynamicTableSizeUpdatePrefix, out intResult)) { SetDynamicHeaderTableSize(intResult); } else { _state = State.DynamicTableSizeUpdate; } } else { // Can't happen throw new HPackDecodingException($"Byte value {b} does not encode a valid header field representation."); } break; case State.HeaderFieldIndex: if (_integerDecoder.TryDecode(b, out intResult)) { OnIndexedHeaderField(intResult, handler); } break; case State.HeaderNameIndex: if (_integerDecoder.TryDecode(b, out intResult)) { OnIndexedHeaderName(intResult); } break; case State.HeaderNameLength: _huffman = (b & HuffmanMask) != 0; if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out intResult)) { OnStringLength(intResult, nextState: State.HeaderName); } else { _state = State.HeaderNameLengthContinue; } break; case State.HeaderNameLengthContinue: if (_integerDecoder.TryDecode(b, out intResult)) { OnStringLength(intResult, nextState: State.HeaderName); } break; case State.HeaderName: _stringOctets[_stringIndex++] = b; if (_stringIndex == _stringLength) { OnString(nextState: State.HeaderValueLength); } break; case State.HeaderValueLength: _huffman = (b & HuffmanMask) != 0; if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out intResult)) { OnStringLength(intResult, nextState: State.HeaderValue); if (intResult == 0) { ProcessHeaderValue(handler); } } else { _state = State.HeaderValueLengthContinue; } break; case State.HeaderValueLengthContinue: if (_integerDecoder.TryDecode(b, out intResult)) { OnStringLength(intResult, nextState: State.HeaderValue); if (intResult == 0) { ProcessHeaderValue(handler); } } break; case State.HeaderValue: _stringOctets[_stringIndex++] = b; if (_stringIndex == _stringLength) { ProcessHeaderValue(handler); } break; case State.DynamicTableSizeUpdate: if (_integerDecoder.TryDecode(b, out intResult)) { SetDynamicHeaderTableSize(intResult); _state = State.Ready; } break; default: // Can't happen throw new HPackDecodingException("The HPACK decoder reached an invalid state."); } }