diff options
author | Alexis La Goutte <alexis.lagoutte@gmail.com> | 2015-11-26 19:32:40 +0100 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2015-11-27 05:32:19 +0000 |
commit | 20a41fae76ab20c7e972bc7955ae901a5d71ef4c (patch) | |
tree | ed4e4f279286514b28c3e2209bddcee13e1bedbe /epan/nghttp2 | |
parent | f5b816d4c92e633453fe65dfa56d80ad32bab477 (diff) |
NGHTTP2: Update to 1.5.0
Change-Id: I18ec89d1d053014a023217f6a07d72c7791fd436
Reviewed-on: https://code.wireshark.org/review/12199
Petri-Dish: Alexis La Goutte <alexis.lagoutte@gmail.com>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/nghttp2')
-rw-r--r-- | epan/nghttp2/nghttp2.h | 430 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.c | 108 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd.h | 6 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_hd_huffman.c | 6 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_helper.c | 20 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2_helper.h | 14 | ||||
-rw-r--r-- | epan/nghttp2/nghttp2ver.h | 4 |
7 files changed, 468 insertions, 120 deletions
diff --git a/epan/nghttp2/nghttp2.h b/epan/nghttp2/nghttp2.h index ad5b501c7c..989b6c9aac 100644 --- a/epan/nghttp2/nghttp2.h +++ b/epan/nghttp2/nghttp2.h @@ -59,7 +59,11 @@ extern "C" { #define NGHTTP2_EXTERN __declspec(dllimport) #endif /* !BUILDING_NGHTTP2 */ #else /* !defined(WIN32) */ +#ifdef BUILDING_NGHTTP2 +#define NGHTTP2_EXTERN __attribute__((visibility("default"))) +#else /* !BUILDING_NGHTTP2 */ #define NGHTTP2_EXTERN +#endif /* !BUILDING_NGHTTP2 */ #endif /* !defined(WIN32) */ /* @@ -72,7 +76,6 @@ extern "C" { #undef NGHTTP2_EXTERN #define NGHTTP2_EXTERN WS_DLL_LOCAL - /** * @macro * @@ -412,7 +415,16 @@ typedef enum { * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was * received and further processing is not possible. */ - NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903 + NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903, + /** + * Possible flooding by peer was detected in this HTTP/2 session. + * Flooding is measured by how many PING and SETTINGS frames with + * ACK flag set are queued for transmission. These frames are + * response for the peer initiated frames, and peer can cause memory + * exhaustion on server side to send these frames forever and does + * not read network. + */ + NGHTTP2_ERR_FLOODED = -904 } nghttp2_error; /** @@ -430,7 +442,19 @@ typedef enum { * Header Field never Indexed" representation must be used in HPACK * encoding). Other implementation calls this bit as "sensitive". */ - NGHTTP2_NV_FLAG_NO_INDEX = 0x01 + NGHTTP2_NV_FLAG_NO_INDEX = 0x01, + /** + * This flag is set solely by application. If this flag is set, the + * library does not make a copy of header field name. This could + * improve performance. + */ + NGHTTP2_NV_FLAG_NO_COPY_NAME = 0x02, + /** + * This flag is set solely by application. If this flag is set, the + * library does not make a copy of header field value. This could + * improve performance. + */ + NGHTTP2_NV_FLAG_NO_COPY_VALUE = 0x04 } nghttp2_nv_flag; /** @@ -442,17 +466,27 @@ typedef struct { /** * 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 + * guaranteed to be NULL-terminated. For some callbacks + * (:type:`nghttp2_before_frame_send_callback`, + * :type:`nghttp2_on_frame_send_callback`, and + * :type:`nghttp2_on_frame_not_send_callback`), it may not be + * NULL-terminated if header field is passed from application with + * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`). When application + * is constructing this struct, |name| is not required to be * NULL-terminated. */ uint8_t *name; /** * 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. + * is guaranteed to be NULL-terminated. For some callbacks + * (:type:`nghttp2_before_frame_send_callback`, + * :type:`nghttp2_on_frame_send_callback`, and + * :type:`nghttp2_on_frame_not_send_callback`), it may not be + * NULL-terminated if header field is passed from application with + * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`). When + * application is constructing this struct, |value| is not required + * to be NULL-terminated. */ uint8_t *value; /** @@ -1195,26 +1229,30 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, * :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). + * bytes. If ``frame->data.padlen > 0``, send 1 byte of value + * ``frame->data.padlen - 1``. Then send exactly |length| bytes of + * application data. Finally, if ``frame->data.padlen > 1``, send + * ``frame->data.padlen - 1`` bytes of zero as 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 + * If it cannot send any data at 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. + * in that state, and all we can do is tear down connection). When + * data is fully processed, but application wants to make + * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return + * immediately without processing next frames, return + * :enum:`NGHTTP2_ERR_PAUSE`. 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, @@ -2313,8 +2351,8 @@ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session); * buffer up small chunks of data as necessary to avoid this * situation. */ -NGHTTP2_EXTERN 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 @@ -2379,6 +2417,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, * when |session| was configured as server and * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. + * :enum:`NGHTTP2_ERR_FLOODED` + * Flooding was detected in this HTTP/2 session, and it must be + * closed. This is most likely caused by misbehaviour of peer. */ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); @@ -2415,6 +2456,9 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); * when |session| was configured as server and * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. + * :enum:`NGHTTP2_ERR_FLOODED` + * Flooding was detected in this HTTP/2 session, and it must be + * closed. This is most likely caused by misbehaviour of peer. */ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, @@ -2506,7 +2550,7 @@ nghttp2_session_set_stream_user_data(nghttp2_session *session, * include the deferred DATA frames. */ NGHTTP2_EXTERN size_t - nghttp2_session_get_outbound_queue_size(nghttp2_session *session); +nghttp2_session_get_outbound_queue_size(nghttp2_session *session); /** * @function @@ -2522,8 +2566,9 @@ NGHTTP2_EXTERN size_t * * This function returns -1 if it fails. */ -NGHTTP2_EXTERN 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 @@ -2535,8 +2580,9 @@ NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_recv_data_length( * * This function returns -1 if it fails. */ -NGHTTP2_EXTERN 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 @@ -2553,7 +2599,7 @@ NGHTTP2_EXTERN int32_t nghttp2_session_get_stream_effective_local_window_size( * This function returns -1 if it fails. */ NGHTTP2_EXTERN int32_t - nghttp2_session_get_effective_recv_data_length(nghttp2_session *session); +nghttp2_session_get_effective_recv_data_length(nghttp2_session *session); /** * @function @@ -2566,7 +2612,7 @@ NGHTTP2_EXTERN int32_t * This function returns -1 if it fails. */ NGHTTP2_EXTERN int32_t - nghttp2_session_get_effective_local_window_size(nghttp2_session *session); +nghttp2_session_get_effective_local_window_size(nghttp2_session *session); /** * @function @@ -2583,8 +2629,8 @@ NGHTTP2_EXTERN int32_t * This function returns -1 if it fails. */ NGHTTP2_EXTERN int32_t - nghttp2_session_get_stream_remote_window_size(nghttp2_session *session, - int32_t stream_id); +nghttp2_session_get_stream_remote_window_size(nghttp2_session *session, + int32_t stream_id); /** * @function @@ -2594,7 +2640,7 @@ NGHTTP2_EXTERN int32_t * This function always succeeds. */ NGHTTP2_EXTERN int32_t - nghttp2_session_get_remote_window_size(nghttp2_session *session); +nghttp2_session_get_remote_window_size(nghttp2_session *session); /** * @function @@ -2720,8 +2766,8 @@ NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session); * :enum:`nghttp2_settings_id`. */ NGHTTP2_EXTERN uint32_t - nghttp2_session_get_remote_settings(nghttp2_session *session, - nghttp2_settings_id id); +nghttp2_session_get_remote_settings(nghttp2_session *session, + nghttp2_settings_id id); /** * @function @@ -2750,7 +2796,7 @@ NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session, * function returns 1 << 31. */ NGHTTP2_EXTERN uint32_t - nghttp2_session_get_next_stream_id(nghttp2_session *session); +nghttp2_session_get_next_stream_id(nghttp2_session *session); /** * @function @@ -2822,10 +2868,55 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, /** * @function * + * Changes priority of existing stream denoted by |stream_id|. The + * new priority specification is |pri_spec|. + * + * The priority is changed silently and instantly, and no PRIORITY + * frame will be sent to notify the peer of this change. This + * function may be useful for server to change the priority of pushed + * stream. + * + * If |session| is initialized as server, and ``pri_spec->stream_id`` + * points to the idle stream, the idle stream is created if it does + * not exist. The created idle stream will depend on root stream + * (stream 0) with weight 16. + * + * If stream denoted by ``pri_spec->stream_id`` is not found, we use + * default priority instead of given |pri_spec|. That is make stream + * depend on root stream with weight 16. + * + * 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` + * Attempted to depend on itself; or no stream exist for the given + * |stream_id|; or |stream_id| is 0 + */ +NGHTTP2_EXTERN int +nghttp2_session_change_stream_priority(nghttp2_session *session, + int32_t stream_id, + const nghttp2_priority_spec *pri_spec); + +/** + * @function + * * Performs post-process of HTTP Upgrade request. This function can * be called from both client and server, but the behavior is very * different in each other. * + * .. warning:: + * + * This function is deprecated in favor of + * `nghttp2_session_upgrade2()`, because this function lacks the + * parameter to tell the library the request method used in the + * original HTTP request. This information is required for client + * to validate actual response body length against content-length + * header field (see `nghttp2_option_set_no_http_messaging()`). If + * HEAD is used in request, the length of response body must be 0 + * regardless of value included in content-length header field. + * * If called from client side, the |settings_payload| must be the * value sent in ``HTTP2-Settings`` header field and must be decoded * by base64url decoder. The |settings_payloadlen| is the length of @@ -2863,6 +2954,51 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, /** * @function * + * Performs post-process of HTTP Upgrade request. This function can + * be called from both client and server, but the behavior is very + * different in each other. + * + * If called from client side, the |settings_payload| must be the + * value sent in ``HTTP2-Settings`` header field and must be decoded + * by base64url decoder. The |settings_payloadlen| is the length of + * |settings_payload|. The |settings_payload| is unpacked and its + * setting values will be submitted using `nghttp2_submit_settings()`. + * This means that the client application code does not need to submit + * SETTINGS by itself. The stream with stream ID=1 is opened and the + * |stream_user_data| is used for its stream_user_data. The opened + * stream becomes half-closed (local) state. + * + * If called from server side, the |settings_payload| must be the + * value received in ``HTTP2-Settings`` header field and must be + * decoded by base64url decoder. The |settings_payloadlen| is the + * length of |settings_payload|. It is treated as if the SETTINGS + * frame with that payload is received. Thus, callback functions for + * the reception of SETTINGS frame will be invoked. The stream with + * stream ID=1 is opened. The |stream_user_data| is ignored. The + * opened stream becomes half-closed (remote). + * + * If the request method is HEAD, pass nonzero value to + * |head_request|. Otherwise, pass 0. + * + * 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 |settings_payload| is badly formed. + * :enum:`NGHTTP2_ERR_PROTO` + * The stream ID 1 is already used or closed; or is not available. + */ +NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session, + const uint8_t *settings_payload, + size_t settings_payloadlen, + int head_request, + void *stream_user_data); + +/** + * @function + * * Serializes the SETTINGS values |iv| in the |buf|. The size of the * |buf| is specified by |buflen|. The number of entries in the |iv| * array is given by |niv|. The required space in |buf| for the |niv| @@ -2882,8 +3018,8 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, * The provided |buflen| size is too small to hold the output. */ NGHTTP2_EXTERN ssize_t - nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen, - const nghttp2_settings_entry *iv, size_t niv); +nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen, + const nghttp2_settings_entry *iv, size_t niv); /** * @function @@ -2950,7 +3086,15 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * * 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. + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. * * HTTP/2 specification has requirement about header fields in the * request HEADERS. See the specification for more details. @@ -2986,11 +3130,11 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * */ 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); +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 @@ -3006,7 +3150,15 @@ NGHTTP2_EXTERN int32_t * * 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. + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. * * HTTP/2 specification has requirement about header fields in the * response HEADERS. See the specification for more details. @@ -3063,7 +3215,15 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, * * 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. + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. * * For server, trailer must be followed by response HEADERS or * response DATA. The library does not check that response HEADERS @@ -3139,7 +3299,15 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * * 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. + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. * * The |stream_user_data| is a pointer to an arbitrary data which is * associated to the stream this frame will open. Therefore it is @@ -3177,11 +3345,10 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * */ 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); +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 @@ -3337,7 +3504,15 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, * * 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. + * |nva| is preserved. For header fields with + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name + * and value are not copied respectively. With + * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to + * pass header field name in lowercase. The application should + * maintain the references to them until + * :type:`nghttp2_on_frame_send_callback` or + * :type:`nghttp2_on_frame_not_send_callback` is called. * * The |promised_stream_user_data| is a pointer to an arbitrary data * which is associated to the promised stream this frame will open and @@ -3376,9 +3551,9 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, * */ 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); +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 @@ -3467,7 +3642,33 @@ NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session, * This function always succeeds. */ NGHTTP2_EXTERN int32_t - nghttp2_session_get_last_proc_stream_id(nghttp2_session *session); +nghttp2_session_get_last_proc_stream_id(nghttp2_session *session); + +/** + * @function + * + * Returns nonzero if new request can be sent from local endpoint. + * + * This function return 0 if request is not allowed for this session. + * There are several reasons why request is not allowed. Some of the + * reasons are: session is server; stream ID has been spent; GOAWAY + * has been sent or received. + * + * The application can call `nghttp2_submit_request()` without + * consulting this function. In that case, `nghttp2_submit_request()` + * may return error. Or, request is failed to sent, and + * :type:`nghttp2_on_stream_close_callback` is called. + */ +NGHTTP2_EXTERN int +nghttp2_session_check_request_allowed(nghttp2_session *session); + +/** + * @function + * + * Returns nonzero if |session| is initialized as server side session. + */ +NGHTTP2_EXTERN int +nghttp2_session_check_server_session(nghttp2_session *session); /** * @function @@ -3734,8 +3935,8 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, * The provided |buflen| size is too small to hold the output. */ 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); +nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf, + size_t buflen, const nghttp2_nv *nva, size_t nvlen); /** * @function @@ -3747,6 +3948,48 @@ NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater, const nghttp2_nv *nva, size_t nvlen); +/** + * @function + * + * Returns the number of entries that header table of |deflater| + * contains. This is the sum of the number of static table and + * dynamic table, so the return value is at least 61. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Returns the table entry denoted by |idx| from header table of + * |deflater|. The |idx| is 1-based, and idx=1 returns first entry of + * static table. idx=62 returns first entry of dynamic table if it + * exists. Specifying idx=0 is error, and this function returns NULL. + * If |idx| is strictly greater than the number of entries the tables + * contain, this function returns NULL. + */ +NGHTTP2_EXTERN +const nghttp2_nv * +nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx); + +/** + * @function + * + * Returns the used dynamic table size, including the overhead 32 + * bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater); + +/** + * @function + * + * Returns the maximum dynamic table size. + */ +NGHTTP2_EXTERN +size_t +nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater); + struct nghttp2_hd_inflater; /** @@ -3939,6 +4182,48 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, NGHTTP2_EXTERN int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater); +/** + * @function + * + * Returns the number of entries that header table of |inflater| + * contains. This is the sum of the number of static table and + * dynamic table, so the return value is at least 61. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Returns the table entry denoted by |idx| from header table of + * |inflater|. The |idx| is 1-based, and idx=1 returns first entry of + * static table. idx=62 returns first entry of dynamic table if it + * exists. Specifying idx=0 is error, and this function returns NULL. + * If |idx| is strictly greater than the number of entries the tables + * contain, this function returns NULL. + */ +NGHTTP2_EXTERN +const nghttp2_nv * +nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx); + +/** + * @function + * + * Returns the used dynamic table size, including the overhead 32 + * bytes per entry described in RFC 7541. + */ +NGHTTP2_EXTERN +size_t nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater); + +/** + * @function + * + * Returns the maximum dynamic table size. + */ +NGHTTP2_EXTERN +size_t +nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater); + struct nghttp2_stream; /** @@ -3962,8 +4247,8 @@ typedef struct nghttp2_stream nghttp2_stream; * call of `nghttp2_session_send()`, `nghttp2_session_mem_send()`, * `nghttp2_session_recv()`, and `nghttp2_session_mem_recv()`. */ -nghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, - int32_t stream_id); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id); /** * @enum @@ -4008,7 +4293,8 @@ typedef enum { * `nghttp2_session_get_root_stream()` will have stream state * :enum:`NGHTTP2_STREAM_STATE_IDLE`. */ -nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream); +NGHTTP2_EXTERN nghttp2_stream_proto_state +nghttp2_stream_get_state(nghttp2_stream *stream); /** * @function @@ -4017,7 +4303,8 @@ nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream); * stream ID 0. The returned pointer is valid until |session| is * freed by `nghttp2_session_del()`. */ -nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_session_get_root_stream(nghttp2_session *session); /** * @function @@ -4025,9 +4312,10 @@ nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session); * Returns the parent stream of |stream| in dependency tree. Returns * NULL if there is no such stream. */ -nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_parent(nghttp2_stream *stream); -int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); +NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); /** * @function @@ -4035,7 +4323,8 @@ int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); * Returns the next sibling stream of |stream| in dependency tree. * Returns NULL if there is no such stream. */ -nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_next_sibling(nghttp2_stream *stream); /** * @function @@ -4043,7 +4332,8 @@ nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream); * Returns the previous sibling stream of |stream| in dependency tree. * Returns NULL if there is no such stream. */ -nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); /** * @function @@ -4051,21 +4341,23 @@ nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); * Returns the first child stream of |stream| in dependency tree. * Returns NULL if there is no such stream. */ -nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream); +NGHTTP2_EXTERN nghttp2_stream * +nghttp2_stream_get_first_child(nghttp2_stream *stream); /** * @function * * Returns dependency weight to the parent stream of |stream|. */ -int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); +NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); /** * @function * * Returns the sum of the weight for |stream|'s children. */ -int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); +NGHTTP2_EXTERN int32_t +nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); #ifdef __cplusplus } diff --git a/epan/nghttp2/nghttp2_hd.c b/epan/nghttp2/nghttp2_hd.c index 69239829e8..15faa8f328 100644 --- a/epan/nghttp2/nghttp2_hd.c +++ b/epan/nghttp2/nghttp2_hd.c @@ -509,12 +509,14 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name, flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_NAME_ALLOC); ent->nv.name = (uint8_t *)""; } else { - /* copy including terminating NULL byte */ - ent->nv.name = (uint8_t *)nghttp2_memdup(name, namelen + 1, mem); + /* name may not be NULL terminated on compression. */ + ent->nv.name = (uint8_t *)nghttp2_mem_malloc(mem, namelen + 1); if (ent->nv.name == NULL) { rv = NGHTTP2_ERR_NOMEM; goto fail; } + memcpy(ent->nv.name, name, namelen); + ent->nv.name[namelen] = '\0'; } } else { ent->nv.name = name; @@ -525,12 +527,14 @@ int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name, flags = (uint8_t)(flags & ~NGHTTP2_HD_FLAG_VALUE_ALLOC); ent->nv.value = (uint8_t *)""; } else { - /* copy including terminating NULL byte */ - ent->nv.value = (uint8_t *)nghttp2_memdup(value, valuelen + 1, mem); + /* value may not be NULL terminated on compression. */ + ent->nv.value = (uint8_t *)nghttp2_mem_malloc(mem, valuelen + 1); if (ent->nv.value == NULL) { rv = NGHTTP2_ERR_NOMEM; goto fail2; } + memcpy(ent->nv.value, value, valuelen); + ent->nv.value[valuelen] = '\0'; } } else { ent->nv.value = value; @@ -796,6 +800,7 @@ int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) { } inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; + inflater->min_hd_table_bufsize_max = UINT32_MAX; inflater->ent_keep = NULL; inflater->nv_keep = NULL; @@ -1257,9 +1262,6 @@ add_hd_table_incremental(nghttp2_hd_context *context, const nghttp2_nv *nv, new_ent->seq = context->next_seq++; new_ent->hash = hash; - DEBUGF(fprintf(stderr, "deflatehd: indexed at %zu\n", - context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH)); - if (map) { hd_map_insert(map, new_ent); } @@ -1321,7 +1323,8 @@ static search_result search_hd_table(nghttp2_hd_context *context, return res; } - res.index = context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH; + res.index = + (ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH); if (exact_match) { res.name_value_match = 1; @@ -1378,9 +1381,24 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, return NGHTTP2_ERR_INVALID_STATE; } - inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE; + /* It seems that encoder is not required to send dynamic table size + update if the table size is not changed after applying + SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this + is the intention of the editor. If new maximum table size is + strictly smaller than the current negotiated maximum size, + encoder must send dynamic table size update. In other cases, we + cannot expect it to do so. */ + if (inflater->ctx.hd_table_bufsize_max > settings_hd_table_bufsize_max) { + inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE; + /* Remember minimum value, and validate that encoder sends the + value less than or equal to this. */ + inflater->min_hd_table_bufsize_max = settings_hd_table_bufsize_max; + } + inflater->settings_hd_table_bufsize_max = settings_hd_table_bufsize_max; + inflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max; + hd_context_shrink_table_size(&inflater->ctx, NULL); return 0; } @@ -1428,7 +1446,8 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs, nghttp2_mem *mem; uint32_t hash; - DEBUGF(fprintf(stderr, "deflatehd: deflating %s: %s\n", nv->name, nv->value)); + DEBUGF(fprintf(stderr, "deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen, + nv->name, (int)nv->valuelen, nv->value)); mem = deflater->ctx.mem; @@ -2130,8 +2149,10 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, break; case NGHTTP2_HD_STATE_READ_TABLE_SIZE: rfin = 0; - rv = hd_inflate_read_len(inflater, &rfin, in, last, 5, - inflater->settings_hd_table_bufsize_max); + rv = hd_inflate_read_len( + inflater, &rfin, in, last, 5, + nghttp2_min(inflater->min_hd_table_bufsize_max, + inflater->settings_hd_table_bufsize_max)); if (rv < 0) { goto fail; } @@ -2140,6 +2161,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, goto almost_ok; } DEBUGF(fprintf(stderr, "inflatehd: table_size=%zu\n", inflater->left)); + inflater->min_hd_table_bufsize_max = UINT32_MAX; inflater->ctx.hd_table_bufsize_max = inflater->left; hd_context_shrink_table_size(&inflater->ctx, NULL); inflater->state = NGHTTP2_HD_STATE_INFLATE_START; @@ -2397,7 +2419,8 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, if (in_final) { DEBUGF(fprintf(stderr, "inflatehd: in_final set\n")); - if (inflater->state != NGHTTP2_HD_STATE_OPCODE) { + if (inflater->state != NGHTTP2_HD_STATE_OPCODE && + inflater->state != NGHTTP2_HD_STATE_INFLATE_START) { DEBUGF(fprintf(stderr, "inflatehd: unacceptable state=%d\n", inflater->state)); rv = NGHTTP2_ERR_HEADER_COMP; @@ -2409,7 +2432,7 @@ ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, return (ssize_t)(in - first); almost_ok: - if (in_final && inflater->state != NGHTTP2_HD_STATE_OPCODE) { + if (in_final) { DEBUGF(fprintf(stderr, "inflatehd: input ended prematurely\n")); rv = NGHTTP2_ERR_HEADER_COMP; @@ -2492,3 +2515,60 @@ ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final, uint8_t *last, size_t prefix) { return decode_length(res, shift_ptr, final, initial, shift, in, last, prefix); } + +static size_t hd_get_num_table_entries(nghttp2_hd_context *context) { + return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH; +} + +static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context, + size_t idx) { + if (idx == 0) { + return NULL; + } + + --idx; + + if (!INDEX_RANGE_VALID(context, idx)) { + return NULL; + } + + return &nghttp2_hd_table_get(context, idx)->nv; +} + +size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) { + return hd_get_num_table_entries(&deflater->ctx); +} + +const nghttp2_nv * +nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx) { + return hd_get_table_entry(&deflater->ctx, idx); +} + +size_t +nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater) { + return deflater->ctx.hd_table_bufsize; +} + +size_t +nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater) { + return deflater->ctx.hd_table_bufsize_max; +} + +size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater) { + return hd_get_num_table_entries(&inflater->ctx); +} + +const nghttp2_nv * +nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx) { + return hd_get_table_entry(&inflater->ctx, idx); +} + +size_t +nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater) { + return inflater->ctx.hd_table_bufsize; +} + +size_t +nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater) { + return inflater->ctx.hd_table_bufsize_max; +} diff --git a/epan/nghttp2/nghttp2_hd.h b/epan/nghttp2/nghttp2_hd.h index 36adaf6ef4..f28c341a18 100644 --- a/epan/nghttp2/nghttp2_hd.h +++ b/epan/nghttp2/nghttp2_hd.h @@ -240,6 +240,8 @@ struct nghttp2_hd_inflater { /* The maximum header table size the inflater supports. This is the same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ size_t settings_hd_table_bufsize_max; + /* Minimum header table size set by nghttp2_hd_inflate_change_table_size */ + size_t min_hd_table_bufsize_max; /* The number of next shift to decode integer */ size_t shift; nghttp2_hd_opcode opcode; @@ -375,8 +377,8 @@ int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv, int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size); /* For unittesting purpose */ -NGHTTP2_EXTERN nghttp2_hd_entry * -nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index); +nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context, + size_t index); /* For unittesting purpose */ ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final, diff --git a/epan/nghttp2/nghttp2_hd_huffman.c b/epan/nghttp2/nghttp2_hd_huffman.c index fb2d167b03..48638b7527 100644 --- a/epan/nghttp2/nghttp2_hd_huffman.c +++ b/epan/nghttp2/nghttp2_hd_huffman.c @@ -30,9 +30,6 @@ #include "nghttp2_hd.h" -extern const nghttp2_huff_sym huff_sym_table[]; -extern const nghttp2_huff_decode huff_decode_table[][16]; - /* * Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits| * bits are not filled yet. The |rembits| must be in range [1, 8], @@ -157,7 +154,8 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src, const nghttp2_huff_sym *sym = &huff_sym_table[256]; assert(avail); /* Caution we no longer adjust avail here */ - nghttp2_bufs_fast_orb(bufs, (uint8_t)(sym->code >> (sym->nbits - rembits))); + nghttp2_bufs_fast_orb( + bufs, (uint8_t)(sym->code >> (sym->nbits - (size_t)rembits))); } return 0; diff --git a/epan/nghttp2/nghttp2_helper.c b/epan/nghttp2/nghttp2_helper.c index c75e082424..feec30d0aa 100644 --- a/epan/nghttp2/nghttp2_helper.c +++ b/epan/nghttp2/nghttp2_helper.c @@ -51,21 +51,6 @@ uint32_t nghttp2_get_uint32(const uint8_t *data) { return g_ntohl(n); } -void *nghttp2_memdup(const void *src, size_t n, nghttp2_mem *mem) { - void *dest; - - if (n == 0) { - return NULL; - } - - dest = nghttp2_mem_malloc(mem, n); - if (dest == NULL) { - return NULL; - } - memcpy(dest, src, n); - return dest; -} - /* Generated by gendowncasetbl.py */ static const uint8_t DOWNCASE_TBL[] = { 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, @@ -230,7 +215,7 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr, int nghttp2_should_send_window_update(int32_t local_window_size, int32_t recv_window_size) { - return recv_window_size >= local_window_size / 2; + return recv_window_size > 0 && recv_window_size >= local_window_size / 2; } const char *nghttp2_strerror(int error_code) { @@ -309,6 +294,9 @@ const char *nghttp2_strerror(int error_code) { return "The user callback function failed"; case NGHTTP2_ERR_BAD_CLIENT_MAGIC: return "Received bad client magic byte string"; + case NGHTTP2_ERR_FLOODED: + return "Flooding was detected in this HTTP/2 session, and it must be " + "closed"; default: return "Unknown error code"; } diff --git a/epan/nghttp2/nghttp2_helper.h b/epan/nghttp2/nghttp2_helper.h index 48008cf4f6..589864ba61 100644 --- a/epan/nghttp2/nghttp2_helper.h +++ b/epan/nghttp2/nghttp2_helper.h @@ -41,7 +41,7 @@ #define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0) #define nghttp2_struct_of(ptr, type, member) \ - ((type *)(void *)((char *)(ptr) - offsetof(type, member))) + ((type *)(void *)((char *)(ptr)-offsetof(type, member))) /* * Copies 2 byte unsigned integer |n| in host byte order to |buf| in @@ -67,18 +67,6 @@ uint16_t nghttp2_get_uint16(const uint8_t *data); */ uint32_t nghttp2_get_uint32(const uint8_t *data); -/* - * Allocates |n| bytes of memory and copy the memory region pointed by - * |src| with the length |n| bytes into it. Returns the allocated memory. - * - * This function returns pointer to allocated memory, or one of the - * following negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -void *nghttp2_memdup(const void *src, size_t n, nghttp2_mem *mem); - void nghttp2_downcase(uint8_t *s, size_t len); /* diff --git a/epan/nghttp2/nghttp2ver.h b/epan/nghttp2/nghttp2ver.h index 173f4648cd..120477697f 100644 --- a/epan/nghttp2/nghttp2ver.h +++ b/epan/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.3.3" +#define NGHTTP2_VERSION "1.5.0" /** * @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 0x010303 +#define NGHTTP2_VERSION_NUM 0x010500 #endif /* NGHTTP2VER_H */ |