Beispiel #1
0
        public HPackEncoder Encode(string name, string value, HPackFlags flags = HPackFlags.None)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            int index = 0;

            switch (flags & IndexingMask)
            {
            case HPackFlags.WithoutIndexing:
                if (TryGetIndex(name, value, out index))
                {
                    return(FinishWrite(EncodeHeader(index, _buffer.Span.Slice(_bufferConsumed))));
                }

                if (TryGetIndex(name, out index))
                {
                    name = null;
                }
                break;

            case HPackFlags.NewIndexed:
                TableEntry newEntry = new TableEntry(name, value);

                if (TryGetIndex(name, out index))
                {
                    name = null;
                }

                AddDynamicEntry(newEntry);
                break;
            }

            return(FinishWrite(EncodeHeaderImpl(index, name, value, flags, _buffer.Span.Slice(_bufferConsumed))));
        }
        private static int EncodeHeaderImpl(int nameIdx, string name, string value, HPackFlags flags, Span <byte> headerBlock)
        {
            const HPackFlags IndexingMask = HPackFlags.NeverIndexed | HPackFlags.NewIndexed | HPackFlags.WithoutIndexing;

            Debug.Assert((nameIdx != 0) != (name != null), $"Only one of {nameof(nameIdx)} or {nameof(name)} can be used.");
            Debug.Assert(name != null || (flags & HPackFlags.HuffmanEncodeName) == 0, "An indexed name can not be huffman encoded.");

            byte prefix, prefixMask;

            switch (flags & IndexingMask)
            {
            case HPackFlags.WithoutIndexing:
                prefix     = 0;
                prefixMask = 0b11110000;
                break;

            case HPackFlags.NewIndexed:
                prefix     = 0b01000000;
                prefixMask = 0b11000000;
                break;

            case HPackFlags.NeverIndexed:
                prefix     = 0b00010000;
                prefixMask = 0b11110000;
                break;

            default:
                throw new Exception("invalid indexing flag");
            }

            int bytesGenerated = EncodeInteger(nameIdx, prefix, prefixMask, headerBlock);

            if (name != null)
            {
                bytesGenerated += EncodeString(name, headerBlock.Slice(bytesGenerated), (flags & HPackFlags.HuffmanEncodeName) != 0);
            }

            bytesGenerated += EncodeString(value, headerBlock.Slice(bytesGenerated), (flags & HPackFlags.HuffmanEncodeValue) != 0);
            return(bytesGenerated);
        }
 /// <summary>
 /// Encodes a header using a literal name and value.
 /// </summary>
 /// <param name="name">A literal name to encode for this header.</param>
 /// <param name="value">A literal value to encode for this header.</param>
 /// <param name="headerBlock">A span to write the encoded header to.</param>
 /// <returns>The number of bytes written to <paramref name="headerBlock"/>.</returns>
 public static int EncodeHeader(string name, string value, HPackFlags flags, Span <byte> headerBlock)
 {
     return(EncodeHeaderImpl(0, name, value, flags, headerBlock));
 }
 /// <summary>
 /// Encodes a header using an indexed name and literal value.
 /// </summary>
 /// <param name="nameIdx">An index of a header containing the name for this header.</param>
 /// <param name="value">A literal value to encode for this header.</param>
 /// <param name="headerBlock">A span to write the encoded header to.</param>
 /// <returns>The number of bytes written to <paramref name="headerBlock"/>.</returns>
 public static int EncodeHeader(int nameIdx, string value, HPackFlags flags, Span <byte> headerBlock)
 {
     Debug.Assert(nameIdx > 0);
     return(EncodeHeaderImpl(nameIdx, null, value, flags, headerBlock));
 }
Beispiel #5
0
        static void GenerateSeeds()
        {
            Random rng = new Random(0);

            HPackEncoder.TableEntry[] staticIndexedHeaders = HPackEncoder.s_staticTable.Where(x => x.Value.Length != 0).ToArray();
            string[] staticIndexedNames = HPackEncoder.s_staticTable.Select(x => x.Name).Distinct().ToArray();

            int seedLen = 1024;

            for (int i = 0; i < 10; ++i)
            {
                Console.WriteLine($"generating seed {i}");

                seedLen += rng.Next(1024, 10240);

                GenerateSeed(enc =>
                {
                    enc.EncodeNewDynamicTableSize(4096);

                    while (enc.BytesWritten < seedLen)
                    {
                        string name, value;
                        HPackFlags flags = HPackFlags.None;

                        int type = rng.Next(5);
                        switch (type)
                        {
                        case 0:
                            Console.WriteLine("fully indexed, static.");
                            HPackEncoder.TableEntry e = staticIndexedHeaders[rng.Next(staticIndexedHeaders.Length)];
                            (name, value)             = (e.Name, e.Value);
                            break;

                        case 1:
                            if (enc.DynamicTableCount == 0 || rng.Next(5) == 0)
                            {
                                Console.WriteLine("new dynamic index.");
                                name  = GenerateName();
                                value = GenerateValue();
                                flags = HPackFlags.NewIndexed;
                            }
                            else
                            {
                                Console.WriteLine("fully indexed, dynamic.");
                                e             = enc.DynamicTable.ElementAt(rng.Next(enc.DynamicTableCount));
                                (name, value) = (e.Name, e.Value);
                            }
                            break;

                        case 2:
                            Console.WriteLine("indexed name, static.");
                            name  = staticIndexedNames[rng.Next(staticIndexedNames.Length)];
                            value = GenerateValue();
                            break;

                        case 3:
                            if (enc.DynamicTableCount == 0 || rng.Next(5) == 0)
                            {
                                Console.WriteLine("new dynamic index.");
                                name  = GenerateName();
                                value = GenerateValue();
                                flags = HPackFlags.NewIndexed;
                            }
                            else
                            {
                                Console.WriteLine("indexed name, dynamic.");
                                e     = enc.DynamicTable.ElementAt(rng.Next(enc.DynamicTableCount));
                                name  = e.Name;
                                value = GenerateValue();
                            }
                            break;

                        case 4:     // literal name.
                            Console.WriteLine("literal name.");
                            name  = GenerateName();
                            value = GenerateValue();
                            break;

                        default:
                            throw new Exception("should never be reached A");
                        }

                        Debug.Assert(name != null);
                        Debug.Assert(value != null);

                        if (flags != HPackFlags.NewIndexed)
                        {
                            switch (rng.Next(3))
                            {
                            case 0:
                                flags |= HPackFlags.WithoutIndexing;
                                break;

                            case 1:
                                flags |= HPackFlags.NewIndexed;
                                break;

                            case 2:
                                flags |= HPackFlags.NeverIndexed;
                                break;

                            default:
                                throw new Exception("should never be reached B");
                            }
                        }

                        if (rng.Next(2) == 0)
                        {
                            flags |= HPackFlags.HuffmanEncodeName;
                        }
                        if (rng.Next(2) == 0)
                        {
                            flags |= HPackFlags.HuffmanEncodeValue;
                        }

                        enc.Encode(name, value, flags);
                    }
                });
            }

            string GenerateName() => GenerateString(rng.Next(4, 16));
            string GenerateValue() => GenerateString(rng.Next(4, 64));

            string GenerateString(int len)
            {
                char[] buffer = new char[len];

                for (int i = 0; i < len; ++i)
                {
                    buffer[i] = (char)('a' + rng.Next(0, 26));
                }

                return(new string(buffer));
            }
        }