diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 1428ca7a..638c6458 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -325,6 +325,7 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, } deflater->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max; + deflater->min_hd_table_bufsize_max = UINT32_MAX; return 0; } @@ -917,6 +918,9 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, deflater->ctx.hd_table_bufsize_max = next_bufsize; + deflater->min_hd_table_bufsize_max = + nghttp2_min(deflater->min_hd_table_bufsize_max, next_bufsize); + deflater->notify_table_size_change = 1; hd_context_shrink_table_size(&deflater->ctx); @@ -1054,8 +1058,21 @@ int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, } if(deflater->notify_table_size_change) { + size_t min_hd_table_bufsize_max; + + min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max; deflater->notify_table_size_change = 0; + deflater->min_hd_table_bufsize_max = UINT32_MAX; + + if(deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) { + + rv = emit_table_size(bufs, min_hd_table_bufsize_max); + + if(rv != 0) { + goto fail; + } + } rv = emit_table_size(bufs, deflater->ctx.hd_table_bufsize_max); diff --git a/lib/nghttp2_hd.h b/lib/nghttp2_hd.h index c180d675..907701d8 100644 --- a/lib/nghttp2_hd.h +++ b/lib/nghttp2_hd.h @@ -120,6 +120,8 @@ struct nghttp2_hd_deflater { nghttp2_hd_context ctx; /* The upper limit of the header table size the deflater accepts. */ size_t deflate_hd_table_bufsize_max; + /* Minimum header table size notified in the next context update */ + size_t min_hd_table_bufsize_max; /* If nonzero, send header table size using encoding context update in the next deflate process */ uint8_t notify_table_size_change; diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index f6752095..485762d7 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -585,6 +585,7 @@ void test_nghttp2_hd_change_table_size(void) nghttp2_hd_inflater inflater; nghttp2_nv nva[] = { MAKE_NV("alpha", "bravo"), MAKE_NV("charlie", "delta") }; + nghttp2_nv nva2[] = { MAKE_NV(":path", "/") }; nghttp2_bufs bufs; ssize_t rv; nva_out out; @@ -796,6 +797,36 @@ void test_nghttp2_hd_change_table_size(void) nghttp2_hd_inflate_free(&inflater); nghttp2_hd_deflate_free(&deflater); + /* Check that context update emitted twice */ + nghttp2_hd_deflate_init2(&deflater, 4096); + nghttp2_hd_inflate_init(&inflater); + + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0)); + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 3000)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 0)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 3000)); + + CU_ASSERT(0 == deflater.min_hd_table_bufsize_max); + CU_ASSERT(3000 == deflater.ctx.hd_table_bufsize_max); + + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva2, 1); + blocklen = nghttp2_bufs_len(&bufs); + + CU_ASSERT(0 == rv); + CU_ASSERT(3 < blocklen); + CU_ASSERT(3000 == deflater.ctx.hd_table_bufsize_max); + CU_ASSERT(UINT32_MAX == deflater.min_hd_table_bufsize_max); + + CU_ASSERT(blocklen == inflate_hd(&inflater, &out, &bufs, 0)); + CU_ASSERT(3000 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(3000 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + nghttp2_bufs_reset(&bufs); + + nghttp2_hd_inflate_free(&inflater); + nghttp2_hd_deflate_free(&deflater); + nghttp2_bufs_free(&bufs); }