From 2a96d433ecb542b0109da562ffacc040c7bac38d Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 14 May 2016 18:25:20 +0900 Subject: [PATCH] Add nghttp2_hd_inflate_hd2() and deprecate nghttp2_hd_inflate_hd() The difference between them are former has const qualifier to the |in| parameter, which is desirable since it is effectively read-only. --- doc/Makefile.am | 1 + lib/includes/nghttp2/nghttp2.h | 88 +++++++++++++++++++++++++++++++++- lib/nghttp2_hd.c | 38 +++++++++------ lib/nghttp2_hd.h | 6 +-- lib/nghttp2_session.c | 4 +- python/cnghttp2.pxd | 7 +-- python/nghttp2.pyx | 6 +-- tests/nghttp2_test_helper.c | 4 +- 8 files changed, 125 insertions(+), 29 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index d23a68a6..4e992625 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -47,6 +47,7 @@ APIDOCS= \ nghttp2_hd_inflate_get_num_table_entries.rst \ nghttp2_hd_inflate_get_table_entry.rst \ nghttp2_hd_inflate_hd.rst \ + nghttp2_hd_inflate_hd2.rst \ nghttp2_hd_inflate_new.rst \ nghttp2_hd_inflate_new2.rst \ nghttp2_http2_strerror.rst \ diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index c9609051..d14f32c2 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -4553,7 +4553,7 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater); * This function must not be called while header block is being * inflated. In other words, this function must be called after * initialization of |inflater|, but before calling - * `nghttp2_hd_inflate_hd()`, or after + * `nghttp2_hd_inflate_hd2()`, or after * `nghttp2_hd_inflate_end_headers()`. Otherwise, * `NGHTTP2_ERR_INVALID_STATE` was returned. * @@ -4594,6 +4594,10 @@ typedef enum { /** * @function * + * .. warning:: + * + * Deprecated. Use `nghttp2_hd_inflate_hd2()` instead. + * * Inflates name/value block stored in |in| with length |inlen|. This * function performs decompression. For each successful emission of * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in @@ -4673,6 +4677,88 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, int *inflate_flags, uint8_t *in, size_t inlen, int in_final); +/** + * @function + * + * Inflates name/value block stored in |in| with length |inlen|. This + * function performs decompression. For each successful emission of + * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + * |*inflate_flags| and name/value pair is assigned to the |nv_out| + * and the function returns. The caller must not free the members of + * |nv_out|. + * + * The |nv_out| may include pointers to the memory region in the |in|. + * The caller must retain the |in| while the |nv_out| is used. + * + * The application should call this function repeatedly until the + * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and + * return value is non-negative. This means the all input values are + * processed successfully. Then the application must call + * `nghttp2_hd_inflate_end_headers()` to prepare for the next header + * block input. + * + * The caller can feed complete compressed header block. It also can + * feed it in several chunks. The caller must set |in_final| to + * nonzero if the given input is the last block of the compressed + * header. + * + * This function returns the number of bytes processed if it succeeds, + * or one of the following negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + * :enum:`NGHTTP2_ERR_HEADER_COMP` + * Inflation process has failed. + * :enum:`NGHTTP2_ERR_BUFFER_ERROR` + * The header field name or value is too large. + * + * Example follows:: + * + * int inflate_header_block(nghttp2_hd_inflater *hd_inflater, + * uint8_t *in, size_t inlen, int final) + * { + * ssize_t rv; + * + * for(;;) { + * nghttp2_nv nv; + * int inflate_flags = 0; + * + * rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags, + * in, inlen, final); + * + * if(rv < 0) { + * fprintf(stderr, "inflate failed with error code %zd", rv); + * return -1; + * } + * + * in += rv; + * inlen -= rv; + * + * if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + * fwrite(nv.name, nv.namelen, 1, stderr); + * fprintf(stderr, ": "); + * fwrite(nv.value, nv.valuelen, 1, stderr); + * fprintf(stderr, "\n"); + * } + * if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) { + * nghttp2_hd_inflate_end_headers(hd_inflater); + * break; + * } + * if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && + * inlen == 0) { + * break; + * } + * } + * + * return 0; + * } + * + */ +NGHTTP2_EXTERN ssize_t +nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, + int *inflate_flags, const uint8_t *in, size_t inlen, + int in_final); + /** * @function * diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 2225b7d8..d8cfe24d 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -862,11 +862,11 @@ static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) { * of bytes processed, or returns -1, indicating decoding error. */ static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *final, - uint32_t initial, size_t shift, uint8_t *in, - uint8_t *last, size_t prefix) { + uint32_t initial, size_t shift, const uint8_t *in, + const uint8_t *last, size_t prefix) { uint32_t k = (uint8_t)((1 << prefix) - 1); uint32_t n = initial; - uint8_t *start = in; + const uint8_t *start = in; *shift_ptr = 0; *final = 0; @@ -1625,8 +1625,8 @@ static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater, * Integer decoding failed */ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin, - uint8_t *in, uint8_t *last, size_t prefix, - size_t maxlen) { + const uint8_t *in, const uint8_t *last, + size_t prefix, size_t maxlen) { ssize_t rv; uint32_t out; @@ -1667,8 +1667,8 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin, * Huffman decoding failed */ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, - nghttp2_buf *buf, uint8_t *in, - uint8_t *last) { + nghttp2_buf *buf, const uint8_t *in, + const uint8_t *last) { ssize_t readlen; int final = 0; if ((size_t)(last - in) >= inflater->left) { @@ -1699,7 +1699,7 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, * Header decompression failed */ static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf, - uint8_t *in, uint8_t *last) { + const uint8_t *in, const uint8_t *last) { size_t len = nghttp2_min((size_t)(last - in), inflater->left); buf->last = nghttp2_cpymem(buf->last, in, len); @@ -1822,11 +1822,18 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, int *inflate_flags, uint8_t *in, size_t inlen, int in_final) { + return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, in, inlen, + in_final); +} + +ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, + nghttp2_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, int in_final) { ssize_t rv; nghttp2_hd_nv hd_nv; - rv = nghttp2_hd_inflate_hd2(inflater, &hd_nv, inflate_flags, in, inlen, - in_final); + rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen, + in_final); if (rv < 0) { return rv; @@ -1845,12 +1852,13 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out, return rv; } -ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out, int *inflate_flags, - uint8_t *in, size_t inlen, int in_final) { +ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, + int in_final) { ssize_t rv = 0; - uint8_t *first = in; - uint8_t *last = in + inlen; + const uint8_t *first = in; + const uint8_t *last = in + inlen; int rfin = 0; int busy = 0; nghttp2_mem *mem; diff --git a/lib/nghttp2_hd.h b/lib/nghttp2_hd.h index b0e93852..1da9eb58 100644 --- a/lib/nghttp2_hd.h +++ b/lib/nghttp2_hd.h @@ -353,9 +353,9 @@ void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater); * that return values and semantics are the same as * nghttp2_hd_inflate_hd(). */ -ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_hd_nv *nv_out, int *inflate_flags, - uint8_t *in, size_t inlen, int in_final); +ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater, + nghttp2_hd_nv *nv_out, int *inflate_flags, + const uint8_t *in, size_t inlen, int in_final); /* For unittesting purpose */ int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index, diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 0f7fd853..b498d968 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3475,8 +3475,8 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, DEBUGF(fprintf(stderr, "recv: decoding header block %zu bytes\n", inlen)); for (;;) { inflate_flags = 0; - proclen = nghttp2_hd_inflate_hd2(&session->hd_inflater, &nv, &inflate_flags, - in, inlen, final); + proclen = nghttp2_hd_inflate_hd_nv(&session->hd_inflater, &nv, + &inflate_flags, in, inlen, final); if (nghttp2_is_fatal((int)proclen)) { return (int)proclen; } diff --git a/python/cnghttp2.pxd b/python/cnghttp2.pxd index 3c829f82..0d25fdb3 100644 --- a/python/cnghttp2.pxd +++ b/python/cnghttp2.pxd @@ -314,9 +314,10 @@ cdef extern from 'nghttp2/nghttp2.h': int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, size_t hd_table_bufsize_max) - ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *inflate_flags, - uint8_t *input, size_t inlen, int in_final) + ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, + nghttp2_nv *nv_out, int *inflate_flags, + const uint8_t *input, size_t inlen, + int in_final) int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) diff --git a/python/nghttp2.pyx b/python/nghttp2.pyx index 633cc337..5def868e 100644 --- a/python/nghttp2.pyx +++ b/python/nghttp2.pyx @@ -191,9 +191,9 @@ cdef class HDInflater: res = [] while True: inflate_flags = 0 - rv = cnghttp2.nghttp2_hd_inflate_hd(self._inflater, &nv, - &inflate_flags, - buf, buflen, 1) + rv = cnghttp2.nghttp2_hd_inflate_hd2(self._inflater, &nv, + &inflate_flags, + buf, buflen, 1) if rv < 0: raise Exception(_strerror(rv)) buf += rv diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index dcd4ddb8..8d48423f 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -178,8 +178,8 @@ ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out, for (;;) { inflate_flags = 0; - rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, bp.pos, - nghttp2_buf_len(&bp), final); + rv = nghttp2_hd_inflate_hd2(inflater, &nv, &inflate_flags, bp.pos, + nghttp2_buf_len(&bp), final); if (rv < 0) { return rv;