< Summary

Information
Class: System.Net.Http.HPack.HPackEncoder
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncoder.cs
Line coverage
23%
Covered lines: 48
Uncovered lines: 160
Coverable lines: 208
Total lines: 643
Line coverage: 23%
Branch coverage
12%
Covered branches: 9
Total branches: 72
Branch coverage: 12.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

D:\runner\runtime\src\libraries\Common\src\System\Net\Http\aspnetcore\Http2\Hpack\HPackEncoder.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4#nullable enable
 5using System.Buffers;
 6using System.Collections.Generic;
 7using System.Diagnostics;
 8using System.Text;
 9
 10namespace System.Net.Http.HPack
 11{
 12    internal static partial class HPackEncoder
 13    {
 14        // Things we should add:
 15        // * Huffman encoding
 16        //
 17        // Things we should consider adding:
 18        // * Dynamic table encoding:
 19        //   This would make the encoder stateful, which complicates things significantly.
 20        //   Additionally, it's not clear exactly what strings we would add to the dynamic table
 21        //   without some additional guidance from the user about this.
 22        //   So for now, don't do dynamic encoding.
 23
 24        /// <summary>Encodes an "Indexed Header Field".</summary>
 25        public static bool EncodeIndexedHeaderField(int index, Span<byte> destination, out int bytesWritten)
 026        {
 27            // From https://tools.ietf.org/html/rfc7541#section-6.1
 28            // ----------------------------------------------------
 29            //   0   1   2   3   4   5   6   7
 30            // +---+---+---+---+---+---+---+---+
 31            // | 1 |        Index (7+)         |
 32            // +---+---------------------------+
 33
 034            if (destination.Length != 0)
 035            {
 036                destination[0] = 0x80;
 037                return IntegerEncoder.Encode(index, 7, destination, out bytesWritten);
 38            }
 39
 040            bytesWritten = 0;
 041            return false;
 042        }
 43
 44        /// <summary>Encodes the status code of a response to the :status field.</summary>
 45        public static bool EncodeStatusHeader(int statusCode, Span<byte> destination, out int bytesWritten)
 46        {
 47            // Bytes written depend on whether the status code value maps directly to an index
 48            if (H2StaticTable.TryGetStatusIndex(statusCode, out var index))
 49            {
 50                // Status codes which exist in the HTTP/2 StaticTable.
 51                return EncodeIndexedHeaderField(index, destination, out bytesWritten);
 52            }
 53            else
 54            {
 55                // If the status code doesn't have a static index then we need to include the full value.
 56                // Write a status index and then the number bytes as a string literal.
 57                if (!EncodeLiteralHeaderFieldWithoutIndexing(H2StaticTable.Status200, destination, out var nameLength))
 58                {
 59                    bytesWritten = 0;
 60                    return false;
 61                }
 62
 63                var statusBytes = StatusCodes.ToStatusBytes(statusCode);
 64
 65                if (!EncodeStringLiteral(statusBytes, destination.Slice(nameLength), out var valueLength))
 66                {
 67                    bytesWritten = 0;
 68                    return false;
 69                }
 70
 71                bytesWritten = nameLength + valueLength;
 72                return true;
 73            }
 74        }
 75
 76        /// <summary>Encodes a "Literal Header Field without Indexing".</summary>
 77        public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, string value, Encoding? valueEncoding, Spa
 078        {
 79            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 80            // ------------------------------------------------------
 81            //   0   1   2   3   4   5   6   7
 82            // +---+---+---+---+---+---+---+---+
 83            // | 0 | 0 | 0 | 0 |  Index (4+)   |
 84            // +---+---+-----------------------+
 85            // | H |     Value Length (7+)     |
 86            // +---+---------------------------+
 87            // | Value String (Length octets)  |
 88            // +-------------------------------+
 89
 090            if ((uint)destination.Length >= 2)
 091            {
 092                destination[0] = 0;
 093                if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
 094                {
 095                    Debug.Assert(indexLength >= 1);
 096                    if (EncodeStringLiteral(value, valueEncoding, destination.Slice(indexLength), out int nameLength))
 097                    {
 098                        bytesWritten = indexLength + nameLength;
 099                        return true;
 100                    }
 0101                }
 0102            }
 103
 0104            bytesWritten = 0;
 0105            return false;
 0106        }
 107
 108        /// <summary>Encodes a "Literal Header Field never Indexing".</summary>
 109        public static bool EncodeLiteralHeaderFieldNeverIndexing(int index, string value, Encoding? valueEncoding, Span<
 110        {
 111            // From https://tools.ietf.org/html/rfc7541#section-6.2.3
 112            // ------------------------------------------------------
 113            //   0   1   2   3   4   5   6   7
 114            // +---+---+---+---+---+---+---+---+
 115            // | 0 | 0 | 0 | 1 |  Index (4+)   |
 116            // +---+---+-----------------------+
 117            // | H |     Value Length (7+)     |
 118            // +---+---------------------------+
 119            // | Value String (Length octets)  |
 120            // +-------------------------------+
 121
 122            if ((uint)destination.Length >= 2)
 123            {
 124                destination[0] = 0x10;
 125                if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
 126                {
 127                    Debug.Assert(indexLength >= 1);
 128                    if (EncodeStringLiteral(value, valueEncoding, destination.Slice(indexLength), out int nameLength))
 129                    {
 130                        bytesWritten = indexLength + nameLength;
 131                        return true;
 132                    }
 133                }
 134            }
 135
 136            bytesWritten = 0;
 137            return false;
 138        }
 139
 140        /// <summary>Encodes a "Literal Header Field with Indexing".</summary>
 141        public static bool EncodeLiteralHeaderFieldIndexing(int index, string value, Encoding? valueEncoding, Span<byte>
 142        {
 143            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 144            // ------------------------------------------------------
 145            //   0   1   2   3   4   5   6   7
 146            // +---+---+---+---+---+---+---+---+
 147            // | 0 | 1 |      Index (6+)       |
 148            // +---+---+-----------------------+
 149            // | H |     Value Length (7+)     |
 150            // +---+---------------------------+
 151            // | Value String (Length octets)  |
 152            // +-------------------------------+
 153
 154            if ((uint)destination.Length >= 2)
 155            {
 156                destination[0] = 0x40;
 157                if (IntegerEncoder.Encode(index, 6, destination, out int indexLength))
 158                {
 159                    Debug.Assert(indexLength >= 1);
 160                    if (EncodeStringLiteral(value, valueEncoding, destination.Slice(indexLength), out int nameLength))
 161                    {
 162                        bytesWritten = indexLength + nameLength;
 163                        return true;
 164                    }
 165                }
 166            }
 167
 168            bytesWritten = 0;
 169            return false;
 170        }
 171
 172        /// <summary>
 173        /// Encodes a "Literal Header Field without Indexing", but only the index portion;
 174        /// a subsequent call to <c>EncodeStringLiteral</c> must be used to encode the associated value.
 175        /// </summary>
 176        public static bool EncodeLiteralHeaderFieldWithoutIndexing(int index, Span<byte> destination, out int bytesWritt
 48177        {
 178            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 179            // ------------------------------------------------------
 180            //   0   1   2   3   4   5   6   7
 181            // +---+---+---+---+---+---+---+---+
 182            // | 0 | 0 | 0 | 0 |  Index (4+)   |
 183            // +---+---+-----------------------+
 184            //
 185            // ... expected after this:
 186            //
 187            // | H |     Value Length (7+)     |
 188            // +---+---------------------------+
 189            // | Value String (Length octets)  |
 190            // +-------------------------------+
 191
 48192            if ((uint)destination.Length != 0)
 48193            {
 48194                destination[0] = 0;
 48195                if (IntegerEncoder.Encode(index, 4, destination, out int indexLength))
 48196                {
 48197                    Debug.Assert(indexLength >= 1);
 48198                    bytesWritten = indexLength;
 48199                    return true;
 200                }
 0201            }
 202
 0203            bytesWritten = 0;
 0204            return false;
 48205        }
 206
 207        /// <summary>Encodes a "Literal Header Field with Indexing - New Name".</summary>
 208        public static bool EncodeLiteralHeaderFieldIndexingNewName(string name, string value, Encoding? valueEncoding, S
 209        {
 210            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 211            // ------------------------------------------------------
 212            //   0   1   2   3   4   5   6   7
 213            // +---+---+---+---+---+---+---+---+
 214            // | 0 | 1 |           0           |
 215            // +---+---+-----------------------+
 216            // | H |     Name Length (7+)      |
 217            // +---+---------------------------+
 218            // |  Name String (Length octets)  |
 219            // +---+---------------------------+
 220            // | H |     Value Length (7+)     |
 221            // +---+---------------------------+
 222            // | Value String (Length octets)  |
 223            // +-------------------------------+
 224
 225            return EncodeLiteralHeaderNewNameCore(0x40, name, value, valueEncoding, destination, out bytesWritten);
 226        }
 227
 228        /// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
 229        public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, string value, Encoding? valueEnco
 230        {
 231            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 232            // ------------------------------------------------------
 233            //   0   1   2   3   4   5   6   7
 234            // +---+---+---+---+---+---+---+---+
 235            // | 0 | 0 | 0 | 0 |       0       |
 236            // +---+---+-----------------------+
 237            // | H |     Name Length (7+)      |
 238            // +---+---------------------------+
 239            // |  Name String (Length octets)  |
 240            // +---+---------------------------+
 241            // | H |     Value Length (7+)     |
 242            // +---+---------------------------+
 243            // | Value String (Length octets)  |
 244            // +-------------------------------+
 245
 246            return EncodeLiteralHeaderNewNameCore(0, name, value, valueEncoding, destination, out bytesWritten);
 247        }
 248
 249        /// <summary>Encodes a "Literal Header Field never Indexing - New Name".</summary>
 250        public static bool EncodeLiteralHeaderFieldNeverIndexingNewName(string name, string value, Encoding? valueEncodi
 251        {
 252            // From https://tools.ietf.org/html/rfc7541#section-6.2.3
 253            // ------------------------------------------------------
 254            //   0   1   2   3   4   5   6   7
 255            // +---+---+---+---+---+---+---+---+
 256            // | 0 | 0 | 0 | 1 |       0       |
 257            // +---+---+-----------------------+
 258            // | H |     Name Length (7+)      |
 259            // +---+---------------------------+
 260            // |  Name String (Length octets)  |
 261            // +---+---------------------------+
 262            // | H |     Value Length (7+)     |
 263            // +---+---------------------------+
 264            // | Value String (Length octets)  |
 265            // +-------------------------------+
 266
 267            return EncodeLiteralHeaderNewNameCore(0x10, name, value, valueEncoding, destination, out bytesWritten);
 268        }
 269
 270        private static bool EncodeLiteralHeaderNewNameCore(byte mask, string name, string value, Encoding? valueEncoding
 271        {
 272            if ((uint)destination.Length >= 3)
 273            {
 274                destination[0] = mask;
 275                if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
 276                    EncodeStringLiteral(value, valueEncoding, destination.Slice(1 + nameLength), out int valueLength))
 277                {
 278                    bytesWritten = 1 + nameLength + valueLength;
 279                    return true;
 280                }
 281            }
 282
 283            bytesWritten = 0;
 284            return false;
 285        }
 286
 287        /// <summary>Encodes a "Literal Header Field without Indexing - New Name".</summary>
 288        public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, ReadOnlySpan<string> values, byte
 0289        {
 290            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 291            // ------------------------------------------------------
 292            //   0   1   2   3   4   5   6   7
 293            // +---+---+---+---+---+---+---+---+
 294            // | 0 | 0 | 0 | 0 |       0       |
 295            // +---+---+-----------------------+
 296            // | H |     Name Length (7+)      |
 297            // +---+---------------------------+
 298            // |  Name String (Length octets)  |
 299            // +---+---------------------------+
 300            // | H |     Value Length (7+)     |
 301            // +---+---------------------------+
 302            // | Value String (Length octets)  |
 303            // +-------------------------------+
 304
 0305            if ((uint)destination.Length >= 3)
 0306            {
 0307                destination[0] = 0;
 0308                if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength) &&
 0309                    EncodeStringLiterals(values, separator, valueEncoding, destination.Slice(1 + nameLength), out int va
 0310                {
 0311                    bytesWritten = 1 + nameLength + valueLength;
 0312                    return true;
 313                }
 0314            }
 315
 0316            bytesWritten = 0;
 0317            return false;
 0318        }
 319
 320        /// <summary>
 321        /// Encodes a "Literal Header Field without Indexing - New Name", but only the name portion;
 322        /// a subsequent call to <c>EncodeStringLiteral</c> must be used to encode the associated value.
 323        /// </summary>
 324        public static bool EncodeLiteralHeaderFieldWithoutIndexingNewName(string name, Span<byte> destination, out int b
 50325        {
 326            // From https://tools.ietf.org/html/rfc7541#section-6.2.2
 327            // ------------------------------------------------------
 328            //   0   1   2   3   4   5   6   7
 329            // +---+---+---+---+---+---+---+---+
 330            // | 0 | 0 | 0 | 0 |       0       |
 331            // +---+---+-----------------------+
 332            // | H |     Name Length (7+)      |
 333            // +---+---------------------------+
 334            // |  Name String (Length octets)  |
 335            // +---+---------------------------+
 336            //
 337            // ... expected after this:
 338            //
 339            // | H |     Value Length (7+)     |
 340            // +---+---------------------------+
 341            // | Value String (Length octets)  |
 342            // +-------------------------------+
 343
 50344            if ((uint)destination.Length >= 2)
 50345            {
 50346                destination[0] = 0;
 50347                if (EncodeLiteralHeaderName(name, destination.Slice(1), out int nameLength))
 50348                {
 50349                    bytesWritten = 1 + nameLength;
 50350                    return true;
 351                }
 0352            }
 353
 0354            bytesWritten = 0;
 0355            return false;
 50356        }
 357
 358        private static bool EncodeLiteralHeaderName(string value, Span<byte> destination, out int bytesWritten)
 50359        {
 360            // From https://tools.ietf.org/html/rfc7541#section-5.2
 361            // ------------------------------------------------------
 362            //   0   1   2   3   4   5   6   7
 363            // +---+---+---+---+---+---+---+---+
 364            // | H |    String Length (7+)     |
 365            // +---+---------------------------+
 366            // |  String Data (Length octets)  |
 367            // +-------------------------------+
 368
 50369            Debug.Assert(Ascii.IsValid(value));
 370
 50371            if (destination.Length != 0)
 50372            {
 50373                destination[0] = 0; // TODO: Use Huffman encoding
 50374                if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength))
 50375                {
 50376                    Debug.Assert(integerLength >= 1);
 377
 50378                    destination = destination.Slice(integerLength);
 50379                    if (value.Length <= destination.Length)
 50380                    {
 50381                        OperationStatus status = Ascii.ToLower(value, destination, out int valueBytesWritten);
 50382                        Debug.Assert(status == OperationStatus.Done);
 50383                        Debug.Assert(valueBytesWritten == value.Length);
 384
 50385                        bytesWritten = integerLength + value.Length;
 50386                        return true;
 387                    }
 0388                }
 0389            }
 390
 0391            bytesWritten = 0;
 0392            return false;
 50393        }
 394
 395        private static void EncodeValueStringPart(string value, Span<byte> destination)
 0396        {
 0397            Debug.Assert(destination.Length >= value.Length);
 398
 0399            OperationStatus status = Ascii.FromUtf16(value, destination, out int bytesWritten);
 400
 0401            if (status == OperationStatus.InvalidData)
 0402            {
 0403                throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
 404            }
 405
 0406            Debug.Assert(status == OperationStatus.Done);
 0407            Debug.Assert(bytesWritten == value.Length);
 0408        }
 409
 410        public static bool EncodeStringLiteral(ReadOnlySpan<byte> value, Span<byte> destination, out int bytesWritten)
 411        {
 412            // From https://tools.ietf.org/html/rfc7541#section-5.2
 413            // ------------------------------------------------------
 414            //   0   1   2   3   4   5   6   7
 415            // +---+---+---+---+---+---+---+---+
 416            // | H |    String Length (7+)     |
 417            // +---+---------------------------+
 418            // |  String Data (Length octets)  |
 419            // +-------------------------------+
 420
 421            if (destination.Length != 0)
 422            {
 423                destination[0] = 0; // TODO: Use Huffman encoding
 424                if (IntegerEncoder.Encode(value.Length, 7, destination, out int integerLength))
 425                {
 426                    Debug.Assert(integerLength >= 1);
 427
 428                    destination = destination.Slice(integerLength);
 429                    if (value.Length <= destination.Length)
 430                    {
 431                        // Note: No validation. Bytes should have already been validated.
 432                        value.CopyTo(destination);
 433
 434                        bytesWritten = integerLength + value.Length;
 435                        return true;
 436                    }
 437                }
 438            }
 439
 440            bytesWritten = 0;
 441            return false;
 442        }
 443
 444        public static bool EncodeStringLiteral(string value, Span<byte> destination, out int bytesWritten)
 445        {
 446            return EncodeStringLiteral(value, valueEncoding: null, destination, out bytesWritten);
 447        }
 448
 449        public static bool EncodeStringLiteral(string value, Encoding? valueEncoding, Span<byte> destination, out int by
 0450        {
 451            // From https://tools.ietf.org/html/rfc7541#section-5.2
 452            // ------------------------------------------------------
 453            //   0   1   2   3   4   5   6   7
 454            // +---+---+---+---+---+---+---+---+
 455            // | H |    String Length (7+)     |
 456            // +---+---------------------------+
 457            // |  String Data (Length octets)  |
 458            // +-------------------------------+
 459
 0460            if (destination.Length != 0)
 0461            {
 0462                destination[0] = 0; // TODO: Use Huffman encoding
 463
 0464                int encodedStringLength = valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1)
 0465                    ? value.Length
 0466                    : valueEncoding.GetByteCount(value);
 467
 0468                if (IntegerEncoder.Encode(encodedStringLength, 7, destination, out int integerLength))
 0469                {
 0470                    Debug.Assert(integerLength >= 1);
 0471                    destination = destination.Slice(integerLength);
 0472                    if (encodedStringLength <= destination.Length)
 0473                    {
 0474                        if (valueEncoding is null)
 0475                        {
 0476                            EncodeValueStringPart(value, destination);
 0477                        }
 478                        else
 0479                        {
 0480                            int written = valueEncoding.GetBytes(value, destination);
 0481                            Debug.Assert(written == encodedStringLength);
 0482                        }
 483
 0484                        bytesWritten = integerLength + encodedStringLength;
 0485                        return true;
 486                    }
 0487                }
 0488            }
 489
 0490            bytesWritten = 0;
 0491            return false;
 0492        }
 493
 494        public static bool EncodeDynamicTableSizeUpdate(int value, Span<byte> destination, out int bytesWritten)
 495        {
 496            // From https://tools.ietf.org/html/rfc7541#section-6.3
 497            // ----------------------------------------------------
 498            //   0   1   2   3   4   5   6   7
 499            // +---+---+---+---+---+---+---+---+
 500            // | 0 | 0 | 1 |   Max size (5+)   |
 501            // +---+---------------------------+
 502
 503            if (destination.Length != 0)
 504            {
 505                destination[0] = 0x20;
 506                return IntegerEncoder.Encode(value, 5, destination, out bytesWritten);
 507            }
 508
 509            bytesWritten = 0;
 510            return false;
 511        }
 512
 513        public static bool EncodeStringLiterals(ReadOnlySpan<string> values, byte[]? separator, Encoding? valueEncoding,
 0514        {
 0515            bytesWritten = 0;
 516
 0517            if (values.Length == 0)
 0518            {
 0519                return EncodeStringLiteral("", valueEncoding: null, destination, out bytesWritten);
 520            }
 0521            else if (values.Length == 1)
 0522            {
 0523                return EncodeStringLiteral(values[0], valueEncoding, destination, out bytesWritten);
 524            }
 525
 0526            if (destination.Length != 0)
 0527            {
 0528                Debug.Assert(separator != null);
 0529                Debug.Assert(Ascii.IsValid(separator));
 0530                int valueLength = checked((values.Length - 1) * separator.Length);
 531
 532                // Calculate length of all values.
 0533                if (valueEncoding is null || ReferenceEquals(valueEncoding, Encoding.Latin1))
 0534                {
 0535                    foreach (string part in values)
 0536                    {
 0537                        valueLength = checked(valueLength + part.Length);
 0538                    }
 0539                }
 540                else
 0541                {
 0542                    foreach (string part in values)
 0543                    {
 0544                        valueLength = checked(valueLength + valueEncoding.GetByteCount(part));
 0545                    }
 0546                }
 547
 0548                destination[0] = 0;
 0549                if (IntegerEncoder.Encode(valueLength, 7, destination, out int integerLength))
 0550                {
 0551                    Debug.Assert(integerLength >= 1);
 0552                    destination = destination.Slice(integerLength);
 0553                    if (destination.Length >= valueLength)
 0554                    {
 0555                        if (valueEncoding is null)
 0556                        {
 0557                            string value = values[0];
 0558                            EncodeValueStringPart(value, destination);
 0559                            destination = destination.Slice(value.Length);
 560
 0561                            for (int i = 1; i < values.Length; i++)
 0562                            {
 0563                                separator.CopyTo(destination);
 0564                                destination = destination.Slice(separator.Length);
 565
 0566                                value = values[i];
 0567                                EncodeValueStringPart(value, destination);
 0568                                destination = destination.Slice(value.Length);
 0569                            }
 0570                        }
 571                        else
 0572                        {
 0573                            int written = valueEncoding.GetBytes(values[0], destination);
 0574                            destination = destination.Slice(written);
 575
 0576                            for (int i = 1; i < values.Length; i++)
 0577                            {
 0578                                separator.CopyTo(destination);
 0579                                destination = destination.Slice(separator.Length);
 580
 0581                                written = valueEncoding.GetBytes(values[i], destination);
 0582                                destination = destination.Slice(written);
 0583                            }
 0584                        }
 585
 0586                        bytesWritten = integerLength + valueLength;
 0587                        return true;
 588                    }
 0589                }
 0590            }
 591
 0592            return false;
 0593        }
 594
 595        /// <summary>
 596        /// Encodes a "Literal Header Field without Indexing" to a new array, but only the index portion;
 597        /// a subsequent call to <c>EncodeStringLiteral</c> must be used to encode the associated value.
 598        /// </summary>
 599        public static byte[] EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(int index)
 48600        {
 48601            Span<byte> span = stackalloc byte[256];
 48602            bool success = EncodeLiteralHeaderFieldWithoutIndexing(index, span, out int length);
 48603            Debug.Assert(success, $"Stack-allocated space was too small for index '{index}'.");
 48604            return span.Slice(0, length).ToArray();
 48605        }
 606
 607        /// <summary>
 608        /// Encodes a "Literal Header Field without Indexing - New Name" to a new array, but only the name portion;
 609        /// a subsequent call to <c>EncodeStringLiteral</c> must be used to encode the associated value.
 610        /// </summary>
 611        public static byte[] EncodeLiteralHeaderFieldWithoutIndexingNewNameToAllocatedArray(string name)
 50612        {
 50613            Span<byte> span = stackalloc byte[256];
 50614            bool success = EncodeLiteralHeaderFieldWithoutIndexingNewName(name, span, out int length);
 50615            Debug.Assert(success, $"Stack-allocated space was too small for \"{name}\".");
 50616            return span.Slice(0, length).ToArray();
 50617        }
 618
 619        /// <summary>Encodes a "Literal Header Field without Indexing" to a new array.</summary>
 620        public static byte[] EncodeLiteralHeaderFieldWithoutIndexingToAllocatedArray(int index, string value)
 0621        {
 0622            Span<byte> span =
 0623#if DEBUG
 0624                stackalloc byte[4]; // to validate growth algorithm
 625#else
 626                stackalloc byte[512];
 627#endif
 0628            while (true)
 0629            {
 0630                if (EncodeLiteralHeaderFieldWithoutIndexing(index, value, valueEncoding: null, span, out int length))
 0631                {
 0632                    return span.Slice(0, length).ToArray();
 633                }
 634
 635                // This is a rare path, only used once per HTTP/2 connection and only
 636                // for very long host names.  Just allocate rather than complicate
 637                // the code with ArrayPool usage.  In practice we should never hit this,
 638                // as hostnames should be <= 255 characters.
 0639                span = new byte[span.Length * 2];
 0640            }
 0641        }
 642    }
 643}