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);
    }
        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());
        }
Example #3
0
        public void KnownSingleValueResponseHeaders()
        {
            _enumerator.Initialize(_knownSingleValueResponseHeaders);

            if (_enumerator.MoveNext())
            {
            }
        }
    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);
    }
    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 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);
        }
Example #7
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);
        }
Example #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);
        }
Example #10
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);
        }
    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));
    }
    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);
    }
    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);
    }
Example #14
0
 public void BeginEncodeHeaders_KnownHeaders()
 {
     _http2HeadersEnumerator.Initialize(_knownResponseHeaders);
     HPackHeaderWriter.BeginEncodeHeaders(_hpackEncoder, _http2HeadersEnumerator, _buffer, out _);
 }