H/QPackEncoder overloads accepting Encoding (#24448)
This commit is contained in:
parent
b9e663bffb
commit
e3501ddd4a
|
|
@ -4,6 +4,7 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace System.Net.Http.HPack
|
namespace System.Net.Http.HPack
|
||||||
{
|
{
|
||||||
|
|
@ -96,7 +97,7 @@ namespace System.Net.Http.HPack
|
||||||
if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
|
if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
|
||||||
{
|
{
|
||||||
Debug.Assert(indexLength >= 1);
|
Debug.Assert(indexLength >= 1);
|
||||||
if (EncodeStringLiteral(value, destination.Slice(indexLength), out int nameLength))
|
if (EncodeStringLiteral(value, valueEncoding: null, destination.Slice(indexLength), out int nameLength))
|
||||||
{
|
{
|
||||||
bytesWritten = indexLength + nameLength;
|
bytesWritten = indexLength + nameLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -128,7 +129,7 @@ namespace System.Net.Http.HPack
|
||||||
if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
|
if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
|
||||||
{
|
{
|
||||||
Debug.Assert(indexLength >= 1);
|
Debug.Assert(indexLength >= 1);
|
||||||
if (EncodeStringLiteral(value, destination.Slice(indexLength), out int nameLength))
|
if (EncodeStringLiteral(value, valueEncoding: null, destination.Slice(indexLength), out int nameLength))
|
||||||
{
|
{
|
||||||
bytesWritten = indexLength + nameLength;
|
bytesWritten = indexLength + nameLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -160,7 +161,7 @@ namespace System.Net.Http.HPack
|
||||||
if (IntegerEncoder.Encode(index, 6, destination, out int indexLength))
|
if (IntegerEncoder.Encode(index, 6, destination, out int indexLength))
|
||||||
{
|
{
|
||||||
Debug.Assert(indexLength >= 1);
|
Debug.Assert(indexLength >= 1);
|
||||||
if (EncodeStringLiteral(value, destination.Slice(indexLength), out int nameLength))
|
if (EncodeStringLiteral(value, valueEncoding: null, destination.Slice(indexLength), out int nameLength))
|
||||||
{
|
{
|
||||||
bytesWritten = indexLength + nameLength;
|
bytesWritten = indexLength + nameLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -276,7 +277,7 @@ namespace System.Net.Http.HPack
|
||||||
{
|
{
|
||||||
destination[0] = mask;
|
destination[0] = mask;
|
||||||
if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
|
if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
|
||||||
EncodeStringLiteral(value, destination.Slice(1 + nameLength), out int valueLength))
|
EncodeStringLiteral(value, valueEncoding: null, destination.Slice(1 + nameLength), out int valueLength))
|
||||||
{
|
{
|
||||||
bytesWritten = 1 + nameLength + valueLength;
|
bytesWritten = 1 + nameLength + valueLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -289,6 +290,11 @@ namespace System.Net.Http.HPack
|
||||||
|
|
||||||
/// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
|
/// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
|
||||||
public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, ReadOnlySpan<string> values, string separator, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, ReadOnlySpan<string> values, string separator, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
return EncodeLiteralHeaderFieldWithoutIndexingNewName(name, values, separator, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, ReadOnlySpan<string> values, string separator, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
// From https://tools.ietf.org/html/rfc7541#section-6.2.2
|
// From https://tools.ietf.org/html/rfc7541#section-6.2.2
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
@ -309,7 +315,7 @@ namespace System.Net.Http.HPack
|
||||||
{
|
{
|
||||||
destination[0] = 0;
|
destination[0] = 0;
|
||||||
if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
|
if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
|
||||||
EncodeStringLiterals(values, separator, destination.Slice(1 + nameLength), out int valueLength))
|
EncodeStringLiterals(values, separator, valueEncoding, destination.Slice(1 + nameLength), out int valueLength))
|
||||||
{
|
{
|
||||||
bytesWritten = 1 + nameLength + valueLength;
|
bytesWritten = 1 + nameLength + valueLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -395,27 +401,20 @@ namespace System.Net.Http.HPack
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool EncodeStringLiteralValue(string value, Span<byte> destination, out int bytesWritten)
|
private static void EncodeValueStringPart(string value, Span<byte> destination)
|
||||||
{
|
{
|
||||||
if (value.Length <= destination.Length)
|
Debug.Assert(destination.Length >= value.Length);
|
||||||
{
|
|
||||||
for (int i = 0; i < value.Length; i++)
|
|
||||||
{
|
|
||||||
char c = value[i];
|
|
||||||
if ((c & 0xFF80) != 0)
|
|
||||||
{
|
|
||||||
throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
destination[i] = (byte)c;
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
{
|
||||||
|
char c = value[i];
|
||||||
|
if ((c & 0xFF80) != 0)
|
||||||
|
{
|
||||||
|
throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten = value.Length;
|
destination[i] = (byte)c;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten = 0;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool EncodeStringLiteral(ReadOnlySpan<byte> value, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeStringLiteral(ReadOnlySpan<byte> value, Span<byte> destination, out int bytesWritten)
|
||||||
|
|
@ -453,6 +452,11 @@ namespace System.Net.Http.HPack
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool EncodeStringLiteral(string value, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeStringLiteral(string value, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
return EncodeStringLiteral(value, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeStringLiteral(string value, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
// From https://tools.ietf.org/html/rfc7541#section-5.2
|
// From https://tools.ietf.org/html/rfc7541#section-5.2
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
@ -466,13 +470,28 @@ namespace System.Net.Http.HPack
|
||||||
if (destination.Length != 0)
|
if (destination.Length != 0)
|
||||||
{
|
{
|
||||||
destination[0] = 0; // TODO: Use Huffman encoding
|
destination[0] = 0; // TODO: Use Huffman encoding
|
||||||
if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength))
|
|
||||||
|
int encodedStringLength = valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1)
|
||||||
|
? value.Length
|
||||||
|
: valueEncoding.GetByteCount(value);
|
||||||
|
|
||||||
|
if (IntegerEncoder.Encode(encodedStringLength, 7, destination, out int integerLength))
|
||||||
{
|
{
|
||||||
Debug.Assert(integerLength >= 1);
|
Debug.Assert(integerLength >= 1);
|
||||||
|
destination = destination.Slice(integerLength);
|
||||||
if (EncodeStringLiteralValue(value, destination.Slice(integerLength), out int valueLength))
|
if (encodedStringLength <= destination.Length)
|
||||||
{
|
{
|
||||||
bytesWritten = integerLength + valueLength;
|
if (valueEncoding is null)
|
||||||
|
{
|
||||||
|
EncodeValueStringPart(value, destination);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int written = valueEncoding.GetBytes(value, destination);
|
||||||
|
Debug.Assert(written == encodedStringLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesWritten = integerLength + encodedStringLength;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -502,56 +521,87 @@ namespace System.Net.Http.HPack
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool EncodeStringLiterals(ReadOnlySpan<string> values, string? separator, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeStringLiterals(ReadOnlySpan<string> values, string? separator, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
return EncodeStringLiterals(values, separator, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeStringLiterals(ReadOnlySpan<string> values, string? separator, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
bytesWritten = 0;
|
bytesWritten = 0;
|
||||||
|
|
||||||
if (values.Length == 0)
|
if (values.Length == 0)
|
||||||
{
|
{
|
||||||
return EncodeStringLiteral("", destination, out bytesWritten);
|
return EncodeStringLiteral("", valueEncoding: null, destination, out bytesWritten);
|
||||||
}
|
}
|
||||||
else if (values.Length == 1)
|
else if (values.Length == 1)
|
||||||
{
|
{
|
||||||
return EncodeStringLiteral(values[0], destination, out bytesWritten);
|
return EncodeStringLiteral(values[0], valueEncoding, destination, out bytesWritten);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination.Length != 0)
|
if (destination.Length != 0)
|
||||||
{
|
{
|
||||||
int valueLength = 0;
|
Debug.Assert(separator != null);
|
||||||
|
int valueLength;
|
||||||
|
|
||||||
// Calculate length of all parts and separators.
|
// Calculate length of all parts and separators.
|
||||||
foreach (string part in values)
|
if (valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1))
|
||||||
{
|
{
|
||||||
valueLength = checked((int)(valueLength + part.Length));
|
valueLength = checked((int)(values.Length - 1) * separator.Length);
|
||||||
|
foreach (string part in values)
|
||||||
|
{
|
||||||
|
valueLength = checked((int)(valueLength + part.Length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueLength = checked((int)(values.Length - 1) * valueEncoding.GetByteCount(separator));
|
||||||
|
foreach (string part in values)
|
||||||
|
{
|
||||||
|
valueLength = checked((int)(valueLength + valueEncoding.GetByteCount(part)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(separator != null);
|
|
||||||
valueLength = checked((int)(valueLength + (values.Length - 1) * separator.Length));
|
|
||||||
|
|
||||||
destination[0] = 0;
|
destination[0] = 0;
|
||||||
if (IntegerEncoder.Encode(valueLength, 7, destination, out int integerLength))
|
if (IntegerEncoder.Encode(valueLength, 7, destination, out int integerLength))
|
||||||
{
|
{
|
||||||
Debug.Assert(integerLength >= 1);
|
Debug.Assert(integerLength >= 1);
|
||||||
|
destination = destination.Slice(integerLength);
|
||||||
int encodedLength = 0;
|
if (destination.Length >= valueLength)
|
||||||
for (int j = 0; j < values.Length; j++)
|
|
||||||
{
|
{
|
||||||
if (j != 0 && !EncodeStringLiteralValue(separator, destination.Slice(integerLength), out encodedLength))
|
if (valueEncoding is null)
|
||||||
{
|
{
|
||||||
return false;
|
string value = values[0];
|
||||||
|
EncodeValueStringPart(value, destination);
|
||||||
|
destination = destination.Slice(value.Length);
|
||||||
|
|
||||||
|
for (int i = 1; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
EncodeValueStringPart(separator, destination);
|
||||||
|
destination = destination.Slice(separator.Length);
|
||||||
|
|
||||||
|
value = values[i];
|
||||||
|
EncodeValueStringPart(value, destination);
|
||||||
|
destination = destination.Slice(value.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int written = valueEncoding.GetBytes(values[0], destination);
|
||||||
|
destination = destination.Slice(written);
|
||||||
|
|
||||||
|
for (int i = 1; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
written = valueEncoding.GetBytes(separator, destination);
|
||||||
|
destination = destination.Slice(written);
|
||||||
|
|
||||||
|
written = valueEncoding.GetBytes(values[i], destination);
|
||||||
|
destination = destination.Slice(written);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
integerLength += encodedLength;
|
bytesWritten = integerLength + valueLength;
|
||||||
|
return true;
|
||||||
if (!EncodeStringLiteralValue(values[j], destination.Slice(integerLength), out encodedLength))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
integerLength += encodedLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesWritten = integerLength;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net.Http.HPack;
|
using System.Net.Http.HPack;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace System.Net.Http.QPack
|
namespace System.Net.Http.QPack
|
||||||
{
|
{
|
||||||
|
|
@ -59,6 +60,11 @@ namespace System.Net.Http.QPack
|
||||||
// - T is constant 1 here, indicating a static table reference.
|
// - T is constant 1 here, indicating a static table reference.
|
||||||
// - H is constant 0 here, as we do not yet perform Huffman coding.
|
// - H is constant 0 here, as we do not yet perform Huffman coding.
|
||||||
public static bool EncodeLiteralHeaderFieldWithStaticNameReference(int index, string value, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeLiteralHeaderFieldWithStaticNameReference(int index, string value, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
return EncodeLiteralHeaderFieldWithStaticNameReference(index, value, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeLiteralHeaderFieldWithStaticNameReference(int index, string value, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
// Requires at least two bytes (one for name reference header, one for value length)
|
// Requires at least two bytes (one for name reference header, one for value length)
|
||||||
if (destination.Length >= 2)
|
if (destination.Length >= 2)
|
||||||
|
|
@ -68,7 +74,7 @@ namespace System.Net.Http.QPack
|
||||||
{
|
{
|
||||||
destination = destination.Slice(headerBytesWritten);
|
destination = destination.Slice(headerBytesWritten);
|
||||||
|
|
||||||
if (EncodeValueString(value, destination, out int valueBytesWritten))
|
if (EncodeValueString(value, valueEncoding, destination, out int valueBytesWritten))
|
||||||
{
|
{
|
||||||
bytesWritten = headerBytesWritten + valueBytesWritten;
|
bytesWritten = headerBytesWritten + valueBytesWritten;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -81,7 +87,7 @@ namespace System.Net.Http.QPack
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes just the name part of a Literal Header Field With Static Name Reference. Must call <see cref="EncodeValueString(string, Span{byte}, out int)"/> after to encode the header's value.
|
/// Encodes just the name part of a Literal Header Field With Static Name Reference. Must call <see cref="EncodeValueString(string, Encoding?, Span{byte}, out int)"/> after to encode the header's value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(int index)
|
public static byte[] EncodeLiteralHeaderFieldWithStaticNameReferenceToArray(int index)
|
||||||
{
|
{
|
||||||
|
|
@ -119,7 +125,12 @@ namespace System.Net.Http.QPack
|
||||||
// - H is constant 0 here, as we do not yet perform Huffman coding.
|
// - H is constant 0 here, as we do not yet perform Huffman coding.
|
||||||
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, string value, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, string value, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
if (EncodeNameString(name, destination, out int nameLength) && EncodeValueString(value, destination.Slice(nameLength), out int valueLength))
|
return EncodeLiteralHeaderFieldWithoutNameReference(name, value, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, string value, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
if (EncodeNameString(name, destination, out int nameLength) && EncodeValueString(value, valueEncoding, destination.Slice(nameLength), out int valueLength))
|
||||||
{
|
{
|
||||||
bytesWritten = nameLength + valueLength;
|
bytesWritten = nameLength + valueLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -136,7 +147,12 @@ namespace System.Net.Http.QPack
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, ReadOnlySpan<string> values, string valueSeparator, Span<byte> destination, out int bytesWritten)
|
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, ReadOnlySpan<string> values, string valueSeparator, Span<byte> destination, out int bytesWritten)
|
||||||
{
|
{
|
||||||
if (EncodeNameString(name, destination, out int nameLength) && EncodeValueString(values, valueSeparator, destination.Slice(nameLength), out int valueLength))
|
return EncodeLiteralHeaderFieldWithoutNameReference(name, values, valueSeparator, valueEncoding: null, destination, out bytesWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeLiteralHeaderFieldWithoutNameReference(string name, ReadOnlySpan<string> values, string valueSeparator, Encoding? valueEncoding, Span<byte> destination, out int bytesWritten)
|
||||||
|
{
|
||||||
|
if (EncodeNameString(name, destination, out int nameLength) && EncodeValueString(values, valueSeparator, valueEncoding, destination.Slice(nameLength), out int valueLength))
|
||||||
{
|
{
|
||||||
bytesWritten = nameLength + valueLength;
|
bytesWritten = nameLength + valueLength;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -147,7 +163,7 @@ namespace System.Net.Http.QPack
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes just the value part of a Literawl Header Field Without Static Name Reference. Must call <see cref="EncodeValueString(string, Span{byte}, out int)"/> after to encode the header's value.
|
/// Encodes just the value part of a Literawl Header Field Without Static Name Reference. Must call <see cref="EncodeValueString(string, Encoding?, Span{byte}, out int)"/> after to encode the header's value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] EncodeLiteralHeaderFieldWithoutNameReferenceToArray(string name)
|
public static byte[] EncodeLiteralHeaderFieldWithoutNameReferenceToArray(string name)
|
||||||
{
|
{
|
||||||
|
|
@ -169,19 +185,32 @@ namespace System.Net.Http.QPack
|
||||||
return temp.Slice(0, bytesWritten).ToArray();
|
return temp.Slice(0, bytesWritten).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool EncodeValueString(string s, Span<byte> buffer, out int length)
|
private static bool EncodeValueString(string s, Encoding? valueEncoding, Span<byte> buffer, out int length)
|
||||||
{
|
{
|
||||||
if (buffer.Length != 0)
|
if (buffer.Length != 0)
|
||||||
{
|
{
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
if (IntegerEncoder.Encode(s.Length, 7, buffer, out int nameLength))
|
|
||||||
|
int encodedStringLength = valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1)
|
||||||
|
? s.Length
|
||||||
|
: valueEncoding.GetByteCount(s);
|
||||||
|
|
||||||
|
if (IntegerEncoder.Encode(encodedStringLength, 7, buffer, out int nameLength))
|
||||||
{
|
{
|
||||||
buffer = buffer.Slice(nameLength);
|
buffer = buffer.Slice(nameLength);
|
||||||
if (buffer.Length >= s.Length)
|
if (buffer.Length >= encodedStringLength)
|
||||||
{
|
{
|
||||||
EncodeValueStringPart(s, buffer);
|
if (valueEncoding is null)
|
||||||
|
{
|
||||||
|
EncodeValueStringPart(s, buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int written = valueEncoding.GetBytes(s, buffer);
|
||||||
|
Debug.Assert(written == encodedStringLength);
|
||||||
|
}
|
||||||
|
|
||||||
length = nameLength + s.Length;
|
length = nameLength + encodedStringLength;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,25 +224,42 @@ namespace System.Net.Http.QPack
|
||||||
/// Encodes a value by concatenating a collection of strings, separated by a separator string.
|
/// Encodes a value by concatenating a collection of strings, separated by a separator string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool EncodeValueString(ReadOnlySpan<string> values, string? separator, Span<byte> buffer, out int length)
|
public static bool EncodeValueString(ReadOnlySpan<string> values, string? separator, Span<byte> buffer, out int length)
|
||||||
|
{
|
||||||
|
return EncodeValueString(values, separator, valueEncoding: null, buffer, out length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EncodeValueString(ReadOnlySpan<string> values, string? separator, Encoding? valueEncoding, Span<byte> buffer, out int length)
|
||||||
{
|
{
|
||||||
if (values.Length == 1)
|
if (values.Length == 1)
|
||||||
{
|
{
|
||||||
return EncodeValueString(values[0], buffer, out length);
|
return EncodeValueString(values[0], valueEncoding, buffer, out length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (values.Length == 0)
|
if (values.Length == 0)
|
||||||
{
|
{
|
||||||
// TODO: this will be called with a string array from HttpHeaderCollection. Can we ever get a 0-length array from that? Assert if not.
|
// TODO: this will be called with a string array from HttpHeaderCollection. Can we ever get a 0-length array from that? Assert if not.
|
||||||
return EncodeValueString(string.Empty, buffer, out length);
|
return EncodeValueString(string.Empty, valueEncoding: null, buffer, out length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer.Length > 0)
|
if (buffer.Length > 0)
|
||||||
{
|
{
|
||||||
Debug.Assert(separator != null);
|
Debug.Assert(separator != null);
|
||||||
int valueLength = separator.Length * (values.Length - 1);
|
int valueLength;
|
||||||
for (int i = 0; i < values.Length; ++i)
|
if (valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1))
|
||||||
{
|
{
|
||||||
valueLength += values[i].Length;
|
valueLength = separator.Length * (values.Length - 1);
|
||||||
|
foreach (string part in values)
|
||||||
|
{
|
||||||
|
valueLength += part.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueLength = valueEncoding.GetByteCount(separator) * (values.Length - 1);
|
||||||
|
foreach (string part in values)
|
||||||
|
{
|
||||||
|
valueLength += valueEncoding.GetByteCount(part);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[0] = 0;
|
buffer[0] = 0;
|
||||||
|
|
@ -222,18 +268,35 @@ namespace System.Net.Http.QPack
|
||||||
buffer = buffer.Slice(nameLength);
|
buffer = buffer.Slice(nameLength);
|
||||||
if (buffer.Length >= valueLength)
|
if (buffer.Length >= valueLength)
|
||||||
{
|
{
|
||||||
string value = values[0];
|
if (valueEncoding is null)
|
||||||
EncodeValueStringPart(value, buffer);
|
|
||||||
buffer = buffer.Slice(value.Length);
|
|
||||||
|
|
||||||
for (int i = 1; i < values.Length; ++i)
|
|
||||||
{
|
{
|
||||||
EncodeValueStringPart(separator, buffer);
|
string value = values[0];
|
||||||
buffer = buffer.Slice(separator.Length);
|
|
||||||
|
|
||||||
value = values[i];
|
|
||||||
EncodeValueStringPart(value, buffer);
|
EncodeValueStringPart(value, buffer);
|
||||||
buffer = buffer.Slice(value.Length);
|
buffer = buffer.Slice(value.Length);
|
||||||
|
|
||||||
|
for (int i = 1; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
EncodeValueStringPart(separator, buffer);
|
||||||
|
buffer = buffer.Slice(separator.Length);
|
||||||
|
|
||||||
|
value = values[i];
|
||||||
|
EncodeValueStringPart(value, buffer);
|
||||||
|
buffer = buffer.Slice(value.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int written = valueEncoding.GetBytes(values[0], buffer);
|
||||||
|
buffer = buffer.Slice(written);
|
||||||
|
|
||||||
|
for (int i = 1; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
written = valueEncoding.GetBytes(separator, buffer);
|
||||||
|
buffer = buffer.Slice(written);
|
||||||
|
|
||||||
|
written = valueEncoding.GetBytes(values[i], buffer);
|
||||||
|
buffer = buffer.Slice(written);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
length = nameLength + valueLength;
|
length = nameLength + valueLength;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue