Skip to content

Commit

Permalink
Sync changes from ASP.NET Core dynamic HPack (#34247)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Apr 2, 2020
1 parent 1c74287 commit 73d8178
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace System.Net.Http.HPack
{
internal static class HPackEncoder
internal partial class HPackEncoder
{
// Things we should add:
// * Huffman encoding
Expand Down Expand Up @@ -109,6 +109,70 @@ public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, string val
return false;
}

/// <summary>Encodes a "Literal Header Field never Indexing".</summary>
public static bool EncodeLiteralHeaderFieldNeverIndexing(int index, string value, Span<byte> destination, out int bytesWritten)
{
// From https://tools.ietf.org/html/rfc7541#section-6.2.3
// ------------------------------------------------------
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 1 | Index (4+) |
// +---+---+-----------------------+
// | H | Value Length (7+) |
// +---+---------------------------+
// | Value String (Length octets) |
// +-------------------------------+

if ((uint)destination.Length >= 2)
{
destination[0] = 0x10;
if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
{
Debug.Assert(indexLength >= 1);
if (EncodeStringLiteral(value, destination.Slice(indexLength), out int nameLength))
{
bytesWritten = indexLength + nameLength;
return true;
}
}
}

bytesWritten = 0;
return false;
}

/// <summary>Encodes a "Literal Header Field with Indexing".</summary>
public static bool EncodeLiteralHeaderFieldIndexing(int index, string value, Span<byte> destination, out int bytesWritten)
{
// From https://tools.ietf.org/html/rfc7541#section-6.2.2
// ------------------------------------------------------
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 1 | Index (6+) |
// +---+---+-----------------------+
// | H | Value Length (7+) |
// +---+---------------------------+
// | Value String (Length octets) |
// +-------------------------------+

if ((uint)destination.Length >= 2)
{
destination[0] = 0x40;
if (IntegerEncoder.Encode(index, 6, destination, out int indexLength))
{
Debug.Assert(indexLength >= 1);
if (EncodeStringLiteral(value, destination.Slice(indexLength), out int nameLength))
{
bytesWritten = indexLength + nameLength;
return true;
}
}
}

bytesWritten = 0;
return false;
}

/// <summary>
/// Encodes a "Literal Header Field without Indexing", but only the index portion;
/// a subsequent call to <c>EncodeStringLiteral</c> must be used to encode the associated value.
Expand Down Expand Up @@ -144,6 +208,27 @@ public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, Span<byte>
return false;
}

/// <summary>Encodes a "Literal Header Field with Indexing - New Name".</summary>
public static bool EncodeLiteralHeaderFieldIndexingNewName(string name, string value, Span<byte> destination, out int bytesWritten)
{
// From https://tools.ietf.org/html/rfc7541#section-6.2.2
// ------------------------------------------------------
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 1 | 0 |
// +---+---+-----------------------+
// | H | Name Length (7+) |
// +---+---------------------------+
// | Name String (Length octets) |
// +---+---------------------------+
// | H | Value Length (7+) |
// +---+---------------------------+
// | Value String (Length octets) |
// +-------------------------------+

return EncodeLiteralHeaderNewNameCore(0x40, name, value, destination, out bytesWritten);
}

/// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, string value, Span<byte> destination, out int bytesWritten)
{
Expand All @@ -162,9 +247,35 @@ public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, s
// | Value String (Length octets) |
// +-------------------------------+

return EncodeLiteralHeaderNewNameCore(0, name, value, destination, out bytesWritten);
}

/// <summary>Encodes a "Literal Header Field never Indexing - New Name".</summary>
public static bool EncodeLiteralHeaderFieldNeverIndexingNewName(string name, string value, Span<byte> destination, out int bytesWritten)
{
// From https://tools.ietf.org/html/rfc7541#section-6.2.3
// ------------------------------------------------------
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 1 | 0 |
// +---+---+-----------------------+
// | H | Name Length (7+) |
// +---+---------------------------+
// | Name String (Length octets) |
// +---+---------------------------+
// | H | Value Length (7+) |
// +---+---------------------------+
// | Value String (Length octets) |
// +-------------------------------+

return EncodeLiteralHeaderNewNameCore(0x10, name, value, destination, out bytesWritten);
}

private static bool EncodeLiteralHeaderNewNameCore(byte mask, string name, string value, Span<byte> destination, out int bytesWritten)
{
if ((uint)destination.Length >= 3)
{
destination[0] = 0;
destination[0] = mask;
if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
EncodeStringLiteral(value, destination.Slice(1 + nameLength), out int valueLength))
{
Expand Down Expand Up @@ -372,6 +483,25 @@ public static bool EncodeStringLiteral(string value, Span<byte> destination, out
return false;
}

public static bool EncodeDynamicTableSizeUpdate(int value, Span<byte> destination, out int bytesWritten)
{
// From https://tools.ietf.org/html/rfc7541#section-6.3
// ----------------------------------------------------
// 0 1 2 3 4 5 6 7
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 1 | Max size (5+) |
// +---+---------------------------+

if (destination.Length != 0)
{
destination[0] = 0x20;
return IntegerEncoder.Encode(value, 5, destination, out bytesWritten);
}

bytesWritten = 0;
return false;
}

public static bool EncodeStringLiterals(ReadOnlySpan<string> values, string? separator, Span<byte> destination, out int bytesWritten)
{
bytesWritten = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace System.Net.Http.HPack
{
internal static class StatusCodes
internal static partial class StatusCodes
{
// This uses C# compiler's ability to refer to static data directly. For more information see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static

Expand Down

0 comments on commit 73d8178

Please sign in to comment.