private static bool EncodeHeader(KnownHeaderType knownHeaderType, string name, string value, Span <byte> buffer, out int length) { var hPackStaticTableId = GetResponseHeaderStaticTableId(knownHeaderType); if (hPackStaticTableId == -1) { return(HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, buffer, out length)); } else { return(HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(hPackStaticTableId, value, buffer, out length)); } }
public bool EncodeHeader(Span <byte> buffer, int staticTableIndex, HeaderEncodingHint encodingHint, string name, string value, Encoding?valueEncoding, out int bytesWritten) { Debug.Assert(!_pendingTableSizeUpdate, "Dynamic table size update should be encoded before headers."); // Never index sensitive value. if (encodingHint == HeaderEncodingHint.NeverIndex) { int index = ResolveDynamicTableIndex(staticTableIndex, name); return(index == -1 ? HPackEncoder.EncodeLiteralHeaderFieldNeverIndexingNewName(name, value, valueEncoding, buffer, out bytesWritten) : HPackEncoder.EncodeLiteralHeaderFieldNeverIndexing(index, value, valueEncoding, buffer, out bytesWritten)); } // No dynamic table. Only use the static table. if (!_allowDynamicCompression || _maxHeaderTableSize == 0 || encodingHint == HeaderEncodingHint.IgnoreIndex) { return(staticTableIndex == -1 ? HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, valueEncoding, buffer, out bytesWritten) : HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(staticTableIndex, value, valueEncoding, buffer, out bytesWritten)); } // Header is greater than the maximum table size. // Don't attempt to add dynamic header as all existing dynamic headers will be removed. var headerLength = HeaderField.GetLength(name.Length, valueEncoding?.GetByteCount(value) ?? value.Length); if (headerLength > _maxHeaderTableSize) { int index = ResolveDynamicTableIndex(staticTableIndex, name); return(index == -1 ? HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, valueEncoding, buffer, out bytesWritten) : HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexing(index, value, valueEncoding, buffer, out bytesWritten)); } return(EncodeDynamicHeader(buffer, staticTableIndex, name, value, headerLength, valueEncoding, out bytesWritten)); }
private static bool EncodeHeader(string name, string value, Span <byte> buffer, out int length) { return(HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, value, valueEncoding: null, buffer, out length)); }
// adapted from Header serialization code in Http2Connection.cs private static Memory <byte> HPackEncode(HttpHeaders headers) { var buffer = new ArrayBuffer(4); FillAvailableSpaceWithOnes(buffer); foreach (KeyValuePair <HeaderDescriptor, string[]> header in headers.GetHeaderDescriptorsAndValues()) { KnownHeader knownHeader = header.Key.KnownHeader; if (knownHeader != null) { // For all other known headers, send them via their pre-encoded name and the associated value. WriteBytes(knownHeader.Http2EncodedName); string separator = null; if (header.Value.Length > 1) { HttpHeaderParser parser = header.Key.Parser; if (parser != null && parser.SupportsMultipleValues) { separator = parser.Separator; } else { separator = HttpHeaderParser.DefaultSeparator; } } WriteLiteralHeaderValues(header.Value, separator); } else { // The header is not known: fall back to just encoding the header name and value(s). WriteLiteralHeader(header.Key.Name, header.Value); } } return(buffer.ActiveMemory); void WriteBytes(ReadOnlySpan <byte> bytes) { if (bytes.Length > buffer.AvailableLength) { buffer.EnsureAvailableSpace(bytes.Length); FillAvailableSpaceWithOnes(buffer); } bytes.CopyTo(buffer.AvailableSpan); buffer.Commit(bytes.Length); } void WriteLiteralHeaderValues(string[] values, string separator) { int bytesWritten; while (!HPackEncoder.EncodeStringLiterals(values, separator, buffer.AvailableSpan, out bytesWritten)) { buffer.EnsureAvailableSpace(buffer.AvailableLength + 1); FillAvailableSpaceWithOnes(buffer); } buffer.Commit(bytesWritten); } void WriteLiteralHeader(string name, string[] values) { int bytesWritten; while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, values, HttpHeaderParser.DefaultSeparator, buffer.AvailableSpan, out bytesWritten)) { buffer.EnsureAvailableSpace(buffer.AvailableLength + 1); FillAvailableSpaceWithOnes(buffer); } buffer.Commit(bytesWritten); } // force issues related to buffer not being zeroed out void FillAvailableSpaceWithOnes(ArrayBuffer buffer) => buffer.AvailableSpan.Fill(0xff); }
// adapted from Header serialization code in Http2Connection.cs private static Memory <byte> HPackEncode(HttpHeaders headers, Encoding?valueEncoding) { var buffer = new ArrayBuffer(4); FillAvailableSpaceWithOnes(buffer); string[] headerValues = Array.Empty <string>(); foreach (HeaderEntry header in headers.GetEntries()) { int headerValuesCount = HttpHeaders.GetStoreValuesIntoStringArray(header.Key, header.Value, ref headerValues); Assert.InRange(headerValuesCount, 0, int.MaxValue); ReadOnlySpan <string> headerValuesSpan = headerValues.AsSpan(0, headerValuesCount); KnownHeader knownHeader = header.Key.KnownHeader; if (knownHeader != null) { // For all other known headers, send them via their pre-encoded name and the associated value. WriteBytes(knownHeader.Http2EncodedName); string separator = null; if (headerValuesSpan.Length > 1) { HttpHeaderParser parser = header.Key.Parser; if (parser != null && parser.SupportsMultipleValues) { separator = parser.Separator; } else { separator = HttpHeaderParser.DefaultSeparator; } } WriteLiteralHeaderValues(headerValuesSpan, separator); } else { // The header is not known: fall back to just encoding the header name and value(s). WriteLiteralHeader(header.Key.Name, headerValuesSpan); } } return(buffer.ActiveMemory); void WriteBytes(ReadOnlySpan <byte> bytes) { if (bytes.Length > buffer.AvailableLength) { buffer.EnsureAvailableSpace(bytes.Length); FillAvailableSpaceWithOnes(buffer); } bytes.CopyTo(buffer.AvailableSpan); buffer.Commit(bytes.Length); } void WriteLiteralHeaderValues(ReadOnlySpan <string> values, string separator) { int bytesWritten; while (!HPackEncoder.EncodeStringLiterals(values, separator, valueEncoding, buffer.AvailableSpan, out bytesWritten)) { buffer.EnsureAvailableSpace(buffer.AvailableLength + 1); FillAvailableSpaceWithOnes(buffer); } buffer.Commit(bytesWritten); } void WriteLiteralHeader(string name, ReadOnlySpan <string> values) { int bytesWritten; while (!HPackEncoder.EncodeLiteralHeaderFieldWithoutIndexingNewName(name, values, HttpHeaderParser.DefaultSeparator, valueEncoding, buffer.AvailableSpan, out bytesWritten)) { buffer.EnsureAvailableSpace(buffer.AvailableLength + 1); FillAvailableSpaceWithOnes(buffer); } buffer.Commit(bytesWritten); } // force issues related to buffer not being zeroed out void FillAvailableSpaceWithOnes(ArrayBuffer buffer) => buffer.AvailableSpan.Fill(0xff); }