private void OnIndexedHeaderField(int index, HeaderCallback onHeader) { HeaderField header = GetHeader(index); onHeader(new Span <byte>(header.Name), new Span <byte>(header.Value)); _state = State.Ready; }
private void OnIndexedHeaderField(int index, HeaderCallback onHeader, object onHeaderState) { HeaderField header = GetHeader(index); onHeader(onHeaderState, new ReadOnlySpan <byte>(header.Name), new ReadOnlySpan <byte>(header.Value)); _state = State.Ready; }
// Called when we have complete header with name and value. private void OnHeaderComplete(HeaderCallback onHeader, object onHeaderState, ReadOnlySpan <byte> headerName, ReadOnlySpan <byte> headerValue) { // Call provided callback. onHeader(onHeaderState, headerName, headerValue); if (_index) { _dynamicTable.Insert(headerName, headerValue); } }
private static void readHeader <T>(BinaryReader reader, IList <T> items, HeaderCallback <T> readCallback) { // Count int count = BinaryReaderTools.ReadNumber(reader); // Items) for (int i = 0; i < count; i++) { string itemAsText = BinaryReaderTools.ReadString(reader); T item = readCallback(itemAsText); items.Add(item); } }
public void Decode(ReadOnlySpan <byte> data, HeaderCallback onHeader, object onHeaderState) { for (int i = 0; i < data.Length; i++) { byte b = data[i]; switch (_state) { case State.Ready: // TODO: Instead of masking and comparing each prefix value, // consider doing a 16-way switch on the first four bits (which is the max prefix size). // Look at this once we have more concrete perf data. if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation) { int val = b & ~IndexedHeaderFieldMask; if (_integerDecoder.StartDecode((byte)val, IndexedHeaderFieldPrefix)) { OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState); } else { _state = State.HeaderFieldIndex; } } else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation) { _index = true; int val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation) { _index = false; int val = b & ~LiteralHeaderFieldWithoutIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation) { _index = false; int val = b & ~LiteralHeaderFieldNeverIndexedMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & DynamicTableSizeUpdateMask) == DynamicTableSizeUpdateRepresentation) { if (_integerDecoder.StartDecode((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 Debug.Fail("Unreachable code"); throw new InternalException(); } break; case State.HeaderFieldIndex: if (_integerDecoder.Decode(b)) { OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState); } break; case State.HeaderNameIndex: if (_integerDecoder.Decode(b)) { OnIndexedHeaderName(_integerDecoder.Value); } break; case State.HeaderNameLength: _huffman = (b & HuffmanMask) != 0; if (_integerDecoder.StartDecode((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.StartDecode((byte)(b & ~HuffmanMask), StringLengthPrefix)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); } else { _state = State.HeaderValueLengthContinue; } break; case State.HeaderValueLengthContinue: if (_integerDecoder.Decode(b)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); } break; case State.HeaderValue: _stringOctets[_stringIndex++] = b; if (_stringIndex == _stringLength) { OnString(nextState: State.Ready); var headerNameSpan = new ReadOnlySpan <byte>(_headerName, 0, _headerNameLength); var headerValueSpan = new ReadOnlySpan <byte>(_headerValueOctets, 0, _headerValueLength); onHeader(onHeaderState, headerNameSpan, headerValueSpan); if (_index) { _dynamicTable.Insert(headerNameSpan, headerValueSpan); } } break; case State.DynamicTableSizeUpdate: if (_integerDecoder.Decode(b)) { if (_integerDecoder.Value > _maxDynamicTableSize) { // Dynamic table size update is too large. throw new HPackDecodingException(); } _dynamicTable.Resize(_integerDecoder.Value); _state = State.Ready; } break; default: // Can't happen Debug.Fail("HPACK decoder reach an invalid state"); throw new InternalException(_state); } } }
public void Decode(ReadOnlySpan <byte> data, bool endHeaders, HeaderCallback onHeader, object onHeaderState) { for (int i = 0; i < data.Length; i++) { byte b = data[i]; switch (_state) { case State.Ready: // TODO: Instead of masking and comparing each prefix value, // consider doing a 16-way switch on the first four bits (which is the max prefix size). // Look at this once we have more concrete perf data. if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation) { _headersObserved = true; int val = b & ~IndexedHeaderFieldMask; if (_integerDecoder.StartDecode((byte)val, IndexedHeaderFieldPrefix)) { OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState); } else { _state = State.HeaderFieldIndex; } } else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation) { _headersObserved = true; _index = true; int val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation) { _headersObserved = true; _index = false; int val = b & ~LiteralHeaderFieldWithoutIndexingMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } else { _state = State.HeaderNameIndex; } } else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation) { _headersObserved = true; _index = false; int val = b & ~LiteralHeaderFieldNeverIndexedMask; if (val == 0) { _state = State.HeaderNameLength; } else if (_integerDecoder.StartDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix)) { OnIndexedHeaderName(_integerDecoder.Value); } 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(SR.net_http_hpack_late_dynamic_table_size_update); } if (_integerDecoder.StartDecode((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 Debug.Fail("Unreachable code"); throw new InternalException(); } break; case State.HeaderFieldIndex: if (_integerDecoder.Decode(b)) { OnIndexedHeaderField(_integerDecoder.Value, onHeader, onHeaderState); } break; case State.HeaderNameIndex: if (_integerDecoder.Decode(b)) { OnIndexedHeaderName(_integerDecoder.Value); } break; case State.HeaderNameLength: _huffman = (b & HuffmanMask) != 0; if (_integerDecoder.StartDecode((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.StartDecode((byte)(b & ~HuffmanMask), StringLengthPrefix)) { if (_integerDecoder.Value > 0) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); } else { OnStringLength(_integerDecoder.Value, nextState: State.Ready); OnHeaderComplete(onHeader, onHeaderState, new ReadOnlySpan <byte>(_headerName, 0, _headerNameLength), new ReadOnlySpan <byte>()); } } else { _state = State.HeaderValueLengthContinue; } break; case State.HeaderValueLengthContinue: if (_integerDecoder.Decode(b)) { OnStringLength(_integerDecoder.Value, nextState: State.HeaderValue); } break; case State.HeaderValue: _stringOctets[_stringIndex++] = b; if (_stringIndex == _stringLength) { OnString(nextState: State.Ready); var headerNameSpan = new ReadOnlySpan <byte>(_headerName, 0, _headerNameLength); var headerValueSpan = new ReadOnlySpan <byte>(_headerValueOctets, 0, _headerValueLength); OnHeaderComplete(onHeader, onHeaderState, headerNameSpan, headerValueSpan); } break; case State.DynamicTableSizeUpdate: if (_integerDecoder.Decode(b)) { if (_integerDecoder.Value > _maxDynamicTableSize) { // Dynamic table size update is too large. throw new HPackDecodingException(); } _dynamicTable.Resize(_integerDecoder.Value); _state = State.Ready; } break; default: // Can't happen Debug.Fail("HPACK decoder reach an invalid state"); throw new InternalException(_state); } } if (endHeaders) { if (_state != State.Ready) { throw new HPackDecodingException(SR.net_http_hpack_incomplete_header_block); } _headersObserved = false; } }
private static void ReadHeader <T>(BinaryReader reader, ICollection <T> items, HeaderCallback <T> readCallback) { // Count var count = BinaryReaderTools.ReadNumber(reader); // Items for (var i = 0; i < count; i++) { var itemAsText = BinaryReaderTools.ReadString(reader); var item = readCallback(itemAsText); items.Add(item); } }