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); }
public static bool EncodeStringLiteral(string value, Span <byte> destination, out int bytesWritten) { // From https://tools.ietf.org/html/rfc7541#section-5.2 // ------------------------------------------------------ // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | H | String Length (7+) | // +---+---------------------------+ // | String Data (Length octets) | // +-------------------------------+ if (destination.Length != 0) { destination[0] = 0; // TODO: Use Huffman encoding if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength)) { Debug.Assert(integerLength >= 1); if (EncodeStringLiteralValue(value, destination.Slice(integerLength), out int valueLength)) { bytesWritten = integerLength + valueLength; return(true); } } } bytesWritten = 0; return(false); }
/// <summary> /// Encodes a "Literal Header Field without Indexing", but only the index portion; /// a subsequent call to <see cref="EncodeStringLiteral"/> must be used to encode the associated value. /// </summary> public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, 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 | 0 | 0 | 0 | Index (4+) | // +---+---+-----------------------+ // // ... expected after this: // // | H | Value Length (7+) | // +---+---------------------------+ // | Value String (Length octets) | // +-------------------------------+ if ((uint)destination.Length != 0) { destination[0] = 0; if (IntegerEncoder.Encode(index, 4, destination, out int indexLength)) { Debug.Assert(indexLength >= 1); bytesWritten = indexLength; return(true); } } bytesWritten = 0; return(false); }
public static bool EncodeStringLiteral(ReadOnlySpan <byte> value, Span <byte> destination, out int bytesWritten) { // From https://tools.ietf.org/html/rfc7541#section-5.2 // ------------------------------------------------------ // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | H | String Length (7+) | // +---+---------------------------+ // | String Data (Length octets) | // +-------------------------------+ if (destination.Length != 0) { destination[0] = 0; // TODO: Use Huffman encoding if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength)) { Debug.Assert(integerLength >= 1); destination = destination.Slice(integerLength); if (value.Length <= destination.Length) { // Note: No validation. Bytes should have already been validated. value.CopyTo(destination); bytesWritten = integerLength + value.Length; return(true); } } } bytesWritten = 0; return(false); }
public static bool EncodeStringLiterals(ReadOnlySpan <string> values, string?separator, Span <byte> destination, out int bytesWritten) { bytesWritten = 0; if (values.Length == 0) { return(EncodeStringLiteral("", destination, out bytesWritten)); } else if (values.Length == 1) { return(EncodeStringLiteral(values[0], destination, out bytesWritten)); } if (destination.Length != 0) { int valueLength = 0; // Calculate length of all parts and separators. foreach (string part in values) { valueLength = checked ((int)(valueLength + part.Length)); } Debug.Assert(separator != null); valueLength = checked ((int)(valueLength + (values.Length - 1) * separator.Length)); destination[0] = 0; if (IntegerEncoder.Encode(valueLength, 7, destination, out int integerLength)) { Debug.Assert(integerLength >= 1); int encodedLength = 0; for (int j = 0; j < values.Length; j++) { if (j != 0 && !EncodeStringLiteralValue(separator, destination.Slice(integerLength), out encodedLength)) { return(false); } integerLength += encodedLength; if (!EncodeStringLiteralValue(values[j], destination.Slice(integerLength), out encodedLength)) { return(false); } integerLength += encodedLength; } bytesWritten = integerLength; return(true); } } return(false); }
public static bool EncodeStringLiteral(string value, Span <byte> destination, out int bytesWritten, bool toLower) { // From https://tools.ietf.org/html/rfc7541#section-5.2 // ------------------------------------------------------ // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | H | String Length (7+) | // +---+---------------------------+ // | String Data (Length octets) | // +-------------------------------+ if (destination.Length != 0) { destination[0] = 0; // TODO: Use Huffman encoding if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength)) { Debug.Assert(integerLength >= 1); destination = destination.Slice(integerLength); if (value.Length <= destination.Length) { if (toLower) { for (int i = 0; i < value.Length; i++) { char c = value[i]; destination[i] = (byte)((uint)(c - 'A') <= ('Z' - 'A') ? c | 0x20 : c); } } else { for (int i = 0; i < value.Length; i++) { destination[i] = (byte)value[i]; } } bytesWritten = integerLength + value.Length; return(true); } } } bytesWritten = 0; return(false); }
// Things we should add: // * Huffman encoding // // Things we should consider adding: // * Dynamic table encoding: // This would make the encoder stateful, which complicates things significantly. // Additionally, it's not clear exactly what strings we would add to the dynamic table // without some additional guidance from the user about this. // So for now, don't do dynamic encoding. /// <summary>Encodes an "Indexed Header Field".</summary> public static bool EncodeIndexedHeaderField(int index, Span <byte> destination, out int bytesWritten) { // From https://tools.ietf.org/html/rfc7541#section-6.1 // ---------------------------------------------------- // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | 1 | Index (7+) | // +---+---------------------------+ if (destination.Length != 0) { destination[0] = 0x80; return(IntegerEncoder.Encode(index, 7, destination, out bytesWritten)); } bytesWritten = 0; 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 EncodeStringLiteral(string value, Encoding?valueEncoding, Span <byte> destination, out int bytesWritten) { // From https://tools.ietf.org/html/rfc7541#section-5.2 // ------------------------------------------------------ // 0 1 2 3 4 5 6 7 // +---+---+---+---+---+---+---+---+ // | H | String Length (7+) | // +---+---------------------------+ // | String Data (Length octets) | // +-------------------------------+ if (destination.Length != 0) { destination[0] = 0; // TODO: Use Huffman encoding 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); destination = destination.Slice(integerLength); if (encodedStringLength <= destination.Length) { if (valueEncoding is null) { EncodeValueStringPart(value, destination); } else { int written = valueEncoding.GetBytes(value, destination); Debug.Assert(written == encodedStringLength); } bytesWritten = integerLength + encodedStringLength; return(true); } } } bytesWritten = 0; return(false); }
public static bool EncodeStringLiterals(ReadOnlySpan <string> values, string?separator, Encoding?valueEncoding, Span <byte> destination, out int bytesWritten) { bytesWritten = 0; if (values.Length == 0) { return(EncodeStringLiteral("", valueEncoding: null, destination, out bytesWritten)); } else if (values.Length == 1) { return(EncodeStringLiteral(values[0], valueEncoding, destination, out bytesWritten)); } if (destination.Length != 0) { Debug.Assert(separator != null); int valueLength; // Calculate length of all parts and separators. if (valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1)) { 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))); } } destination[0] = 0; if (IntegerEncoder.Encode(valueLength, 7, destination, out int integerLength)) { Debug.Assert(integerLength >= 1); destination = destination.Slice(integerLength); if (destination.Length >= valueLength) { if (valueEncoding is null) { 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); } } bytesWritten = integerLength + valueLength; return(true); } } }