diff options
author | Alexis La Goutte <alexis.lagoutte@gmail.com> | 2016-05-26 23:05:33 +0200 |
---|---|---|
committer | Pascal Quantin <pascal.quantin@gmail.com> | 2016-05-31 07:18:25 +0000 |
commit | 68903e7b934ddeb909899ac7aa1249adfed69d8f (patch) | |
tree | 216c50d862b914929e787d49747504ad21fbcf7c /epan | |
parent | 7723ed6494498726feafe47858038d569cc82203 (diff) |
Update to nghttp2 1.11.1
Change-Id: I308b4db02b1501f38b2693b45b2b9bd6054376d1
Reviewed-on: https://code.wireshark.org/review/15579
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/nghttp2/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/nghttp2/Makefile.common | 4 | ||||
-rw-r--r-- | epan/nghttp2/README.nghttp2 | 1 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2.h | 345 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_buf.h | 6 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.c | 1030 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.h | 180 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd_huffman.c | 29 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_helper.c | 35 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_mem.c | 4 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_mem.h | 1 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_rcbuf.c | 99 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_rcbuf.h | 80 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2ver.h | 4 |
14 files changed, 889 insertions, 930 deletions
diff --git a/epan/nghttp2/CMakeLists.txt b/epan/nghttp2/CMakeLists.txt index f3f35c1b36..7a4851a3a9 100644 --- a/epan/nghttp2/CMakeLists.txt +++ b/epan/nghttp2/CMakeLists.txt @@ -31,6 +31,7 @@ set(NGHTTP2_FILES nghttp2_hd_huffman_data.c nghttp2_helper.c nghttp2_mem.c + nghttp2_rcbuf.c ) source_group(nghttp2 FILES ${NGHTTP2_FILES}) diff --git a/epan/nghttp2/Makefile.common b/epan/nghttp2/Makefile.common index 5ff688188d..277993be72 100644 --- a/epan/nghttp2/Makefile.common +++ b/epan/nghttp2/Makefile.common @@ -27,7 +27,8 @@ LIBNGHTTP2_SRC = \ nghttp2_hd_huffman.c \ nghttp2_hd_huffman_data.c \ nghttp2_helper.c \ - nghttp2_mem.c + nghttp2_mem.c \ + nghttp2_rcbuf.c LIBNGHTTP2_INCLUDES = \ nghttp2_buf.h \ @@ -36,6 +37,7 @@ LIBNGHTTP2_INCLUDES = \ nghttp2_helper.h \ nghttp2_int.h \ nghttp2_mem.h \ + nghttp2_rcbuf.h \ nghttp2.h \ nghttp2ver.h diff --git a/epan/nghttp2/README.nghttp2 b/epan/nghttp2/README.nghttp2 index 6fb82c1a2a..4c77a872ab 100644 --- a/epan/nghttp2/README.nghttp2 +++ b/epan/nghttp2/README.nghttp2 @@ -11,6 +11,7 @@ cp ../../../nghttp2/lib/nghttp2_hd*.[ch] . cp ../../../nghttp2/lib/nghttp2_helper.[ch] . cp ../../../nghttp2/lib/nghttp2_int.h . cp ../../../nghttp2/lib/nghttp2_mem.[ch] . +cp ../../../nghttp2/lib/nghttp2_rcbuf.[ch] . cp ../../../nghttp2/lib/includes/nghttp2/nghttp2.h . cp ../../../nghttp2/lib/includes/nghttp2/nghttp2ver.h . diff --git a/epan/nghttp2/nghttp2.h b/epan/nghttp2/nghttp2.h index 87472fa9ad..2fbcfb9aa0 100644 --- a/epan/nghttp2/nghttp2.h +++ b/epan/nghttp2/nghttp2.h @@ -432,6 +432,55 @@ typedef enum { } nghttp2_error; /** + * @struct + * + * The object representing single contiguous buffer. + */ +typedef struct { + /** + * The pointer to the buffer. + */ + uint8_t *base; + /** + * The length of the buffer. + */ + size_t len; +} nghttp2_vec; + +struct nghttp2_rcbuf; + +/** + * @typedef + * + * The object representing reference counted buffer. The details of + * this structure are intentionally hidden from the public API. + */ +typedef struct nghttp2_rcbuf nghttp2_rcbuf; + +/** + * @function + * + * Increments the reference count of |rcbuf| by 1. + */ +NGHTTP2_EXTERN void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf); + +/** + * @function + * + * Decrements the reference count of |rcbuf| by 1. If the reference + * count becomes zero, the object pointed by |rcbuf| will be freed. + * In this case, application must not use |rcbuf| again. + */ +NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf); + +/** + * @function + * + * Returns the underlying buffer managed by |rcbuf|. + */ +NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf); + +/** * @enum * * The flags for header field name/value pair. @@ -554,7 +603,12 @@ typedef enum { * callbacks because the library processes this frame type and its * preceding HEADERS/PUSH_PROMISE as a single frame. */ - NGHTTP2_CONTINUATION = 0x09 + NGHTTP2_CONTINUATION = 0x09, + /** + * The ALTSVC frame, which is defined in `RFC 7383 + * <https://tools.ietf.org/html/rfc7838#section-4>`_. + */ + NGHTTP2_ALTSVC = 0x0a } nghttp2_frame_type; /** @@ -1642,6 +1696,32 @@ typedef int (*nghttp2_on_header_callback)(nghttp2_session *session, /** * @functypedef * + * Callback function invoked when a header name/value pair is received + * for the |frame|. The |name| is header name. The |value| is header + * value. The |flags| is bitwise OR of one or more of + * :type:`nghttp2_nv_flag`. + * + * This callback behaves like :type:`nghttp2_on_header_callback`, + * except that |name| and |value| are stored in reference counted + * buffer. If application wishes to keep these references without + * copying them, use `nghttp2_rcbuf_incref()` to increment their + * reference count. It is the application's responsibility to call + * `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so + * as not to leak memory. If the |session| is created by + * `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`, + * the function to free memory is the one belongs to the mem + * parameter. As long as this free function alives, |name| and + * |value| can live after |session| was destroyed. + */ +typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, + const nghttp2_frame *frame, + nghttp2_rcbuf *name, + nghttp2_rcbuf *value, uint8_t flags, + void *user_data); + +/** + * @functypedef + * * Callback function invoked when the library asks application how * many padding bytes are required for the transmission of the * |frame|. The application must choose the total length of payload @@ -1809,6 +1889,31 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, const nghttp2_frame *frame, void *user_data); +/** + * @functypedef + * + * Callback function invoked when library provides the error message + * intended for human consumption. This callback is solely for + * debugging purpose. The |msg| is typically NULL-terminated string + * of length |len|. |len| does not include the sentinel NULL + * character. + * + * The format of error message may change between nghttp2 library + * versions. The application should not depend on the particular + * format. + * + * Normally, application should return 0 from this callback. If fatal + * error occurred while doing something in this callback, application + * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * library will return immediately with return value + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value + * is returned from this callback, they are treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not + * rely on this details. + */ +typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, + size_t len, void *user_data); + struct nghttp2_session_callbacks; /** @@ -1953,7 +2058,10 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback( * @function * * Sets callback function invoked when a header name/value pair is - * received. + * received. If both + * `nghttp2_session_callbacks_set_on_header_callback()` and + * `nghttp2_session_callbacks_set_on_header_callback2()` are used to + * set callbacks, the latter has the precedence. */ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback( nghttp2_session_callbacks *cbs, @@ -1962,6 +2070,16 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback( /** * @function * + * Sets callback function invoked when a header name/value pair is + * received. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2( + nghttp2_session_callbacks *cbs, + nghttp2_on_header_callback2 on_header_callback2); + +/** + * @function + * * Sets callback function invoked when the library asks application * how many padding bytes are required for the transmission of the * given frame. @@ -2033,6 +2151,15 @@ nghttp2_session_callbacks_set_on_extension_chunk_recv_callback( nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback); /** + * @function + * + * Sets callback function invoked when library tells error message to + * the application. + */ +NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback( + nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback); + +/** * @functypedef * * Custom memory allocator to replace malloc(). The |mem_user_data| @@ -2266,6 +2393,40 @@ nghttp2_option_set_user_recv_extension_type(nghttp2_option *option, /** * @function * + * Sets extension frame type the application is willing to receive + * using builtin handler. The |type| is the extension frame type to + * receive, and must be strictly greater than 0x9. Otherwise, this + * function does nothing. The application can call this function + * multiple times to set more than one frame type to receive. The + * application does not have to call this function if it just sends + * extension frames. + * + * If same frame type is passed to both + * `nghttp2_option_set_builtin_recv_extension_type()` and + * `nghttp2_option_set_user_recv_extension_type()`, the latter takes + * precedence. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, + uint8_t type); + +/** + * @function + * + * This option prevents the library from sending PING frame with ACK + * flag set automatically when PING frame without ACK flag set is + * received. If this option is set to nonzero, the library won't send + * PING frame with ACK flag set in the response for incoming PING + * frame. The application can send PING frame with ACK flag set using + * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags + * parameter. + */ +NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, + int val); + +/** + * @function + * * Initializes |*session_ptr| for client use. The all members of * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr| * does not store |callbacks|. The |user_data| is an arbitrary user @@ -3239,6 +3400,16 @@ NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code); /** * @function * + * Returns string representation of HTTP/2 error code |error_code| + * (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code == + * NGHTTP2_PROTOCOL_ERROR``). If string representation is unknown for + * given |error_code|, this function returns string ``unknown``. + */ +NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code); + +/** + * @function + * * Initializes |pri_spec| with the |stream_id| of the stream to depend * on with |weight| and its exclusive flag. If |exclusive| is * nonzero, exclusive flag is set. @@ -3785,8 +3956,12 @@ nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags, * received PING frame. The library automatically submits PING frame * in this case. * - * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * The |flags| is bitwise OR of 0 or more of the following value. + * + * * :enum:`NGHTTP2_FLAG_ACK` + * + * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags| + * should be :enum:`NGHTTP2_FLAG_NONE`. * * If the |opaque_data| is non ``NULL``, then it should point to the 8 * bytes array of memory to specify opaque data to send with PING @@ -3976,6 +4151,80 @@ NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session, int32_t stream_id, void *payload); /** + * @struct + * + * The payload of ALTSVC frame. ALTSVC frame is a non-critical + * extension to HTTP/2. If this frame is received, and + * `nghttp2_option_set_user_recv_extension_type()` is not set, and + * `nghttp2_option_set_builtin_recv_extension_type()` is set for + * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to + * this struct. + * + * It has the following members: + */ +typedef struct { + /** + * The pointer to origin which this alternative service is + * associated with. This is not necessarily NULL-terminated. + */ + uint8_t *origin; + /** + * The length of the |origin|. + */ + size_t origin_len; + /** + * The pointer to Alt-Svc field value contained in ALTSVC frame. + * This is not necessarily NULL-terminated. + */ + uint8_t *field_value; + /** + * The length of the |field_value|. + */ + size_t field_value_len; +} nghttp2_ext_altsvc; + +/** + * @function + * + * Submits ALTSVC frame. + * + * ALTSVC frame is a non-critical extension to HTTP/2, and defined in + * is defined in `RFC 7383 + * <https://tools.ietf.org/html/rfc7838#section-4>`_. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |origin| points to the origin this alternative service is + * associated with. The |origin_len| is the length of the origin. If + * |stream_id| is 0, the origin must be specified. If |stream_id| is + * not zero, the origin must be empty (in other words, |origin_len| + * must be 0). + * + * The ALTSVC frame is only usable from server side. If this function + * is invoked with client side session, this function returns + * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * + * 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_INVALID_STATE` + * The function is called from client side session + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The sum of |origin_len| and |field_value_len| is larger than + * 16382; or |origin_len| is 0 while |stream_id| is 0; or + * |origin_len| is not 0 while |stream_id| is not 0. + */ +NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *origin, + size_t origin_len, + const uint8_t *field_value, + size_t field_value_len); + +/** * @function * * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and @@ -4316,7 +4565,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. * @@ -4357,6 +4606,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 @@ -4439,6 +4692,88 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, /** * @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 + * * Signals the end of decompression for one header block. * * This function returns 0 if it succeeds. Currently this function diff --git a/epan/nghttp2/nghttp2_buf.h b/epan/nghttp2/nghttp2_buf.h index 072e835ec1..fcb4b64416 100644 --- a/epan/nghttp2/nghttp2_buf.h +++ b/epan/nghttp2/nghttp2_buf.h @@ -73,7 +73,7 @@ typedef struct { /* * Initializes the |buf|. No memory is allocated in this function. Use - * nghttp2_buf_reserve() or nghttp2_buf_reserve2() to allocate memory. + * nghttp2_buf_reserve() to allocate memory. */ void nghttp2_buf_init(nghttp2_buf *buf); @@ -312,8 +312,8 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b); } while (0) /* - * Copies all data stored in |bufs| to the contagious buffer. This - * function allocates the contagious memory to store all data in + * Copies all data stored in |bufs| to the contiguous buffer. This + * function allocates the contiguous memory to store all data in * |bufs| and assigns it to |*out|. * * The contents of |bufs| is left unchanged. diff --git a/epan/nghttp2/nghttp2_hd.c b/epan/nghttp2/nghttp2_hd.c index 28598554bc..377067db1f 100644 --- a/epan/nghttp2/nghttp2_hd.c +++ b/epan/nghttp2/nghttp2_hd.c @@ -34,15 +34,17 @@ /* Make scalar initialization form of nghttp2_hd_entry */ #define MAKE_STATIC_ENT(N, V, T, H) \ { \ - { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \ - , NULL, 0, (H), (T), 1, NGHTTP2_HD_FLAG_NONE \ + { NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1 } \ + , {NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ + {(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \ + T, H \ } /* Generated by mkstatictbl.py */ /* 3rd parameter is nghttp2_token value for header field name. We use first enum value if same header names are repeated (e.g., :status). */ -static nghttp2_hd_entry static_table[] = { +static nghttp2_hd_static_entry static_table[] = { MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), @@ -114,7 +116,7 @@ static int memeq(const void *s1, const void *s2, size_t n) { * This function was generated by genlibtokenlookup.py. Inspired by * h2o header lookup. https://github.com/h2o/h2o */ -static int lookup_token(const uint8_t *name, size_t namelen) { +static int32_t lookup_token(const uint8_t *name, size_t namelen) { switch (namelen) { case 2: switch (name[1]) { @@ -137,26 +139,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_AGE; } break; - case 'n': - if (lstreq("tc", name, 2)) { - return NGHTTP2_TOKEN_TCN; - } - break; - case 'p': - if (lstreq("p3", name, 2)) { - return NGHTTP2_TOKEN_P3P; - } - break; - case 't': - if (lstreq("dn", name, 2)) { - return NGHTTP2_TOKEN_DNT; - } - break; - case 'v': - if (lstreq("ts", name, 2)) { - return NGHTTP2_TOKEN_TSV; - } - break; } break; case 4: @@ -217,31 +199,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; case 6: switch (name[5]) { - case 'a': - if (lstreq("pragm", name, 5)) { - return NGHTTP2_TOKEN_PRAGMA; - } - break; case 'e': if (lstreq("cooki", name, 5)) { return NGHTTP2_TOKEN_COOKIE; } break; - case 'n': - if (lstreq("origi", name, 5)) { - return NGHTTP2_TOKEN_ORIGIN; - } - break; case 'r': if (lstreq("serve", name, 5)) { return NGHTTP2_TOKEN_SERVER; } break; - case 's': - if (lstreq("statu", name, 5)) { - return NGHTTP2_TOKEN_STATUS; - } - break; case 't': if (lstreq("accep", name, 5)) { return NGHTTP2_TOKEN_ACCEPT; @@ -254,11 +221,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; case 7: switch (name[6]) { - case 'c': - if (lstreq("alt-sv", name, 6)) { - return NGHTTP2_TOKEN_ALT_SVC; - } - break; case 'd': if (lstreq(":metho", name, 6)) { return NGHTTP2_TOKEN__METHOD; @@ -277,14 +239,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { if (lstreq("upgrad", name, 6)) { return NGHTTP2_TOKEN_UPGRADE; } - if (lstreq("x-cach", name, 6)) { - return NGHTTP2_TOKEN_X_CACHE; - } - break; - case 'g': - if (lstreq("warnin", name, 6)) { - return NGHTTP2_TOKEN_WARNING; - } break; case 'h': if (lstreq("refres", name, 6)) { @@ -295,9 +249,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { if (lstreq("refere", name, 6)) { return NGHTTP2_TOKEN_REFERER; } - if (lstreq("traile", name, 6)) { - return NGHTTP2_TOKEN_TRAILER; - } break; case 's': if (lstreq(":statu", name, 6)) { @@ -346,25 +297,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; } break; - case 9: - switch (name[8]) { - case 'd': - if (lstreq("forwarde", name, 8)) { - return NGHTTP2_TOKEN_FORWARDED; - } - break; - case 'e': - if (lstreq("negotiat", name, 8)) { - return NGHTTP2_TOKEN_NEGOTIATE; - } - break; - case 'h': - if (lstreq("accept-c", name, 8)) { - return NGHTTP2_TOKEN_ACCEPT_CH; - } - break; - } - break; case 10: switch (name[9]) { case 'e': @@ -380,11 +312,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_CONNECTION; } break; - case 's': - if (lstreq("alternate", name, 9)) { - return NGHTTP2_TOKEN_ALTERNATES; - } - break; case 't': if (lstreq("user-agen", name, 9)) { return NGHTTP2_TOKEN_USER_AGENT; @@ -399,16 +326,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; case 11: switch (name[10]) { - case '2': - if (lstreq("set-cookie", name, 10)) { - return NGHTTP2_TOKEN_SET_COOKIE2; - } - break; - case '5': - if (lstreq("content-md", name, 10)) { - return NGHTTP2_TOKEN_CONTENT_MD5; - } - break; case 'r': if (lstreq("retry-afte", name, 10)) { return NGHTTP2_TOKEN_RETRY_AFTER; @@ -423,37 +340,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_CONTENT_TYPE; } break; - case 'h': - if (lstreq("accept-patc", name, 11)) { - return NGHTTP2_TOKEN_ACCEPT_PATCH; - } - break; - case 'p': - if (lstreq("x-webkit-cs", name, 11)) { - return NGHTTP2_TOKEN_X_WEBKIT_CSP; - } - break; case 's': if (lstreq("max-forward", name, 11)) { return NGHTTP2_TOKEN_MAX_FORWARDS; } break; - case 'y': - if (lstreq("variant-var", name, 11)) { - return NGHTTP2_TOKEN_VARIANT_VARY; - } - if (lstreq("x-powered-b", name, 11)) { - return NGHTTP2_TOKEN_X_POWERED_BY; - } - break; } break; case 13: switch (name[12]) { case 'd': - if (lstreq("last-event-i", name, 12)) { - return NGHTTP2_TOKEN_LAST_EVENT_ID; - } if (lstreq("last-modifie", name, 12)) { return NGHTTP2_TOKEN_LAST_MODIFIED; } @@ -462,9 +358,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { if (lstreq("content-rang", name, 12)) { return NGHTTP2_TOKEN_CONTENT_RANGE; } - if (lstreq("x-wap-profil", name, 12)) { - return NGHTTP2_TOKEN_X_WAP_PROFILE; - } break; case 'h': if (lstreq("if-none-matc", name, 12)) { @@ -480,9 +373,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { if (lstreq("authorizatio", name, 12)) { return NGHTTP2_TOKEN_AUTHORIZATION; } - if (lstreq("x-api-versio", name, 12)) { - return NGHTTP2_TOKEN_X_API_VERSION; - } break; case 's': if (lstreq("accept-range", name, 12)) { @@ -493,21 +383,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; case 14: switch (name[13]) { - case 'd': - if (lstreq("x-att-devicei", name, 13)) { - return NGHTTP2_TOKEN_X_ATT_DEVICEID; - } - break; case 'h': if (lstreq("content-lengt", name, 13)) { return NGHTTP2_TOKEN_CONTENT_LENGTH; } break; - case 'p': - if (lstreq("x-cache-looku", name, 13)) { - return NGHTTP2_TOKEN_X_CACHE_LOOKUP; - } - break; case 't': if (lstreq("accept-charse", name, 13)) { return NGHTTP2_TOKEN_ACCEPT_CHARSET; @@ -518,40 +398,15 @@ static int lookup_token(const uint8_t *name, size_t namelen) { case 15: switch (name[14]) { case 'e': - if (lstreq("accept-datetim", name, 14)) { - return NGHTTP2_TOKEN_ACCEPT_DATETIME; - } if (lstreq("accept-languag", name, 14)) { return NGHTTP2_TOKEN_ACCEPT_LANGUAGE; } - if (lstreq("x-ua-compatibl", name, 14)) { - return NGHTTP2_TOKEN_X_UA_COMPATIBLE; - } break; case 'g': if (lstreq("accept-encodin", name, 14)) { return NGHTTP2_TOKEN_ACCEPT_ENCODING; } break; - case 'r': - if (lstreq("x-forwarded-fo", name, 14)) { - return NGHTTP2_TOKEN_X_FORWARDED_FOR; - } - break; - case 's': - if (lstreq("accept-feature", name, 14)) { - return NGHTTP2_TOKEN_ACCEPT_FEATURES; - } - if (lstreq("front-end-http", name, 14)) { - return NGHTTP2_TOKEN_FRONT_END_HTTPS; - } - if (lstreq("public-key-pin", name, 14)) { - return NGHTTP2_TOKEN_PUBLIC_KEY_PINS; - } - if (lstreq("x-frame-option", name, 14)) { - return NGHTTP2_TOKEN_X_FRAME_OPTIONS; - } - break; } break; case 16: @@ -569,11 +424,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_CONTENT_ENCODING; } break; - case 'h': - if (lstreq("x-requested-wit", name, 15)) { - return NGHTTP2_TOKEN_X_REQUESTED_WITH; - } - break; case 'n': if (lstreq("content-locatio", name, 15)) { return NGHTTP2_TOKEN_CONTENT_LOCATION; @@ -581,14 +431,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { if (lstreq("proxy-connectio", name, 15)) { return NGHTTP2_TOKEN_PROXY_CONNECTION; } - if (lstreq("x-xss-protectio", name, 15)) { - return NGHTTP2_TOKEN_X_XSS_PROTECTION; - } - break; - case 't': - if (lstreq("x-forwarded-hos", name, 15)) { - return NGHTTP2_TOKEN_X_FORWARDED_HOST; - } break; } break; @@ -604,16 +446,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_TRANSFER_ENCODING; } break; - case 'o': - if (lstreq("x-forwarded-prot", name, 16)) { - return NGHTTP2_TOKEN_X_FORWARDED_PROTO; - } - break; - case 'y': - if (lstreq("sec-websocket-ke", name, 16)) { - return NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY; - } - break; } break; case 18: @@ -623,11 +455,6 @@ static int lookup_token(const uint8_t *name, size_t namelen) { return NGHTTP2_TOKEN_PROXY_AUTHENTICATE; } break; - case 'n': - if (lstreq("x-content-duratio", name, 17)) { - return NGHTTP2_TOKEN_X_CONTENT_DURATION; - } - break; } break; case 19: @@ -647,80 +474,12 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; } break; - case 20: - switch (name[19]) { - case 'n': - if (lstreq("sec-websocket-origi", name, 19)) { - return NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN; - } - break; - } - break; - case 21: - switch (name[20]) { - case 'l': - if (lstreq("x-dnsprefetch-contro", name, 20)) { - return NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL; - } - break; - case 'n': - if (lstreq("sec-websocket-versio", name, 20)) { - return NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION; - } - break; - } - break; - case 22: - switch (name[21]) { - case 'e': - if (lstreq("access-control-max-ag", name, 21)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE; - } - break; - case 'l': - if (lstreq("sec-websocket-protoco", name, 21)) { - return NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL; - } - break; - case 's': - if (lstreq("x-content-type-option", name, 21)) { - return NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS; - } - break; - } - break; - case 23: - switch (name[22]) { - case 'y': - if (lstreq("content-security-polic", name, 22)) { - return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY; - } - break; - } - break; - case 24: - switch (name[23]) { - case 's': - if (lstreq("sec-websocket-extension", name, 23)) { - return NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS; - } - break; - } - break; case 25: switch (name[24]) { - case 's': - if (lstreq("upgrade-insecure-request", name, 24)) { - return NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS; - } - break; case 'y': if (lstreq("strict-transport-securit", name, 24)) { return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY; } - if (lstreq("x-content-security-polic", name, 24)) { - return NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY; - } break; } break; @@ -733,143 +492,37 @@ static int lookup_token(const uint8_t *name, size_t namelen) { break; } break; - case 28: - switch (name[27]) { - case 's': - if (lstreq("access-control-allow-header", name, 27)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS; - } - if (lstreq("access-control-allow-method", name, 27)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS; - } - break; - } - break; - case 29: - switch (name[28]) { - case 'd': - if (lstreq("access-control-request-metho", name, 28)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD; - } - break; - case 's': - if (lstreq("access-control-expose-header", name, 28)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS; - } - break; - } - break; - case 30: - switch (name[29]) { - case 's': - if (lstreq("access-control-request-header", name, 29)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS; - } - break; - } - break; - case 32: - switch (name[31]) { - case 's': - if (lstreq("access-control-allow-credential", name, 31)) { - return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS; - } - break; - } - break; - case 35: - switch (name[34]) { - case 'y': - if (lstreq("content-security-policy-report-onl", name, 34)) { - return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY; - } - break; - } - break; } return -1; } -int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name, - size_t namelen, uint8_t *value, size_t valuelen, - int token, nghttp2_mem *mem) { - int rv = 0; - - /* Since nghttp2_hd_entry is used for indexing, ent->nv.flags always - NGHTTP2_NV_FLAG_NONE */ - ent->nv.flags = NGHTTP2_NV_FLAG_NONE; - - if ((flags & NGHTTP2_HD_FLAG_NAME_ALLOC) && - (flags & NGHTTP2_HD_FLAG_NAME_GIFT) == 0) { - if (namelen == 0) { - flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_NAME_ALLOC); - ent->nv.name = (uint8_t *)""; - } else { - /* name may not be NULL terminated on compression. */ - ent->nv.name = (uint8_t *)nghttp2_mem_malloc(mem, namelen + 1); - if (ent->nv.name == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail; - } - memcpy(ent->nv.name, name, namelen); - ent->nv.name[namelen] = '\0'; - } - } else { - ent->nv.name = name; - } - if ((flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) && - (flags & NGHTTP2_HD_FLAG_VALUE_GIFT) == 0) { - if (valuelen == 0) { - flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_VALUE_ALLOC); - ent->nv.value = (uint8_t *)""; - } else { - /* value may not be NULL terminated on compression. */ - ent->nv.value = (uint8_t *)nghttp2_mem_malloc(mem, valuelen + 1); - if (ent->nv.value == NULL) { - rv = NGHTTP2_ERR_NOMEM; - goto fail2; - } - memcpy(ent->nv.value, value, valuelen); - ent->nv.value[valuelen] = '\0'; - } - } else { - ent->nv.value = value; - } - ent->nv.namelen = namelen; - ent->nv.valuelen = valuelen; - ent->token = token; - ent->ref = 1; - ent->flags = flags; +void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) { + ent->nv = *nv; + ent->cnv.name = nv->name->base; + ent->cnv.namelen = nv->name->len; + ent->cnv.value = nv->value->base; + ent->cnv.valuelen = nv->value->len; + ent->cnv.flags = nv->flags; ent->next = NULL; ent->hash = 0; - return 0; - -fail2: - if ((flags & NGHTTP2_HD_FLAG_NAME_ALLOC) && - (flags & NGHTTP2_HD_FLAG_NAME_GIFT) == 0) { - nghttp2_mem_free(mem, ent->nv.name); - } -fail: - return rv; + nghttp2_rcbuf_incref(ent->nv.name); + nghttp2_rcbuf_incref(ent->nv.value); } -void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem) { - assert(ent->ref == 0); - if (ent->flags & NGHTTP2_HD_FLAG_NAME_ALLOC) { - nghttp2_mem_free(mem, ent->nv.name); - } - if (ent->flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) { - nghttp2_mem_free(mem, ent->nv.value); - } +void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) { + nghttp2_rcbuf_decref(ent->nv.value); + nghttp2_rcbuf_decref(ent->nv.name); } -static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) { - return a->namelen == b->namelen && memeq(a->name, b->name, a->namelen); +static int name_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { + return a->name->len == b->namelen && + memeq(a->name->base, b->name, b->namelen); } -static int value_eq(const nghttp2_nv *a, const nghttp2_nv *b) { - return a->valuelen == b->valuelen && memeq(a->value, b->value, a->valuelen); +static int value_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) { + return a->value->len == b->valuelen && + memeq(a->value->base, b->value, b->valuelen); } static uint32_t name_hash(const nghttp2_nv *nv) { @@ -905,7 +558,7 @@ static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { } static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, - const nghttp2_nv *nv, int token, + const nghttp2_nv *nv, int32_t token, uint32_t hash) { nghttp2_hd_entry *p; nghttp2_hd_entry *res = NULL; @@ -913,7 +566,7 @@ static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, *exact_match = 0; for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) { - if (token != p->token || + if (token != p->nv.token || (token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) { continue; } @@ -931,28 +584,19 @@ static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match, } static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { - nghttp2_hd_entry **bucket; - nghttp2_hd_entry *p; + nghttp2_hd_entry **dst; - bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; + dst = &map->table[ent->hash & (HD_MAP_SIZE - 1)]; - if (*bucket == NULL) { - return; - } + for (; *dst; dst = &(*dst)->next) { + if (*dst != ent) { + continue; + } - if (*bucket == ent) { - *bucket = ent->next; + *dst = ent->next; ent->next = NULL; return; } - - for (p = *bucket; p; p = p->next) { - if (p->next == ent) { - p->next = ent->next; - ent->next = NULL; - return; - } - } } static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, @@ -1008,8 +652,8 @@ static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) { } for (i = 0; i < ringbuf->len; ++i) { nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i); - --ent->ref; - nghttp2_hd_entry_free(ent, mem); + + nghttp2_hd_entry_free(ent); nghttp2_mem_free(mem, ent); } nghttp2_mem_free(mem, ringbuf->buffer); @@ -1098,49 +742,37 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) { inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; inflater->min_hd_table_bufsize_max = UINT32_MAX; - inflater->ent_keep = NULL; - inflater->nv_keep = NULL; + inflater->nv_name_keep = NULL; + inflater->nv_value_keep = NULL; inflater->opcode = NGHTTP2_HD_OPCODE_NONE; inflater->state = NGHTTP2_HD_STATE_INFLATE_START; - rv = nghttp2_bufs_init3(&inflater->nvbufs, NGHTTP2_HD_MAX_NV / 8, 8, 1, 0, - mem); + nghttp2_buf_init(&inflater->namebuf); + nghttp2_buf_init(&inflater->valuebuf); - if (rv != 0) { - goto nvbufs_fail; - } + inflater->namercbuf = NULL; + inflater->valuercbuf = NULL; inflater->huffman_encoded = 0; inflater->index = 0; inflater->left = 0; inflater->shift = 0; - inflater->newnamelen = 0; inflater->index_required = 0; inflater->no_index = 0; return 0; -nvbufs_fail: - hd_context_free(&inflater->ctx); fail: return rv; } static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) { - nghttp2_mem *mem; + nghttp2_rcbuf_decref(inflater->nv_value_keep); + nghttp2_rcbuf_decref(inflater->nv_name_keep); - mem = inflater->ctx.mem; - if (inflater->ent_keep) { - if (inflater->ent_keep->ref == 0) { - nghttp2_hd_entry_free(inflater->ent_keep, mem); - nghttp2_mem_free(mem, inflater->ent_keep); - } - inflater->ent_keep = NULL; - } - - nghttp2_mem_free(mem, inflater->nv_keep); - inflater->nv_keep = NULL; + inflater->nv_value_keep = NULL; + inflater->nv_name_keep = NULL; } void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) { @@ -1149,7 +781,10 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) { void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) { hd_inflate_keep_free(inflater); - nghttp2_bufs_free(&inflater->nvbufs); + + nghttp2_rcbuf_decref(inflater->valuercbuf); + nghttp2_rcbuf_decref(inflater->namercbuf); + hd_context_free(&inflater->ctx); } @@ -1157,23 +792,13 @@ static size_t entry_room(size_t namelen, size_t valuelen) { return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen; } -static int emit_indexed_header(nghttp2_nv *nv_out, int *token_out, - nghttp2_hd_entry *ent) { - DEBUGF(fprintf(stderr, "inflatehd: header emission: %s: %s\n", ent->nv.name, - ent->nv.value)); +static int emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) { + DEBUGF(fprintf(stderr, "inflatehd: header emission: %s: %s\n", nv->name->base, + nv->value->base)); /* ent->ref may be 0. This happens if the encoder emits literal block larger than header table capacity with indexing. */ - *nv_out = ent->nv; - *token_out = ent->token; - return 0; -} - -static int emit_literal_header(nghttp2_nv *nv_out, int *token_out, - nghttp2_nv *nv) { - DEBUGF(fprintf(stderr, "inflatehd: header emission: %s: %s\n", nv->name, - nv->value)); *nv_out = *nv; - *token_out = lookup_token(nv->name, nv->namelen); + return 0; } @@ -1237,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; @@ -1481,17 +1106,16 @@ static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv, return 0; } -static nghttp2_hd_entry * -add_hd_table_incremental(nghttp2_hd_context *context, const nghttp2_nv *nv, - int token, uint8_t entry_flags, nghttp2_hd_map *map, - uint32_t hash) { +static int add_hd_table_incremental(nghttp2_hd_context *context, + nghttp2_hd_nv *nv, nghttp2_hd_map *map, + uint32_t hash) { int rv; nghttp2_hd_entry *new_ent; size_t room; nghttp2_mem *mem; mem = context->mem; - room = entry_room(nv->namelen, nv->valuelen); + room = entry_room(nv->name->len, nv->value->len); while (context->hd_table_bufsize + room > context->hd_table_bufsize_max && context->hd_table.len > 0) { @@ -1499,72 +1123,53 @@ add_hd_table_incremental(nghttp2_hd_context *context, const nghttp2_nv *nv, size_t idx = context->hd_table.len - 1; nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); - context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); + context->hd_table_bufsize -= + entry_room(ent->nv.name->len, ent->nv.value->len); DEBUGF(fprintf(stderr, "hpack: remove item from header table: %s: %s\n", - ent->nv.name, ent->nv.value)); + (char *)ent->nv.name->base, (char *)ent->nv.value->base)); hd_ringbuf_pop_back(&context->hd_table); if (map) { hd_map_remove(map, ent); } - if (--ent->ref == 0) { - nghttp2_hd_entry_free(ent, mem); - nghttp2_mem_free(mem, ent); - } - } - new_ent = (nghttp2_hd_entry *)nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry)); - if (new_ent == NULL) { - return NULL; - } - - rv = nghttp2_hd_entry_init(new_ent, entry_flags, nv->name, nv->namelen, - nv->value, nv->valuelen, token, mem); - if (rv != 0) { - nghttp2_mem_free(mem, new_ent); - return NULL; + nghttp2_hd_entry_free(ent); + nghttp2_mem_free(mem, ent); } if (room > context->hd_table_bufsize_max) { /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is - immediately evicted. */ - --new_ent->ref; - } else { - rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem); + immediately evicted. So we don't allocate memory for it. */ + return 0; + } - if (rv != 0) { - --new_ent->ref; + new_ent = (nghttp2_hd_entry *)nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry)); + if (new_ent == NULL) { + return NGHTTP2_ERR_NOMEM; + } - if ((entry_flags & NGHTTP2_HD_FLAG_NAME_ALLOC) && - (entry_flags & NGHTTP2_HD_FLAG_NAME_GIFT)) { - /* nv->name are managed by caller. */ - new_ent->nv.name = NULL; - new_ent->nv.namelen = 0; - } - if ((entry_flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) && - (entry_flags & NGHTTP2_HD_FLAG_VALUE_GIFT)) { - /* nv->value are managed by caller. */ - new_ent->nv.value = NULL; - new_ent->nv.valuelen = 0; - } + nghttp2_hd_entry_init(new_ent, nv); - nghttp2_hd_entry_free(new_ent, mem); - nghttp2_mem_free(mem, new_ent); + rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem); - return NULL; - } + if (rv != 0) { + nghttp2_hd_entry_free(new_ent); + nghttp2_mem_free(mem, new_ent); - new_ent->seq = context->next_seq++; - new_ent->hash = hash; + return rv; + } - if (map) { - hd_map_insert(map, new_ent); - } + new_ent->seq = context->next_seq++; + new_ent->hash = hash; - context->hd_table_bufsize += room; + if (map) { + hd_map_insert(map, new_ent); } - return new_ent; + + context->hd_table_bufsize += room; + + return 0; } typedef struct { @@ -1573,10 +1178,11 @@ typedef struct { uint8_t name_value_match; } search_result; -static search_result search_static_table(const nghttp2_nv *nv, int token, +static search_result search_static_table(const nghttp2_nv *nv, int32_t token, int indexing_mode) { search_result res = {token, 0}; int i; + nghttp2_hd_static_entry *ent; if (indexing_mode == NGHTTP2_HD_NEVER_INDEXING) { return res; @@ -1585,7 +1191,9 @@ static search_result search_static_table(const nghttp2_nv *nv, int token, for (i = token; i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token; ++i) { - if (value_eq(&static_table[i].nv, nv)) { + ent = &static_table[i]; + if (ent->value.len == nv->valuelen && + memcmp(ent->value.base, nv->value, nv->valuelen) == 0) { res.index = i; res.name_value_match = 1; return res; @@ -1595,7 +1203,7 @@ static search_result search_static_table(const nghttp2_nv *nv, int token, } static search_result search_hd_table(nghttp2_hd_context *context, - const nghttp2_nv *nv, int token, + const nghttp2_nv *nv, int32_t token, int indexing_mode, nghttp2_hd_map *map, uint32_t hash) { search_result res = {-1, 0}; @@ -1639,15 +1247,15 @@ static void hd_context_shrink_table_size(nghttp2_hd_context *context, context->hd_table.len > 0) { size_t idx = context->hd_table.len - 1; nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx); - context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); + context->hd_table_bufsize -= + entry_room(ent->nv.name->len, ent->nv.value->len); hd_ringbuf_pop_back(&context->hd_table); if (map) { hd_map_remove(map, ent); } - if (--ent->ref == 0) { - nghttp2_hd_entry_free(ent, mem); - nghttp2_mem_free(mem, ent); - } + + nghttp2_hd_entry_free(ent); + nghttp2_mem_free(mem, ent); } } @@ -1706,19 +1314,32 @@ static size_t get_max_index(nghttp2_hd_context *context) { return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH - 1; } -nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context, - size_t idx) { +nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) { assert(INDEX_RANGE_VALID(context, idx)); if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { - return hd_ringbuf_get(&context->hd_table, - idx - NGHTTP2_STATIC_TABLE_LENGTH); + return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) + ->nv; } else { - return &static_table[idx]; + nghttp2_hd_static_entry *ent = &static_table[idx]; + nghttp2_hd_nv nv = {&ent->name, &ent->value, ent->token, + NGHTTP2_NV_FLAG_NONE}; + return nv; + } +} + +static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context, + size_t idx) { + assert(INDEX_RANGE_VALID(context, idx)); + if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) { + return &hd_ringbuf_get(&context->hd_table, + idx - NGHTTP2_STATIC_TABLE_LENGTH)->cnv; } + + return &static_table[idx].cnv; } static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater, - const nghttp2_nv *nv, int token) { + const nghttp2_nv *nv, int32_t token) { if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE || token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG || token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE || @@ -1738,7 +1359,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, search_result res; ssize_t idx; int indexing_mode; - int token; + int32_t token; nghttp2_mem *mem; uint32_t hash = 0; @@ -1787,27 +1408,35 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, } if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) { - nghttp2_hd_entry *new_ent; + nghttp2_hd_nv hd_nv; + if (idx != -1 && idx < (ssize_t)NGHTTP2_STATIC_TABLE_LENGTH) { - nghttp2_nv nv_indname; - nv_indname = *nv; - nv_indname.name = - nghttp2_hd_table_get(&deflater->ctx, (size_t)idx)->nv.name; - new_ent = add_hd_table_incremental(&deflater->ctx, &nv_indname, token, - NGHTTP2_HD_FLAG_VALUE_ALLOC, - &deflater->map, hash); + hd_nv.name = nghttp2_hd_table_get(&deflater->ctx, (size_t)idx).name; + nghttp2_rcbuf_incref(hd_nv.name); } else { - new_ent = add_hd_table_incremental(&deflater->ctx, nv, token, - NGHTTP2_HD_FLAG_NAME_ALLOC | - NGHTTP2_HD_FLAG_VALUE_ALLOC, - &deflater->map, hash); + rv = nghttp2_rcbuf_new2(&hd_nv.name, nv->name, nv->namelen, mem); + if (rv != 0) { + return rv; + } } - if (!new_ent) { - return NGHTTP2_ERR_HEADER_COMP; + + rv = nghttp2_rcbuf_new2(&hd_nv.value, nv->value, nv->valuelen, mem); + + if (rv != 0) { + nghttp2_rcbuf_decref(hd_nv.name); + return rv; } - if (new_ent->ref == 0) { - nghttp2_hd_entry_free(new_ent, mem); - nghttp2_mem_free(mem, new_ent); + + hd_nv.token = token; + hd_nv.flags = NGHTTP2_NV_FLAG_NONE; + + rv = add_hd_table_incremental(&deflater->ctx, &hd_nv, &deflater->map, hash); + + nghttp2_rcbuf_decref(hd_nv.value); + nghttp2_rcbuf_decref(hd_nv.name); + + if (rv != 0) { + return NGHTTP2_ERR_HEADER_COMP; } } if (idx == -1) { @@ -1996,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; @@ -2036,19 +1665,17 @@ static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin, * Out of memory * NGHTTP2_ERR_HEADER_COMP * Huffman decoding failed - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. */ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, - nghttp2_bufs *bufs, 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) { last = in + inflater->left; final = 1; } - readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, bufs, in, + readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in, (size_t)(last - in), final); if (readlen < 0) { @@ -2070,17 +1697,13 @@ static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater, * Out of memory * NGHTTP2_ERR_HEADER_COMP * Header decompression failed - * NGHTTP2_ERR_BUFFER_ERROR - * Out of buffer space. */ -static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, - nghttp2_bufs *bufs, uint8_t *in, uint8_t *last) { - int rv; +static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf, + const uint8_t *in, const uint8_t *last) { size_t len = nghttp2_min((size_t)(last - in), inflater->left); - rv = nghttp2_bufs_add(bufs, in, len); - if (rv != 0) { - return rv; - } + + buf->last = nghttp2_cpymem(buf->last, in, len); + inflater->left -= len; return (ssize_t)len; } @@ -2097,116 +1720,10 @@ static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, * Out of memory */ static int hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *token_out) { - nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index); - - emit_indexed_header(nv_out, token_out, ent); - - return 0; -} - -static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv, - int value_only) { - ssize_t rv; - size_t buflen; - uint8_t *buf; - nghttp2_buf *pbuf; - - if (inflater->index_required || - inflater->nvbufs.head != inflater->nvbufs.cur) { - - rv = nghttp2_bufs_remove(&inflater->nvbufs, &buf); - - if (rv < 0) { - return NGHTTP2_ERR_NOMEM; - } - - nghttp2_bufs_reset(&inflater->nvbufs); - - buflen = (size_t)rv; - - if (value_only) { - /* we don't use this value, so no need to NULL-terminate */ - nv->name = NULL; - nv->namelen = 0; - - nv->value = buf; - nv->valuelen = buflen - 1; - } else { - nv->name = buf; - nv->namelen = inflater->newnamelen; - - nv->value = buf + nv->namelen + 1; - nv->valuelen = buflen - nv->namelen - 2; - } - - return 0; - } - - /* If we are not going to store header in header table and - name/value are in first chunk, we just refer them from nv, - instead of mallocing another memory. */ - - pbuf = &inflater->nvbufs.head->buf; - - if (value_only) { - /* we don't use this value, so no need to NULL-terminate */ - nv->name = NULL; - nv->namelen = 0; - - nv->value = pbuf->pos; - nv->valuelen = nghttp2_buf_len(pbuf) - 1; - } else { - nv->name = pbuf->pos; - nv->namelen = inflater->newnamelen; - - nv->value = pbuf->pos + nv->namelen + 1; - nv->valuelen = nghttp2_buf_len(pbuf) - nv->namelen - 2; - } - - /* Resetting does not change the content of first buffer */ - nghttp2_bufs_reset(&inflater->nvbufs); - - return 0; -} - -static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv, - nghttp2_hd_entry *ent_name) { -#ifndef NDEBUG - size_t rv; -#endif - size_t buflen; - uint8_t *buf; - nghttp2_mem *mem; + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); - mem = inflater->ctx.mem; - - /* Allocate buffer including name in ent_name, plus terminating - NULL. */ - buflen = ent_name->nv.namelen + 1 + nghttp2_bufs_len(&inflater->nvbufs); - - buf = (uint8_t *)nghttp2_mem_malloc(mem, buflen); - if (buf == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - /* Copy including terminal NULL */ - memcpy(buf, ent_name->nv.name, ent_name->nv.namelen + 1); -#ifndef NDEBUG - rv = -#endif - nghttp2_bufs_remove_copy(&inflater->nvbufs, - buf + ent_name->nv.namelen + 1); - assert(ent_name->nv.namelen + 1 + rv == buflen); - - nghttp2_bufs_reset(&inflater->nvbufs); - - nv->name = buf; - nv->namelen = ent_name->nv.namelen; - - nv->value = buf + nv->namelen + 1; - nv->valuelen = buflen - nv->namelen - 2; + emit_header(nv_out, &nv); return 0; } @@ -2223,17 +1740,9 @@ static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater, * Out of memory */ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *token_out) { + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv; int rv; - nghttp2_nv nv; - nghttp2_mem *mem; - - mem = inflater->ctx.mem; - - rv = hd_inflate_remove_bufs(inflater, &nv, 0 /* name and value */); - if (rv != 0) { - return NGHTTP2_ERR_NOMEM; - } if (inflater->no_index) { nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; @@ -2241,36 +1750,25 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, nv.flags = NGHTTP2_NV_FLAG_NONE; } - if (inflater->index_required) { - nghttp2_hd_entry *new_ent; - uint8_t ent_flags; - - /* nv->value points to the middle of the buffer pointed by - nv->name. So we just need to keep track of nv->name for memory - management. */ - ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT; - - new_ent = add_hd_table_incremental(&inflater->ctx, &nv, - lookup_token(nv.name, nv.namelen), - ent_flags, NULL, 0); + nv.name = inflater->namercbuf; + nv.value = inflater->valuercbuf; + nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len); - if (new_ent) { - emit_indexed_header(nv_out, token_out, new_ent); - inflater->ent_keep = new_ent; + if (inflater->index_required) { + rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); - return 0; + if (rv != 0) { + return rv; } - - nghttp2_mem_free(mem, nv.name); - - return NGHTTP2_ERR_NOMEM; } - emit_literal_header(nv_out, token_out, &nv); + emit_header(nv_out, &nv); - if (nv.name != inflater->nvbufs.head->buf.pos) { - inflater->nv_keep = nv.name; - } + inflater->nv_name_keep = nv.name; + inflater->nv_value_keep = nv.value; + + inflater->namercbuf = NULL; + inflater->valuercbuf = NULL; return 0; } @@ -2287,13 +1785,11 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater, * Out of memory */ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *token_out) { + nghttp2_hd_nv *nv_out) { + nghttp2_hd_nv nv; int rv; - nghttp2_nv nv; - nghttp2_hd_entry *ent_name; - nghttp2_mem *mem; - mem = inflater->ctx.mem; + nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index); if (inflater->no_index) { nv.flags = NGHTTP2_NV_FLAG_NO_INDEX; @@ -2301,88 +1797,73 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater, nv.flags = NGHTTP2_NV_FLAG_NONE; } - ent_name = nghttp2_hd_table_get(&inflater->ctx, inflater->index); - - if (inflater->index_required) { - nghttp2_hd_entry *new_ent; - uint8_t ent_flags; + nghttp2_rcbuf_incref(nv.name); - if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) { - /* We don't copy name in static table */ - rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */); - if (rv != 0) { - return NGHTTP2_ERR_NOMEM; - } - nv.name = ent_name->nv.name; - nv.namelen = ent_name->nv.namelen; + nv.value = inflater->valuercbuf; - ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT; - } else { - rv = hd_inflate_remove_bufs_with_name(inflater, &nv, ent_name); - if (rv != 0) { - return NGHTTP2_ERR_NOMEM; - } - /* nv->name and nv->value are in the same buffer. */ - ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT; + if (inflater->index_required) { + rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0); + if (rv != 0) { + nghttp2_rcbuf_decref(nv.name); + return NGHTTP2_ERR_NOMEM; } + } - new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token, - ent_flags, NULL, 0); + emit_header(nv_out, &nv); - /* At this point, ent_name might be deleted. */ + inflater->nv_name_keep = nv.name; + inflater->nv_value_keep = nv.value; - if (new_ent) { - emit_indexed_header(nv_out, token_out, new_ent); + inflater->valuercbuf = NULL; - inflater->ent_keep = new_ent; + return 0; +} - return 0; - } +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); +} - if (inflater->index < NGHTTP2_STATIC_TABLE_LENGTH) { - nghttp2_mem_free(mem, nv.value); - } else { - nghttp2_mem_free(mem, nv.name); - } +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; - return NGHTTP2_ERR_NOMEM; - } + rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen, + in_final); - rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */); - if (rv != 0) { - return NGHTTP2_ERR_NOMEM; + if (rv < 0) { + return rv; } - nv.name = ent_name->nv.name; - nv.namelen = ent_name->nv.namelen; + if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) { + nv_out->name = hd_nv.name->base; + nv_out->namelen = hd_nv.name->len; - emit_literal_header(nv_out, token_out, &nv); + nv_out->value = hd_nv.value->base; + nv_out->valuelen = hd_nv.value->len; - if (nv.value != inflater->nvbufs.head->buf.pos) { - inflater->nv_keep = nv.value; + nv_out->flags = hd_nv.flags; } - return 0; -} - -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) { - int token; - - return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, &token, in, - inlen, in_final); + return rv; } -ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *inflate_flags, - int *token_out, 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; + + mem = inflater->ctx.mem; if (inflater->ctx.bad) { return NGHTTP2_ERR_HEADER_COMP; @@ -2390,7 +1871,6 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, DEBUGF(fprintf(stderr, "inflatehd: start state=%d\n", inflater->state)); hd_inflate_keep_free(inflater); - *token_out = -1; *inflate_flags = NGHTTP2_HD_INFLATE_NONE; for (; in != last || busy;) { busy = 0; @@ -2496,7 +1976,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, inflater->index = inflater->left; --inflater->index; - rv = hd_inflate_commit_indexed(inflater, nv_out, token_out); + rv = hd_inflate_commit_indexed(inflater, nv_out); if (rv < 0) { goto fail; } @@ -2541,12 +2021,24 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF; + + rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, + mem); } else { inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME; + rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem); } + + if (rv != 0) { + goto fail; + } + + nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base, + inflater->namercbuf->len); + break; case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF: - rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last); + rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last); if (rv < 0) { goto fail; } @@ -2562,18 +2054,14 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, goto almost_ok; } - inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs); - - rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); - if (rv != 0) { - goto fail; - } + *inflater->namebuf.last = '\0'; + inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; break; case NGHTTP2_HD_STATE_NEWNAME_READ_NAME: - rv = hd_inflate_read(inflater, &inflater->nvbufs, in, last); + rv = hd_inflate_read(inflater, &inflater->namebuf, in, last); if (rv < 0) { goto fail; } @@ -2588,12 +2076,8 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, goto almost_ok; } - inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs); - - rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); - if (rv != 0) { - goto fail; - } + *inflater->namebuf.last = '\0'; + inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf); inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN; @@ -2625,15 +2109,27 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; + + rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, + mem); } else { inflater->state = NGHTTP2_HD_STATE_READ_VALUE; + + rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem); + } + + if (rv != 0) { + goto fail; } + nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base, + inflater->valuercbuf->len); + busy = 1; break; case NGHTTP2_HD_STATE_READ_VALUEHUFF: - rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last); + rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last); if (rv < 0) { goto fail; } @@ -2649,15 +2145,13 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, goto almost_ok; } - rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); - if (rv != 0) { - goto fail; - } + *inflater->valuebuf.last = '\0'; + inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { - rv = hd_inflate_commit_newname(inflater, nv_out, token_out); + rv = hd_inflate_commit_newname(inflater, nv_out); } else { - rv = hd_inflate_commit_indname(inflater, nv_out, token_out); + rv = hd_inflate_commit_indname(inflater, nv_out); } if (rv != 0) { @@ -2669,7 +2163,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, return (ssize_t)(in - first); case NGHTTP2_HD_STATE_READ_VALUE: - rv = hd_inflate_read(inflater, &inflater->nvbufs, in, last); + rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last); if (rv < 0) { DEBUGF(fprintf(stderr, "inflatehd: value read failure %zd: %s\n", rv, nghttp2_strerror((int)rv))); @@ -2686,15 +2180,13 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, goto almost_ok; } - rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0'); - if (rv != 0) { - goto fail; - } + *inflater->valuebuf.last = '\0'; + inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf); if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) { - rv = hd_inflate_commit_newname(inflater, nv_out, token_out); + rv = hd_inflate_commit_newname(inflater, nv_out); } else { - rv = hd_inflate_commit_indname(inflater, nv_out, token_out); + rv = hd_inflate_commit_indname(inflater, nv_out); } if (rv != 0) { @@ -2828,7 +2320,7 @@ static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context, return NULL; } - return &nghttp2_hd_table_get(context, idx)->nv; + return nghttp2_hd_table_get2(context, idx); } size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) { diff --git a/epan/nghttp2/nghttp2_hd.h b/epan/nghttp2/nghttp2_hd.h index b942d93c23..6fb0083dc8 100644 --- a/epan/nghttp2/nghttp2_hd.h +++ b/epan/nghttp2/nghttp2_hd.h @@ -34,6 +34,7 @@ #include "nghttp2_hd_huffman.h" #include "nghttp2_buf.h" #include "nghttp2_mem.h" +#include "nghttp2_rcbuf.h" #define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE #define NGHTTP2_HD_ENTRY_OVERHEAD 32 @@ -105,88 +106,36 @@ typedef enum { NGHTTP2_TOKEN_VARY = 58, NGHTTP2_TOKEN_VIA = 59, NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60, - NGHTTP2_TOKEN_ACCEPT_CH, - NGHTTP2_TOKEN_ACCEPT_DATETIME, - NGHTTP2_TOKEN_ACCEPT_FEATURES, - NGHTTP2_TOKEN_ACCEPT_PATCH, - NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS, - NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS, - NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS, - NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS, - NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE, - NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS, - NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD, - NGHTTP2_TOKEN_ALT_SVC, - NGHTTP2_TOKEN_ALTERNATES, + NGHTTP2_TOKEN_TE, NGHTTP2_TOKEN_CONNECTION, - NGHTTP2_TOKEN_CONTENT_MD5, - NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY, - NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY, - NGHTTP2_TOKEN_DNT, - NGHTTP2_TOKEN_FORWARDED, - NGHTTP2_TOKEN_FRONT_END_HTTPS, NGHTTP2_TOKEN_KEEP_ALIVE, - NGHTTP2_TOKEN_LAST_EVENT_ID, - NGHTTP2_TOKEN_NEGOTIATE, - NGHTTP2_TOKEN_ORIGIN, - NGHTTP2_TOKEN_P3P, - NGHTTP2_TOKEN_PRAGMA, NGHTTP2_TOKEN_PROXY_CONNECTION, - NGHTTP2_TOKEN_PUBLIC_KEY_PINS, - NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS, - NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY, - NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN, - NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL, - NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION, - NGHTTP2_TOKEN_SET_COOKIE2, - NGHTTP2_TOKEN_STATUS, - NGHTTP2_TOKEN_TCN, - NGHTTP2_TOKEN_TE, - NGHTTP2_TOKEN_TRAILER, - NGHTTP2_TOKEN_TSV, NGHTTP2_TOKEN_UPGRADE, - NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS, - NGHTTP2_TOKEN_VARIANT_VARY, - NGHTTP2_TOKEN_WARNING, - NGHTTP2_TOKEN_X_API_VERSION, - NGHTTP2_TOKEN_X_ATT_DEVICEID, - NGHTTP2_TOKEN_X_CACHE, - NGHTTP2_TOKEN_X_CACHE_LOOKUP, - NGHTTP2_TOKEN_X_CONTENT_DURATION, - NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY, - NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS, - NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL, - NGHTTP2_TOKEN_X_FORWARDED_FOR, - NGHTTP2_TOKEN_X_FORWARDED_HOST, - NGHTTP2_TOKEN_X_FORWARDED_PROTO, - NGHTTP2_TOKEN_X_FRAME_OPTIONS, - NGHTTP2_TOKEN_X_POWERED_BY, - NGHTTP2_TOKEN_X_REQUESTED_WITH, - NGHTTP2_TOKEN_X_UA_COMPATIBLE, - NGHTTP2_TOKEN_X_WAP_PROFILE, - NGHTTP2_TOKEN_X_WEBKIT_CSP, - NGHTTP2_TOKEN_X_XSS_PROTECTION, } nghttp2_token; -typedef enum { - NGHTTP2_HD_FLAG_NONE = 0, - /* Indicates name was dynamically allocated and must be freed */ - NGHTTP2_HD_FLAG_NAME_ALLOC = 1, - /* Indicates value was dynamically allocated and must be freed */ - NGHTTP2_HD_FLAG_VALUE_ALLOC = 1 << 1, - /* Indicates that the name was gifted to the entry and no copying - necessary. */ - NGHTTP2_HD_FLAG_NAME_GIFT = 1 << 2, - /* Indicates that the value was gifted to the entry and no copying - necessary. */ - NGHTTP2_HD_FLAG_VALUE_GIFT = 1 << 3 -} nghttp2_hd_flags; - struct nghttp2_hd_entry; typedef struct nghttp2_hd_entry nghttp2_hd_entry; +typedef struct { + /* The buffer containing header field name. NULL-termination is + guaranteed. */ + nghttp2_rcbuf *name; + /* The buffer containing header field value. NULL-termination is + guaranteed. */ + nghttp2_rcbuf *value; + /* nghttp2_token value for name. It could be -1 if we have no token + for that header field name. */ + int32_t token; + /* Bitwise OR of one or more of nghttp2_nv_flag. */ + uint8_t flags; +} nghttp2_hd_nv; + struct nghttp2_hd_entry { - nghttp2_nv nv; + /* The header field name/value pair */ + nghttp2_hd_nv nv; + /* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry + APIs to keep backward compatibility. */ + nghttp2_nv cnv; /* The next entry which shares same bucket in hash table. */ nghttp2_hd_entry *next; /* The sequence number. We will increment it by one whenever we @@ -194,14 +143,17 @@ struct nghttp2_hd_entry { uint32_t seq; /* The hash value for header name (nv.name). */ uint32_t hash; - /* nghttp2_token value for nv.name. It could be -1 if we have no - token for that header field name. */ - int token; - /* Reference count */ - uint8_t ref; - uint8_t flags; }; +/* The entry used for static header table. */ +typedef struct { + nghttp2_rcbuf name; + nghttp2_rcbuf value; + nghttp2_nv cnv; + int32_t token; + uint32_t hash; +} nghttp2_hd_static_entry; + typedef struct { nghttp2_hd_entry **buffer; size_t mask; @@ -275,24 +227,18 @@ struct nghttp2_hd_deflater { struct nghttp2_hd_inflater { nghttp2_hd_context ctx; - /* header buffer */ - nghttp2_bufs nvbufs; /* Stores current state of huffman decoding */ nghttp2_hd_huff_decode_context huff_decode_ctx; - /* Pointer to the nghttp2_hd_entry which is used current header - emission. This is required because in some cases the - ent_keep->ref == 0 and we have to keep track of it. */ - nghttp2_hd_entry *ent_keep; - /* Pointer to the name/value pair buffer which is used in the - current header emission. */ - uint8_t *nv_keep; + /* header buffer */ + nghttp2_buf namebuf, valuebuf; + nghttp2_rcbuf *namercbuf, *valuercbuf; + /* Pointer to the name/value pair which are used in the current + header emission. */ + nghttp2_rcbuf *nv_name_keep, *nv_value_keep; /* The number of bytes to read */ size_t left; /* The index in indexed repr or indexed name */ size_t index; - /* The length of new name encoded in literal. For huffman encoded - string, this is the length after it is decoded. */ - size_t newnamelen; /* The maximum header table size the inflater supports. This is the same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ size_t settings_hd_table_bufsize_max; @@ -312,24 +258,16 @@ struct nghttp2_hd_inflater { }; /* - * Initializes the |ent| members. If NGHTTP2_HD_FLAG_NAME_ALLOC bit - * set in the |flags|, the content pointed by the |name| with length - * |namelen| is copied. Likewise, if NGHTTP2_HD_FLAG_VALUE_ALLOC bit - * set in the |flags|, the content pointed by the |value| with length - * |valuelen| is copied. The |token| is enum number looked up by - * |name|. It could be -1 if we don't have that enum value. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. + * Initializes the |ent| members. The reference counts of nv->name + * and nv->value are increased by one for each. */ -int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name, - size_t namelen, uint8_t *value, size_t valuelen, - int token, nghttp2_mem *mem); +void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv); -void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem); +/* + * This function decreases the reference counts of nv->name and + * nv->value. + */ +void nghttp2_hd_entry_free(nghttp2_hd_entry *ent); /* * Initializes |deflater| for deflating name/values pairs. @@ -410,16 +348,14 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem); void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater); /* - * Similar to nghttp2_hd_inflate_hd(), but this takes additional - * output parameter |token|. On successful header emission, it - * contains nghttp2_token value for nv_out->name. It could be -1 if - * we don't have enum value for the name. Other than that return - * values and semantics are the same as nghttp2_hd_inflate_hd(). + * Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv + * instead of nghttp2_nv as output parameter |nv_out|. Other than + * that return values and semantics are the same as + * nghttp2_hd_inflate_hd(). */ -ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, - nghttp2_nv *nv_out, int *inflate_flags, - int *token, 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, @@ -433,8 +369,7 @@ int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size); /* For unittesting purpose */ -nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context, - size_t index); +nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index); /* For unittesting purpose */ ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final, @@ -470,11 +405,10 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx); /* - * Decodes the given data |src| with length |srclen|. The |ctx| must + * Decodes the given data |src| with length |srclen|. The |ctx| must * be initialized by nghttp2_hd_huff_decode_context_init(). The result - * will be added to |dest|. This function may expand |dest| as - * needed. The caller is responsible to release the memory of |dest| - * by calling nghttp2_bufs_free(). + * will be written to |buf|. This function assumes that |buf| has the + * enough room to store the decoded byte string. * * The caller must set the |final| to nonzero if the given input is * the final block. @@ -486,13 +420,11 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx); * * NGHTTP2_ERR_NOMEM * Out of memory. - * NGHTTP2_ERR_BUFFER_ERROR - * Maximum buffer capacity size exceeded. * NGHTTP2_ERR_HEADER_COMP * Decoding process has failed. */ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, - nghttp2_bufs *bufs, const uint8_t *src, + nghttp2_buf *buf, const uint8_t *src, size_t srclen, int final); #endif /* NGHTTP2_HD_H */ diff --git a/epan/nghttp2/nghttp2_hd_huffman.c b/epan/nghttp2/nghttp2_hd_huffman.c index 48638b7527..3fb0d8863d 100644 --- a/epan/nghttp2/nghttp2_hd_huffman.c +++ b/epan/nghttp2/nghttp2_hd_huffman.c @@ -166,31 +166,10 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { ctx->accept = 1; } -/* Use macro to make the code simpler..., but error case is tricky. - We spent most of the CPU in decoding, so we are doing this - thing. */ -#define hd_huff_decode_sym_emit(bufs, sym, avail) \ - do { \ - if ((avail)) { \ - nghttp2_bufs_fast_addb((bufs), (sym)); \ - --(avail); \ - } else { \ - rv = nghttp2_bufs_addb((bufs), (sym)); \ - if (rv != 0) { \ - return rv; \ - } \ - (avail) = nghttp2_bufs_cur_avail((bufs)); \ - } \ - } while (0) - ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, - nghttp2_bufs *bufs, const uint8_t *src, + nghttp2_buf *buf, const uint8_t *src, size_t srclen, int final) { size_t i; - int rv; - size_t avail; - - avail = nghttp2_bufs_cur_avail(bufs); /* We use the decoding algorithm described in http://graphics.ics.uci.edu/pub/Prefix.pdf */ @@ -202,8 +181,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, return NGHTTP2_ERR_HEADER_COMP; } if (t->flags & NGHTTP2_HUFF_SYM) { - /* this is macro, and may return from this function on error */ - hd_huff_decode_sym_emit(bufs, t->sym, avail); + *buf->last++ = t->sym; } t = &huff_decode_table[t->state][src[i] & 0xf]; @@ -211,8 +189,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, return NGHTTP2_ERR_HEADER_COMP; } if (t->flags & NGHTTP2_HUFF_SYM) { - /* this is macro, and may return from this function on error */ - hd_huff_decode_sym_emit(bufs, t->sym, avail); + *buf->last++ = t->sym; } ctx->state = t->state; diff --git a/epan/nghttp2/nghttp2_helper.c b/epan/nghttp2/nghttp2_helper.c index 4f839e49fe..ada3b0ff5e 100644 --- a/epan/nghttp2/nghttp2_helper.c +++ b/epan/nghttp2/nghttp2_helper.c @@ -451,3 +451,38 @@ uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) { return dest + len; } + +const char *nghttp2_http2_strerror(uint32_t error_code) { + switch (error_code) { + case NGHTTP2_NO_ERROR: + return "NO_ERROR"; + case NGHTTP2_PROTOCOL_ERROR: + return "PROTOCOL_ERROR"; + case NGHTTP2_INTERNAL_ERROR: + return "INTERNAL_ERROR"; + case NGHTTP2_FLOW_CONTROL_ERROR: + return "FLOW_CONTROL_ERROR"; + case NGHTTP2_SETTINGS_TIMEOUT: + return "SETTINGS_TIMEOUT"; + case NGHTTP2_STREAM_CLOSED: + return "STREAM_CLOSED"; + case NGHTTP2_FRAME_SIZE_ERROR: + return "FRAME_SIZE_ERROR"; + case NGHTTP2_REFUSED_STREAM: + return "REFUSED_STREAM"; + case NGHTTP2_CANCEL: + return "CANCEL"; + case NGHTTP2_COMPRESSION_ERROR: + return "COMPRESSION_ERROR"; + case NGHTTP2_CONNECT_ERROR: + return "CONNECT_ERROR"; + case NGHTTP2_ENHANCE_YOUR_CALM: + return "ENHANCE_YOUR_CALM"; + case NGHTTP2_INADEQUATE_SECURITY: + return "INADEQUATE_SECURITY"; + case NGHTTP2_HTTP_1_1_REQUIRED: + return "HTTP_1_1_REQUIRED"; + default: + return "unknown"; + } +} diff --git a/epan/nghttp2/nghttp2_mem.c b/epan/nghttp2/nghttp2_mem.c index e7d5aae3b8..317363a70d 100644 --- a/epan/nghttp2/nghttp2_mem.c +++ b/epan/nghttp2/nghttp2_mem.c @@ -52,6 +52,10 @@ void nghttp2_mem_free(nghttp2_mem *mem, void *ptr) { mem->free(ptr, mem->mem_user_data); } +void nghttp2_mem_free2(nghttp2_free free, void *ptr, void *mem_user_data) { + free(ptr, mem_user_data); +} + void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size) { return mem->calloc(nmemb, size, mem->mem_user_data); } diff --git a/epan/nghttp2/nghttp2_mem.h b/epan/nghttp2/nghttp2_mem.h index 47e3fcdfd0..55b187e8e1 100644 --- a/epan/nghttp2/nghttp2_mem.h +++ b/epan/nghttp2/nghttp2_mem.h @@ -38,6 +38,7 @@ nghttp2_mem *nghttp2_mem_default(void); |mem|. */ void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size); void nghttp2_mem_free(nghttp2_mem *mem, void *ptr); +void nghttp2_mem_free2(nghttp2_free free, void *ptr, void *mem_user_data); void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size); void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size); diff --git a/epan/nghttp2/nghttp2_rcbuf.c b/epan/nghttp2/nghttp2_rcbuf.c new file mode 100644 index 0000000000..5daef07b7d --- /dev/null +++ b/epan/nghttp2/nghttp2_rcbuf.c @@ -0,0 +1,99 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2016 Tatsuhiro Tsujikawa + * + * 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 "nghttp2_rcbuf.h" + +#include <string.h> +#include <assert.h> + +#include "nghttp2_mem.h" + +int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, + nghttp2_mem *mem) { + uint8_t *p; + + p = (uint8_t *)nghttp2_mem_malloc(mem, sizeof(nghttp2_rcbuf) + size); + if (p == NULL) { + return NGHTTP2_ERR_NOMEM; + } + + *rcbuf_ptr = (nghttp2_rcbuf *)(void *)p; + + (*rcbuf_ptr)->mem_user_data = mem->mem_user_data; + (*rcbuf_ptr)->free = mem->free; + (*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf); + (*rcbuf_ptr)->len = size; + (*rcbuf_ptr)->ref = 1; + + return 0; +} + +int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, + size_t srclen, nghttp2_mem *mem) { + int rv; + + rv = nghttp2_rcbuf_new(rcbuf_ptr, srclen + 1, mem); + if (rv != 0) { + return rv; + } + + memcpy((*rcbuf_ptr)->base, src, srclen); + + (*rcbuf_ptr)->len = srclen; + (*rcbuf_ptr)->base[srclen] = '\0'; + + return 0; +} + +/* + * Frees |rcbuf| itself, regardless of its reference cout. + */ +void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf) { + nghttp2_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data); +} + +void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf) { + if (rcbuf->ref == -1) { + return; + } + + ++rcbuf->ref; +} + +void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf) { + if (rcbuf == NULL || rcbuf->ref == -1) { + return; + } + + assert(rcbuf->ref > 0); + + if (--rcbuf->ref == 0) { + nghttp2_rcbuf_del(rcbuf); + } +} + +nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) { + nghttp2_vec res = {rcbuf->base, rcbuf->len}; + return res; +} diff --git a/epan/nghttp2/nghttp2_rcbuf.h b/epan/nghttp2/nghttp2_rcbuf.h new file mode 100644 index 0000000000..aba4b60d4a --- /dev/null +++ b/epan/nghttp2/nghttp2_rcbuf.h @@ -0,0 +1,80 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2016 Tatsuhiro Tsujikawa + * + * 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. + */ +#ifndef NGHTTP2_RCBUF_H +#define NGHTTP2_RCBUF_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <nghttp2.h> + +struct nghttp2_rcbuf { + /* custom memory allocator belongs to the mem parameter when + creating this object. */ + void *mem_user_data; + nghttp2_free free; + /* The pointer to the underlying buffer */ + uint8_t *base; + /* Size of buffer pointed by |base|. */ + size_t len; + /* Reference count */ + int32_t ref; +}; + +/* + * Allocates nghttp2_rcbuf object with |size| as initial buffer size. + * When the function succeeds, the reference count becomes 1. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM: + * Out of memory. + */ +int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem); + +/* + * Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of + * length |srclen|. This function allocates additional byte at the + * end and puts '\0' into it, so that the resulting buffer could be + * used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to + * |srclen|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM: + * Out of memory. + */ +int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, + size_t srclen, nghttp2_mem *mem); + +/* + * Frees |rcbuf| itself, regardless of its reference cout. + */ +void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf); + +#endif /* NGHTTP2_RCBUF_H */ diff --git a/epan/nghttp2/nghttp2ver.h b/epan/nghttp2/nghttp2ver.h index 58472c3276..6638235b43 100644 --- a/epan/nghttp2/nghttp2ver.h +++ b/epan/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.8.0" +#define NGHTTP2_VERSION "1.11.1" /** * @macro @@ -37,6 +37,6 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define NGHTTP2_VERSION_NUM 0x010800 +#define NGHTTP2_VERSION_NUM 0x010b01 #endif /* NGHTTP2VER_H */ |