Exemple #1
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        // 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);
        }
Exemple #8
0
        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);
        }
Exemple #9
0
        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);
        }
Exemple #10
0
        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);
                    }
                }
            }