aboutsummaryrefslogtreecommitdiffstats
path: root/epan/nghttp2
diff options
context:
space:
mode:
authorAlexis La Goutte <alexis.lagoutte@gmail.com>2015-04-29 23:12:12 +0200
committerAlexis La Goutte <alexis.lagoutte@gmail.com>2015-04-30 20:02:43 +0000
commitd0e34312b8f401d10f35f49710cbabbd96f59c38 (patch)
treebbe3923535405756a0b6a999ad42c9d5eda0fede /epan/nghttp2
parent12ec6c4482950dafab1701e709a0a0fee37e399c (diff)
HTTP2: Update to libnghttp2 0.7.13
Change-Id: I69589a90077a9b009f2e1a45531059ebd61a0450 Reviewed-on: https://code.wireshark.org/review/8242 Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com> Reviewed-by: Pascal Quantin <pascal.quantin@gmail.com> Reviewed-by: Alexis La Goutte <alexis.lagoutte@gmail.com>
Diffstat (limited to 'epan/nghttp2')
-rw-r--r--epan/nghttp2/nghttp2.h730
-rw-r--r--epan/nghttp2/nghttp2_buf.c40
-rw-r--r--epan/nghttp2/nghttp2_buf.h16
-rw-r--r--epan/nghttp2/nghttp2_hd.c1001
-rw-r--r--epan/nghttp2/nghttp2_hd.h106
-rw-r--r--epan/nghttp2/nghttp2_hd_huffman.c61
-rw-r--r--epan/nghttp2/nghttp2_helper.h4
-rw-r--r--epan/nghttp2/nghttp2_int.h5
-rw-r--r--epan/nghttp2/nghttp2_net.h53
-rw-r--r--epan/nghttp2/nghttp2ver.h4
10 files changed, 1434 insertions, 586 deletions
diff --git a/epan/nghttp2/nghttp2.h b/epan/nghttp2/nghttp2.h
index e723ef430a..a32104ad64 100644
--- a/epan/nghttp2/nghttp2.h
+++ b/epan/nghttp2/nghttp2.h
@@ -27,6 +27,12 @@
#include "config.h"
+/* Define WIN32 when build target is Win32 API (borrowed from
+ libcurl) */
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#define WIN32
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -37,6 +43,14 @@ extern "C" {
#include "nghttp2ver.h"
+#ifdef NGHTTP2_STATICLIB
+#define NGHTTP2_EXTERN
+#elif defined(WIN32)
+#define NGHTTP2_EXTERN __declspec(dllexport)
+#else /* !defined(WIN32) */
+#define NGHTTP2_EXTERN
+#endif /* !defined(WIN32) */
+
/**
* @macro
*
@@ -229,8 +243,9 @@ typedef enum {
*/
NGHTTP2_ERR_UNSUPPORTED_VERSION = -503,
/**
- * Used as a return value from :type:`nghttp2_send_callback` and
- * :type:`nghttp2_recv_callback` to indicate that the operation
+ * Used as a return value from :type:`nghttp2_send_callback`,
+ * :type:`nghttp2_recv_callback` and
+ * :type:`nghttp2_send_data_callback` to indicate that the operation
* would block.
*/
NGHTTP2_ERR_WOULDBLOCK = -504,
@@ -404,21 +419,27 @@ typedef enum {
*/
typedef struct {
/**
- * The |name| byte string, which is not necessarily ``NULL``
- * terminated.
+ * The |name| byte string. If this struct is presented from library
+ * (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is
+ * guaranteed to be NULL-terminated. When application is
+ * constructing this struct, |name| is not required to be
+ * NULL-terminated.
*/
uint8_t *name;
/**
- * The |value| byte string, which is not necessarily ``NULL``
- * terminated.
+ * The |value| byte string. If this struct is presented from
+ * library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value|
+ * is guaranteed to be NULL-terminated. When application is
+ * constructing this struct, |value| is not required to be
+ * NULL-terminated.
*/
uint8_t *value;
/**
- * The length of the |name|.
+ * The length of the |name|, excluding terminating NULL.
*/
size_t namelen;
/**
- * The length of the |value|.
+ * The length of the |value|, excluding terminating NULL.
*/
size_t valuelen;
/**
@@ -470,7 +491,9 @@ typedef enum {
*/
NGHTTP2_WINDOW_UPDATE = 0x08,
/**
- * The CONTINUATION frame.
+ * The CONTINUATION frame. This frame type won't be passed to any
+ * callbacks because the library processes this frame type and its
+ * preceding HEADERS/PUSH_PROMISE as a single frame.
*/
NGHTTP2_CONTINUATION = 0x09
} nghttp2_frame_type;
@@ -684,7 +707,19 @@ typedef enum {
/**
* Indicates EOF was sensed.
*/
- NGHTTP2_DATA_FLAG_EOF = 0x01
+ NGHTTP2_DATA_FLAG_EOF = 0x01,
+ /**
+ * Indicates that END_STREAM flag must not be set even if
+ * NGHTTP2_DATA_FLAG_EOF is set. Usually this flag is used to send
+ * trailer header fields with `nghttp2_submit_request()` or
+ * `nghttp2_submit_response()`.
+ */
+ NGHTTP2_DATA_FLAG_NO_END_STREAM = 0x02,
+ /**
+ * Indicates that application will send complete DATA frame in
+ * :type:`nghttp2_send_data_callback`.
+ */
+ NGHTTP2_DATA_FLAG_NO_COPY = 0x04
} nghttp2_data_flag;
/**
@@ -697,6 +732,30 @@ typedef enum {
* them in |buf| and return number of data stored in |buf|. If EOF is
* reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|.
*
+ * Sometime it is desirable to avoid copying data into |buf| and let
+ * application to send data directly. To achieve this, set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly
+ * other flags, just like when we do copy), and return the number of
+ * bytes to send without copying data into |buf|. The library, seeing
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
+ * :type:`nghttp2_send_data_callback`. The application must send
+ * complete DATA frame in that callback.
+ *
+ * If this callback is set by `nghttp2_submit_request()`,
+ * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and
+ * `nghttp2_submit_data()` with flag parameter
+ * :enum:`NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA
+ * frame will have END_STREAM flag set. Usually, this is expected
+ * behaviour and all are fine. One exception is send trailer header
+ * fields. You cannot send trailers after sending frame with
+ * END_STREAM set. To avoid this problem, one can set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set
+ * END_STREAM in DATA frame. Then application can use
+ * `nghttp2_submit_trailer()` to send trailers.
+ * `nghttp2_submit_trailer()` can be called inside this callback.
+ *
* If the application wants to postpone DATA frames (e.g.,
* asynchronous I/O, or reading data blocks for long time), it is
* achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
@@ -1150,6 +1209,47 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
/**
* @functypedef
*
+ * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
+ * used in :type:`nghttp2_data_source_read_callback` to send complete
+ * DATA frame.
+ *
+ * The |frame| is a DATA frame to send. The |framehd| is the
+ * serialized frame header (9 bytes). The |length| is the length of
+ * application data to send (this does not include padding). The
+ * |source| is the same pointer passed to
+ * :type:`nghttp2_data_source_read_callback`.
+ *
+ * The application first must send frame header |framehd| of length 9
+ * bytes. If ``frame->padlen > 0``, send 1 byte of value
+ * ``frame->padlen - 1``. Then send exactly |length| bytes of
+ * application data. Finally, if ``frame->padlen > 0``, send
+ * ``frame->padlen - 1`` bytes of zero (they are padding).
+ *
+ * The application has to send complete DATA frame in this callback.
+ * If all data were written successfully, return 0.
+ *
+ * If it cannot send it all, just return
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback
+ * with the same parameters later (It is recommended to send complete
+ * DATA frame at once in this function to deal with error; if partial
+ * frame data has already sent, it is impossible to send another data
+ * in that state, and all we can do is tear down connection). If
+ * application decided to reset this stream, return
+ * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then the library
+ * will send RST_STREAM with INTERNAL_ERROR as error code. The
+ * application can also return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
+ * which will result in connection closure. Returning any other value
+ * is treated as :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ */
+typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
+ nghttp2_frame *frame,
+ const uint8_t *framehd, size_t length,
+ nghttp2_data_source *source,
+ void *user_data);
+
+/**
+ * @functypedef
+ *
* Callback function invoked when |session| wants to receive data from
* the remote peer. The implementation of this function must read at
* most |length| bytes of data and store it in |buf|. The |flags| is
@@ -1178,10 +1278,10 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
/**
* @functypedef
*
- * Callback function invoked by `nghttp2_session_recv()` when a frame
- * is received. The |user_data| pointer is the third argument passed
- * in to the call to `nghttp2_session_client_new()` or
- * `nghttp2_session_server_new()`.
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received. The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
* If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
* member of their data structure are always ``NULL`` and 0
@@ -1216,14 +1316,14 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
/**
* @functypedef
*
- * Callback function invoked by `nghttp2_session_recv()` when an
- * invalid non-DATA frame is received. The |error_code| indicates the
- * error. It is usually one of the :enum:`nghttp2_error_code` but
- * that is not guaranteed. When this callback function is invoked,
- * the library automatically submits either RST_STREAM or GOAWAY
- * frame. The |user_data| pointer is the third argument passed in to
- * the call to `nghttp2_session_client_new()` or
- * `nghttp2_session_server_new()`.
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received. The |error_code| indicates the error. It is usually one
+ * of the :enum:`nghttp2_error_code` but that is not guaranteed. When
+ * this callback function is invoked, the library automatically
+ * submits either RST_STREAM or GOAWAY frame. The |user_data| pointer
+ * is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
* If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
* member of their data structure are always ``NULL`` and 0
@@ -1231,7 +1331,7 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
*
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
- * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
@@ -1264,7 +1364,7 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)(
* region included in the input bytes.
*
* The implementation of this function must return 0 if it succeeds.
- * If nonzero is returned, it is treated as fatal error and
+ * If nonzero is returned, it is treated as fatal error, and
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
@@ -1287,7 +1387,7 @@ typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
*
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
- * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
@@ -1306,7 +1406,7 @@ typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session,
*
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
- * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
@@ -1328,7 +1428,7 @@ typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
*
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
- * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* `nghttp2_session_get_stream_user_data()` can be used to get
@@ -1358,8 +1458,9 @@ typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
*
* The implementation of this function must return 0 if it succeeds.
* If nonzero is returned, it is treated as fatal error and
- * `nghttp2_session_recv()` and `nghttp2_session_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
+ * `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
+ * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_stream_close_callback()`.
@@ -1401,13 +1502,26 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
* frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS``
* containing final response headers (non-1xx status code). The
* trailer headers also has ``frame->headers.cat ==
- * NGHTTP2_HCAT_HEADERS`` which does not containg any status code.
+ * NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
*
- * The implementation of this function must return 0 if it succeeds or
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If nonzero value other than
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, it is treated as
- * if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
+ * :type:`nghttp2_on_header_callback` and
+ * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
+ * reset the stream (promised stream if frame is PUSH_PROMISE). For
+ * critical errors, it must return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the other value is
+ * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * is returned. If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
* `nghttp2_session_mem_recv()` function will immediately return
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
@@ -1439,14 +1553,18 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
* invoked.
*
- * The |value| may be ``NULL`` if the |valuelen| is 0.
+ * Both |name| and |value| are guaranteed to be NULL-terminated. The
+ * |namelen| and |valuelen| do not include terminal NULL. If
+ * `nghttp2_option_set_no_http_messaging()` is used with nonzero
+ * value, NULL character may be included in |name| or |value| before
+ * terminating NULL.
*
* Please note that unless `nghttp2_option_set_no_http_messaging()` is
* used, nghttp2 library does perform validation against the |name|
* and the |value| using `nghttp2_check_header_name()` and
* `nghttp2_check_header_value()`. In addition to this, nghttp2
* performs vaidation based on HTTP Messaging rule, which is briefly
- * explained in `HTTP Messaging`_ section.
+ * explained in :ref:`http-messaging` section.
*
* If the application uses `nghttp2_session_mem_recv()`, it can return
* :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
@@ -1458,12 +1576,15 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* included in the input bytes.
*
* Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
- * the stream by issuing RST_STREAM with
- * :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case,
+ * :type:`nghttp2_on_header_callback` and
* :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a
* different error code is desirable, use
* `nghttp2_submit_rst_stream()` with a desired error code and then
- * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
*
* The implementation of this function must return 0 if it succeeds.
* It may return :enum:`NGHTTP2_ERR_PAUSE` or
@@ -1495,8 +1616,8 @@ typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
* ``frame->hd.length`` means no padding is added. Returning
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
- * `nghttp2_session_send()` function immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_select_padding_callback()`.
@@ -1588,7 +1709,8 @@ typedef struct nghttp2_session_callbacks nghttp2_session_callbacks;
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
+NGHTTP2_EXTERN int
+nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
/**
* @function
@@ -1596,7 +1718,8 @@ int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
* Frees any resources allocated for |callbacks|. If |callbacks| is
* ``NULL``, this function does nothing.
*/
-void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
/**
* @function
@@ -1606,7 +1729,7 @@ void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
* uses solely `nghttp2_session_mem_send()` to serialize data to
* transmit.
*/
-void nghttp2_session_callbacks_set_send_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback(
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback);
/**
@@ -1617,26 +1740,28 @@ void nghttp2_session_callbacks_set_send_callback(
* application uses solely `nghttp2_session_mem_recv()` to process
* received data.
*/
-void nghttp2_session_callbacks_set_recv_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback(
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback);
/**
* @function
*
- * Sets callback function invoked by `nghttp2_session_recv()` when a
- * frame is received.
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received.
*/
-void nghttp2_session_callbacks_set_on_frame_recv_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_recv_callback on_frame_recv_callback);
/**
* @function
*
- * Sets callback function invoked by `nghttp2_session_recv()` when an
- * invalid non-DATA frame is received.
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received.
*/
-void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback);
@@ -1646,7 +1771,7 @@ void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
* Sets callback function invoked when a chunk of data in DATA frame
* is received.
*/
-void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback);
@@ -1655,7 +1780,7 @@ void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
*
* Sets callback function invoked before a non-DATA frame is sent.
*/
-void nghttp2_session_callbacks_set_before_frame_send_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_before_frame_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_before_frame_send_callback before_frame_send_callback);
@@ -1664,7 +1789,7 @@ void nghttp2_session_callbacks_set_before_frame_send_callback(
*
* Sets callback function invoked after a frame is sent.
*/
-void nghttp2_session_callbacks_set_on_frame_send_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_send_callback on_frame_send_callback);
@@ -1674,7 +1799,7 @@ void nghttp2_session_callbacks_set_on_frame_send_callback(
* Sets callback function invoked when a non-DATA frame is not sent
* because of an error.
*/
-void nghttp2_session_callbacks_set_on_frame_not_send_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_not_send_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_frame_not_send_callback on_frame_not_send_callback);
@@ -1683,7 +1808,7 @@ void nghttp2_session_callbacks_set_on_frame_not_send_callback(
*
* Sets callback function invoked when the stream is closed.
*/
-void nghttp2_session_callbacks_set_on_stream_close_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_stream_close_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_stream_close_callback on_stream_close_callback);
@@ -1693,7 +1818,7 @@ void nghttp2_session_callbacks_set_on_stream_close_callback(
* Sets callback function invoked when the reception of header block
* in HEADERS or PUSH_PROMISE is started.
*/
-void nghttp2_session_callbacks_set_on_begin_headers_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_begin_headers_callback on_begin_headers_callback);
@@ -1703,7 +1828,7 @@ void nghttp2_session_callbacks_set_on_begin_headers_callback(
* Sets callback function invoked when a header name/value pair is
* received.
*/
-void nghttp2_session_callbacks_set_on_header_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_header_callback on_header_callback);
@@ -1714,7 +1839,7 @@ void nghttp2_session_callbacks_set_on_header_callback(
* how many padding bytes are required for the transmission of the
* given frame.
*/
-void nghttp2_session_callbacks_set_select_padding_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback(
nghttp2_session_callbacks *cbs,
nghttp2_select_padding_callback select_padding_callback);
@@ -1724,7 +1849,8 @@ void nghttp2_session_callbacks_set_select_padding_callback(
* Sets callback function determine the length allowed in
* :type:`nghttp2_data_source_read_callback`.
*/
-void nghttp2_session_callbacks_set_data_source_read_length_callback(
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_data_source_read_length_callback(
nghttp2_session_callbacks *cbs,
nghttp2_data_source_read_length_callback data_source_read_length_callback);
@@ -1733,11 +1859,22 @@ void nghttp2_session_callbacks_set_data_source_read_length_callback(
*
* Sets callback function invoked when a frame header is received.
*/
-void nghttp2_session_callbacks_set_on_begin_frame_callback(
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback(
nghttp2_session_callbacks *cbs,
nghttp2_on_begin_frame_callback on_begin_frame_callback);
/**
+ * @function
+ *
+ * Sets callback function invoked when
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :type:`nghttp2_data_source_read_callback` to avoid data copy.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
+ nghttp2_session_callbacks *cbs,
+ nghttp2_send_data_callback send_data_callback);
+
+/**
* @functypedef
*
* Custom memory allocator to replace malloc(). The |mem_user_data|
@@ -1856,7 +1993,7 @@ typedef struct nghttp2_option nghttp2_option;
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_option_new(nghttp2_option **option_ptr);
+NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
/**
* @function
@@ -1864,7 +2001,7 @@ int nghttp2_option_new(nghttp2_option **option_ptr);
* Frees any resources allocated for |option|. If |option| is
* ``NULL``, this function does nothing.
*/
-void nghttp2_option_del(nghttp2_option *option);
+NGHTTP2_EXTERN void nghttp2_option_del(nghttp2_option *option);
/**
* @function
@@ -1876,7 +2013,8 @@ void nghttp2_option_del(nghttp2_option *option);
* data. Don't use `nghttp2_submit_window_update()` for this purpose.
* By default, this option is set to zero.
*/
-void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
/**
* @function
@@ -1893,8 +2031,9 @@ void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
* overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
-void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
- uint32_t val);
+NGHTTP2_EXTERN void
+nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
+ uint32_t val);
/**
* @function
@@ -1912,7 +2051,8 @@ void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
* one, `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` will
* return error :enum:`NGHTTP2_ERR_BAD_PREFACE`, which is fatal error.
*/
-void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val);
+NGHTTP2_EXTERN void
+nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val);
/**
* @function
@@ -1920,11 +2060,12 @@ void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val);
* By default, nghttp2 library enforces subset of HTTP Messaging rules
* described in `HTTP/2 specification, section 8
* <https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-8>`_.
- * See `HTTP Messaging`_ section for details. For those applications
- * who use nghttp2 library as non-HTTP use, give nonzero to |val| to
- * disable this enforcement.
+ * See :ref:`http-messaging` section for details. For those
+ * applications who use nghttp2 library as non-HTTP use, give nonzero
+ * to |val| to disable this enforcement.
*/
-void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val);
+NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
+ int val);
/**
* @function
@@ -1947,9 +2088,10 @@ void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val);
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_client_new(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data);
+NGHTTP2_EXTERN int
+nghttp2_session_client_new(nghttp2_session **session_ptr,
+ const nghttp2_session_callbacks *callbacks,
+ void *user_data);
/**
* @function
@@ -1972,9 +2114,10 @@ int nghttp2_session_client_new(nghttp2_session **session_ptr,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_server_new(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data);
+NGHTTP2_EXTERN int
+nghttp2_session_server_new(nghttp2_session **session_ptr,
+ const nghttp2_session_callbacks *callbacks,
+ void *user_data);
/**
* @function
@@ -1997,9 +2140,10 @@ int nghttp2_session_server_new(nghttp2_session **session_ptr,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_client_new2(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data, const nghttp2_option *option);
+NGHTTP2_EXTERN int
+nghttp2_session_client_new2(nghttp2_session **session_ptr,
+ const nghttp2_session_callbacks *callbacks,
+ void *user_data, const nghttp2_option *option);
/**
* @function
@@ -2022,9 +2166,10 @@ int nghttp2_session_client_new2(nghttp2_session **session_ptr,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_server_new2(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data, const nghttp2_option *option);
+NGHTTP2_EXTERN int
+nghttp2_session_server_new2(nghttp2_session **session_ptr,
+ const nghttp2_session_callbacks *callbacks,
+ void *user_data, const nghttp2_option *option);
/**
* @function
@@ -2047,10 +2192,9 @@ int nghttp2_session_server_new2(nghttp2_session **session_ptr,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_client_new3(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data, const nghttp2_option *option,
- nghttp2_mem *mem);
+NGHTTP2_EXTERN int nghttp2_session_client_new3(
+ nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+ void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
/**
* @function
@@ -2073,10 +2217,9 @@ int nghttp2_session_client_new3(nghttp2_session **session_ptr,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_server_new3(nghttp2_session **session_ptr,
- const nghttp2_session_callbacks *callbacks,
- void *user_data, const nghttp2_option *option,
- nghttp2_mem *mem);
+NGHTTP2_EXTERN int nghttp2_session_server_new3(
+ nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+ void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
/**
* @function
@@ -2084,7 +2227,7 @@ int nghttp2_session_server_new3(nghttp2_session **session_ptr,
* Frees any resources allocated for |session|. If |session| is
* ``NULL``, this function does nothing.
*/
-void nghttp2_session_del(nghttp2_session *session);
+NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
/**
* @function
@@ -2133,7 +2276,7 @@ void nghttp2_session_del(nghttp2_session *session);
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
*/
-int nghttp2_session_send(nghttp2_session *session);
+NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
/**
* @function
@@ -2165,8 +2308,8 @@ int nghttp2_session_send(nghttp2_session *session);
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-ssize_t nghttp2_session_mem_send(nghttp2_session *session,
- const uint8_t **data_ptr);
+NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
+ const uint8_t **data_ptr);
/**
* @function
@@ -2231,7 +2374,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
* when |session| was configured as server and
* `nghttp2_option_set_recv_client_preface()` is used.
*/
-int nghttp2_session_recv(nghttp2_session *session);
+NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
/**
* @function
@@ -2266,8 +2409,9 @@ int nghttp2_session_recv(nghttp2_session *session);
* when |session| was configured as server and
* `nghttp2_option_set_recv_client_preface()` is used.
*/
-ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
- size_t inlen);
+NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
+ const uint8_t *in,
+ size_t inlen);
/**
* @function
@@ -2283,7 +2427,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id);
+NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
+ int32_t stream_id);
/**
* @function
@@ -2295,7 +2440,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id);
* `nghttp2_session_want_write()` return 0, the application should
* drop the connection.
*/
-int nghttp2_session_want_read(nghttp2_session *session);
+NGHTTP2_EXTERN int nghttp2_session_want_read(nghttp2_session *session);
/**
* @function
@@ -2307,7 +2452,7 @@ int nghttp2_session_want_read(nghttp2_session *session);
* `nghttp2_session_want_write()` return 0, the application should
* drop the connection.
*/
-int nghttp2_session_want_write(nghttp2_session *session);
+NGHTTP2_EXTERN int nghttp2_session_want_write(nghttp2_session *session);
/**
* @function
@@ -2321,8 +2466,9 @@ int nghttp2_session_want_write(nghttp2_session *session);
* ``NULL``. If the stream does not exist, this function returns
* ``NULL``.
*/
-void *nghttp2_session_get_stream_user_data(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN void *
+nghttp2_session_get_stream_user_data(nghttp2_session *session,
+ int32_t stream_id);
/**
* @function
@@ -2342,9 +2488,9 @@ void *nghttp2_session_get_stream_user_data(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The stream does not exist
*/
-int nghttp2_session_set_stream_user_data(nghttp2_session *session,
- int32_t stream_id,
- void *stream_user_data);
+NGHTTP2_EXTERN int
+nghttp2_session_set_stream_user_data(nghttp2_session *session,
+ int32_t stream_id, void *stream_user_data);
/**
* @function
@@ -2352,7 +2498,8 @@ int nghttp2_session_set_stream_user_data(nghttp2_session *session,
* Returns the number of frames in the outbound queue. This does not
* include the deferred DATA frames.
*/
-size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
+NGHTTP2_EXTERN size_t
+ nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
/**
* @function
@@ -2368,9 +2515,8 @@ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
*
* This function returns -1 if it fails.
*/
-int32_t
-nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_recv_data_length(
+ nghttp2_session *session, int32_t stream_id);
/**
* @function
@@ -2382,9 +2528,8 @@ nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session,
*
* This function returns -1 if it fails.
*/
-int32_t
-nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_local_window_size(
+ nghttp2_session *session, int32_t stream_id);
/**
* @function
@@ -2400,8 +2545,8 @@ nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
*
* This function returns -1 if it fails.
*/
-int32_t
-nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
+NGHTTP2_EXTERN int32_t
+ nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
/**
* @function
@@ -2413,8 +2558,8 @@ nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
*
* This function returns -1 if it fails.
*/
-int32_t
-nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
+NGHTTP2_EXTERN int32_t
+ nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
/**
* @function
@@ -2430,8 +2575,9 @@ nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
*
* This function returns -1 if it fails.
*/
-int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN int32_t
+ nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
+ int32_t stream_id);
/**
* @function
@@ -2440,7 +2586,8 @@ int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
*
* This function always succeeds.
*/
-int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session);
+NGHTTP2_EXTERN int32_t
+ nghttp2_session_get_remote_window_size(nghttp2_session *session);
/**
* @function
@@ -2448,8 +2595,9 @@ int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session);
* Returns 1 if local peer half closed the given stream |stream_id|.
* Returns 0 if it did not. Returns -1 if no such stream exists.
*/
-int nghttp2_session_get_stream_local_close(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_local_close(nghttp2_session *session,
+ int32_t stream_id);
/**
* @function
@@ -2457,8 +2605,9 @@ int nghttp2_session_get_stream_local_close(nghttp2_session *session,
* Returns 1 if remote peer half closed the given stream |stream_id|.
* Returns 0 if it did not. Returns -1 if no such stream exists.
*/
-int nghttp2_session_get_stream_remote_close(nghttp2_session *session,
- int32_t stream_id);
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_remote_close(nghttp2_session *session,
+ int32_t stream_id);
/**
* @function
@@ -2486,8 +2635,8 @@ int nghttp2_session_get_stream_remote_close(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_session_terminate_session(nghttp2_session *session,
- uint32_t error_code);
+NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
+ uint32_t error_code);
/**
* @function
@@ -2515,9 +2664,9 @@ int nghttp2_session_terminate_session(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |last_stream_id| is invalid.
*/
-int nghttp2_session_terminate_session2(nghttp2_session *session,
- int32_t last_stream_id,
- uint32_t error_code);
+NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
+ int32_t last_stream_id,
+ uint32_t error_code);
/**
* @function
@@ -2554,7 +2703,7 @@ int nghttp2_session_terminate_session2(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_INVALID_STATE`
* The |session| is initialized as client.
*/
-int nghttp2_submit_shutdown_notice(nghttp2_session *session);
+NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
/**
* @function
@@ -2563,8 +2712,9 @@ int nghttp2_submit_shutdown_notice(nghttp2_session *session);
* The |id| must be one of values defined in
* :enum:`nghttp2_settings_id`.
*/
-uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
- nghttp2_settings_id id);
+NGHTTP2_EXTERN uint32_t
+ nghttp2_session_get_remote_settings(nghttp2_session *session,
+ nghttp2_settings_id id);
/**
* @function
@@ -2578,10 +2728,12 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
*
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |next_stream_id| is strictly less than the value
- * `nghttp2_session_get_next_stream_id()` returns.
+ * `nghttp2_session_get_next_stream_id()` returns; or
+ * |next_stream_id| is invalid (e.g., even integer for client, or
+ * odd integer for server).
*/
-int nghttp2_session_set_next_stream_id(nghttp2_session *session,
- int32_t next_stream_id);
+NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session,
+ int32_t next_stream_id);
/**
* @function
@@ -2590,14 +2742,19 @@ int nghttp2_session_set_next_stream_id(nghttp2_session *session,
* uint32_t. If we run out of stream ID for this session, this
* function returns 1 << 31.
*/
-uint32_t nghttp2_session_get_next_stream_id(nghttp2_session *session);
+NGHTTP2_EXTERN uint32_t
+ nghttp2_session_get_next_stream_id(nghttp2_session *session);
/**
* @function
*
* Tells the |session| that |size| bytes for a stream denoted by
* |stream_id| were consumed by application and are ready to
- * WINDOW_UPDATE. This function is intended to be used without
+ * WINDOW_UPDATE. The consumed bytes are counted towards both
+ * connection and stream level WINDOW_UPDATE (see
+ * `nghttp2_session_consume_connection()` and
+ * `nghttp2_session_consume_stream()` to update consumption
+ * independently). This function is intended to be used without
* automatic window update (see
* `nghttp2_option_set_no_auto_window_update()`).
*
@@ -2611,8 +2768,49 @@ uint32_t nghttp2_session_get_next_stream_id(nghttp2_session *session);
* :enum:`NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
-int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id,
- size_t size);
+NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
+ int32_t stream_id, size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for connection level. Note that
+ * HTTP/2 maintains connection and stream level flow control windows
+ * independently.
+ *
+ * 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`
+ * Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
+ size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for stream denoted by |stream_id|.
+ * Note that HTTP/2 maintains connection and stream level flow control
+ * windows independently.
+ *
+ * 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_ARGUMENT`
+ * The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
+ int32_t stream_id,
+ size_t size);
/**
* @function
@@ -2650,9 +2848,10 @@ int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id,
* :enum:`NGHTTP2_ERR_PROTO`
* The stream ID 1 is already used or closed; or is not available.
*/
-int nghttp2_session_upgrade(nghttp2_session *session,
- const uint8_t *settings_payload,
- size_t settings_payloadlen, void *stream_user_data);
+NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
+ const uint8_t *settings_payload,
+ size_t settings_payloadlen,
+ void *stream_user_data);
/**
* @function
@@ -2675,9 +2874,9 @@ int nghttp2_session_upgrade(nghttp2_session *session,
* :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
-ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
- const nghttp2_settings_entry *iv,
- size_t niv);
+NGHTTP2_EXTERN ssize_t
+ nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
+ const nghttp2_settings_entry *iv, size_t niv);
/**
* @function
@@ -2685,7 +2884,7 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
* Returns string describing the |lib_error_code|. The
* |lib_error_code| must be one of the :enum:`nghttp2_error`.
*/
-const char *nghttp2_strerror(int lib_error_code);
+NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code);
/**
* @function
@@ -2697,9 +2896,9 @@ const char *nghttp2_strerror(int lib_error_code);
* The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
* :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
*/
-void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
- int32_t stream_id, int32_t weight,
- int exclusive);
+NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
+ int32_t stream_id,
+ int32_t weight, int exclusive);
/**
* @function
@@ -2708,14 +2907,16 @@ void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
* are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and
* exclusive = 0.
*/
-void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
+NGHTTP2_EXTERN void
+nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
/**
* @function
*
* Returns nonzero if the |pri_spec| is filled with default values.
*/
-int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
+NGHTTP2_EXTERN int
+nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
/**
* @function
@@ -2728,8 +2929,8 @@ int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members.
*
- * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
@@ -2777,11 +2978,12 @@ int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* frame.
*
*/
-int32_t nghttp2_submit_request(nghttp2_session *session,
- const nghttp2_priority_spec *pri_spec,
- const nghttp2_nv *nva, size_t nvlen,
- const nghttp2_data_provider *data_prd,
- void *stream_user_data);
+NGHTTP2_EXTERN int32_t
+ nghttp2_submit_request(nghttp2_session *session,
+ const nghttp2_priority_spec *pri_spec,
+ const nghttp2_nv *nva, size_t nvlen,
+ const nghttp2_data_provider *data_prd,
+ void *stream_user_data);
/**
* @function
@@ -2832,9 +3034,58 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
* program crash. It is generally considered to a programming error
* to commit response twice.
*/
-int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
- const nghttp2_nv *nva, size_t nvlen,
- const nghttp2_data_provider *data_prd);
+NGHTTP2_EXTERN int
+nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
+ const nghttp2_nv *nva, size_t nvlen,
+ const nghttp2_data_provider *data_prd);
+
+/**
+ * @function
+ *
+ * Submits trailer HEADERS against the stream |stream_id|.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements. The application is responsible not to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva|.
+ *
+ * This function creates copies of all name/value pairs in |nva|. It
+ * also lower-cases all names in |nva|. The order of elements in
+ * |nva| is preserved.
+ *
+ * For server, trailer must be followed by response HEADERS or
+ * response DATA. The library does not check that response HEADERS
+ * has already sent and if `nghttp2_submit_trailer()` is called before
+ * any response HEADERS submission (usually by
+ * `nghttp2_submit_response()`), the content of |nva| will be sent as
+ * reponse headers, which will result in error.
+ *
+ * This function has the same effect with `nghttp2_submit_headers()`,
+ * with flags = :enum:`NGHTTP2_FLAG_END_HEADERS` and both pri_spec and
+ * stream_user_data to NULL.
+ *
+ * To submit trailer after `nghttp2_submit_response()` is called, the
+ * application has to specify :type:`nghttp2_data_provider` to
+ * `nghttp2_submit_response()`. In side
+ * :type:`nghttp2_data_source_read_callback`, when setting
+ * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`. After that, the
+ * application can send trailer using `nghttp2_submit_trailer()`.
+ * `nghttp2_submit_trailer()` can be used inside
+ * :type:`nghttp2_data_source_read_callback`.
+ *
+ * This function returns 0 if it succeeds and |stream_id| is -1.
+ * Otherwise, 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_ARGUMENT`
+ * The |stream_id| is 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
+ int32_t stream_id,
+ const nghttp2_nv *nva, size_t nvlen);
/**
* @function
@@ -2862,8 +3113,8 @@ int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``,
* this function will copy its data members.
*
- * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
@@ -2908,11 +3159,12 @@ int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* frame.
*
*/
-int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
- int32_t stream_id,
- const nghttp2_priority_spec *pri_spec,
- const nghttp2_nv *nva, size_t nvlen,
- void *stream_user_data);
+NGHTTP2_EXTERN int32_t
+ nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const nghttp2_priority_spec *pri_spec,
+ const nghttp2_nv *nva, size_t nvlen,
+ void *stream_user_data);
/**
* @function
@@ -2948,9 +3200,9 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
* course, all data except for last one must not have
* :enum:`NGHTTP2_FLAG_END_STREAM` flag set in |flags|.
*/
-int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
- int32_t stream_id,
- const nghttp2_data_provider *data_prd);
+NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const nghttp2_data_provider *data_prd);
/**
* @function
@@ -2966,8 +3218,8 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* `nghttp2_priority_spec_init()`. This function will copy its data
* members.
*
- * The `pri_spec->weight` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If `pri_spec->weight` is
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is
* strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
* :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
@@ -2981,9 +3233,10 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
* depend on itself.
*/
-int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
- int32_t stream_id,
- const nghttp2_priority_spec *pri_spec);
+NGHTTP2_EXTERN int
+nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const nghttp2_priority_spec *pri_spec);
/**
* @function
@@ -3004,8 +3257,9 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
*/
-int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
- int32_t stream_id, uint32_t error_code);
+NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
+ uint8_t flags, int32_t stream_id,
+ uint32_t error_code);
/**
* @function
@@ -3040,8 +3294,10 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
- const nghttp2_settings_entry *iv, size_t niv);
+NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
+ uint8_t flags,
+ const nghttp2_settings_entry *iv,
+ size_t niv);
/**
* @function
@@ -3100,10 +3356,10 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
* frame.
*
*/
-int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
- int32_t stream_id, const nghttp2_nv *nva,
- size_t nvlen,
- void *promised_stream_user_data);
+NGHTTP2_EXTERN int32_t
+ nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id, const nghttp2_nv *nva,
+ size_t nvlen, void *promised_stream_user_data);
/**
* @function
@@ -3126,8 +3382,8 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
- const uint8_t *opaque_data);
+NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
+ const uint8_t *opaque_data);
/**
* @function
@@ -3174,9 +3430,11 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
* The |opaque_data_len| is too large; the |last_stream_id| is
* invalid.
*/
-int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
- int32_t last_stream_id, uint32_t error_code,
- const uint8_t *opaque_data, size_t opaque_data_len);
+NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session,
+ uint8_t flags, int32_t last_stream_id,
+ uint32_t error_code,
+ const uint8_t *opaque_data,
+ size_t opaque_data_len);
/**
* @function
@@ -3189,7 +3447,8 @@ int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
*
* This function always succeeds.
*/
-int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
+NGHTTP2_EXTERN int32_t
+ nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
/**
* @function
@@ -3199,6 +3458,9 @@ int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
* The |flags| is currently ignored and should be
* :enum:`NGHTTP2_FLAG_NONE`.
*
+ * The |stream_id| is the stream ID to send this WINDOW_UPDATE. To
+ * send connection level WINDOW_UPDATE, specify 0 to |stream_id|.
+ *
* If the |window_size_increment| is positive, the WINDOW_UPDATE with
* that value as window_size_increment is queued. If the
* |window_size_increment| is larger than the received bytes from the
@@ -3223,9 +3485,10 @@ int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
- int32_t stream_id,
- int32_t window_size_increment);
+NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
+ uint8_t flags,
+ int32_t stream_id,
+ int32_t window_size_increment);
/**
* @function
@@ -3234,11 +3497,12 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
* parameters, but is deprecated and will be removed in a future
* release. This function does nothing and just return 0.
*/
-int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
- int32_t stream_id, uint32_t max_age, uint16_t port,
- const uint8_t *protocol_id, size_t protocol_id_len,
- const uint8_t *host, size_t host_len,
- const uint8_t *origin, size_t origin_len);
+NGHTTP2_EXTERN int
+nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id, uint32_t max_age, uint16_t port,
+ const uint8_t *protocol_id, size_t protocol_id_len,
+ const uint8_t *host, size_t host_len,
+ const uint8_t *origin, size_t origin_len);
/**
* @function
@@ -3249,7 +3513,8 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
* returns positive integer if ``lhs->name`` is found to be greater
* than ``rhs->name``; or returns 0 otherwise.
*/
-int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs);
+NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
+ const nghttp2_nv *rhs);
/**
* @function
@@ -3308,8 +3573,10 @@ int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs);
* SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj);
*
*/
-int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
- const unsigned char *in, unsigned int inlen);
+NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
+ unsigned char *outlen,
+ const unsigned char *in,
+ unsigned int inlen);
/**
* @function
@@ -3320,7 +3587,7 @@ int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
* version number and if the condition is not met, this function will
* return a ``NULL``. Pass in 0 to skip the version checking.
*/
-nghttp2_info *nghttp2_version(int least_version);
+NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version);
/**
* @function
@@ -3328,7 +3595,7 @@ nghttp2_info *nghttp2_version(int least_version);
* Returns nonzero if the :type:`nghttp2_error` library error code
* |lib_error| is fatal.
*/
-int nghttp2_is_fatal(int lib_error);
+NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error);
/**
* @function
@@ -3339,7 +3606,7 @@ int nghttp2_is_fatal(int lib_error);
* Because this is a header field name in HTTP2, the upper cased alphabet
* is treated as error.
*/
-int nghttp2_check_header_name(const uint8_t *name, size_t len);
+NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
/**
* @function
@@ -3348,7 +3615,7 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len);
* is valid according to
* http://tools.ietf.org/html/rfc7230#section-3.2
*/
-int nghttp2_check_header_value(const uint8_t *value, size_t len);
+NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
/* HPACK API */
@@ -3377,8 +3644,8 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
- size_t deflate_hd_table_bufsize_max);
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
+ size_t deflate_hd_table_bufsize_max);
/**
* @function
@@ -3395,16 +3662,16 @@ int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*/
-int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
- size_t deflate_hd_table_bufsize_max,
- nghttp2_mem *mem);
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
+ size_t deflate_hd_table_bufsize_max,
+ nghttp2_mem *mem);
/**
* @function
*
* Deallocates any resources allocated for |deflater|.
*/
-void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
+NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
/**
* @function
@@ -3429,8 +3696,9 @@ void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
- size_t settings_hd_table_bufsize_max);
+NGHTTP2_EXTERN int
+nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
+ size_t settings_hd_table_bufsize_max);
/**
* @function
@@ -3459,9 +3727,9 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
* :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
-ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
- size_t buflen, const nghttp2_nv *nva,
- size_t nvlen);
+NGHTTP2_EXTERN ssize_t
+ nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
+ size_t buflen, const nghttp2_nv *nva, size_t nvlen);
/**
* @function
@@ -3469,8 +3737,9 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
* Returns an upper bound on the compressed size after deflation of
* |nva| of length |nvlen|.
*/
-size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
- const nghttp2_nv *nva, size_t nvlen);
+NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
+ const nghttp2_nv *nva,
+ size_t nvlen);
struct nghttp2_hd_inflater;
@@ -3494,7 +3763,7 @@ typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
/**
* @function
@@ -3511,15 +3780,15 @@ int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*/
-int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
- nghttp2_mem *mem);
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
+ nghttp2_mem *mem);
/**
* @function
*
* Deallocates any resources allocated for |inflater|.
*/
-void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
+NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
/**
* @function
@@ -3536,8 +3805,9 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
-int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
- size_t settings_hd_table_bufsize_max);
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
+ size_t settings_hd_table_bufsize_max);
/**
* @enum
@@ -3636,9 +3906,10 @@ typedef enum {
* }
*
*/
-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);
+NGHTTP2_EXTERN 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);
/**
* @function
@@ -3648,7 +3919,8 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
* This function returns 0 if it succeeds. Currently this function
* always succeeds.
*/
-int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
#ifdef __cplusplus
}
diff --git a/epan/nghttp2/nghttp2_buf.c b/epan/nghttp2/nghttp2_buf.c
index f747ae989a..821edb98e7 100644
--- a/epan/nghttp2/nghttp2_buf.c
+++ b/epan/nghttp2/nghttp2_buf.c
@@ -410,36 +410,46 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
len += nghttp2_buf_len(&chain->buf);
}
- if (!len) {
+ if (len == 0) {
res = NULL;
- } else {
- res = (uint8_t *)nghttp2_mem_malloc(bufs->mem, len);
+ return 0;
+ }
- if (res == NULL) {
- return NGHTTP2_ERR_NOMEM;
- }
+ res = (uint8_t *)nghttp2_mem_malloc(bufs->mem, len);
+ if (res == NULL) {
+ return NGHTTP2_ERR_NOMEM;
}
nghttp2_buf_wrap_init(&resbuf, res, len);
for (chain = bufs->head; chain; chain = chain->next) {
buf = &chain->buf;
-
- if (resbuf.last) {
- resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
- }
-
- nghttp2_buf_reset(buf);
- nghttp2_buf_shift_right(&chain->buf, bufs->offset);
+ resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
}
- bufs->cur = bufs->head;
-
*out = res;
return (ssize_t)len;
}
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
+ size_t len;
+ nghttp2_buf_chain *chain;
+ nghttp2_buf *buf;
+ nghttp2_buf resbuf;
+
+ len = nghttp2_bufs_len(bufs);
+
+ nghttp2_buf_wrap_init(&resbuf, out, len);
+
+ for (chain = bufs->head; chain; chain = chain->next) {
+ buf = &chain->buf;
+ resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
+ }
+
+ return len;
+}
+
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
nghttp2_buf_chain *chain, *ci;
size_t k;
diff --git a/epan/nghttp2/nghttp2_buf.h b/epan/nghttp2/nghttp2_buf.h
index 108147e914..a84dc7bea2 100644
--- a/epan/nghttp2/nghttp2_buf.h
+++ b/epan/nghttp2/nghttp2_buf.h
@@ -313,9 +313,8 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
* function allocates the contagious memory to store all data in
* |bufs| and assigns it to |*out|.
*
- * On successful return, nghttp2_bufs_len(bufs) returns 0, just like
- * after calling nghttp2_bufs_reset().
-
+ * The contents of |bufs| is left unchanged.
+ *
* This function returns the length of copied data and assigns the
* pointer to copied data to |*out| if it succeeds, or one of the
* following negative error codes:
@@ -326,6 +325,17 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
/*
+ * Copies all data stored in |bufs| to |out|. This function assumes
+ * that the buffer space pointed by |out| has at least
+ * nghttp2_bufs(bufs) bytes.
+ *
+ * The contents of |bufs| is left unchanged.
+ *
+ * This function returns the length of copied data.
+ */
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
+
+/*
* Resets |bufs| and makes the buffers empty.
*/
void nghttp2_bufs_reset(nghttp2_bufs *bufs);
diff --git a/epan/nghttp2/nghttp2_hd.c b/epan/nghttp2/nghttp2_hd.c
index 81726cd5f1..2f0c00228a 100644
--- a/epan/nghttp2/nghttp2_hd.c
+++ b/epan/nghttp2/nghttp2_hd.c
@@ -31,118 +31,472 @@
#include "nghttp2_helper.h"
#include "nghttp2_int.h"
-#define STATIC_TABLE_LENGTH 61
-
-/* Make scalar initialization form of nghttp2_nv */
-#define MAKE_STATIC_ENT(I, N, V, NH, VH) \
+/* Make scalar initialization form of nghttp2_hd_entry */
+#define MAKE_STATIC_ENT(N, V, T) \
{ \
- { \
- { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \
- , (NH), (VH), 1, NGHTTP2_HD_FLAG_NONE \
- } \
- , I \
+ { (uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0 } \
+ , (T), 1, NGHTTP2_HD_FLAG_NONE \
}
/* Generated by mkstatictbl.py */
-/* Sorted by hash(name) and its table index */
-static nghttp2_hd_static_entry static_table[] = {
- MAKE_STATIC_ENT(20, "age", "", 96511u, 0u),
- MAKE_STATIC_ENT(59, "via", "", 116750u, 0u),
- MAKE_STATIC_ENT(32, "date", "", 3076014u, 0u),
- MAKE_STATIC_ENT(33, "etag", "", 3123477u, 0u),
- MAKE_STATIC_ENT(36, "from", "", 3151786u, 0u),
- MAKE_STATIC_ENT(37, "host", "", 3208616u, 0u),
- MAKE_STATIC_ENT(44, "link", "", 3321850u, 0u),
- MAKE_STATIC_ENT(58, "vary", "", 3612210u, 0u),
- MAKE_STATIC_ENT(38, "if-match", "", 34533653u, 0u),
- MAKE_STATIC_ENT(41, "if-range", "", 39145613u, 0u),
- MAKE_STATIC_ENT(3, ":path", "/", 56997727u, 47u),
- MAKE_STATIC_ENT(4, ":path", "/index.html", 56997727u, 2144181430u),
- MAKE_STATIC_ENT(21, "allow", "", 92906313u, 0u),
- MAKE_STATIC_ENT(49, "range", "", 108280125u, 0u),
- MAKE_STATIC_ENT(14, "accept-charset", "", 124285319u, 0u),
- MAKE_STATIC_ENT(43, "last-modified", "", 150043680u, 0u),
- MAKE_STATIC_ENT(48, "proxy-authorization", "", 329532250u, 0u),
- MAKE_STATIC_ENT(57, "user-agent", "", 486342275u, 0u),
- MAKE_STATIC_ENT(40, "if-none-match", "", 646073760u, 0u),
- MAKE_STATIC_ENT(30, "content-type", "", 785670158u, 0u),
- MAKE_STATIC_ENT(16, "accept-language", "", 802785917u, 0u),
- MAKE_STATIC_ENT(50, "referer", "", 1085069613u, 0u),
- MAKE_STATIC_ENT(51, "refresh", "", 1085444827u, 0u),
- MAKE_STATIC_ENT(55, "strict-transport-security", "", 1153852136u, 0u),
- MAKE_STATIC_ENT(54, "set-cookie", "", 1237214767u, 0u),
- MAKE_STATIC_ENT(56, "transfer-encoding", "", 1274458357u, 0u),
- MAKE_STATIC_ENT(17, "accept-ranges", "", 1397189435u, 0u),
- MAKE_STATIC_ENT(42, "if-unmodified-since", "", 1454068927u, 0u),
- MAKE_STATIC_ENT(46, "max-forwards", "", 1619948695u, 0u),
- MAKE_STATIC_ENT(45, "location", "", 1901043637u, 0u),
- MAKE_STATIC_ENT(52, "retry-after", "", 1933352567u, 0u),
- MAKE_STATIC_ENT(25, "content-encoding", "", 2095084583u, 0u),
- MAKE_STATIC_ENT(28, "content-location", "", 2284906121u, 0u),
- MAKE_STATIC_ENT(39, "if-modified-since", "", 2302095846u, 0u),
- MAKE_STATIC_ENT(18, "accept", "", 2871506184u, 0u),
- MAKE_STATIC_ENT(29, "content-range", "", 2878374633u, 0u),
- MAKE_STATIC_ENT(22, "authorization", "", 2909397113u, 0u),
- MAKE_STATIC_ENT(31, "cookie", "", 2940209764u, 0u),
- MAKE_STATIC_ENT(0, ":authority", "", 2962729033u, 0u),
- MAKE_STATIC_ENT(35, "expires", "", 2985731892u, 0u),
- MAKE_STATIC_ENT(34, "expect", "", 3005803609u, 0u),
- MAKE_STATIC_ENT(24, "content-disposition", "", 3027699811u, 0u),
- MAKE_STATIC_ENT(26, "content-language", "", 3065240108u, 0u),
- MAKE_STATIC_ENT(1, ":method", "GET", 3153018267u, 70454u),
- MAKE_STATIC_ENT(2, ":method", "POST", 3153018267u, 2461856u),
- MAKE_STATIC_ENT(27, "content-length", "", 3162187450u, 0u),
- MAKE_STATIC_ENT(19, "access-control-allow-origin", "", 3297999203u, 0u),
- MAKE_STATIC_ENT(5, ":scheme", "http", 3322585695u, 3213448u),
- MAKE_STATIC_ENT(6, ":scheme", "https", 3322585695u, 99617003u),
- MAKE_STATIC_ENT(7, ":status", "200", 3338091692u, 49586u),
- MAKE_STATIC_ENT(8, ":status", "204", 3338091692u, 49590u),
- MAKE_STATIC_ENT(9, ":status", "206", 3338091692u, 49592u),
- MAKE_STATIC_ENT(10, ":status", "304", 3338091692u, 50551u),
- MAKE_STATIC_ENT(11, ":status", "400", 3338091692u, 51508u),
- MAKE_STATIC_ENT(12, ":status", "404", 3338091692u, 51512u),
- MAKE_STATIC_ENT(13, ":status", "500", 3338091692u, 52469u),
- MAKE_STATIC_ENT(53, "server", "", 3389140803u, 0u),
- MAKE_STATIC_ENT(47, "proxy-authenticate", "", 3993199572u, 0u),
- MAKE_STATIC_ENT(60, "www-authenticate", "", 4051929931u, 0u),
- MAKE_STATIC_ENT(23, "cache-control", "", 4086191634u, 0u),
- MAKE_STATIC_ENT(15, "accept-encoding", "gzip, deflate", 4127597688u,
- 1733326877u),
+/* 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[] = {
+ MAKE_STATIC_ENT(":authority", "", 0),
+ MAKE_STATIC_ENT(":method", "GET", 1),
+ MAKE_STATIC_ENT(":method", "POST", 1),
+ MAKE_STATIC_ENT(":path", "/", 3),
+ MAKE_STATIC_ENT(":path", "/index.html", 3),
+ MAKE_STATIC_ENT(":scheme", "http", 5),
+ MAKE_STATIC_ENT(":scheme", "https", 5),
+ MAKE_STATIC_ENT(":status", "200", 7),
+ MAKE_STATIC_ENT(":status", "204", 7),
+ MAKE_STATIC_ENT(":status", "206", 7),
+ MAKE_STATIC_ENT(":status", "304", 7),
+ MAKE_STATIC_ENT(":status", "400", 7),
+ MAKE_STATIC_ENT(":status", "404", 7),
+ MAKE_STATIC_ENT(":status", "500", 7),
+ MAKE_STATIC_ENT("accept-charset", "", 14),
+ MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15),
+ MAKE_STATIC_ENT("accept-language", "", 16),
+ MAKE_STATIC_ENT("accept-ranges", "", 17),
+ MAKE_STATIC_ENT("accept", "", 18),
+ MAKE_STATIC_ENT("access-control-allow-origin", "", 19),
+ MAKE_STATIC_ENT("age", "", 20),
+ MAKE_STATIC_ENT("allow", "", 21),
+ MAKE_STATIC_ENT("authorization", "", 22),
+ MAKE_STATIC_ENT("cache-control", "", 23),
+ MAKE_STATIC_ENT("content-disposition", "", 24),
+ MAKE_STATIC_ENT("content-encoding", "", 25),
+ MAKE_STATIC_ENT("content-language", "", 26),
+ MAKE_STATIC_ENT("content-length", "", 27),
+ MAKE_STATIC_ENT("content-location", "", 28),
+ MAKE_STATIC_ENT("content-range", "", 29),
+ MAKE_STATIC_ENT("content-type", "", 30),
+ MAKE_STATIC_ENT("cookie", "", 31),
+ MAKE_STATIC_ENT("date", "", 32),
+ MAKE_STATIC_ENT("etag", "", 33),
+ MAKE_STATIC_ENT("expect", "", 34),
+ MAKE_STATIC_ENT("expires", "", 35),
+ MAKE_STATIC_ENT("from", "", 36),
+ MAKE_STATIC_ENT("host", "", 37),
+ MAKE_STATIC_ENT("if-match", "", 38),
+ MAKE_STATIC_ENT("if-modified-since", "", 39),
+ MAKE_STATIC_ENT("if-none-match", "", 40),
+ MAKE_STATIC_ENT("if-range", "", 41),
+ MAKE_STATIC_ENT("if-unmodified-since", "", 42),
+ MAKE_STATIC_ENT("last-modified", "", 43),
+ MAKE_STATIC_ENT("link", "", 44),
+ MAKE_STATIC_ENT("location", "", 45),
+ MAKE_STATIC_ENT("max-forwards", "", 46),
+ MAKE_STATIC_ENT("proxy-authenticate", "", 47),
+ MAKE_STATIC_ENT("proxy-authorization", "", 48),
+ MAKE_STATIC_ENT("range", "", 49),
+ MAKE_STATIC_ENT("referer", "", 50),
+ MAKE_STATIC_ENT("refresh", "", 51),
+ MAKE_STATIC_ENT("retry-after", "", 52),
+ MAKE_STATIC_ENT("server", "", 53),
+ MAKE_STATIC_ENT("set-cookie", "", 54),
+ MAKE_STATIC_ENT("strict-transport-security", "", 55),
+ MAKE_STATIC_ENT("transfer-encoding", "", 56),
+ MAKE_STATIC_ENT("user-agent", "", 57),
+ MAKE_STATIC_ENT("vary", "", 58),
+ MAKE_STATIC_ENT("via", "", 59),
+ MAKE_STATIC_ENT("www-authenticate", "", 60),
};
-/* Index to the position in static_table */
-const size_t static_table_index[] = {
- 38, 43, 44, 10, 11, 47, 48, 49, 50, 51, 52, 53, 54, 55, 14, 60,
- 20, 26, 34, 46, 0, 12, 36, 59, 41, 31, 42, 45, 32, 35, 19, 37,
- 2, 3, 40, 39, 4, 5, 8, 33, 18, 9, 27, 15, 6, 29, 28, 57,
- 16, 13, 21, 22, 30, 56, 24, 23, 25, 17, 7, 1, 58};
-
-const size_t NGHTTP2_STATIC_TABLE_LENGTH =
- sizeof(static_table) / sizeof(static_table[0]);
-
static int memeq(const void *s1, const void *s2, size_t n) {
- const uint8_t *a = (const uint8_t *)s1, *b = (const uint8_t *)s2;
- uint8_t c = 0;
- while (n > 0) {
- c |= (*a++) ^ (*b++);
- --n;
- }
- return c == 0;
+ return memcmp(s1, s2, n) == 0;
}
-static uint32_t hash(const uint8_t *s, size_t n) {
- uint32_t h = 0;
- while (n > 0) {
- h = h * 31 + *s++;
- --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) {
+ switch (namelen) {
+ case 2:
+ switch (name[1]) {
+ case 'e':
+ if (lstreq("t", name, 1)) {
+ return NGHTTP2_TOKEN_TE;
+ }
+ break;
+ }
+ break;
+ case 3:
+ switch (name[2]) {
+ case 'a':
+ if (lstreq("vi", name, 2)) {
+ return NGHTTP2_TOKEN_VIA;
+ }
+ break;
+ case 'e':
+ if (lstreq("ag", name, 2)) {
+ return NGHTTP2_TOKEN_AGE;
+ }
+ break;
+ }
+ break;
+ case 4:
+ switch (name[3]) {
+ case 'e':
+ if (lstreq("dat", name, 3)) {
+ return NGHTTP2_TOKEN_DATE;
+ }
+ break;
+ case 'g':
+ if (lstreq("eta", name, 3)) {
+ return NGHTTP2_TOKEN_ETAG;
+ }
+ break;
+ case 'k':
+ if (lstreq("lin", name, 3)) {
+ return NGHTTP2_TOKEN_LINK;
+ }
+ break;
+ case 'm':
+ if (lstreq("fro", name, 3)) {
+ return NGHTTP2_TOKEN_FROM;
+ }
+ break;
+ case 't':
+ if (lstreq("hos", name, 3)) {
+ return NGHTTP2_TOKEN_HOST;
+ }
+ break;
+ case 'y':
+ if (lstreq("var", name, 3)) {
+ return NGHTTP2_TOKEN_VARY;
+ }
+ break;
+ }
+ break;
+ case 5:
+ switch (name[4]) {
+ case 'e':
+ if (lstreq("rang", name, 4)) {
+ return NGHTTP2_TOKEN_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq(":pat", name, 4)) {
+ return NGHTTP2_TOKEN__PATH;
+ }
+ if (lstreq(":pat", name, 4)) {
+ return NGHTTP2_TOKEN__PATH;
+ }
+ break;
+ case 'w':
+ if (lstreq("allo", name, 4)) {
+ return NGHTTP2_TOKEN_ALLOW;
+ }
+ break;
+ }
+ break;
+ case 6:
+ switch (name[5]) {
+ case 'e':
+ if (lstreq("cooki", name, 5)) {
+ return NGHTTP2_TOKEN_COOKIE;
+ }
+ break;
+ case 'r':
+ if (lstreq("serve", name, 5)) {
+ return NGHTTP2_TOKEN_SERVER;
+ }
+ break;
+ case 't':
+ if (lstreq("accep", name, 5)) {
+ return NGHTTP2_TOKEN_ACCEPT;
+ }
+ if (lstreq("expec", name, 5)) {
+ return NGHTTP2_TOKEN_EXPECT;
+ }
+ break;
+ }
+ break;
+ case 7:
+ switch (name[6]) {
+ case 'd':
+ if (lstreq(":metho", name, 6)) {
+ return NGHTTP2_TOKEN__METHOD;
+ }
+ if (lstreq(":metho", name, 6)) {
+ return NGHTTP2_TOKEN__METHOD;
+ }
+ break;
+ case 'e':
+ if (lstreq(":schem", name, 6)) {
+ return NGHTTP2_TOKEN__SCHEME;
+ }
+ if (lstreq(":schem", name, 6)) {
+ return NGHTTP2_TOKEN__SCHEME;
+ }
+ if (lstreq("upgrad", name, 6)) {
+ return NGHTTP2_TOKEN_UPGRADE;
+ }
+ break;
+ case 'h':
+ if (lstreq("refres", name, 6)) {
+ return NGHTTP2_TOKEN_REFRESH;
+ }
+ break;
+ case 'r':
+ if (lstreq("refere", name, 6)) {
+ return NGHTTP2_TOKEN_REFERER;
+ }
+ break;
+ case 's':
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq(":statu", name, 6)) {
+ return NGHTTP2_TOKEN__STATUS;
+ }
+ if (lstreq("expire", name, 6)) {
+ return NGHTTP2_TOKEN_EXPIRES;
+ }
+ break;
+ }
+ break;
+ case 8:
+ switch (name[7]) {
+ case 'e':
+ if (lstreq("if-rang", name, 7)) {
+ return NGHTTP2_TOKEN_IF_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq("if-matc", name, 7)) {
+ return NGHTTP2_TOKEN_IF_MATCH;
+ }
+ break;
+ case 'n':
+ if (lstreq("locatio", name, 7)) {
+ return NGHTTP2_TOKEN_LOCATION;
+ }
+ break;
+ }
+ break;
+ case 10:
+ switch (name[9]) {
+ case 'e':
+ if (lstreq("keep-aliv", name, 9)) {
+ return NGHTTP2_TOKEN_KEEP_ALIVE;
+ }
+ if (lstreq("set-cooki", name, 9)) {
+ return NGHTTP2_TOKEN_SET_COOKIE;
+ }
+ break;
+ case 'n':
+ if (lstreq("connectio", name, 9)) {
+ return NGHTTP2_TOKEN_CONNECTION;
+ }
+ break;
+ case 't':
+ if (lstreq("user-agen", name, 9)) {
+ return NGHTTP2_TOKEN_USER_AGENT;
+ }
+ break;
+ case 'y':
+ if (lstreq(":authorit", name, 9)) {
+ return NGHTTP2_TOKEN__AUTHORITY;
+ }
+ break;
+ }
+ break;
+ case 11:
+ switch (name[10]) {
+ case 'r':
+ if (lstreq("retry-afte", name, 10)) {
+ return NGHTTP2_TOKEN_RETRY_AFTER;
+ }
+ break;
+ }
+ break;
+ case 12:
+ switch (name[11]) {
+ case 'e':
+ if (lstreq("content-typ", name, 11)) {
+ return NGHTTP2_TOKEN_CONTENT_TYPE;
+ }
+ break;
+ case 's':
+ if (lstreq("max-forward", name, 11)) {
+ return NGHTTP2_TOKEN_MAX_FORWARDS;
+ }
+ break;
+ }
+ break;
+ case 13:
+ switch (name[12]) {
+ case 'd':
+ if (lstreq("last-modifie", name, 12)) {
+ return NGHTTP2_TOKEN_LAST_MODIFIED;
+ }
+ break;
+ case 'e':
+ if (lstreq("content-rang", name, 12)) {
+ return NGHTTP2_TOKEN_CONTENT_RANGE;
+ }
+ break;
+ case 'h':
+ if (lstreq("if-none-matc", name, 12)) {
+ return NGHTTP2_TOKEN_IF_NONE_MATCH;
+ }
+ break;
+ case 'l':
+ if (lstreq("cache-contro", name, 12)) {
+ return NGHTTP2_TOKEN_CACHE_CONTROL;
+ }
+ break;
+ case 'n':
+ if (lstreq("authorizatio", name, 12)) {
+ return NGHTTP2_TOKEN_AUTHORIZATION;
+ }
+ break;
+ case 's':
+ if (lstreq("accept-range", name, 12)) {
+ return NGHTTP2_TOKEN_ACCEPT_RANGES;
+ }
+ break;
+ }
+ break;
+ case 14:
+ switch (name[13]) {
+ case 'h':
+ if (lstreq("content-lengt", name, 13)) {
+ return NGHTTP2_TOKEN_CONTENT_LENGTH;
+ }
+ break;
+ case 't':
+ if (lstreq("accept-charse", name, 13)) {
+ return NGHTTP2_TOKEN_ACCEPT_CHARSET;
+ }
+ break;
+ }
+ break;
+ case 15:
+ switch (name[14]) {
+ case 'e':
+ if (lstreq("accept-languag", name, 14)) {
+ return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
+ }
+ break;
+ case 'g':
+ if (lstreq("accept-encodin", name, 14)) {
+ return NGHTTP2_TOKEN_ACCEPT_ENCODING;
+ }
+ break;
+ }
+ break;
+ case 16:
+ switch (name[15]) {
+ case 'e':
+ if (lstreq("content-languag", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_LANGUAGE;
+ }
+ if (lstreq("www-authenticat", name, 15)) {
+ return NGHTTP2_TOKEN_WWW_AUTHENTICATE;
+ }
+ break;
+ case 'g':
+ if (lstreq("content-encodin", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_ENCODING;
+ }
+ break;
+ case 'n':
+ if (lstreq("content-locatio", name, 15)) {
+ return NGHTTP2_TOKEN_CONTENT_LOCATION;
+ }
+ if (lstreq("proxy-connectio", name, 15)) {
+ return NGHTTP2_TOKEN_PROXY_CONNECTION;
+ }
+ break;
+ }
+ break;
+ case 17:
+ switch (name[16]) {
+ case 'e':
+ if (lstreq("if-modified-sinc", name, 16)) {
+ return NGHTTP2_TOKEN_IF_MODIFIED_SINCE;
+ }
+ break;
+ case 'g':
+ if (lstreq("transfer-encodin", name, 16)) {
+ return NGHTTP2_TOKEN_TRANSFER_ENCODING;
+ }
+ break;
+ }
+ break;
+ case 18:
+ switch (name[17]) {
+ case 'e':
+ if (lstreq("proxy-authenticat", name, 17)) {
+ return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
+ }
+ break;
+ }
+ break;
+ case 19:
+ switch (name[18]) {
+ case 'e':
+ if (lstreq("if-unmodified-sinc", name, 18)) {
+ return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE;
+ }
+ break;
+ case 'n':
+ if (lstreq("content-dispositio", name, 18)) {
+ return NGHTTP2_TOKEN_CONTENT_DISPOSITION;
+ }
+ if (lstreq("proxy-authorizatio", name, 18)) {
+ return NGHTTP2_TOKEN_PROXY_AUTHORIZATION;
+ }
+ break;
+ }
+ break;
+ case 25:
+ switch (name[24]) {
+ case 'y':
+ if (lstreq("strict-transport-securit", name, 24)) {
+ return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
+ }
+ break;
+ }
+ break;
+ case 27:
+ switch (name[26]) {
+ case 'n':
+ if (lstreq("access-control-allow-origi", name, 26)) {
+ return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
+ }
+ break;
+ }
+ break;
}
- return h;
+ 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,
- uint32_t name_hash, uint32_t value_hash,
- nghttp2_mem *mem) {
+ int token, nghttp2_mem *mem) {
int rv = 0;
/* Since nghttp2_hd_entry is used for indexing, ent->nv.flags always
@@ -152,10 +506,11 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
if ((flags & NGHTTP2_HD_FLAG_NAME_ALLOC) &&
(flags & NGHTTP2_HD_FLAG_NAME_GIFT) == 0) {
if (namelen == 0) {
- /* We should not allow empty header field name */
- ent->nv.name = NULL;
+ flags &= ~NGHTTP2_HD_FLAG_NAME_ALLOC;
+ ent->nv.name = (uint8_t *)"";
} else {
- ent->nv.name = (uint8_t *)nghttp2_memdup(name, namelen, mem);
+ /* copy including terminating NULL byte */
+ ent->nv.name = (uint8_t *)nghttp2_memdup(name, namelen + 1, mem);
if (ent->nv.name == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail;
@@ -167,9 +522,11 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
if ((flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) &&
(flags & NGHTTP2_HD_FLAG_VALUE_GIFT) == 0) {
if (valuelen == 0) {
- ent->nv.value = NULL;
+ flags &= ~NGHTTP2_HD_FLAG_VALUE_ALLOC;
+ ent->nv.value = (uint8_t *)"";
} else {
- ent->nv.value = (uint8_t *)nghttp2_memdup(value, valuelen, mem);
+ /* copy including terminating NULL byte */
+ ent->nv.value = (uint8_t *)nghttp2_memdup(value, valuelen + 1, mem);
if (ent->nv.value == NULL) {
rv = NGHTTP2_ERR_NOMEM;
goto fail2;
@@ -180,12 +537,10 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
}
ent->nv.namelen = namelen;
ent->nv.valuelen = valuelen;
+ ent->token = token;
ent->ref = 1;
ent->flags = flags;
- ent->name_hash = name_hash;
- ent->value_hash = value_hash;
-
return 0;
fail2:
@@ -403,25 +758,23 @@ 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, nghttp2_hd_entry *ent) {
- DEBUGF(fprintf(stderr, "inflatehd: header emission: "));
- DEBUGF(fwrite(ent->nv.name, ent->nv.namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(ent->nv.value, ent->nv.valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+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));
/* 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, nghttp2_nv *nv) {
- DEBUGF(fprintf(stderr, "inflatehd: header emission: "));
- DEBUGF(fwrite(nv->name, nv->namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(nv->value, nv->valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+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;
}
@@ -642,38 +995,39 @@ static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
return rv;
}
-static uint8_t pack_first_byte(int inc_indexing, int no_index) {
- if (inc_indexing) {
+static uint8_t pack_first_byte(int indexing_mode) {
+ switch (indexing_mode) {
+ case NGHTTP2_HD_WITH_INDEXING:
return 0x40u;
- }
-
- if (no_index) {
+ case NGHTTP2_HD_WITHOUT_INDEXING:
+ return 0;
+ case NGHTTP2_HD_NEVER_INDEXING:
return 0x10u;
+ default:
+ assert(0);
}
-
+ /* This is required to compile with android NDK r10d +
+ --enable-werror */
return 0;
}
static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
- const nghttp2_nv *nv, int inc_indexing) {
+ const nghttp2_nv *nv, int indexing_mode) {
int rv;
uint8_t *bufp;
size_t blocklen;
uint8_t sb[16];
size_t prefixlen;
- int no_index;
- no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
-
- if (inc_indexing) {
+ if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
prefixlen = 6;
} else {
prefixlen = 4;
}
DEBUGF(fprintf(stderr, "deflatehd: emit indname index=%zu, valuelen=%zu, "
- "indexing=%d, no_index=%d\n",
- idx, nv->valuelen, inc_indexing, no_index));
+ "indexing_mode=%d\n",
+ idx, nv->valuelen, indexing_mode));
blocklen = count_encoded_length(idx + 1, prefixlen);
@@ -683,7 +1037,7 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
bufp = sb;
- *bufp = pack_first_byte(inc_indexing, no_index);
+ *bufp = pack_first_byte(indexing_mode);
encode_length(bufp, idx + 1, prefixlen);
@@ -701,17 +1055,14 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
}
static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
- int inc_indexing) {
+ int indexing_mode) {
int rv;
- int no_index;
-
- no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
DEBUGF(fprintf(stderr, "deflatehd: emit newname namelen=%zu, valuelen=%zu, "
- "indexing=%d, no_index=%d\n",
- nv->namelen, nv->valuelen, inc_indexing, no_index));
+ "indexing_mode=%d\n",
+ nv->namelen, nv->valuelen, indexing_mode));
- rv = nghttp2_bufs_addb(bufs, pack_first_byte(inc_indexing, no_index));
+ rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
if (rv != 0) {
return rv;
}
@@ -731,8 +1082,7 @@ static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
const nghttp2_nv *nv,
- uint32_t name_hash,
- uint32_t value_hash,
+ int token,
uint8_t entry_flags) {
int rv;
nghttp2_hd_entry *new_ent;
@@ -750,11 +1100,9 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen);
- DEBUGF(fprintf(stderr, "hpack: remove item from header table: "));
- DEBUGF(fwrite(ent->nv.name, ent->nv.namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(ent->nv.value, ent->nv.valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+ DEBUGF(fprintf(stderr, "hpack: remove item from header table: %s: %s\n",
+ ent->nv.name, ent->nv.value));
+
hd_ringbuf_pop_back(&context->hd_table);
if (--ent->ref == 0) {
nghttp2_hd_entry_free(ent, mem);
@@ -768,8 +1116,7 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
}
rv = nghttp2_hd_entry_init(new_ent, entry_flags, nv->name, nv->namelen,
- nv->value, nv->valuelen, name_hash, value_hash,
- mem);
+ nv->value, nv->valuelen, token, mem);
if (rv != 0) {
nghttp2_mem_free(mem, new_ent);
return NULL;
@@ -810,11 +1157,15 @@ static nghttp2_hd_entry *add_hd_table_incremental(nghttp2_hd_context *context,
}
static int name_eq(const nghttp2_nv *a, const nghttp2_nv *b) {
- return a->namelen == b->namelen && memeq(a->name, b->name, a->namelen);
+ return a->namelen == b->namelen &&
+ a->name[a->namelen - 1] == b->name[a->namelen - 1] &&
+ memeq(a->name, b->name, a->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);
+ return a->valuelen == b->valuelen &&
+ a->value[a->valuelen - 1] == b->value[a->valuelen - 1] &&
+ memeq(a->value, b->value, a->valuelen);
}
typedef struct {
@@ -823,61 +1174,54 @@ typedef struct {
uint8_t name_value_match;
} search_result;
+static search_result search_static_table(const nghttp2_nv *nv, int token,
+ int indexing_mode) {
+ search_result res = {token, 0};
+ int i;
+
+ if (indexing_mode == NGHTTP2_HD_NEVER_INDEXING) {
+ return res;
+ }
+
+ for (i = token;
+ i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token;
+ ++i) {
+ if (value_eq(&static_table[i].nv, nv)) {
+ res.index = i;
+ res.name_value_match = 1;
+ return res;
+ }
+ }
+ return res;
+}
+
static search_result search_hd_table(nghttp2_hd_context *context,
- const nghttp2_nv *nv, uint32_t name_hash,
- uint32_t value_hash) {
- ssize_t left = -1, right = (ssize_t)STATIC_TABLE_LENGTH;
+ const nghttp2_nv *nv, int token,
+ int indexing_mode) {
search_result res = {-1, 0};
size_t i;
- int use_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) == 0;
-
- /* Search dynamic table first, so that we can find recently used
- entry first */
- if (use_index) {
- for (i = 0; i < context->hd_table.len; ++i) {
- nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, i);
- if (ent->name_hash != name_hash || !name_eq(&ent->nv, nv)) {
- continue;
- }
- if (res.index == -1) {
- res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
- }
-
- if (ent->value_hash == value_hash && value_eq(&ent->nv, nv)) {
- res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
- res.name_value_match = 1;
- return res;
- }
+ if (token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
+ res = search_static_table(nv, token, indexing_mode);
+ if (res.name_value_match) {
+ return res;
}
}
- while (right - left > 1) {
- ssize_t mid = (left + right) / 2;
- nghttp2_hd_entry *ent = &static_table[mid].ent;
- if (ent->name_hash < name_hash) {
- left = mid;
- } else {
- right = mid;
+ for (i = 0; i < context->hd_table.len; ++i) {
+ nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, i);
+ if (ent->token != token || (token == -1 && !name_eq(&ent->nv, nv))) {
+ continue;
}
- }
- for (i = right; i < STATIC_TABLE_LENGTH; ++i) {
- nghttp2_hd_entry *ent = &static_table[i].ent;
- if (ent->name_hash != name_hash) {
- break;
+ if (res.index == -1) {
+ res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
}
- if (name_eq(&ent->nv, nv)) {
- if (res.index == -1) {
- res.index = (ssize_t)(static_table[i].index);
- }
- if (use_index && ent->value_hash == value_hash &&
- value_eq(&ent->nv, nv)) {
- res.index = (ssize_t)(static_table[i].index);
- res.name_value_match = 1;
- return res;
- }
+ if (indexing_mode != NGHTTP2_HD_NEVER_INDEXING && value_eq(&ent->nv, nv)) {
+ res.index = (ssize_t)(i + NGHTTP2_STATIC_TABLE_LENGTH);
+ res.name_value_match = 1;
+ return res;
}
}
@@ -940,29 +1284,23 @@ nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context,
return hd_ringbuf_get(&context->hd_table,
idx - NGHTTP2_STATIC_TABLE_LENGTH);
} else {
- return &static_table[static_table_index[idx]].ent;
+ return &static_table[idx];
}
}
-#define name_match(NV, NAME) \
- (nv->namelen == sizeof(NAME) - 1 && memeq(nv->name, NAME, sizeof(NAME) - 1))
-
-static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
- const nghttp2_nv *nv) {
- if ((nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) ||
+static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
+ const nghttp2_nv *nv, int 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 ||
+ token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION ||
+ token == NGHTTP2_TOKEN_SET_COOKIE ||
entry_room(nv->namelen, nv->valuelen) >
deflater->ctx.hd_table_bufsize_max * 3 / 4) {
- return 0;
+ return NGHTTP2_HD_WITHOUT_INDEXING;
}
-#ifdef NGHTTP2_XHD
- return !name_match(nv, NGHTTP2_XHD);
-#else /* !NGHTTP2_XHD */
- return !name_match(nv, ":path") && !name_match(nv, "content-length") &&
- !name_match(nv, "set-cookie") && !name_match(nv, "etag") &&
- !name_match(nv, "if-modified-since") &&
- !name_match(nv, "if-none-match") && !name_match(nv, "location") &&
- !name_match(nv, "age");
-#endif /* !NGHTTP2_XHD */
+
+ return NGHTTP2_HD_WITH_INDEXING;
}
static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
@@ -970,20 +1308,28 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
int rv;
search_result res;
ssize_t idx;
- int incidx = 0;
- uint32_t name_hash = hash(nv->name, nv->namelen);
- uint32_t value_hash = hash(nv->value, nv->valuelen);
+ int indexing_mode;
+ int token;
nghttp2_mem *mem;
- DEBUGF(fprintf(stderr, "deflatehd: deflating "));
- DEBUGF(fwrite(nv->name, nv->namelen, 1, stderr));
- DEBUGF(fprintf(stderr, ": "));
- DEBUGF(fwrite(nv->value, nv->valuelen, 1, stderr));
- DEBUGF(fprintf(stderr, "\n"));
+ DEBUGF(fprintf(stderr, "deflatehd: deflating %s: %s\n", nv->name, nv->value));
mem = deflater->ctx.mem;
- res = search_hd_table(&deflater->ctx, nv, name_hash, value_hash);
+ token = lookup_token(nv->name, nv->namelen);
+
+ /* Don't index authorization header field since it may contain low
+ entropy secret data (e.g., id/password). Also cookie header
+ field with less than 20 bytes value is also never indexed. This
+ is the same criteria used in Firefox codebase. */
+ indexing_mode =
+ token == NGHTTP2_TOKEN_AUTHORIZATION ||
+ (token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) ||
+ (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
+ ? NGHTTP2_HD_NEVER_INDEXING
+ : hd_deflate_decide_indexing(deflater, nv, token);
+
+ res = search_hd_table(&deflater->ctx, nv, token, indexing_mode);
idx = res.index;
@@ -1003,19 +1349,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
DEBUGF(fprintf(stderr, "deflatehd: name match index=%zd\n", res.index));
}
- if (hd_deflate_should_indexing(deflater, nv)) {
+ if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
nghttp2_hd_entry *new_ent;
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, idx)->nv.name;
- new_ent =
- add_hd_table_incremental(&deflater->ctx, &nv_indname, name_hash,
- value_hash, NGHTTP2_HD_FLAG_VALUE_ALLOC);
+ new_ent = add_hd_table_incremental(&deflater->ctx, &nv_indname, token,
+ NGHTTP2_HD_FLAG_VALUE_ALLOC);
} else {
- new_ent = add_hd_table_incremental(
- &deflater->ctx, nv, name_hash, value_hash,
- NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC);
+ new_ent = add_hd_table_incremental(&deflater->ctx, nv, token,
+ NGHTTP2_HD_FLAG_NAME_ALLOC |
+ NGHTTP2_HD_FLAG_VALUE_ALLOC);
}
if (!new_ent) {
return NGHTTP2_ERR_HEADER_COMP;
@@ -1024,12 +1369,11 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
nghttp2_hd_entry_free(new_ent, mem);
nghttp2_mem_free(mem, new_ent);
}
- incidx = 1;
}
if (idx == -1) {
- rv = emit_newname_block(bufs, nv, incidx);
+ rv = emit_newname_block(bufs, nv, indexing_mode);
} else {
- rv = emit_indname_block(bufs, idx, nv, incidx);
+ rv = emit_indname_block(bufs, idx, nv, indexing_mode);
}
if (rv != 0) {
return rv;
@@ -1313,10 +1657,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) {
+ nghttp2_nv *nv_out, int *token_out) {
nghttp2_hd_entry *ent = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
- emit_indexed_header(nv_out, ent);
+ emit_indexed_header(nv_out, token_out, ent);
return 0;
}
@@ -1337,18 +1681,24 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
return NGHTTP2_ERR_NOMEM;
}
+ nghttp2_bufs_reset(&inflater->nvbufs);
+
buflen = 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;
- nv->valuelen = buflen - nv->namelen;
+ nv->value = buf + nv->namelen + 1;
+ nv->valuelen = buflen - nv->namelen - 2;
+ }
return 0;
}
@@ -1360,15 +1710,19 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
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;
- nv->valuelen = nghttp2_buf_len(pbuf) - nv->namelen;
+ 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);
@@ -1376,6 +1730,42 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
return 0;
}
+static int hd_inflate_remove_bufs_with_name(nghttp2_hd_inflater *inflater,
+ nghttp2_nv *nv,
+ nghttp2_hd_entry *ent_name) {
+ size_t rv;
+ size_t buflen;
+ uint8_t *buf;
+ nghttp2_mem *mem;
+
+ 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);
+ rv = 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;
+
+ return 0;
+}
+
/*
* Finalize literal header representation - new name- reception. If
* header is emitted, |*nv_out| is filled with that value and 0 is
@@ -1388,7 +1778,7 @@ static int hd_inflate_remove_bufs(nghttp2_hd_inflater *inflater, nghttp2_nv *nv,
* Out of memory
*/
static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
- nghttp2_nv *nv_out) {
+ nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv;
nghttp2_mem *mem;
@@ -1415,12 +1805,11 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
management. */
ent_flags = NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_NAME_GIFT;
- new_ent =
- add_hd_table_incremental(&inflater->ctx, &nv, hash(nv.name, nv.namelen),
- hash(nv.value, nv.valuelen), ent_flags);
+ new_ent = add_hd_table_incremental(
+ &inflater->ctx, &nv, lookup_token(nv.name, nv.namelen), ent_flags);
if (new_ent) {
- emit_indexed_header(nv_out, new_ent);
+ emit_indexed_header(nv_out, token_out, new_ent);
inflater->ent_keep = new_ent;
return 0;
@@ -1431,7 +1820,7 @@ static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
return NGHTTP2_ERR_NOMEM;
}
- emit_literal_header(nv_out, &nv);
+ emit_literal_header(nv_out, token_out, &nv);
if (nv.name != inflater->nvbufs.head->buf.pos) {
inflater->nv_keep = nv.name;
@@ -1452,7 +1841,7 @@ 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) {
+ nghttp2_nv *nv_out, int *token_out) {
int rv;
nghttp2_nv nv;
nghttp2_hd_entry *ent_name;
@@ -1460,11 +1849,6 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
mem = inflater->ctx.mem;
- rv = hd_inflate_remove_bufs(inflater, &nv, 1 /* value only */);
- if (rv != 0) {
- return NGHTTP2_ERR_NOMEM;
- }
-
if (inflater->no_index) {
nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
} else {
@@ -1473,34 +1857,36 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
ent_name = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
- nv.name = ent_name->nv.name;
- nv.namelen = ent_name->nv.namelen;
-
if (inflater->index_required) {
nghttp2_hd_entry *new_ent;
uint8_t ent_flags;
- int static_name;
- ent_flags = NGHTTP2_HD_FLAG_VALUE_ALLOC | NGHTTP2_HD_FLAG_VALUE_GIFT;
- static_name = inflater->index < NGHTTP2_STATIC_TABLE_LENGTH;
+ 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;
- if (!static_name) {
- ent_flags |= NGHTTP2_HD_FLAG_NAME_ALLOC;
- /* For entry in static table, we must not touch ref, because it
- is shared by threads */
- ++ent_name->ref;
+ 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;
}
- new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->name_hash,
- hash(nv.value, nv.valuelen), ent_flags);
+ new_ent = add_hd_table_incremental(&inflater->ctx, &nv, ent_name->token,
+ ent_flags);
- if (!static_name && --ent_name->ref == 0) {
- nghttp2_hd_entry_free(ent_name, mem);
- nghttp2_mem_free(mem, ent_name);
- }
+ /* At this point, ent_name might be deleted. */
if (new_ent) {
- emit_indexed_header(nv_out, new_ent);
+ emit_indexed_header(nv_out, token_out, new_ent);
inflater->ent_keep = new_ent;
@@ -1512,7 +1898,15 @@ static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
return NGHTTP2_ERR_NOMEM;
}
- emit_literal_header(nv_out, &nv);
+ 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;
+
+ emit_literal_header(nv_out, token_out, &nv);
if (nv.value != inflater->nvbufs.head->buf.pos) {
inflater->nv_keep = nv.value;
@@ -1524,10 +1918,21 @@ 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) {
+ int token;
+
+ return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, &token, in,
+ inlen, in_final);
+}
+
+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 rv = 0;
uint8_t *first = in;
uint8_t *last = in + inlen;
int rfin = 0;
+ int busy = 0;
if (inflater->ctx.bad) {
return NGHTTP2_ERR_HEADER_COMP;
@@ -1535,8 +1940,10 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
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;) {
+ for (; in != last || busy;) {
+ busy = 0;
switch (inflater->state) {
case NGHTTP2_HD_STATE_OPCODE:
if ((*in & 0xe0u) == 0x20u) {
@@ -1620,7 +2027,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->index = inflater->left;
--inflater->index;
- rv = hd_inflate_commit_indexed(inflater, nv_out);
+ rv = hd_inflate_commit_indexed(inflater, nv_out, token_out);
if (rv < 0) {
goto fail;
}
@@ -1688,6 +2095,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs);
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
break;
@@ -1709,6 +2121,11 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
inflater->newnamelen = nghttp2_bufs_len(&inflater->nvbufs);
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
break;
@@ -1734,19 +2151,6 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
}
DEBUGF(fprintf(stderr, "inflatehd: valuelen=%zu\n", inflater->left));
- if (inflater->left == 0) {
- if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
- } else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
- }
- if (rv != 0) {
- goto fail;
- }
- inflater->state = NGHTTP2_HD_STATE_OPCODE;
- *inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
- return (ssize_t)(in - first);
- }
if (inflater->huffman_encoded) {
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
@@ -1755,6 +2159,9 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
} else {
inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
}
+
+ busy = 1;
+
break;
case NGHTTP2_HD_STATE_READ_VALUEHUFF:
rv = hd_inflate_read_huff(inflater, &inflater->nvbufs, in, last);
@@ -1773,10 +2180,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
goto almost_ok;
}
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
+ rv = hd_inflate_commit_newname(inflater, nv_out, token_out);
} else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
+ rv = hd_inflate_commit_indname(inflater, nv_out, token_out);
}
if (rv != 0) {
@@ -1805,10 +2217,15 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
goto almost_ok;
}
+ rv = nghttp2_bufs_addb(&inflater->nvbufs, '\0');
+ if (rv != 0) {
+ goto fail;
+ }
+
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
- rv = hd_inflate_commit_newname(inflater, nv_out);
+ rv = hd_inflate_commit_newname(inflater, nv_out, token_out);
} else {
- rv = hd_inflate_commit_indname(inflater, nv_out);
+ rv = hd_inflate_commit_indname(inflater, nv_out, token_out);
}
if (rv != 0) {
@@ -1904,14 +2321,14 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
}
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
- nghttp2_nv *nv, int inc_indexing) {
+ nghttp2_nv *nv, int indexing_mode) {
- return emit_indname_block(bufs, idx, nv, inc_indexing);
+ return emit_indname_block(bufs, idx, nv, indexing_mode);
}
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
- int inc_indexing) {
- return emit_newname_block(bufs, nv, inc_indexing);
+ int indexing_mode) {
+ return emit_newname_block(bufs, nv, indexing_mode);
}
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
diff --git a/epan/nghttp2/nghttp2_hd.h b/epan/nghttp2/nghttp2_hd.h
index 1ed42c2ada..204d36ae98 100644
--- a/epan/nghttp2/nghttp2_hd.h
+++ b/epan/nghttp2/nghttp2_hd.h
@@ -49,7 +49,68 @@
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
/* Exported for unit test */
-extern const size_t NGHTTP2_STATIC_TABLE_LENGTH;
+#define NGHTTP2_STATIC_TABLE_LENGTH 61
+
+/* Generated by genlibtokenlookup.py */
+typedef enum {
+ NGHTTP2_TOKEN__AUTHORITY = 0,
+ NGHTTP2_TOKEN__METHOD = 1,
+ NGHTTP2_TOKEN__PATH = 3,
+ NGHTTP2_TOKEN__SCHEME = 5,
+ NGHTTP2_TOKEN__STATUS = 7,
+ NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
+ NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
+ NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
+ NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
+ NGHTTP2_TOKEN_ACCEPT = 18,
+ NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
+ NGHTTP2_TOKEN_AGE = 20,
+ NGHTTP2_TOKEN_ALLOW = 21,
+ NGHTTP2_TOKEN_AUTHORIZATION = 22,
+ NGHTTP2_TOKEN_CACHE_CONTROL = 23,
+ NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
+ NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
+ NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
+ NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
+ NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
+ NGHTTP2_TOKEN_CONTENT_RANGE = 29,
+ NGHTTP2_TOKEN_CONTENT_TYPE = 30,
+ NGHTTP2_TOKEN_COOKIE = 31,
+ NGHTTP2_TOKEN_DATE = 32,
+ NGHTTP2_TOKEN_ETAG = 33,
+ NGHTTP2_TOKEN_EXPECT = 34,
+ NGHTTP2_TOKEN_EXPIRES = 35,
+ NGHTTP2_TOKEN_FROM = 36,
+ NGHTTP2_TOKEN_HOST = 37,
+ NGHTTP2_TOKEN_IF_MATCH = 38,
+ NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
+ NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
+ NGHTTP2_TOKEN_IF_RANGE = 41,
+ NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
+ NGHTTP2_TOKEN_LAST_MODIFIED = 43,
+ NGHTTP2_TOKEN_LINK = 44,
+ NGHTTP2_TOKEN_LOCATION = 45,
+ NGHTTP2_TOKEN_MAX_FORWARDS = 46,
+ NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
+ NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
+ NGHTTP2_TOKEN_RANGE = 49,
+ NGHTTP2_TOKEN_REFERER = 50,
+ NGHTTP2_TOKEN_REFRESH = 51,
+ NGHTTP2_TOKEN_RETRY_AFTER = 52,
+ NGHTTP2_TOKEN_SERVER = 53,
+ NGHTTP2_TOKEN_SET_COOKIE = 54,
+ NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
+ NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
+ NGHTTP2_TOKEN_USER_AGENT = 57,
+ NGHTTP2_TOKEN_VARY = 58,
+ NGHTTP2_TOKEN_VIA = 59,
+ NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
+ NGHTTP2_TOKEN_TE,
+ NGHTTP2_TOKEN_CONNECTION,
+ NGHTTP2_TOKEN_KEEP_ALIVE,
+ NGHTTP2_TOKEN_PROXY_CONNECTION,
+ NGHTTP2_TOKEN_UPGRADE,
+} nghttp2_token;
typedef enum {
NGHTTP2_HD_FLAG_NONE = 0,
@@ -67,19 +128,15 @@ typedef enum {
typedef struct {
nghttp2_nv nv;
- uint32_t name_hash;
- uint32_t value_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;
} nghttp2_hd_entry;
typedef struct {
- nghttp2_hd_entry ent;
- size_t index;
-} nghttp2_hd_static_entry;
-
-typedef struct {
nghttp2_hd_entry **buffer;
size_t mask;
size_t first;
@@ -107,6 +164,12 @@ typedef enum {
NGHTTP2_HD_STATE_READ_VALUE
} nghttp2_hd_inflate_state;
+typedef enum {
+ NGHTTP2_HD_WITH_INDEXING,
+ NGHTTP2_HD_WITHOUT_INDEXING,
+ NGHTTP2_HD_NEVER_INDEXING
+} nghttp2_hd_indexing_mode;
+
typedef struct {
/* dynamic header table */
nghttp2_hd_ringbuf hd_table;
@@ -176,9 +239,8 @@ struct nghttp2_hd_inflater {
* 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 |name_hash| and |value_hash| are hash
- * value for |name| and |value| respectively. The hash function is
- * defined in nghttp2_hd.c.
+ * |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:
@@ -188,8 +250,7 @@ struct nghttp2_hd_inflater {
*/
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
size_t namelen, uint8_t *value, size_t valuelen,
- uint32_t name_hash, uint32_t value_hash,
- nghttp2_mem *mem);
+ int token, nghttp2_mem *mem);
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent, nghttp2_mem *mem);
@@ -271,13 +332,25 @@ 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().
+ */
+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);
+
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
- nghttp2_nv *nv, int inc_indexing);
+ nghttp2_nv *nv, int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
- int inc_indexing);
+ int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
@@ -324,8 +397,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
* 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() or export its content using
- * nghttp2_bufs_remove().
+ * by calling nghttp2_bufs_free().
*
* The caller must set the |final| to nonzero if the given input is
* the final block.
diff --git a/epan/nghttp2/nghttp2_hd_huffman.c b/epan/nghttp2/nghttp2_hd_huffman.c
index 6c4b2b64ce..4df1cd0425 100644
--- a/epan/nghttp2/nghttp2_hd_huffman.c
+++ b/epan/nghttp2/nghttp2_hd_huffman.c
@@ -168,10 +168,27 @@ 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,
size_t srclen, int final) {
- size_t i, j;
+ size_t i;
int rv;
size_t avail;
@@ -180,30 +197,28 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
/* We use the decoding algorithm described in
http://graphics.ics.uci.edu/pub/Prefix.pdf */
for (i = 0; i < srclen; ++i) {
- uint8_t in = src[i] >> 4;
- for (j = 0; j < 2; ++j) {
- const nghttp2_huff_decode *t;
+ const nghttp2_huff_decode *t;
- t = &huff_decode_table[ctx->state][in];
- if (t->flags & NGHTTP2_HUFF_FAIL) {
- return NGHTTP2_ERR_HEADER_COMP;
- }
- if (t->flags & NGHTTP2_HUFF_SYM) {
- if (avail) {
- nghttp2_bufs_fast_addb(bufs, t->sym);
- --avail;
- } else {
- rv = nghttp2_bufs_addb(bufs, t->sym);
- if (rv != 0) {
- return rv;
- }
- avail = nghttp2_bufs_cur_avail(bufs);
- }
- }
- ctx->state = t->state;
- ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
- in = src[i] & 0xf;
+ t = &huff_decode_table[ctx->state][src[i] >> 4];
+ if (t->flags & NGHTTP2_HUFF_FAIL) {
+ 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);
+ }
+
+ t = &huff_decode_table[t->state][src[i] & 0xf];
+ if (t->flags & NGHTTP2_HUFF_FAIL) {
+ 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);
+ }
+
+ ctx->state = t->state;
+ ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0;
}
if (final && !ctx->accept) {
return NGHTTP2_ERR_HEADER_COMP;
diff --git a/epan/nghttp2/nghttp2_helper.h b/epan/nghttp2/nghttp2_helper.h
index 0facb1ce41..19595b0cf8 100644
--- a/epan/nghttp2/nghttp2_helper.h
+++ b/epan/nghttp2/nghttp2_helper.h
@@ -27,12 +27,16 @@
#include <config.h>
+#include <string.h>
+
#include <nghttp2.h>
#include "nghttp2_mem.h"
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
+#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
+
/*
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
* network byte order.
diff --git a/epan/nghttp2/nghttp2_int.h b/epan/nghttp2/nghttp2_int.h
index 3d77eaab58..c26c8e99a1 100644
--- a/epan/nghttp2/nghttp2_int.h
+++ b/epan/nghttp2/nghttp2_int.h
@@ -39,7 +39,8 @@
} while (0)
#endif
-typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
+/* "less" function, return nonzero if |lhs| is less than |rhs|. */
+typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
/* Internal error code. They must be in the range [-499, -100],
inclusive. */
@@ -51,7 +52,7 @@ typedef enum {
* Invalid HTTP header field was received but it can be treated as
* if it was not received because of compatibility reasons.
*/
- NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
+ NGHTTP2_ERR_IGN_HTTP_HEADER = -105
} nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */
diff --git a/epan/nghttp2/nghttp2_net.h b/epan/nghttp2/nghttp2_net.h
index 3f82adf721..16b52b3263 100644
--- a/epan/nghttp2/nghttp2_net.h
+++ b/epan/nghttp2/nghttp2_net.h
@@ -37,8 +37,55 @@
#include <netinet/in.h>
#endif /* HAVE_NETINET_IN_H */
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif /* HAVE_WINSOCK2_H */
+#include <nghttp2.h>
+
+#if defined(WIN32)
+/* Windows requires ws2_32 library for ntonl family functions. We
+ define inline functions for those function so that we don't have
+ dependeny on that lib. */
+
+#ifdef _MSC_VER
+#define STIN static __inline
+#else
+#define STIN static inline
+#endif
+
+STIN uint32_t htonl(uint32_t hostlong) {
+ uint32_t res;
+ unsigned char *p = (unsigned char *)&res;
+ *p++ = hostlong >> 24;
+ *p++ = (hostlong >> 16) & 0xffu;
+ *p++ = (hostlong >> 8) & 0xffu;
+ *p = hostlong & 0xffu;
+ return res;
+}
+
+STIN uint16_t htons(uint16_t hostshort) {
+ uint16_t res;
+ unsigned char *p = (unsigned char *)&res;
+ *p++ = hostshort >> 8;
+ *p = hostshort & 0xffu;
+ return res;
+}
+
+STIN uint32_t ntohl(uint32_t netlong) {
+ uint32_t res;
+ unsigned char *p = (unsigned char *)&netlong;
+ res = *p++ << 24;
+ res += *p++ << 16;
+ res += *p++ << 8;
+ res += *p;
+ return res;
+}
+
+STIN uint16_t ntohs(uint16_t netshort) {
+ uint16_t res;
+ unsigned char *p = (unsigned char *)&netshort;
+ res = *p++ << 8;
+ res += *p;
+ return res;
+}
+
+#endif /* WIN32 */
#endif /* NGHTTP2_NET_H */
diff --git a/epan/nghttp2/nghttp2ver.h b/epan/nghttp2/nghttp2ver.h
index 51134a1b4d..8e67b275de 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 "0.7.5"
+#define NGHTTP2_VERSION "0.7.13"
/**
* @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 0x000705
+#define NGHTTP2_VERSION_NUM 0x00070d
#endif /* NGHTTP2VER_H */