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>
This commit is contained in:
Alexis La Goutte 2015-11-26 19:32:40 +01:00 committed by Anders Broman
parent f5b816d4c9
commit 20a41fae76
7 changed files with 468 additions and 120 deletions

View File

@ -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
@ -2819,6 +2865,40 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
int32_t stream_id,
size_t size);
/**
* @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
*
@ -2826,6 +2906,17 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
* 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
@ -2860,6 +2951,51 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
size_t settings_payloadlen,
void *stream_user_data);
/**
* @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
*
@ -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
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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";
}

View File

@ -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);
/*

View File

@ -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 */