diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:32:08 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:32:08 +0000 |
commit | 328ad0a41c6bdf596224ff2e9ab9c0fabde8634d (patch) | |
tree | 973585a56cea8664b4be63b5bb737b443e4e2b76 /tests/nghttp3_qpack_test.c | |
parent | Initial commit. (diff) | |
download | nghttp3-328ad0a41c6bdf596224ff2e9ab9c0fabde8634d.tar.xz nghttp3-328ad0a41c6bdf596224ff2e9ab9c0fabde8634d.zip |
Adding upstream version 0.8.0.upstream/0.8.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/nghttp3_qpack_test.c')
-rw-r--r-- | tests/nghttp3_qpack_test.c | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/tests/nghttp3_qpack_test.c b/tests/nghttp3_qpack_test.c new file mode 100644 index 0000000..c8e1983 --- /dev/null +++ b/tests/nghttp3_qpack_test.c @@ -0,0 +1,779 @@ +/* + * nghttp3 + * + * Copyright (c) 2019 nghttp3 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nghttp3_qpack_test.h" + +#include <stdlib.h> + +#include <CUnit/CUnit.h> + +#include "nghttp3_qpack.h" +#include "nghttp3_macro.h" +#include "nghttp3_test_helper.h" + +static void check_decode_header(nghttp3_qpack_decoder *dec, nghttp3_buf *pbuf, + nghttp3_buf *rbuf, nghttp3_buf *ebuf, + int64_t stream_id, const nghttp3_nv *nva, + size_t nvlen, const nghttp3_mem *mem) { + nghttp3_ssize nread; + nghttp3_qpack_stream_context sctx; + nghttp3_qpack_nv qnv; + const nghttp3_nv *nv; + uint8_t flags; + size_t i = 0; + + nread = + nghttp3_qpack_decoder_read_encoder(dec, ebuf->pos, nghttp3_buf_len(ebuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(ebuf) == nread); + + nghttp3_qpack_stream_context_init(&sctx, stream_id, mem); + + nread = nghttp3_qpack_decoder_read_request( + dec, &sctx, &qnv, &flags, pbuf->pos, nghttp3_buf_len(pbuf), 0); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(pbuf) == nread); + + for (; nghttp3_buf_len(rbuf);) { + nread = nghttp3_qpack_decoder_read_request( + dec, &sctx, &qnv, &flags, rbuf->pos, nghttp3_buf_len(rbuf), 1); + + CU_ASSERT(nread > 0); + + if (nread < 0) { + break; + } + + rbuf->pos += nread; + + if (flags & NGHTTP3_QPACK_DECODE_FLAG_FINAL) { + break; + } + if (flags & NGHTTP3_QPACK_DECODE_FLAG_EMIT) { + nv = &nva[i++]; + CU_ASSERT(nv->namelen == qnv.name->len); + CU_ASSERT(0 == memcmp(nv->name, qnv.name->base, nv->namelen)); + CU_ASSERT(nv->valuelen == qnv.value->len); + CU_ASSERT(0 == memcmp(nv->value, qnv.value->base, nv->valuelen)); + + nghttp3_rcbuf_decref(qnv.name); + nghttp3_rcbuf_decref(qnv.value); + } + } + + CU_ASSERT(i == nvlen); + + nghttp3_qpack_stream_context_free(&sctx); + nghttp3_buf_reset(pbuf); + nghttp3_buf_reset(rbuf); + nghttp3_buf_reset(ebuf); +} + +static void decode_header_block(nghttp3_qpack_decoder *dec, nghttp3_buf *pbuf, + nghttp3_buf *rbuf, int64_t stream_id, + const nghttp3_mem *mem) { + nghttp3_ssize nread; + nghttp3_qpack_stream_context sctx; + nghttp3_qpack_nv qnv; + uint8_t flags; + + nghttp3_qpack_stream_context_init(&sctx, stream_id, mem); + + nread = nghttp3_qpack_decoder_read_request( + dec, &sctx, &qnv, &flags, pbuf->pos, nghttp3_buf_len(pbuf), 0); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(pbuf) == nread); + + for (;;) { + nread = nghttp3_qpack_decoder_read_request( + dec, &sctx, &qnv, &flags, rbuf->pos, nghttp3_buf_len(rbuf), 1); + + CU_ASSERT(nread >= 0); + + if (nread < 0) { + break; + } + + if (flags & NGHTTP3_QPACK_DECODE_FLAG_FINAL) { + CU_ASSERT(nread == 0); + CU_ASSERT(!(flags & NGHTTP3_QPACK_DECODE_FLAG_EMIT)); + CU_ASSERT(0 == nghttp3_buf_len(rbuf)); + CU_ASSERT(nghttp3_buf_len(&dec->dbuf) > 0); + + break; + } + + CU_ASSERT(nread > 0); + CU_ASSERT(flags & NGHTTP3_QPACK_DECODE_FLAG_EMIT); + + nghttp3_rcbuf_decref(qnv.name); + nghttp3_rcbuf_decref(qnv.value); + + rbuf->pos += nread; + } + + nghttp3_qpack_stream_context_free(&sctx); +} + +void test_nghttp3_qpack_encoder_encode(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_encoder enc; + nghttp3_qpack_decoder dec; + nghttp3_nv nva[] = { + MAKE_NV(":path", "/rsrc.php/v3/yn/r/rIPZ9Qkrdd9.png"), + MAKE_NV(":authority", "static.xx.fbcdn.net"), + MAKE_NV(":scheme", "https"), + MAKE_NV(":method", "GET"), + MAKE_NV("accept-encoding", "gzip, deflate, br"), + MAKE_NV("accept-language", "en-US,en;q=0.9"), + MAKE_NV( + "user-agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36(KHTML, " + "like Gecko) Chrome/63.0.3239.70 Safari/537.36"), + MAKE_NV("accept", "image/webp,image/apng,image/*,*/*;q=0.8"), + MAKE_NV("referer", "https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/" + "dzXGESIlGQQ.css"), + }; + int rv; + nghttp3_buf pbuf, rbuf, ebuf; + nghttp3_qpack_stream *stream; + nghttp3_qpack_header_block_ref *ref; + + nghttp3_buf_init(&pbuf); + nghttp3_buf_init(&rbuf); + nghttp3_buf_init(&ebuf); + rv = nghttp3_qpack_encoder_init(&enc, 4096, mem); + + CU_ASSERT(0 == rv); + + nghttp3_qpack_encoder_set_max_blocked_streams(&enc, 1); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 4096); + + rv = nghttp3_qpack_decoder_init(&dec, 4096, 1, mem); + + CU_ASSERT(0 == rv); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 0, nva, + nghttp3_arraylen(nva)); + + CU_ASSERT(0 == rv); + + stream = nghttp3_qpack_encoder_find_stream(&enc, 0); + + CU_ASSERT(NULL != stream); + CU_ASSERT(nghttp3_qpack_encoder_stream_is_blocked(&enc, stream)); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + ref = + *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0); + + CU_ASSERT(5 == ref->max_cnt); + CU_ASSERT(1 == ref->min_cnt); + CU_ASSERT(5 == nghttp3_qpack_stream_get_max_cnt(stream)); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_min_cnt(&enc)); + CU_ASSERT(2 == nghttp3_buf_len(&pbuf)); + + check_decode_header(&dec, &pbuf, &rbuf, &ebuf, 0, nva, nghttp3_arraylen(nva), + mem); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 4, nva, + nghttp3_arraylen(nva)); + + CU_ASSERT(0 == rv); + + stream = nghttp3_qpack_encoder_find_stream(&enc, 4); + + CU_ASSERT(NULL == stream); + + check_decode_header(&dec, &pbuf, &rbuf, &ebuf, 4, nva, nghttp3_arraylen(nva), + mem); + + nghttp3_qpack_encoder_ack_header(&enc, 0); + + CU_ASSERT(5 == enc.krcnt); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 8, nva, + nghttp3_arraylen(nva)); + + CU_ASSERT(0 == rv); + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + check_decode_header(&dec, &pbuf, &rbuf, &ebuf, 8, nva, nghttp3_arraylen(nva), + mem); + + nghttp3_qpack_decoder_free(&dec); + nghttp3_qpack_encoder_free(&enc); + nghttp3_buf_free(&ebuf, mem); + nghttp3_buf_free(&rbuf, mem); + nghttp3_buf_free(&pbuf, mem); +} + +void test_nghttp3_qpack_encoder_still_blocked(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_encoder enc; + nghttp3_nv nva1[] = { + MAKE_NV(":status", "103"), + MAKE_NV("link", "foo"), + }; + nghttp3_nv nva2[] = { + MAKE_NV(":status", "200"), + MAKE_NV("content-type", "text/foo"), + }; + int rv; + nghttp3_buf pbuf, rbuf, ebuf; + nghttp3_qpack_stream *stream; + nghttp3_qpack_header_block_ref *ref; + + nghttp3_buf_init(&pbuf); + nghttp3_buf_init(&rbuf); + nghttp3_buf_init(&ebuf); + rv = nghttp3_qpack_encoder_init(&enc, 4096, mem); + + CU_ASSERT(0 == rv); + + nghttp3_qpack_encoder_set_max_blocked_streams(&enc, 1); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 4096); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 0, nva1, + nghttp3_arraylen(nva1)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 0, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + stream = nghttp3_qpack_encoder_find_stream(&enc, 0); + + ref = + *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0); + + CU_ASSERT(nghttp3_ringbuf_len(&stream->refs) > 1); + CU_ASSERT(ref->max_cnt != nghttp3_qpack_stream_get_max_cnt(stream)); + + ref = + *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 1); + + CU_ASSERT(ref->max_cnt == nghttp3_qpack_stream_get_max_cnt(stream)); + + nghttp3_qpack_encoder_ack_header(&enc, 0); + + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + stream = nghttp3_qpack_encoder_find_stream(&enc, 0); + + ref = + *(nghttp3_qpack_header_block_ref **)nghttp3_ringbuf_get(&stream->refs, 0); + + CU_ASSERT(1 == nghttp3_ringbuf_len(&stream->refs)); + CU_ASSERT(ref->max_cnt == nghttp3_qpack_stream_get_max_cnt(stream)); + + nghttp3_qpack_encoder_ack_header(&enc, 0); + + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + CU_ASSERT(NULL == nghttp3_qpack_encoder_find_stream(&enc, 0)); + + nghttp3_qpack_encoder_free(&enc); + nghttp3_buf_free(&ebuf, mem); + nghttp3_buf_free(&rbuf, mem); + nghttp3_buf_free(&pbuf, mem); +} + +void test_nghttp3_qpack_encoder_set_dtable_cap(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_encoder enc; + nghttp3_qpack_decoder dec; + nghttp3_buf pbuf, rbuf, ebuf; + const nghttp3_nv nva1[] = { + MAKE_NV(":path", "/"), + MAKE_NV("date", "bar1"), + }; + const nghttp3_nv nva2[] = { + MAKE_NV(":path", "/"), + MAKE_NV("vary", "bar2"), + }; + int rv; + nghttp3_ssize nread; + + nghttp3_buf_init(&pbuf); + nghttp3_buf_init(&rbuf); + nghttp3_buf_init(&ebuf); + + rv = nghttp3_qpack_encoder_init(&enc, 4096, mem); + + CU_ASSERT(0 == rv); + + nghttp3_qpack_encoder_set_max_blocked_streams(&enc, 3); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 4096); + + rv = nghttp3_qpack_decoder_init(&dec, 4096, 3, mem); + + CU_ASSERT(0 == rv); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 0, nva1, + nghttp3_arraylen(nva1)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == enc.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + enc.ctx.dtable_size); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(1 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(4096 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 0, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 4, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD + + strlen("vary") + strlen("bar2") + + NGHTTP3_QPACK_ENTRY_OVERHEAD == + enc.ctx.dtable_size); + CU_ASSERT(2 == enc.ctx.next_absidx); + CU_ASSERT(2 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(2 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD + + strlen("vary") + strlen("bar2") + + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(4096 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 4, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 0); + + CU_ASSERT(0 == enc.ctx.max_dtable_capacity); + CU_ASSERT(2 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + /* Cannot index more headers because we set max_dtable_capacity to + 0. */ + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 8, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(0 == enc.ctx.max_dtable_capacity); + CU_ASSERT(2 == enc.ctx.next_absidx); + CU_ASSERT(2 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(2 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD + + strlen("vary") + strlen("bar2") + + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(4096 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 8, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + /* Acking stream 0 will evict first entry */ + nghttp3_qpack_encoder_ack_header(&enc, 0); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 12, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(strlen("vary") + strlen("bar2") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + enc.ctx.dtable_size); + CU_ASSERT(0 == enc.ctx.max_dtable_capacity); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + /* decoder still has 2 entries because encoder does not emit Set + Dynamic Table Capacity. */ + CU_ASSERT(2 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD + + strlen("vary") + strlen("bar2") + + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(4096 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 12, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + /* Acking stream 4 will evict another entry */ + nghttp3_qpack_encoder_ack_header(&enc, 4); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 16, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(0 == enc.ctx.dtable_size); + CU_ASSERT(0 == enc.ctx.max_dtable_capacity); + CU_ASSERT(0 == enc.last_max_dtable_update); + CU_ASSERT(SIZE_MAX == enc.min_dtable_update); + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(2 == dec.ctx.next_absidx); + CU_ASSERT(0 == dec.ctx.dtable_size); + CU_ASSERT(0 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 16, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + nghttp3_qpack_decoder_free(&dec); + nghttp3_qpack_encoder_free(&enc); + + /* Check that minimum size is emitted */ + nghttp3_qpack_encoder_init(&enc, 4096, mem); + nghttp3_qpack_encoder_set_max_blocked_streams(&enc, 1); + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 4096); + nghttp3_qpack_decoder_init(&dec, 4096, 1, mem); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 0, nva1, + nghttp3_arraylen(nva1)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == enc.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + enc.ctx.dtable_size); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(1 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(4096 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 0, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 0); + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 1024); + + CU_ASSERT(0 == enc.min_dtable_update); + CU_ASSERT(1024 == enc.last_max_dtable_update); + + nghttp3_qpack_encoder_ack_header(&enc, 0); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf, &rbuf, &ebuf, 4, nva1, + nghttp3_arraylen(nva1)); + + CU_ASSERT(0 == rv); + CU_ASSERT(2 == enc.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + enc.ctx.dtable_size); + CU_ASSERT(SIZE_MAX == enc.min_dtable_update); + CU_ASSERT(1024 == enc.last_max_dtable_update); + CU_ASSERT(1024 == enc.ctx.max_dtable_capacity); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT(nread == (nghttp3_ssize)nghttp3_buf_len(&ebuf)); + CU_ASSERT(2 == dec.ctx.next_absidx); + CU_ASSERT(strlen("date") + strlen("bar1") + NGHTTP3_QPACK_ENTRY_OVERHEAD == + dec.ctx.dtable_size); + CU_ASSERT(1024 == dec.ctx.max_dtable_capacity); + + decode_header_block(&dec, &pbuf, &rbuf, 4, mem); + nghttp3_buf_reset(&pbuf); + nghttp3_buf_reset(&rbuf); + nghttp3_buf_reset(&ebuf); + + nghttp3_qpack_decoder_free(&dec); + nghttp3_qpack_encoder_free(&enc); + nghttp3_buf_free(&ebuf, mem); + nghttp3_buf_free(&rbuf, mem); + nghttp3_buf_free(&pbuf, mem); +} + +void test_nghttp3_qpack_decoder_feedback(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_encoder enc; + nghttp3_qpack_decoder dec; + nghttp3_buf pbuf1, rbuf1, pbuf2, rbuf2, pbuf3, rbuf3, ebuf, dbuf; + const nghttp3_nv nva1[] = { + MAKE_NV(":path", "/"), + MAKE_NV("date", "bar1"), + }; + const nghttp3_nv nva2[] = { + MAKE_NV(":path", "/"), + MAKE_NV("vary", "bar2"), + }; + const nghttp3_nv nva3[] = { + MAKE_NV(":path", "/"), + MAKE_NV("link", "bar3"), + }; + int rv; + nghttp3_ssize nread; + + nghttp3_buf_init(&pbuf1); + nghttp3_buf_init(&rbuf1); + nghttp3_buf_init(&pbuf2); + nghttp3_buf_init(&rbuf2); + nghttp3_buf_init(&pbuf3); + nghttp3_buf_init(&rbuf3); + nghttp3_buf_init(&ebuf); + nghttp3_buf_init(&dbuf); + + nghttp3_buf_reserve(&dbuf, 4096, mem); + + rv = nghttp3_qpack_encoder_init(&enc, 4096, mem); + + CU_ASSERT(0 == rv); + + nghttp3_qpack_encoder_set_max_blocked_streams(&enc, 2); + + nghttp3_qpack_encoder_set_max_dtable_capacity(&enc, 4096); + + rv = nghttp3_qpack_decoder_init(&dec, 4096, 2, mem); + + CU_ASSERT(0 == rv); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf1, &rbuf1, &ebuf, 0, nva1, + nghttp3_arraylen(nva1)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf2, &rbuf2, &ebuf, 4, nva2, + nghttp3_arraylen(nva2)); + + CU_ASSERT(0 == rv); + CU_ASSERT(2 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&ebuf) == nread); + + /* Process stream 4 first */ + decode_header_block(&dec, &pbuf2, &rbuf2, 4, mem); + + CU_ASSERT(2 == dec.written_icnt); + + nghttp3_qpack_decoder_write_decoder(&dec, &dbuf); + + nread = nghttp3_qpack_encoder_read_decoder(&enc, dbuf.pos, + nghttp3_buf_len(&dbuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&dbuf) == nread); + /* This will unblock all streams because higher insert count is + acknowledged. */ + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + CU_ASSERT(1 == nghttp3_map_size(&enc.streams)); + CU_ASSERT(1 == nghttp3_pq_size(&enc.min_cnts)); + CU_ASSERT(0 == nghttp3_ksl_len(&enc.blocked_streams)); + CU_ASSERT(2 == enc.krcnt); + + /* Process stream 0 */ + decode_header_block(&dec, &pbuf1, &rbuf1, 0, mem); + nghttp3_buf_reset(&dbuf); + nghttp3_qpack_decoder_write_decoder(&dec, &dbuf); + + nread = nghttp3_qpack_encoder_read_decoder(&enc, dbuf.pos, + nghttp3_buf_len(&dbuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&dbuf) == nread); + CU_ASSERT(0 == nghttp3_map_size(&enc.streams)); + CU_ASSERT(0 == nghttp3_pq_size(&enc.min_cnts)); + CU_ASSERT(2 == enc.krcnt); + + /* Encode another header, and then read encoder stream only. Write + decoder stream. */ + nghttp3_buf_reset(&ebuf); + rv = nghttp3_qpack_encoder_encode(&enc, &pbuf3, &rbuf3, &ebuf, 8, nva3, + nghttp3_arraylen(nva3)); + + CU_ASSERT(0 == rv); + CU_ASSERT(1 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + + nread = nghttp3_qpack_decoder_read_encoder(&dec, ebuf.pos, + nghttp3_buf_len(&ebuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&ebuf) == nread); + + nghttp3_buf_reset(&dbuf); + nghttp3_qpack_decoder_write_decoder(&dec, &dbuf); + + CU_ASSERT(nghttp3_buf_len(&dbuf) > 0); + CU_ASSERT(3 == dec.written_icnt); + + nread = nghttp3_qpack_encoder_read_decoder(&enc, dbuf.pos, + nghttp3_buf_len(&dbuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&dbuf) == nread); + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + CU_ASSERT(1 == nghttp3_map_size(&enc.streams)); + CU_ASSERT(3 == enc.krcnt); + + /* Cancel stream 8 */ + rv = nghttp3_qpack_decoder_cancel_stream(&dec, 8); + + CU_ASSERT(0 == rv); + + nghttp3_buf_reset(&dbuf); + nghttp3_qpack_decoder_write_decoder(&dec, &dbuf); + + CU_ASSERT(nghttp3_buf_len(&dbuf) > 0); + + nread = nghttp3_qpack_encoder_read_decoder(&enc, dbuf.pos, + nghttp3_buf_len(&dbuf)); + + CU_ASSERT((nghttp3_ssize)nghttp3_buf_len(&dbuf) == nread); + CU_ASSERT(0 == nghttp3_qpack_encoder_get_num_blocked_streams(&enc)); + CU_ASSERT(0 == nghttp3_ksl_len(&enc.blocked_streams)); + CU_ASSERT(0 == nghttp3_pq_size(&enc.min_cnts)); + CU_ASSERT(0 == nghttp3_map_size(&enc.streams)); + + nghttp3_qpack_decoder_free(&dec); + nghttp3_qpack_encoder_free(&enc); + nghttp3_buf_free(&dbuf, mem); + nghttp3_buf_free(&ebuf, mem); + nghttp3_buf_free(&rbuf3, mem); + nghttp3_buf_free(&pbuf3, mem); + nghttp3_buf_free(&rbuf2, mem); + nghttp3_buf_free(&pbuf2, mem); + nghttp3_buf_free(&rbuf1, mem); + nghttp3_buf_free(&pbuf1, mem); +} + +void test_nghttp3_qpack_decoder_stream_overflow(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_decoder dec; + size_t i; + int rv; + + nghttp3_qpack_decoder_init(&dec, 4096, 0, mem); + + for (i = 0;; ++i) { + rv = nghttp3_qpack_decoder_cancel_stream(&dec, (int64_t)i); + if (rv == NGHTTP3_ERR_QPACK_FATAL) { + break; + } + } + + nghttp3_qpack_decoder_free(&dec); +} + +void test_nghttp3_qpack_huffman(void) { + size_t i, j; + uint8_t raw[100], ebuf[4096], dbuf[4096]; + uint8_t *end; + nghttp3_qpack_huffman_decode_context ctx; + nghttp3_ssize nwrite; + + srand(1000000007); + + for (i = 0; i < 100000; ++i) { + for (j = 0; j < sizeof(raw); ++j) { + raw[j] = (uint8_t)round(((double)rand() / RAND_MAX * 255)); + } + end = nghttp3_qpack_huffman_encode(ebuf, raw, sizeof(raw)); + + nghttp3_qpack_huffman_decode_context_init(&ctx); + nwrite = + nghttp3_qpack_huffman_decode(&ctx, dbuf, ebuf, (size_t)(end - ebuf), 1); + if (nwrite <= 0) { + CU_ASSERT(nwrite > 0); + continue; + } + CU_ASSERT((sizeof(raw) == (size_t)nwrite)); + CU_ASSERT(0 == memcmp(raw, dbuf, sizeof(raw))); + } +} + +void test_nghttp3_qpack_huffman_decode_failure_state(void) { + nghttp3_qpack_huffman_decode_context ctx; + const uint8_t data[] = {0xff, 0xff, 0xff, 0xff}; + uint8_t buf[4096]; + nghttp3_ssize nwrite; + + nghttp3_qpack_huffman_decode_context_init(&ctx); + nwrite = nghttp3_qpack_huffman_decode(&ctx, buf, data, sizeof(data) - 1, 0); + + CU_ASSERT(0 == nwrite); + CU_ASSERT(!nghttp3_qpack_huffman_decode_failure_state(&ctx)); + + nwrite = nghttp3_qpack_huffman_decode(&ctx, buf, data, 1, 0); + + CU_ASSERT(0 == nwrite); + CU_ASSERT(nghttp3_qpack_huffman_decode_failure_state(&ctx)); +} + +void test_nghttp3_qpack_decoder_reconstruct_ricnt(void) { + const nghttp3_mem *mem = nghttp3_mem_default(); + nghttp3_qpack_decoder dec; + uint64_t ricnt; + int rv; + + rv = nghttp3_qpack_decoder_init(&dec, 100, 1, mem); + + CU_ASSERT(0 == rv); + + dec.ctx.next_absidx = 10; + + rv = nghttp3_qpack_decoder_reconstruct_ricnt(&dec, &ricnt, 3); + + CU_ASSERT(0 == rv); + CU_ASSERT(8 == ricnt); + + nghttp3_qpack_decoder_free(&dec); +} |