From 7b9a8acc22c180ae625c52c7748ff058bbd31bc1 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 13 May 2014 23:42:55 +0900 Subject: [PATCH] Add HPACK deflation API --- lib/includes/nghttp2/nghttp2.h | 111 ++++++++++++++++++++++++++++++++ lib/nghttp2_buf.c | 31 +++++++++ lib/nghttp2_buf.h | 21 ++++++ lib/nghttp2_frame.c | 4 +- lib/nghttp2_hd.c | 87 ++++++++++++++++++++++++- lib/nghttp2_hd.h | 35 ++-------- python/cnghttp2.pxd | 17 +++-- python/nghttp2.pyx | 4 +- src/deflatehd.cc | 4 +- tests/failmalloc_test.c | 2 +- tests/main.c | 3 + tests/nghttp2_hd_test.c | 113 +++++++++++++++++++++++++++------ tests/nghttp2_hd_test.h | 2 + 13 files changed, 367 insertions(+), 67 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 1a2d63ae..7d8cb57e 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2716,6 +2716,117 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len); /* HPACK API */ +struct nghttp2_hd_deflater; + +/** + * @struct + * + * HPACK deflater object. + */ +typedef struct nghttp2_hd_deflater nghttp2_hd_deflater; + +/** + * @function + * + * Initializes |*deflater_ptr| for deflating name/values pairs. + * + * The |deflate_hd_table_bufsize_max| is the upper bound of header + * table size the deflater will use. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, + size_t deflate_hd_table_bufsize_max); + +/** + * @function + * + * Deallocates any resources allocated for |deflater|. + */ +void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Sets the availability of reference set in the |deflater|. If + * |no_refset| is nonzero, the deflater will first emit "Reference Set + * Emptying" in the each subsequent invocation of + * `nghttp2_hd_deflate_hd()` to clear up reference set. By default, + * the deflater uses reference set. + */ +void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, + uint8_t no_refset); + +/** + * @function + * + * Changes header table size of the |deflater| to + * |settings_hd_table_bufsize_max| bytes. This may trigger eviction + * in the dynamic table. + * + * The |settings_hd_table_bufsize_max| should be the value received in + * SETTINGS_HEADER_TABLE_SIZE. + * + * The deflater never uses more memory than + * ``deflate_hd_table_bufsize_max`` bytes specified in + * `nghttp2_hd_deflate_new()`. Therefore, if + * |settings_hd_table_bufsize_max| > ``deflate_hd_table_bufsize_max``, + * resulting maximum table size becomes + * ``deflate_hd_table_bufsize_max``. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t settings_hd_table_bufsize_max); + +/** + * @function + * + * Deflates the |nva|, which has the |nvlen| name/value pairs, into + * the |buf| of length |buflen|. + * + * If |buf| is not large enough to store the deflated header block, + * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The + * caller should use `nghttp2_hd_deflate_bound()` to know the upper + * bound of buffer size required to deflate given header name/value + * pairs. + * + * Once this function fails, subsequent call of this function always + * returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + * + * After this function returns, it is safe to delete the |nva|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Deflation process has failed. + * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * The provided |buflen| size is too small to hold the output. + */ +ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, + uint8_t *buf, size_t buflen, + nghttp2_nv *nva, size_t nvlen); + +/** + * @function + * + * Returns an upper bound on the compressed size after deflation of + * |nva| of length |nvlen|. + */ +size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, + const nghttp2_nv *nva, size_t nvlen); + struct nghttp2_hd_inflater; /** diff --git a/lib/nghttp2_buf.c b/lib/nghttp2_buf.c index 6de3c0b5..98ef493b 100644 --- a/lib/nghttp2_buf.c +++ b/lib/nghttp2_buf.c @@ -177,6 +177,37 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs) } } +int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len) +{ + nghttp2_buf_chain *chain; + + chain = malloc(sizeof(nghttp2_buf_chain)); + if(chain == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + chain->next = NULL; + + nghttp2_buf_wrap_init(&chain->buf, begin, len); + + bufs->offset = 0; + + bufs->head = chain; + bufs->cur = bufs->head; + + bufs->chunk_length = len; + bufs->chunk_used = 1; + bufs->max_chunk = 1; + bufs->chunk_keep = 1; + + return 0; +} + +void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) +{ + free(bufs->head); +} + void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) { nghttp2_buf_chain *ci; diff --git a/lib/nghttp2_buf.h b/lib/nghttp2_buf.h index dfc248ad..c43362c8 100644 --- a/lib/nghttp2_buf.h +++ b/lib/nghttp2_buf.h @@ -207,6 +207,27 @@ int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length, */ void nghttp2_bufs_free(nghttp2_bufs *bufs); +/* + * Initializes |bufs| using supplied buffer |begin| of length |len|. + * The first buffer bufs->head uses buffer |begin|. The buffer size + * is fixed and no allocate extra chunk buffer is allocated. In other + * words, max_chunk = chunk_keep = 1. To free the resource allocated + * for |bufs|, use nghttp2_bufs_wrap_free(). + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len); + +/* + * Frees any related resource to the |bufs|. This function does not + * free supplied buffer provided in nghttp2_bufs_wrap_init(). + */ +void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs); + /* * Appends the |data| of length |len| to the |bufs|. The write starts * at bufs->cur->buf.last. A new buffers will be allocated to store diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index ac2812e4..59f78115 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -364,7 +364,7 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, buf->last = buf->pos; /* This call will adjust buf->last to the correct position */ - rv = nghttp2_hd_deflate_hd(deflater, bufs, frame->nva, frame->nvlen); + rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); if(rv == NGHTTP2_ERR_BUFFER_ERROR) { rv = NGHTTP2_ERR_HEADER_COMP; @@ -595,7 +595,7 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, buf->last = buf->pos; /* This call will adjust buf->last to the correct position */ - rv = nghttp2_hd_deflate_hd(deflater, bufs, frame->nva, frame->nvlen); + rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); if(rv == NGHTTP2_ERR_BUFFER_ERROR) { rv = NGHTTP2_ERR_HEADER_COMP; diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 632942fa..b7bc1373 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -1203,9 +1203,9 @@ static int deflate_post_process_hd_entry(nghttp2_hd_entry *ent, return 0; } -int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, - nghttp2_bufs *bufs, - nghttp2_nv *nv, size_t nvlen) +int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, + nghttp2_bufs *bufs, + nghttp2_nv *nv, size_t nvlen) { size_t i; int rv = 0; @@ -1259,6 +1259,87 @@ int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, return rv; } +ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, + uint8_t *buf, size_t buflen, + nghttp2_nv *nv, size_t nvlen) +{ + nghttp2_bufs bufs; + int rv; + + rv = nghttp2_bufs_wrap_init(&bufs, buf, buflen); + + if(rv != 0) { + return rv; + } + + rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen); + + buflen = nghttp2_bufs_len(&bufs); + + nghttp2_bufs_wrap_free(&bufs); + + if(rv == NGHTTP2_ERR_BUFFER_ERROR) { + return NGHTTP2_ERR_INSUFF_BUFSIZE; + } + + if(rv != 0) { + return rv; + } + + return buflen; +} + +size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, + const nghttp2_nv *nva, size_t nvlen) +{ + size_t n; + size_t i; + + /* Possible Reference Set Emptying */ + n = 1; + + /* Possible Maximum Header Table Size Change. Encoding (1u << 31) - + 1 using 4 bit prefix requires 6 bytes. */ + n += 6; + + /* Use Literal Header Field without indexing - New Name, since it is + most space consuming format. Also we choose the less one between + non-huffman and huffman, so using literal byte count is + sufficient for upper bound. + + Encoding (1u << 31) - 1 using 7 bit prefix requires 6 bytes. We + need 2 of this for |nvlen| header fields. */ + n += 6 * 2 * nvlen; + + for(i = 0; i < nvlen; ++i) { + n += nva[i].namelen + nva[i].valuelen; + } + + /* Add possible reference set toggle off */ + n += deflater->ctx.hd_table.len; + + return n; +} + +int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr, + size_t deflate_hd_table_bufsize_max) +{ + *deflater_ptr = malloc(sizeof(nghttp2_hd_deflater)); + + if(*deflater_ptr == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + return nghttp2_hd_deflate_init2(*deflater_ptr, deflate_hd_table_bufsize_max); +} + +void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater) +{ + nghttp2_hd_deflate_free(deflater); + + free(deflater); +} + static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater, const uint8_t *in) { diff --git a/lib/nghttp2_hd.h b/lib/nghttp2_hd.h index 12337c50..d0087bca 100644 --- a/lib/nghttp2_hd.h +++ b/lib/nghttp2_hd.h @@ -132,7 +132,7 @@ typedef struct { uint8_t bad; } nghttp2_hd_context; -typedef struct { +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; @@ -142,7 +142,7 @@ typedef struct { /* If nonzero, send header table size using encoding context update in the next deflate process */ uint8_t notify_table_size_change; -} nghttp2_hd_deflater; +}; struct nghttp2_hd_inflater { nghttp2_hd_context ctx; @@ -240,31 +240,6 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, */ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater); -/* - * Sets the availability of reference set in the |deflater|. If - * |no_refset| is nonzero, the deflater will first emit index=0 in the - * each invocation of nghttp2_hd_deflate_hd() to clear up reference - * set. By default, the deflater uses reference set. - */ -void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, - uint8_t no_refset); - -/* - * Changes header table size of the |deflater|. This may trigger - * eviction in the dynamic table. - * - * The |settings_hd_table_bufsize_max| should be the value received in - * SETTINGS_HEADER_TABLE_SIZE. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, - size_t settings_hd_table_bufsize_max); - /* * Deflates the |nva|, which has the |nvlen| name/value pairs, into * the |bufs|. @@ -285,9 +260,9 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, * NGHTTP2_ERR_BUFFER_ERROR * Out of buffer space. */ -int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, - nghttp2_bufs *bufs, - nghttp2_nv *nva, size_t nvlen); +int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, + nghttp2_bufs *bufs, + nghttp2_nv *nva, size_t nvlen); /* * Initializes |inflater| for inflating name/values pairs. diff --git a/python/cnghttp2.pxd b/python/cnghttp2.pxd index 38a170d0..80559c8b 100644 --- a/python/cnghttp2.pxd +++ b/python/cnghttp2.pxd @@ -247,6 +247,11 @@ cdef extern from 'nghttp2/nghttp2.h': const char* nghttp2_strerror(int lib_error_code) + void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, + uint8_t no_refset) + + int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t hd_table_bufsize_max) int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, size_t hd_table_bufsize_max) @@ -302,15 +307,9 @@ cdef extern from 'nghttp2_hd.h': void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) - void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, - uint8_t no_refset) - - int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, - size_t hd_table_bufsize_max) - - int nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, - nghttp2_bufs *bufs, - nghttp2_nv *nva, size_t nvlen) + int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater, + nghttp2_bufs *bufs, + nghttp2_nv *nva, size_t nvlen) nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index) diff --git a/python/nghttp2.pyx b/python/nghttp2.pyx index b8672e8d..e061dfd0 100644 --- a/python/nghttp2.pyx +++ b/python/nghttp2.pyx @@ -122,8 +122,8 @@ cdef class HDDeflater: cnghttp2.nghttp2_bufs_init(&bufs, 4096, 16) - rv = cnghttp2.nghttp2_hd_deflate_hd(&self._deflater, &bufs, - nva, len(headers)) + rv = cnghttp2.nghttp2_hd_deflate_hd_bufs(&self._deflater, &bufs, + nva, len(headers)) free(nva) if rv < 0: diff --git a/src/deflatehd.cc b/src/deflatehd.cc index af5842ff..4f036d18 100644 --- a/src/deflatehd.cc +++ b/src/deflatehd.cc @@ -130,8 +130,8 @@ static void deflate_hd(nghttp2_hd_deflater *deflater, nghttp2_bufs_init2(&bufs, 4096, 16, 0); - rv = nghttp2_hd_deflate_hd(deflater, &bufs, - (nghttp2_nv*)nva.data(), nva.size()); + rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, + (nghttp2_nv*)nva.data(), nva.size()); if(rv < 0) { fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq); exit(EXIT_FAILURE); diff --git a/tests/failmalloc_test.c b/tests/failmalloc_test.c index cb12cfd0..5e22e9fe 100644 --- a/tests/failmalloc_test.c +++ b/tests/failmalloc_test.c @@ -453,7 +453,7 @@ static int deflate_inflate(nghttp2_hd_deflater *deflater, { int rv; - rv = nghttp2_hd_deflate_hd(deflater, bufs, nva, nvlen); + rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, nva, nvlen); if(rv != 0) { return rv; diff --git a/tests/main.c b/tests/main.c index b4afb9cc..8fce69ba 100644 --- a/tests/main.c +++ b/tests/main.c @@ -278,6 +278,9 @@ int main(int argc, char* argv[]) !CU_add_test(pSuite, "hd_deflate_inflate", test_nghttp2_hd_deflate_inflate) || !CU_add_test(pSuite, "hd_no_index", test_nghttp2_hd_no_index) || + !CU_add_test(pSuite, "hd_deflate_bound", + test_nghttp2_hd_deflate_bound) || + !CU_add_test(pSuite, "hd_public_api", test_nghttp2_hd_public_api) || !CU_add_test(pSuite, "adjust_local_window_size", test_nghttp2_adjust_local_window_size) || !CU_add_test(pSuite, "check_header_name", diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index 36ff165e..62ea279a 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -63,7 +63,7 @@ void test_nghttp2_hd_deflate(void) CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater)); CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater)); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva1, ARRLEN(nva1)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva1, ARRLEN(nva1)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -77,7 +77,7 @@ void test_nghttp2_hd_deflate(void) nghttp2_bufs_reset(&bufs); /* Second headers */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva2, ARRLEN(nva2)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva2, ARRLEN(nva2)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -92,7 +92,7 @@ void test_nghttp2_hd_deflate(void) /* Third headers, including same header field name, but value is not the same. */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva3, ARRLEN(nva3)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva3, ARRLEN(nva3)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -106,7 +106,7 @@ void test_nghttp2_hd_deflate(void) nghttp2_bufs_reset(&bufs); /* Fourth headers, including duplicate header fields. */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva4, ARRLEN(nva4)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva4, ARRLEN(nva4)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -120,7 +120,7 @@ void test_nghttp2_hd_deflate(void) nghttp2_bufs_reset(&bufs); /* Fifth headers includes empty value */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva5, ARRLEN(nva5)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva5, ARRLEN(nva5)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -161,7 +161,7 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void) /* Encode 2 same headers. cookie:alpha is not in the reference set, so first emit literal repr and then 2 emits of indexed repr. */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva1, ARRLEN(nva1)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva1, ARRLEN(nva1)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -176,7 +176,7 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void) /* Encode 3 same headers. This time, cookie:alpha is in the reference set, so the encoder emits indexed repr 6 times */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva2, ARRLEN(nva2)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva2, ARRLEN(nva2)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -225,7 +225,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void) /* First emit "h1: ..." to put it in the reference set (index = 0). */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 1); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 1); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -241,7 +241,7 @@ void test_nghttp2_hd_deflate_common_header_eviction(void) /* Encode with second header */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -290,7 +290,7 @@ void test_nghttp2_hd_deflate_clear_refset(void) nghttp2_hd_inflate_init(&inflater); for(i = 0; i < 2; ++i) { - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nv, ARRLEN(nv)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nv, ARRLEN(nv)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -671,7 +671,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); /* This will emit encoding context update with header table size 4096 */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -698,7 +698,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -727,7 +727,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -764,7 +764,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -790,7 +790,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max); CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -827,7 +827,7 @@ void test_nghttp2_hd_change_table_size(void) CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max); /* This emits context update with buffer size 1024 */ - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, 2); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, 2); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -860,7 +860,7 @@ static void check_deflate_inflate(nghttp2_hd_deflater *deflater, frame_pack_bufs_init(&bufs); nva_out_init(&out); - rv = nghttp2_hd_deflate_hd(deflater, &bufs, nva, nvlen); + rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nva, nvlen); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -1061,7 +1061,7 @@ void test_nghttp2_hd_no_index(void) nghttp2_hd_deflate_init(&deflater); nghttp2_hd_inflate_init(&inflater); - rv = nghttp2_hd_deflate_hd(&deflater, &bufs, nva, ARRLEN(nva)); + rv = nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, ARRLEN(nva)); blocklen = nghttp2_bufs_len(&bufs); CU_ASSERT(0 == rv); @@ -1082,3 +1082,80 @@ void test_nghttp2_hd_no_index(void) nghttp2_hd_inflate_free(&inflater); nghttp2_hd_deflate_free(&deflater); } + +void test_nghttp2_hd_deflate_bound(void) +{ + nghttp2_hd_deflater deflater; + nghttp2_nv nva[] = { + MAKE_NV(":method", "GET"), + MAKE_NV("alpha", "bravo") + }; + nghttp2_bufs bufs; + size_t bound, bound2; + + frame_pack_bufs_init(&bufs); + + nghttp2_hd_deflate_init(&deflater); + + bound = nghttp2_hd_deflate_bound(&deflater, nva, ARRLEN(nva)); + + CU_ASSERT(1 + 6 + 6 * 2 * 2 + + nva[0].namelen + nva[0].valuelen + + nva[1].namelen + nva[1].valuelen + == bound); + + nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, nva, ARRLEN(nva)); + + CU_ASSERT(bound > (size_t)nghttp2_bufs_len(&bufs)); + + bound2 = nghttp2_hd_deflate_bound(&deflater, nva, ARRLEN(nva)); + + CU_ASSERT(bound + 2 == bound2); + + nghttp2_bufs_free(&bufs); + nghttp2_hd_deflate_free(&deflater); +} + +void test_nghttp2_hd_public_api(void) +{ + nghttp2_hd_deflater *deflater; + nghttp2_hd_inflater *inflater; + nghttp2_nv nva[] = { + MAKE_NV("alpha", "bravo"), + MAKE_NV("charlie", "delta") + }; + uint8_t buf[4096]; + size_t buflen; + ssize_t blocklen; + nghttp2_bufs bufs; + + CU_ASSERT(0 == nghttp2_hd_deflate_new(&deflater, 4096)); + CU_ASSERT(0 == nghttp2_hd_inflate_new(&inflater)); + + buflen = nghttp2_hd_deflate_bound(deflater, nva, ARRLEN(nva)); + + blocklen = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, ARRLEN(nva)); + + CU_ASSERT(blocklen > 0); + + nghttp2_bufs_wrap_init(&bufs, buf, blocklen); + bufs.head->buf.last += blocklen; + + CU_ASSERT(blocklen == inflate_hd(inflater, NULL, &bufs, 0)); + + nghttp2_bufs_wrap_free(&bufs); + + nghttp2_hd_inflate_del(inflater); + nghttp2_hd_deflate_del(deflater); + + /* See NGHTTP2_ERR_INSUFF_BUFSIZE */ + CU_ASSERT(0 == nghttp2_hd_deflate_new(&deflater, 4096)); + + blocklen = nghttp2_hd_deflate_hd(deflater, buf, blocklen - 1, + nva, ARRLEN(nva)); + + CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == blocklen); + + nghttp2_hd_deflate_del(deflater); +} + diff --git a/tests/nghttp2_hd_test.h b/tests/nghttp2_hd_test.h index 5e089d57..237751ba 100644 --- a/tests/nghttp2_hd_test.h +++ b/tests/nghttp2_hd_test.h @@ -40,5 +40,7 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void); void test_nghttp2_hd_change_table_size(void); void test_nghttp2_hd_deflate_inflate(void); void test_nghttp2_hd_no_index(void); +void test_nghttp2_hd_deflate_bound(void); +void test_nghttp2_hd_public_api(void); #endif /* NGHTTP2_HD_TEST_H */