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