Пример #1
0
    public void BeginEncodeHeaders_CacheControlPrivate_NewIndexValue()
    {
        Span <byte> buffer = new byte[1024 * 16];

        var headers = (IHeaderDictionary) new HttpResponseHeaders();

        headers.CacheControl = "private";

        var enumerator = new Http2HeadersEnumerator();

        enumerator.Initialize(headers);

        var hpackEncoder = new DynamicHPackEncoder();

        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(302, hpackEncoder, enumerator, buffer, out var length));

        var result = buffer.Slice(5, length - 5).ToArray();
        var hex    = BitConverter.ToString(result);

        Assert.Equal("58-07-70-72-69-76-61-74-65", hex);

        var statusHeader = GetHeaderEntry(hpackEncoder, 0);

        Assert.Equal("Cache-Control", statusHeader.Name);
        Assert.Equal("private", statusHeader.Value);
    }
Пример #2
0
    public void BeginEncodeHeaders_MaxHeaderTableSizeUpdated_SizeUpdateInHeaders()
    {
        Span <byte> buffer = new byte[1024 * 16];

        var hpackEncoder = new DynamicHPackEncoder();

        hpackEncoder.UpdateMaxHeaderTableSize(100);

        var enumerator = new Http2HeadersEnumerator();

        // First request
        enumerator.Initialize(new Dictionary <string, StringValues>());
        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(hpackEncoder, enumerator, buffer, out var length));

        Assert.Equal(2, length);

        const byte DynamicTableSizeUpdateMask = 0xe0;

        var integerDecoder = new IntegerDecoder();

        Assert.False(integerDecoder.BeginTryDecode((byte)(buffer[0] & ~DynamicTableSizeUpdateMask), prefixLength: 5, out _));
        Assert.True(integerDecoder.TryDecode(buffer[1], out var result));

        Assert.Equal(100, result);

        // Second request
        enumerator.Initialize(new Dictionary <string, StringValues>());
        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(hpackEncoder, enumerator, buffer, out length));

        Assert.Equal(0, length);
    }
Пример #3
0
    public void BeginEncodeHeaders_ExcludedHeaders_NotAddedToTable(string headerName, bool neverIndex)
    {
        Span <byte> buffer = new byte[1024 * 16];

        var headers = new HttpResponseHeaders();

        headers.Append(headerName, "1");

        var enumerator = new Http2HeadersEnumerator();

        enumerator.Initialize(headers);

        var hpackEncoder = new DynamicHPackEncoder(maxHeaderTableSize: Http2PeerSettings.DefaultHeaderTableSize);

        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(hpackEncoder, enumerator, buffer, out _));

        if (neverIndex)
        {
            Assert.Equal(0x10, buffer[0] & 0x10);
        }
        else
        {
            Assert.Equal(0, buffer[0] & 0x40);
        }

        Assert.Empty(GetHeaderEntries(hpackEncoder));
    }
        public void Initialize_ChangeHeadersSource_EnumeratorUsesNewSource()
        {
            var responseHeaders = new HttpResponseHeaders();

            responseHeaders.Append("Name1", "Value1");
            responseHeaders.Append("Name2", "Value2-1");
            responseHeaders.Append("Name2", "Value2-2");

            var e = new Http2HeadersEnumerator();

            e.Initialize(responseHeaders);

            Assert.True(e.MoveNext());
            Assert.Equal("Name1", e.Current.Key);
            Assert.Equal("Value1", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.True(e.MoveNext());
            Assert.Equal("Name2", e.Current.Key);
            Assert.Equal("Value2-1", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.True(e.MoveNext());
            Assert.Equal("Name2", e.Current.Key);
            Assert.Equal("Value2-2", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            var responseTrailers = new HttpResponseTrailers
            {
                HeaderGrpcStatus = "1"
            };

            responseTrailers.Append("Name1", "Value1");
            responseTrailers.Append("Name2", "Value2-1");
            responseTrailers.Append("Name2", "Value2-2");

            e.Initialize(responseTrailers);

            Assert.True(e.MoveNext());
            Assert.Equal("Grpc-Status", e.Current.Key);
            Assert.Equal("1", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.True(e.MoveNext());
            Assert.Equal("Name1", e.Current.Key);
            Assert.Equal("Value1", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.True(e.MoveNext());
            Assert.Equal("Name2", e.Current.Key);
            Assert.Equal("Value2-1", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.True(e.MoveNext());
            Assert.Equal("Name2", e.Current.Key);
            Assert.Equal("Value2-2", e.Current.Value);
            Assert.Equal(-1, e.HPackStaticTableId);

            Assert.False(e.MoveNext());
        }
Пример #5
0
        public void CanIterateOverResponseTrailers()
        {
            var responseTrailers = new HttpResponseTrailers
            {
                ContentLength = 9,
                HeaderETag    = "ETag!"
            };

            responseTrailers.Append("Name1", "Value1");
            responseTrailers.Append("Name2", "Value2-1");
            responseTrailers.Append("Name2", "Value2-2");
            responseTrailers.Append("Name3", "Value3");

            var e = new Http2HeadersEnumerator();

            e.Initialize(responseTrailers);

            var headers = GetNormalizedHeaders(e);

            Assert.Equal(new[]
            {
                new KeyValuePair <string, string>("ETag", "ETag!"),
                new KeyValuePair <string, string>("Name1", "Value1"),
                new KeyValuePair <string, string>("Name2", "Value2-1"),
                new KeyValuePair <string, string>("Name2", "Value2-2"),
                new KeyValuePair <string, string>("Name3", "Value3"),
            }, headers);
        }
        public void CanIterateOverResponseTrailers()
        {
            var responseTrailers = new HttpResponseTrailers
            {
                ContentLength = 9,
                HeaderETag    = "ETag!"
            };

            responseTrailers.Append("Name1", "Value1");
            responseTrailers.Append("Name2", "Value2-1");
            responseTrailers.Append("Name2", "Value2-2");
            responseTrailers.Append("Name3", "Value3");

            var e = new Http2HeadersEnumerator();

            e.Initialize(responseTrailers);

            var headers = GetNormalizedHeaders(e);

            Assert.Equal(new[]
            {
                CreateHeaderResult(H2StaticTable.ETag, "ETag", "ETag!"),
                CreateHeaderResult(-1, "Name1", "Value1"),
                CreateHeaderResult(-1, "Name2", "Value2-1"),
                CreateHeaderResult(-1, "Name2", "Value2-2"),
                CreateHeaderResult(-1, "Name3", "Value3"),
            }, headers);
        }
Пример #7
0
        public void GlobalSetup()
        {
            _knownSingleValueResponseHeaders = new HttpResponseHeaders
            {
                HeaderServer      = "Value",
                HeaderDate        = "Value",
                HeaderContentType = "Value",
                HeaderSetCookie   = "Value"
            };

            _knownMultipleValueResponseHeaders = new HttpResponseHeaders
            {
                HeaderServer      = new StringValues(new[] { "One", "Two" }),
                HeaderDate        = new StringValues(new[] { "One", "Two" }),
                HeaderContentType = new StringValues(new[] { "One", "Two" }),
                HeaderSetCookie   = new StringValues(new[] { "One", "Two" })
            };

            _unknownSingleValueResponseHeaders = new HttpResponseHeaders();
            _unknownSingleValueResponseHeaders.Append("One", "Value");
            _unknownSingleValueResponseHeaders.Append("Two", "Value");
            _unknownSingleValueResponseHeaders.Append("Three", "Value");
            _unknownSingleValueResponseHeaders.Append("Four", "Value");

            _unknownMultipleValueResponseHeaders = new HttpResponseHeaders();
            _unknownMultipleValueResponseHeaders.Append("One", new StringValues(new[] { "One", "Two" }));
            _unknownMultipleValueResponseHeaders.Append("Two", new StringValues(new[] { "One", "Two" }));
            _unknownMultipleValueResponseHeaders.Append("Three", new StringValues(new[] { "One", "Two" }));
            _unknownMultipleValueResponseHeaders.Append("Four", new StringValues(new[] { "One", "Two" }));

            _enumerator = new Http2HeadersEnumerator();
        }
Пример #8
0
        public void CanIterateOverResponseHeaders()
        {
            var responseHeaders = new HttpResponseHeaders
            {
                ContentLength      = 9,
                HeaderAcceptRanges = "AcceptRanges!",
                HeaderAge          = new StringValues(new[] { "1", "2" }),
                HeaderDate         = "Date!"
            };

            responseHeaders.Append("Name1", "Value1");
            responseHeaders.Append("Name2", "Value2-1");
            responseHeaders.Append("Name2", "Value2-2");
            responseHeaders.Append("Name3", "Value3");

            var e = new Http2HeadersEnumerator();

            e.Initialize(responseHeaders);

            var headers = GetNormalizedHeaders(e);

            Assert.Equal(new[]
            {
                new KeyValuePair <string, string>("Date", "Date!"),
                new KeyValuePair <string, string>("Accept-Ranges", "AcceptRanges!"),
                new KeyValuePair <string, string>("Age", "1"),
                new KeyValuePair <string, string>("Age", "2"),
                new KeyValuePair <string, string>("Content-Length", "9"),
                new KeyValuePair <string, string>("Name1", "Value1"),
                new KeyValuePair <string, string>("Name2", "Value2-1"),
                new KeyValuePair <string, string>("Name2", "Value2-2"),
                new KeyValuePair <string, string>("Name3", "Value3"),
            }, headers);
        }
        public void CanIterateOverResponseHeaders()
        {
            var responseHeaders = (IHeaderDictionary) new HttpResponseHeaders();

            responseHeaders.ContentLength = 9;
            responseHeaders.AcceptRanges  = "AcceptRanges!";
            responseHeaders.Age           = new StringValues(new[] { "1", "2" });
            responseHeaders.Date          = "Date!";
            responseHeaders.GrpcEncoding  = "Identity!";

            responseHeaders.Append("Name1", "Value1");
            responseHeaders.Append("Name2", "Value2-1");
            responseHeaders.Append("Name2", "Value2-2");
            responseHeaders.Append("Name3", "Value3");

            var e = new Http2HeadersEnumerator();

            e.Initialize(responseHeaders);

            var headers = GetNormalizedHeaders(e);

            Assert.Equal(new[]
            {
                CreateHeaderResult(H2StaticTable.Date, "Date", "Date!"),
                CreateHeaderResult(H2StaticTable.AcceptRanges, "Accept-Ranges", "AcceptRanges!"),
                CreateHeaderResult(H2StaticTable.Age, "Age", "1"),
                CreateHeaderResult(H2StaticTable.Age, "Age", "2"),
                CreateHeaderResult(-1, "Grpc-Encoding", "Identity!"),
                CreateHeaderResult(H2StaticTable.ContentLength, "Content-Length", "9"),
                CreateHeaderResult(-1, "Name1", "Value1"),
                CreateHeaderResult(-1, "Name2", "Value2-1"),
                CreateHeaderResult(-1, "Name2", "Value2-2"),
                CreateHeaderResult(-1, "Name3", "Value3"),
            }, headers);
        }
Пример #10
0
    public void GlobalSetup()
    {
        _http2HeadersEnumerator = new Http2HeadersEnumerator();
        _hpackEncoder           = new DynamicHPackEncoder();
        _buffer = new byte[1024 * 1024];

        _knownResponseHeaders = new HttpResponseHeaders();

        var knownHeaders = (IHeaderDictionary)_knownResponseHeaders;

        knownHeaders.Server           = "Kestrel";
        knownHeaders.ContentType      = "application/json";
        knownHeaders.Date             = "Date!";
        knownHeaders.ContentLength    = 0;
        knownHeaders.AcceptRanges     = "Ranges!";
        knownHeaders.TransferEncoding = "Encoding!";
        knownHeaders.Via             = "Via!";
        knownHeaders.Vary            = "Vary!";
        knownHeaders.WWWAuthenticate = "Authenticate!";
        knownHeaders.LastModified    = "Modified!";
        knownHeaders.Expires         = "Expires!";
        knownHeaders.Age             = "Age!";

        _unknownResponseHeaders = new HttpResponseHeaders();
        for (var i = 0; i < 10; i++)
        {
            _unknownResponseHeaders.Append("Unknown" + i, "Value" + i);
        }
    }
        public void GlobalSetup()
        {
            _http2HeadersEnumerator = new Http2HeadersEnumerator();
            _hpackEncoder           = new HPackEncoder();
            _buffer = new byte[1024 * 1024];

            _knownResponseHeaders = new HttpResponseHeaders
            {
                HeaderServer           = "Kestrel",
                HeaderContentType      = "application/json",
                HeaderDate             = "Date!",
                HeaderContentLength    = "0",
                HeaderAcceptRanges     = "Ranges!",
                HeaderTransferEncoding = "Encoding!",
                HeaderVia             = "Via!",
                HeaderVary            = "Vary!",
                HeaderWWWAuthenticate = "Authenticate!",
                HeaderLastModified    = "Modified!",
                HeaderExpires         = "Expires!",
                HeaderAge             = "Age!"
            };

            _unknownResponseHeaders = new HttpResponseHeaders();
            for (var i = 0; i < 10; i++)
            {
                _unknownResponseHeaders.Append("Unknown" + i, "Value" + i);
            }
        }
Пример #12
0
        private KeyValuePair <string, string>[] GetNormalizedHeaders(Http2HeadersEnumerator enumerator)
        {
            var headers = new List <KeyValuePair <string, string> >();

            while (enumerator.MoveNext())
            {
                headers.Add(enumerator.Current);
            }
            return(headers.ToArray());
        }
Пример #13
0
        private static Http2HeadersEnumerator GetHeadersEnumerator(IEnumerable <KeyValuePair <string, string> > headers)
        {
            var groupedHeaders = headers
                                 .GroupBy(k => k.Key)
                                 .ToDictionary(g => g.Key, g => new StringValues(g.Select(gg => gg.Value).ToArray()));

            var enumerator = new Http2HeadersEnumerator();

            enumerator.Initialize(groupedHeaders);
            return(enumerator);
        }
Пример #14
0
    public void BeginEncodeHeaders_HeaderExceedHeaderTableSize_NoIndexAndNoHeaderEntry()
    {
        Span <byte> buffer = new byte[1024 * 16];

        var headers = new HttpResponseHeaders();

        headers.Append("x-Custom", new string('!', (int)Http2PeerSettings.DefaultHeaderTableSize));

        var enumerator = new Http2HeadersEnumerator();

        enumerator.Initialize(headers);

        var hpackEncoder = new DynamicHPackEncoder();

        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(200, hpackEncoder, enumerator, buffer, out var length));

        Assert.Empty(GetHeaderEntries(hpackEncoder));
    }
Пример #15
0
    /// <summary>
    /// Begin encoding headers in the first HEADERS frame.
    /// </summary>
    public static bool BeginEncodeHeaders(DynamicHPackEncoder hpackEncoder, Http2HeadersEnumerator headersEnumerator, Span <byte> buffer, out int length)
    {
        length = 0;

        if (!hpackEncoder.EnsureDynamicTableSizeUpdate(buffer, out var sizeUpdateLength))
        {
            throw new HPackEncodingException(SR.net_http_hpack_encode_failure);
        }
        length += sizeUpdateLength;

        if (!headersEnumerator.MoveNext())
        {
            return(true);
        }

        var done = EncodeHeadersCore(hpackEncoder, headersEnumerator, buffer.Slice(length), throwIfNoneEncoded: true, out var headersLength);

        length += headersLength;
        return(done);
    }
Пример #16
0
    private static bool EncodeHeadersCore(DynamicHPackEncoder hpackEncoder, Http2HeadersEnumerator headersEnumerator, Span <byte> buffer, bool throwIfNoneEncoded, out int length)
    {
        var currentLength = 0;

        do
        {
            var staticTableId = headersEnumerator.HPackStaticTableId;
            var name          = headersEnumerator.Current.Key;
            var value         = headersEnumerator.Current.Value;
            var valueEncoding =
                ReferenceEquals(headersEnumerator.EncodingSelector, KestrelServerOptions.DefaultHeaderEncodingSelector)
                ? null : headersEnumerator.EncodingSelector(name);

            var hint = ResolveHeaderEncodingHint(staticTableId, name);

            if (!hpackEncoder.EncodeHeader(
                    buffer.Slice(currentLength),
                    staticTableId,
                    hint,
                    name,
                    value,
                    valueEncoding,
                    out var headerLength))
            {
                // If the header wasn't written, and no headers have been written, then the header is too large.
                // Throw an error to avoid an infinite loop of attempting to write large header.
                if (currentLength == 0 && throwIfNoneEncoded)
                {
                    throw new HPackEncodingException(SR.net_http_hpack_encode_failure);
                }

                length = currentLength;
                return(false);
            }

            currentLength += headerLength;
        }while (headersEnumerator.MoveNext());

        length = currentLength;
        return(true);
    }
        public static void WriteStartStream(this PipeWriter writer, int streamId, Http2HeadersEnumerator headers, HPackEncoder hpackEncoder, byte[] headerEncodingBuffer, bool endStream)
        {
            var frame = new Http2Frame();

            frame.PrepareHeaders(Http2HeadersFrameFlags.NONE, streamId);

            var buffer = headerEncodingBuffer.AsSpan();
            var done   = hpackEncoder.BeginEncode(headers, buffer, out var length);

            frame.PayloadLength = length;

            if (done)
            {
                frame.HeadersFlags = Http2HeadersFrameFlags.END_HEADERS;
            }

            if (endStream)
            {
                frame.HeadersFlags |= Http2HeadersFrameFlags.END_STREAM;
            }

            Http2FrameWriter.WriteHeader(frame, writer);
            writer.Write(buffer.Slice(0, length));

            while (!done)
            {
                frame.PrepareContinuation(Http2ContinuationFrameFlags.NONE, streamId);

                done = hpackEncoder.Encode(buffer, out length);
                frame.PayloadLength = length;

                if (done)
                {
                    frame.ContinuationFlags = Http2ContinuationFrameFlags.END_HEADERS;
                }

                Http2FrameWriter.WriteHeader(frame, writer);
                writer.Write(buffer.Slice(0, length));
            }
        }
Пример #18
0
    public void BeginEncodeHeaders_Status302_NewIndexValue()
    {
        Span <byte> buffer = new byte[1024 * 16];

        var headers    = new HttpResponseHeaders();
        var enumerator = new Http2HeadersEnumerator();

        enumerator.Initialize(headers);

        var hpackEncoder = new DynamicHPackEncoder();

        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(302, hpackEncoder, enumerator, buffer, out var length));

        var result = buffer.Slice(0, length).ToArray();
        var hex    = BitConverter.ToString(result);

        Assert.Equal("48-03-33-30-32", hex);

        var statusHeader = GetHeaderEntry(hpackEncoder, 0);

        Assert.Equal(":status", statusHeader.Name);
        Assert.Equal("302", statusHeader.Value);
    }
Пример #19
0
 /// <summary>
 /// Continue encoding headers in the next HEADERS frame. The enumerator should already have a current value.
 /// </summary>
 public static bool ContinueEncodeHeaders(DynamicHPackEncoder hpackEncoder, Http2HeadersEnumerator headersEnumerator, Span <byte> buffer, out int length)
 {
     return(EncodeHeadersCore(hpackEncoder, headersEnumerator, buffer, throwIfNoneEncoded: true, out length));
 }
Пример #20
0
    /// <summary>
    /// Begin encoding headers in the first HEADERS frame.
    /// </summary>
    public static bool BeginEncodeHeaders(int statusCode, DynamicHPackEncoder hpackEncoder, Http2HeadersEnumerator headersEnumerator, Span <byte> buffer, out int length)
    {
        length = 0;

        if (!hpackEncoder.EnsureDynamicTableSizeUpdate(buffer, out var sizeUpdateLength))
        {
            throw new HPackEncodingException(SR.net_http_hpack_encode_failure);
        }
        length += sizeUpdateLength;

        if (!EncodeStatusHeader(statusCode, hpackEncoder, buffer.Slice(length), out var statusCodeLength))
        {
            throw new HPackEncodingException(SR.net_http_hpack_encode_failure);
        }
        length += statusCodeLength;

        if (!headersEnumerator.MoveNext())
        {
            return(true);
        }

        // We're ok with not throwing if no headers were encoded because we've already encoded the status.
        // There is a small chance that the header will encode if there is no other content in the next HEADERS frame.
        var done = EncodeHeadersCore(hpackEncoder, headersEnumerator, buffer.Slice(length), throwIfNoneEncoded: false, out var headersLength);

        length += headersLength;
        return(done);
    }
Пример #21
0
    public void BeginEncodeHeaders_MaxHeaderTableSizeExceeded_EvictionsToFit()
    {
        // Test follows example https://tools.ietf.org/html/rfc7541#appendix-C.5

        Span <byte> buffer = new byte[1024 * 16];

        var headers = (IHeaderDictionary) new HttpResponseHeaders();

        headers.CacheControl = "private";
        headers.Date         = "Mon, 21 Oct 2013 20:13:21 GMT";
        headers.Location     = "https://www.example.com";

        var enumerator = new Http2HeadersEnumerator();

        var hpackEncoder = new DynamicHPackEncoder(maxHeaderTableSize: 256);

        // First response
        enumerator.Initialize(headers);
        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(302, hpackEncoder, enumerator, buffer, out var length));

        var result = buffer.Slice(0, length).ToArray();
        var hex    = BitConverter.ToString(result);

        Assert.Equal(
            "48-03-33-30-32-61-1D-4D-6F-6E-2C-20-32-31-20-4F-" +
            "63-74-20-32-30-31-33-20-32-30-3A-31-33-3A-32-31-" +
            "20-47-4D-54-58-07-70-72-69-76-61-74-65-6E-17-68-" +
            "74-74-70-73-3A-2F-2F-77-77-77-2E-65-78-61-6D-70-" +
            "6C-65-2E-63-6F-6D", hex);

        var entries = GetHeaderEntries(hpackEncoder);

        Assert.Collection(entries,
                          e =>
        {
            Assert.Equal("Location", e.Name);
            Assert.Equal("https://www.example.com", e.Value);
            Assert.Equal(63u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Cache-Control", e.Name);
            Assert.Equal("private", e.Value);
            Assert.Equal(52u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Date", e.Name);
            Assert.Equal("Mon, 21 Oct 2013 20:13:21 GMT", e.Value);
            Assert.Equal(65u, e.Size);
        },
                          e =>
        {
            Assert.Equal(":status", e.Name);
            Assert.Equal("302", e.Value);
            Assert.Equal(42u, e.Size);
        });

        Assert.Equal(222u, hpackEncoder.TableSize);

        // Second response
        enumerator.Initialize(headers);
        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(307, hpackEncoder, enumerator, buffer, out length));

        result = buffer.Slice(0, length).ToArray();
        hex    = BitConverter.ToString(result);
        Assert.Equal("48-03-33-30-37-C1-C0-BF", hex);

        entries = GetHeaderEntries(hpackEncoder);
        Assert.Collection(entries,
                          e =>
        {
            Assert.Equal(":status", e.Name);
            Assert.Equal("307", e.Value);
            Assert.Equal(42u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Location", e.Name);
            Assert.Equal("https://www.example.com", e.Value);
            Assert.Equal(63u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Cache-Control", e.Name);
            Assert.Equal("private", e.Value);
            Assert.Equal(52u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Date", e.Name);
            Assert.Equal("Mon, 21 Oct 2013 20:13:21 GMT", e.Value);
            Assert.Equal(65u, e.Size);
        });

        Assert.Equal(222u, hpackEncoder.TableSize);

        // Third response
        headers.Date            = "Mon, 21 Oct 2013 20:13:22 GMT";
        headers.ContentEncoding = "gzip";
        headers.SetCookie       = "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1";

        enumerator.Initialize(headers);
        Assert.True(HPackHeaderWriter.BeginEncodeHeaders(200, hpackEncoder, enumerator, buffer, out length));

        result = buffer.Slice(0, length).ToArray();
        hex    = BitConverter.ToString(result);
        Assert.Equal(
            "88-61-1D-4D-6F-6E-2C-20-32-31-20-4F-63-74-20-32-" +
            "30-31-33-20-32-30-3A-31-33-3A-32-32-20-47-4D-54-" +
            "C1-5A-04-67-7A-69-70-C1-1F-28-38-66-6F-6F-3D-41-" +
            "53-44-4A-4B-48-51-4B-42-5A-58-4F-51-57-45-4F-50-" +
            "49-55-41-58-51-57-45-4F-49-55-3B-20-6D-61-78-2D-" +
            "61-67-65-3D-33-36-30-30-3B-20-76-65-72-73-69-6F-" +
            "6E-3D-31", hex);

        entries = GetHeaderEntries(hpackEncoder);
        Assert.Collection(entries,
                          e =>
        {
            Assert.Equal("Content-Encoding", e.Name);
            Assert.Equal("gzip", e.Value);
            Assert.Equal(52u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Date", e.Name);
            Assert.Equal("Mon, 21 Oct 2013 20:13:22 GMT", e.Value);
            Assert.Equal(65u, e.Size);
        },
                          e =>
        {
            Assert.Equal(":status", e.Name);
            Assert.Equal("307", e.Value);
            Assert.Equal(42u, e.Size);
        },
                          e =>
        {
            Assert.Equal("Location", e.Name);
            Assert.Equal("https://www.example.com", e.Value);
            Assert.Equal(63u, e.Size);
        });

        Assert.Equal(222u, hpackEncoder.TableSize);
    }