private void OnIndexedHeaderField(int index, IHttpHeadersHandler handler) { var header = GetHeader(index); handler.OnHeader(new Span <byte>(header.Name), new Span <byte>(header.Value)); _state = State.Ready; }
public void Decode(Span <byte> data, bool endHeaders, IHttpHeadersHandler handler) { for (var i = 0; i < data.Length; i++) { OnByte(data[i], handler); } if (endHeaders && _state != State.Ready) { throw new HPackDecodingException(CoreStrings.HPackErrorIncompleteHeaderBlock); } }
private void ProcessHeaderValue(IHttpHeadersHandler 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, IHttpHeadersHandler 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, IHttpHeadersHandler 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."); } }
public void OnByte(byte b, IHttpHeadersHandler handler) { switch (_state) { case State.Ready: if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation) { var val = b & ~IndexedHeaderFieldMask; if (_integerDecoder.BeginDecode((byte)val, IndexedHeaderFieldPrefix)) { OnIndexedHeaderField(_integerDecoder.Value, handler); } else { _state = State.HeaderFieldIndex; } } else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation) { _index = true; var val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation) { _index = false; var val = b & ~LiteralHeaderFieldWithoutIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation) { _index = false; var val = b & ~LiteralHeaderFieldNeverIndexedMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.BeginDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & DynamicTableSizeUpdateMask) == DynamicTableSizeUpdateRepresentation) { if (_integerDecoder.BeginDecode((byte)(b & ~DynamicTableSizeUpdateMask), DynamicTableSizeUpdatePrefix)) { // TODO: validate that it's less than what's defined via SETTINGS _dynamicTable.Resize(_integerDecoder.Value); } 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.Decode(b)) { OnIndexedHeaderField(_integerDecoder.Value, handler); } break; case State.HeaderNameIndex: if (_integerDecoder.Decode(b)) { OnIndexedHeaderName(_integerDecoder.Value); } break; case State.HeaderNameLength: _huffman = (b & HuffmanMask) != 0; if (_integerDecoder.BeginDecode((byte)(b & ~HuffmanMask), StringLengthPrefix)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderName); } else { _state = State.HeaderNameLengthContinue; } break; case State.HeaderNameLengthContinue: if (_integerDecoder.Decode(b)) { OnStringLength(_integerDecoder.Value, 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.BeginDecode((byte)(b & ~HuffmanMask), StringLengthPrefix)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); if (_integerDecoder.Value == 0) { ProcessHeaderValue(handler); } } else { _state = State.HeaderValueLengthContinue; } break; case State.HeaderValueLengthContinue: if (_integerDecoder.Decode(b)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); if (_integerDecoder.Value == 0) { ProcessHeaderValue(handler); } } break; case State.HeaderValue: _stringOctets[_stringIndex++] = b; if (_stringIndex == _stringLength) { ProcessHeaderValue(handler); } break; case State.DynamicTableSizeUpdate: if (_integerDecoder.Decode(b)) { if (_integerDecoder.Value > _maxDynamicTableSize) { throw new HPackDecodingException( CoreStrings.FormatHPackErrorDynamicTableSizeUpdateTooLarge(_integerDecoder.Value, _maxDynamicTableSize)); } _dynamicTable.Resize(_integerDecoder.Value); _state = State.Ready; } break; default: // Can't happen throw new HPackDecodingException("The HPACK decoder reached an invalid state."); } }