summaryrefslogtreecommitdiff
path: root/Utilities/cmnghttp2
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-10-31 14:09:53 -0400
committerBrad King <brad.king@kitware.com>2022-10-31 14:09:53 -0400
commit8b736054084a55d09627fed5700e6987a7d9e63f (patch)
tree60838d26abeaa452b37b2975fb52f5081eeb019a /Utilities/cmnghttp2
parent66c953677531b705c7c9e2080c62b47bb896007f (diff)
parent7ce2a682a3e2e488a74dbc745766ac74e12f6a24 (diff)
downloadcmake-8b736054084a55d09627fed5700e6987a7d9e63f.tar.gz
Merge branch 'upstream-nghttp2' into update-nghttp2
# By nghttp2 upstream * upstream-nghttp2: nghttp2 2022-09-21 (87fef4ab)
Diffstat (limited to 'Utilities/cmnghttp2')
-rw-r--r--Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h1144
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.c6
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_buf.h2
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_extpri.c35
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_extpri.h65
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.c111
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_frame.h49
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.c14
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_hd.h1
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_helper.c176
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.c813
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_http.h51
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.c280
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_map.h70
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_net.h6
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.c22
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_option.h15
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.c3
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_outbound_item.h2
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.c3
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_pq.h10
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.c840
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_session.h77
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.c21
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_stream.h26
-rw-r--r--Utilities/cmnghttp2/lib/nghttp2_submit.c102
26 files changed, 3250 insertions, 694 deletions
diff --git a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
index e3aeb9fed3..61a14d99eb 100644
--- a/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
+++ b/Utilities/cmnghttp2/lib/includes/nghttp2/nghttp2.h
@@ -229,6 +229,13 @@ typedef struct {
#define NGHTTP2_CLIENT_MAGIC_LEN 24
/**
+ * @macro
+ *
+ * The default max number of settings per SETTINGS frame
+ */
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
+
+/**
* @enum
*
* Error codes used in this library. The code range is [-999, -500],
@@ -399,12 +406,17 @@ typedef enum {
*/
NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
/**
- * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
- * under unexpected condition and processing was terminated (e.g.,
- * out of memory). If application receives this error code, it must
- * stop using that :type:`nghttp2_session` object and only allowed
- * operation for that object is deallocate it using
- * `nghttp2_session_del()`.
+ * When a local endpoint receives too many settings entries
+ * in a single SETTINGS frame.
+ */
+ NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
+ /**
+ * The errors < :enum:`nghttp2_error.NGHTTP2_ERR_FATAL` mean that
+ * the library is under unexpected condition and processing was
+ * terminated (e.g., out of memory). If application receives this
+ * error code, it must stop using that :type:`nghttp2_session`
+ * object and only allowed operation for that object is deallocate
+ * it using `nghttp2_session_del()`.
*/
NGHTTP2_ERR_FATAL = -900,
/**
@@ -533,9 +545,9 @@ typedef struct {
* :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.
+ * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`).
+ * When application is constructing this struct, |name| is not
+ * required to be NULL-terminated.
*/
uint8_t *name;
/**
@@ -546,9 +558,9 @@ typedef struct {
* :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.
+ * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE`).
+ * When application is constructing this struct, |value| is not
+ * required to be NULL-terminated.
*/
uint8_t *value;
/**
@@ -622,7 +634,11 @@ typedef enum {
* The ORIGIN frame, which is defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*/
- NGHTTP2_ORIGIN = 0x0c
+ NGHTTP2_ORIGIN = 0x0c,
+ /**
+ * The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`.
+ */
+ NGHTTP2_PRIORITY_UPDATE = 0x10
} nghttp2_frame_type;
/**
@@ -691,7 +707,11 @@ typedef enum {
* SETTINGS_ENABLE_CONNECT_PROTOCOL
* (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
*/
- NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
+ NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
+ /**
+ * SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`)
+ */
+ NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
} nghttp2_settings_id;
/* Note: If we add SETTINGS, update the capacity of
NGHTTP2_INBOUND_NUM_IV as well */
@@ -705,8 +725,8 @@ typedef enum {
*
* Default maximum number of incoming concurrent streams. Use
* `nghttp2_submit_settings()` with
- * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
- * maximum number of incoming concurrent streams.
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS`
+ * to change the maximum number of incoming concurrent streams.
*
* .. note::
*
@@ -860,38 +880,41 @@ typedef enum {
* The implementation of this function must read at most |length|
* bytes of data from |source| (or possibly other places) and store
* 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|.
+ * reached, set :enum:`nghttp2_data_flag.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
+ * :enum:`nghttp2_data_flag.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.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 fields.
- * You cannot send trailer fields 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 trailer fields.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`nghttp2_data_flag.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 fields. You cannot send trailer fields after sending frame
+ * with END_STREAM set. To avoid this problem, one can set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along
+ * with :enum:`nghttp2_data_flag.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 trailer fields.
* `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
- * any data in this invocation. The library removes DATA frame from
- * the outgoing queue temporarily. To move back deferred DATA frame
- * to outgoing queue, call `nghttp2_session_resume_data()`.
+ * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED`
+ * without reading any data in this invocation. The library removes
+ * DATA frame from the outgoing queue temporarily. To move back
+ * deferred DATA frame to outgoing queue, call
+ * `nghttp2_session_resume_data()`.
*
* By default, |length| is limited to 16KiB at maximum. If peer
* allows larger frames, application can enlarge transmission buffer
@@ -900,16 +923,17 @@ typedef enum {
*
* If the application just wants to return from
* `nghttp2_session_send()` or `nghttp2_session_mem_send()` without
- * sending anything, return :enum:`NGHTTP2_ERR_PAUSE`.
+ * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`.
*
* In case of error, there are 2 choices. Returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
- * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. 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`. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream by issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. If a different
+ * error code is desirable, use `nghttp2_submit_rst_stream()` with a
+ * desired error code and then return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will
+ * signal the entire session failure.
*/
typedef ssize_t (*nghttp2_data_source_read_callback)(
nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
@@ -1289,8 +1313,9 @@ typedef union {
* |length| bytes of data stored in |data|. The |flags| is currently
* not used and always 0. It must return the number of bytes sent if
* it succeeds. If it cannot send any single byte without blocking,
- * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`. For other errors,
- * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The
+ * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. For
+ * other errors, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The
* |user_data| pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
@@ -1318,9 +1343,10 @@ 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.
+ * Callback function invoked when
+ * :enum:`nghttp2_data_flag.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
@@ -1338,21 +1364,22 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
* If all data were written successfully, return 0.
*
* 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). 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
+ * :enum:`nghttp2_error.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). 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_error.NGHTTP2_ERR_PAUSE`. If application decided to
+ * reset this stream, return
+ * :enum:`nghttp2_error.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.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which will
+ * result in connection closure. Returning any other value is treated
+ * as :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
*/
typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
nghttp2_frame *frame,
@@ -1369,11 +1396,13 @@ typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
* currently not used and always 0. It must return the number of
* bytes written in |buf| if it succeeds. If it cannot read any
* single byte without blocking, it must return
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF before it reads any
- * single byte, it must return :enum:`NGHTTP2_ERR_EOF`. For other
- * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
- * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`. The
- * |user_data| pointer is the third argument passed in to the call to
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF
+ * before it reads any single byte, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`. For other errors, it must
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * Returning 0 is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. The |user_data|
+ * pointer is the third argument passed in to the call to
* `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
*
* This callback is required if the application uses
@@ -1417,7 +1446,8 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
* The implementation of this function must return 0 if it succeeds.
* If nonzero value 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`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
@@ -1445,7 +1475,8 @@ 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_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
@@ -1468,9 +1499,9 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)(
* `nghttp2_session_server_new()`.
*
* If the application uses `nghttp2_session_mem_recv()`, it can return
- * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
- * return without processing further input bytes. The memory by
- * pointed by the |data| is retained until
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes. The memory by pointed by the |data| is retained until
* `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
* The application must retain the input bytes which was used to
* produce the |data| parameter, because it may refer to the memory
@@ -1479,7 +1510,8 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)(
* 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_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
@@ -1499,19 +1531,20 @@ typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
* `nghttp2_session_server_new()`.
*
* The implementation of this function must return 0 if it succeeds.
- * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the
- * transmission of the given frame.
+ * It can also return :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` to
+ * cancel the transmission of the given frame.
*
* If there is a fatal error while executing this callback, the
- * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
- * which makes `nghttp2_session_send()` and
- * `nghttp2_session_mem_send()` functions immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * implementation should return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which makes
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* If the other value is returned, it is treated as if
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. But the
- * implementation should not rely on this since the library may define
- * new return value to extend its capability.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ * But the implementation should not rely on this since the library
+ * may define new return value to extend its capability.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_before_frame_send_callback()`.
@@ -1530,7 +1563,8 @@ 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_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_frame_send_callback()`.
@@ -1552,7 +1586,8 @@ 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_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* `nghttp2_session_get_stream_user_data()` can be used to get
* associated data.
@@ -1583,7 +1618,8 @@ typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
* If nonzero is returned, it is treated as fatal error and
* `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
* `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
- * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * functions immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_stream_close_callback()`.
@@ -1601,10 +1637,11 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
* will be emitted by :type:`nghttp2_on_header_callback`.
*
* The ``frame->hd.flags`` may not have
- * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one
- * or more CONTINUATION frames are involved. But the application does
- * not need to care about that because the header name/value pairs are
- * emitted transparently regardless of CONTINUATION frames.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_HEADERS` flag set, which
+ * indicates that one or more CONTINUATION frames are involved. But
+ * the application does not need to care about that because the header
+ * name/value pairs are emitted transparently regardless of
+ * CONTINUATION frames.
*
* The server applications probably create an object to store
* information about new stream if ``frame->hd.type ==
@@ -1627,26 +1664,31 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
* trailer fields also has ``frame->headers.cat ==
* NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
*
- * 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,
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.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.
+ * return :enum:`nghttp2_error.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
+ * It can return
+ * :enum:`nghttp2_error.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,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * value is returned, it is treated as if
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
* `nghttp2_session_mem_recv()` function will immediately return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
@@ -1663,16 +1705,17 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* The |value| of length |valuelen| is header value. The |flags| is
* bitwise OR of one or more of :type:`nghttp2_nv_flag`.
*
- * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
- * must not index this name/value pair when forwarding it to the next
- * hop. More specifically, "Literal Header Field never Indexed"
- * representation must be used in HPACK encoding.
+ * If :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_INDEX` is set in
+ * |flags|, the receiver must not index this name/value pair when
+ * forwarding it to the next hop. More specifically, "Literal Header
+ * Field never Indexed" representation must be used in HPACK encoding.
*
* When this callback is invoked, ``frame->hd.type`` is either
- * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all
- * header name/value pairs are processed with this callback, and no
- * error has been detected, :type:`nghttp2_on_frame_recv_callback`
- * will be invoked. If there is an error in decompression,
+ * :enum:`nghttp2_frame_type.NGHTTP2_HEADERS` or
+ * :enum:`nghttp2_frame_type.NGHTTP2_PUSH_PROMISE`. After all header
+ * name/value pairs are processed with this callback, and no error has
+ * been detected, :type:`nghttp2_on_frame_recv_callback` will be
+ * invoked. If there is an error in decompression,
* :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
* invoked.
*
@@ -1690,34 +1733,39 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
* 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()`
- * return without processing further input bytes. The memory pointed
- * by |frame|, |name| and |value| parameters are retained until
- * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
- * The application must retain the input bytes which was used to
- * produce these parameters, because it may refer to the memory region
- * included in the input bytes.
- *
- * 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,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
+ * `nghttp2_session_mem_recv()` return without processing further
+ * input bytes. The memory pointed by |frame|, |name| and |value|
+ * parameters are retained until `nghttp2_session_mem_recv()` or
+ * `nghttp2_session_recv()` is called. The application must retain
+ * the input bytes which was used to produce these parameters, because
+ * it may refer to the memory region included in the input bytes.
+ *
+ * Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will
+ * close the stream (promised stream if frame is PUSH_PROMISE) by
+ * issuing RST_STREAM with
+ * :enum:`nghttp2_error_code.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.
+ * return :enum:`nghttp2_error.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
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical
- * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If
- * the other nonzero value is returned, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * It may return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For
+ * other critical failures, it must return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * nonzero value is returned, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_header_callback()`.
@@ -1784,11 +1832,12 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
*
* With this callback, application inspects the incoming invalid
* field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
- * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_PROTOCOL_ERROR`. To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
*
* If 0 is returned, the header field is ignored, and the stream is
* not reset.
@@ -1819,11 +1868,12 @@ typedef int (*nghttp2_on_invalid_header_callback)(
*
* With this callback, application inspects the incoming invalid
* field, and it also can reset stream from this callback by returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the
- * error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error
- * code, call `nghttp2_submit_rst_stream()` with the error code of
- * choice in addition to returning
- * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By
+ * default, the error code is
+ * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. To change the
+ * error code, call `nghttp2_submit_rst_stream()` with the error code
+ * of choice in addition to returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_on_invalid_header_callback2)(
nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name,
@@ -1837,11 +1887,12 @@ typedef int (*nghttp2_on_invalid_header_callback2)(
* |frame|. The application must choose the total length of payload
* including padded bytes in range [frame->hd.length, max_payloadlen],
* inclusive. Choosing number not in this range will be treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Returning
* ``frame->hd.length`` means no padding is added. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_select_padding_callback()`.
@@ -1861,16 +1912,17 @@ typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session,
* |remote_max_frame_size|)]. If a value greater than this range is
* returned than the max allow value will be used. Returning a value
* smaller than this range is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The |frame_type| is provided
- * for future extensibility and identifies the type of frame (see
- * :type:`nghttp2_frame_type`) for which to get the length for.
- * Currently supported frame types are: :enum:`NGHTTP2_DATA`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The
+ * |frame_type| is provided for future extensibility and identifies
+ * the type of frame (see :type:`nghttp2_frame_type`) for which to get
+ * the length for. Currently supported frame types are:
+ * :enum:`nghttp2_frame_type.NGHTTP2_DATA`.
*
* This callback can be used to control the length in bytes for which
* :type:`nghttp2_data_source_read_callback` is allowed to send to the
* remote endpoint. This callback is optional. Returning
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
- * failure.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the
+ * entire session failure.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
@@ -1897,7 +1949,8 @@ typedef ssize_t (*nghttp2_data_source_read_length_callback)(
* The implementation of this function must return 0 if it succeeds.
* If nonzero value 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`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*
* To set this callback to :type:`nghttp2_session_callbacks`, use
* `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
@@ -1916,14 +1969,15 @@ typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
* The implementation of this function must return 0 if it succeeds.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_on_extension_chunk_recv_callback)(
nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
@@ -1953,14 +2007,15 @@ typedef int (*nghttp2_on_extension_chunk_recv_callback)(
* |*payload|, and do its own mechanism to process extension frames.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
void **payload,
@@ -1982,17 +2037,18 @@ typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
* bytes written into |buf| when it succeeds.
*
* To abort processing this extension frame, return
- * :enum:`NGHTTP2_ERR_CANCEL`, and
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and
* :type:`nghttp2_on_frame_not_send_callback` will be invoked.
*
* If fatal error occurred, application should return
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
* `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
- * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the
- * other values are returned, currently they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is
- * strictly larger than |len|, it is treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * immediately return
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other
+ * values are returned, currently they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the return
+ * value is strictly larger than |len|, it is treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
uint8_t *buf, size_t len,
@@ -2017,12 +2073,12 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
*
* Normally, application should return 0 from this callback. If fatal
* error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
*/
typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
size_t len, void *user_data);
@@ -2043,12 +2099,12 @@ typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
*
* Normally, application should return 0 from this callback. If fatal
* error occurred while doing something in this callback, application
- * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case,
- * library will return immediately with return value
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value
- * is returned from this callback, they are treated as
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
- * rely on this details.
+ * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * In this case, library will return immediately with return value
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if
+ * nonzero value is returned from this callback, they are treated as
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application
+ * should not rely on this details.
*/
typedef int (*nghttp2_error_callback2)(nghttp2_session *session,
int lib_error_code, const char *msg,
@@ -2078,7 +2134,7 @@ typedef struct nghttp2_session_callbacks nghttp2_session_callbacks;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2275,7 +2331,7 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback(
* @function
*
* Sets callback function invoked when
- * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :enum:`nghttp2_data_flag.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(
@@ -2458,7 +2514,7 @@ typedef struct nghttp2_option nghttp2_option;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
@@ -2519,7 +2575,8 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
* If this option is not used or used with zero value, if MAGIC does
* not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
* and `nghttp2_session_mem_recv()` will return error
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal
+ * error.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
@@ -2604,8 +2661,8 @@ nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
* received. If this option is set to nonzero, the library won't send
* PING frame with ACK flag set in the response for incoming PING
* frame. The application can send PING frame with ACK flag set using
- * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
- * parameter.
+ * `nghttp2_submit_ping()` with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
+ * as flags parameter.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
int val);
@@ -2619,7 +2676,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
* `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If
* application attempts to send header fields larger than this limit,
* the transmission of the frame fails with error code
- * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FRAME_SIZE_ERROR`.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
@@ -2644,6 +2701,11 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
* This option prevents the library from retaining closed streams to
* maintain the priority tree. If this option is set to nonzero,
* applications can discard closed stream completely to save memory.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, any
+ * closed streams are not retained regardless of this option.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
int val);
@@ -2662,6 +2724,47 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
/**
* @function
*
+ * This function sets the maximum number of SETTINGS entries per
+ * SETTINGS frame that will be accepted. If more than those entries
+ * are received, the peer is considered to be misbehaving and session
+ * will be closed. The default value is 32.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
+ size_t val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, allows server to fallback to
+ * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not
+ * received from client, and server submitted
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * = 1 via `nghttp2_submit_settings()`. Most of the advanced
+ * functionality for RFC 7540 priorities are still disabled. This
+ * fallback only enables the minimal feature set of RFC 7540
+ * priorities to deal with priority signaling from client.
+ *
+ * Client session ignores this option.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option,
+ int val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, turns off RFC 9113 leading and
+ * trailing white spaces validation against HTTP field value. Some
+ * important fields, such as HTTP/2 pseudo header fields, are
+ * validated more strictly and this option does not apply to them.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
* Initializes |*session_ptr| for client use. The all members of
* |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
* does not store |callbacks|. The |user_data| is an arbitrary user
@@ -2677,7 +2780,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2703,7 +2806,7 @@ nghttp2_session_client_new(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2729,7 +2832,7 @@ nghttp2_session_server_new(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2755,7 +2858,7 @@ nghttp2_session_client_new2(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -2781,7 +2884,7 @@ nghttp2_session_server_new2(nghttp2_session **session_ptr,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_client_new3(
@@ -2806,7 +2909,7 @@ NGHTTP2_EXTERN int nghttp2_session_client_new3(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_server_new3(
@@ -2828,12 +2931,14 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
*
* This function retrieves the highest prioritized frame from the
* outbound queue and sends it to the remote peer. It does this as
- * many as possible until the user callback
+ * many times as possible until the user callback
* :type:`nghttp2_send_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty.
- * This function calls several callback functions which are passed
- * when initializing the |session|. Here is the simple time chart
- * which tells when each callback is invoked:
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`, the outbound queue
+ * becomes empty or flow control is triggered (remote window size
+ * becomes depleted or maximum number of concurrent streams is
+ * reached). This function calls several callback functions which are
+ * passed when initializing the |session|. Here is the simple time
+ * chart which tells when each callback is invoked:
*
* 1. Get the next frame to send from outbound queue.
*
@@ -2851,7 +2956,7 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
*
* 6. :type:`nghttp2_before_frame_send_callback` is invoked.
*
- * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from
+ * 7. If :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` is returned from
* :type:`nghttp2_before_frame_send_callback`, the current frame
* transmission is canceled, and
* :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort
@@ -2869,9 +2974,9 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
*/
NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
@@ -2903,7 +3008,7 @@ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
* |*data_ptr| if it succeeds, or one of the following negative error
* codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*
* .. note::
@@ -2925,8 +3030,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
*
* This function receives as many frames as possible until the user
* callback :type:`nghttp2_recv_callback` returns
- * :enum:`NGHTTP2_ERR_WOULDBLOCK`. This function calls several
- * callback functions which are passed when initializing the
+ * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. This function calls
+ * several callback functions which are passed when initializing the
* |session|. Here is the simple time chart which tells when each
* callback is invoked:
*
@@ -2971,18 +3076,18 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_EOF`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`
* The remote peer did shutdown on the connection.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.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.
*/
@@ -2992,7 +3097,7 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
* @function
*
* Processes data |in| as an input from the remote endpoint. The
- * |inlen| indicates the number of bytes in the |in|.
+ * |inlen| indicates the number of bytes to receive in the |in|.
*
* This function behaves like `nghttp2_session_recv()` except that it
* does not use :type:`nghttp2_recv_callback` to receive data; the
@@ -3001,27 +3106,27 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
* are called in the same way as they are in `nghttp2_session_recv()`.
*
* In the current implementation, this function always tries to
- * processes all input data unless either an error occurs or
- * :enum:`NGHTTP2_ERR_PAUSE` is returned from
+ * processes |inlen| bytes of input data unless either an error occurs or
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from
* :type:`nghttp2_on_header_callback` or
* :type:`nghttp2_on_data_chunk_recv_callback`. If
- * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the
- * number of bytes which was used to produce the data or frame for the
- * callback.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value
+ * includes the number of bytes which was used to produce the data or
+ * frame for the callback.
*
* This function returns the number of processed bytes, or one of the
* following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`
* The callback function failed.
- * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`
* Invalid client magic was detected. This error only returns
* when |session| was configured as server and
* `nghttp2_option_set_no_recv_client_magic()` is not used with
* nonzero value.
- * :enum:`NGHTTP2_ERR_FLOODED`
+ * :enum:`nghttp2_error.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.
*/
@@ -3038,9 +3143,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The stream does not exist; or no deferred data exist.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
@@ -3101,7 +3206,7 @@ nghttp2_session_get_stream_user_data(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The stream does not exist
*/
NGHTTP2_EXTERN int
@@ -3318,7 +3423,7 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
@@ -3345,9 +3450,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |last_stream_id| is invalid.
*/
NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
@@ -3362,7 +3467,7 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
*
* This function is only usable for server. If this function is
* called with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
* To gracefully shutdown HTTP/2 session, server should call this
* function to send GOAWAY with last_stream_id (1u << 31) - 1. And
@@ -3384,9 +3489,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The |session| is initialized as client.
*/
NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
@@ -3421,7 +3526,7 @@ NGHTTP2_EXTERN uint32_t nghttp2_session_get_local_settings(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |next_stream_id| is strictly less than the value
* `nghttp2_session_get_next_stream_id()` returns; or
* |next_stream_id| is invalid (e.g., even integer for client, or
@@ -3456,11 +3561,11 @@ nghttp2_session_get_next_stream_id(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
@@ -3477,9 +3582,9 @@ NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
@@ -3496,11 +3601,11 @@ NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* Automatic WINDOW_UPDATE is not disabled.
*/
NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
@@ -3527,12 +3632,17 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Attempted to depend on itself; or no stream exist for the given
* |stream_id|; or |stream_id| is 0
*/
@@ -3570,12 +3680,17 @@ nghttp2_session_change_stream_priority(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Attempted to depend on itself; or stream denoted by |stream_id|
* already exists; or |stream_id| cannot be used to create idle
* stream (in other words, local endpoint has already opened
@@ -3626,11 +3741,11 @@ nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The stream ID 1 is already used or closed; or is not available.
*/
NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
@@ -3670,11 +3785,11 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |settings_payload| is badly formed.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.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,
@@ -3698,10 +3813,10 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
* This function returns the number of bytes written in |buf|, or one
* of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |iv| contains duplicate settings ID or invalid value.
*
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload(
@@ -3732,8 +3847,8 @@ NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code);
* on with |weight| and its exclusive flag. If |exclusive| is
* nonzero, exclusive flag is set.
*
- * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
- * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
+ * The |weight| must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive.
*/
NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
int32_t stream_id,
@@ -3768,11 +3883,17 @@ 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
- * 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`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
@@ -3783,12 +3904,12 @@ 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. 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
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.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.
*
@@ -3810,15 +3931,15 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* This function returns assigned stream ID if it succeeds, or one of
* the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* Trying to depend on itself (new stream ID equals
* ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is server session.
*
* .. warning::
@@ -3853,12 +3974,12 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* 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 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
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.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.
*
@@ -3884,16 +4005,16 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. Normally, this does not happen, but when
* application wrongly calls `nghttp2_submit_response()` twice,
* this may happen.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is client session.
*
* .. warning::
@@ -3919,12 +4040,12 @@ 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. 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
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.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.
*
@@ -3936,16 +4057,16 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* |nva| will be sent as response headers, which will result in error.
*
* This function has the same effect with `nghttp2_submit_headers()`,
- * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and
- * stream_user_data to NULL.
+ * with flags = :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` and both
+ * pri_spec and stream_user_data to NULL.
*
* To submit trailer fields after `nghttp2_submit_response()` is
* called, the application has to specify
* :type:`nghttp2_data_provider` to `nghttp2_submit_response()`.
* Inside of :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 fields using
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM`. After
+ * that, the application can send trailer fields using
* `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used
* inside :type:`nghttp2_data_source_read_callback`.
*
@@ -3953,9 +4074,9 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* Otherwise, this function returns 0 if it succeeds, or one of the
* following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
*/
NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
@@ -3968,10 +4089,10 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* Submits HEADERS frame. The |flags| is bitwise OR of the
* following values:
*
- * * :enum:`NGHTTP2_FLAG_END_STREAM`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`
*
- * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
- * END_STREAM flag set.
+ * If |flags| includes :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`,
+ * this frame has END_STREAM flag set.
*
* The library handles the CONTINUATION frame internally and it
* correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE
@@ -3988,11 +4109,16 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* 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
- * 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`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
*
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
@@ -4003,12 +4129,12 @@ 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. 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
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.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.
*
@@ -4026,19 +4152,19 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* |stream_id| is -1. Otherwise, this function returns 0 if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; or trying to depend on itself (stream ID
* equals ``pri_spec->stream_id``).
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. This happens if stream denoted by |stream_id|
* is in reserved state.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |stream_id| is -1, and |session| is server session.
*
* .. warning::
@@ -4060,8 +4186,8 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers(
*
* Submits one or more DATA frames to the stream |stream_id|. The
* data to be sent are provided by |data_prd|. If |flags| contains
- * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM
- * flag set.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame
+ * has END_STREAM flag set.
*
* This function does not take ownership of the |data_prd|. The
* function copies the members of the |data_prd|.
@@ -4069,27 +4195,28 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
* .. note::
*
* Currently, only one DATA or HEADERS is allowed for a stream at a
* time. Submitting these frames more than once before first DATA
- * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
- * error code. The earliest callback which tells that previous
- * frame is done is :type:`nghttp2_on_frame_send_callback`. In side
- * that callback, new data can be submitted using
- * `nghttp2_submit_data()`. Of course, all data except for last one
- * must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
- * |flags|. This sounds a bit complicated, and we recommend to use
+ * or HEADERS is finished results in
+ * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code. The
+ * earliest callback which tells that previous frame is done is
+ * :type:`nghttp2_on_frame_send_callback`. In side that callback,
+ * new data can be submitted using `nghttp2_submit_data()`. Of
+ * course, all data except for last one must not have
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|.
+ * This sounds a bit complicated, and we recommend to use
* `nghttp2_submit_request()` and `nghttp2_submit_response()` to
* avoid this cascading issue. The experience shows that for HTTP
* use, these two functions are enough to implement both client and
@@ -4106,25 +4233,31 @@ NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* to the priority specification |pri_spec|.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |pri_spec| is priority specification of this request. ``NULL``
* is not allowed for this function. To specify the priority, use
* `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
- * 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`.
+ * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`,
+ * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight``
+ * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
+ * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
+ * :macro:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, this function does
+ * nothing and returns 0.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
* depend on itself.
*/
@@ -4134,6 +4267,61 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
const nghttp2_priority_spec *pri_spec);
/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency
+ * level for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level
+ * for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_HIGH 0
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for
+ * :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LOW 7
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency
+ * levels for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1)
+
+/**
+ * @struct
+ *
+ * :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities
+ * specification for a stream.
+ */
+typedef struct nghttp2_extpri {
+ /**
+ * :member:`urgency` is the urgency of a stream, it must be in
+ * [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`,
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the
+ * highest urgency.
+ */
+ uint32_t urgency;
+ /**
+ * :member:`inc` indicates that a content can be processed
+ * incrementally or not. If inc is 0, it cannot be processed
+ * incrementally. If inc is 1, it can be processed incrementally.
+ * Other value is not permitted.
+ */
+ int inc;
+} nghttp2_extpri;
+
+/**
* @function
*
* Submits RST_STREAM frame to cancel/reject the stream |stream_id|
@@ -4142,14 +4330,14 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
* The pre-defined error code is one of :enum:`nghttp2_error_code`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
*/
NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
@@ -4164,7 +4352,7 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* indicates the number of :type:`nghttp2_settings_entry`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This function does not take ownership of the |iv|. This function
* copies all the elements in the |iv|.
@@ -4173,16 +4361,17 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
* RST_STREAM is issued against such a stream.
*
- * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted
- * by the library and application could not send it at its will.
+ * SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is
+ * automatically submitted by the library and application could not
+ * send it at its will.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |iv| contains invalid value (e.g., initial window size
* strictly greater than (1 << 31) - 1.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
@@ -4210,12 +4399,12 @@ 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. 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
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set,
+ * header field name and value are not copied respectively. With
+ * :enum:`nghttp2_nv_flag.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.
*
@@ -4234,18 +4423,18 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* This function returns assigned promised stream ID if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_PROTO`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* This function was invoked when |session| is initialized as
* client.
- * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; The |stream_id| does not designate stream
* that peer initiated.
- * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
* .. warning::
@@ -4274,10 +4463,10 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise(
*
* The |flags| is bitwise OR of 0 or more of the following value.
*
- * * :enum:`NGHTTP2_FLAG_ACK`
+ * * :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK`
*
* Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
- * should be :enum:`NGHTTP2_FLAG_NONE`.
+ * should be :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* If the |opaque_data| is non ``NULL``, then it should point to the 8
* bytes array of memory to specify opaque data to send with PING
@@ -4287,7 +4476,7 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise(
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
@@ -4302,7 +4491,7 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
* The pre-defined error code is one of :enum:`nghttp2_error_code`.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |last_stream_id| is peer's stream ID or 0. So if |session| is
* initialized as client, |last_stream_id| must be even or 0. If
@@ -4332,9 +4521,9 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |opaque_data_len| is too large; the |last_stream_id| is
* invalid.
*/
@@ -4390,7 +4579,7 @@ nghttp2_session_check_server_session(nghttp2_session *session);
* Submits WINDOW_UPDATE frame.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.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|.
@@ -4417,9 +4606,9 @@ nghttp2_session_check_server_session(nghttp2_session *session);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_FLOW_CONTROL`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_FLOW_CONTROL`
* The local window size overflow or gets negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
@@ -4437,7 +4626,7 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
* to transmission queue.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* This sounds similar to `nghttp2_submit_window_update()`, but there
* are 2 differences. The first difference is that this function
@@ -4456,9 +4645,9 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is negative.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4489,18 +4678,19 @@ nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags,
*
* The standard HTTP/2 frame cannot be sent with this function, so
* |type| must be strictly grater than 0x9. Otherwise, this function
- * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
+ * will fail with error code
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* If :type:`nghttp2_pack_extension_callback` is not set.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* If |type| specifies standard HTTP/2 frame type. The frame
* types in the rage [0x0, 0x9], both inclusive, are standard
* HTTP/2 frame type, and cannot be sent using this function.
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
*/
NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
@@ -4514,8 +4704,8 @@ NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
* extension to HTTP/2. If this frame is received, and
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ALTSVC`,
+ * ``nghttp2_extension.payload`` will point to this struct.
*
* It has the following members:
*/
@@ -4549,7 +4739,7 @@ typedef struct {
* `RFC 7383 <https://tools.ietf.org/html/rfc7838#section-4>`_.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |origin| points to the origin this alternative service is
* associated with. The |origin_len| is the length of the origin. If
@@ -4559,16 +4749,16 @@ typedef struct {
*
* The ALTSVC frame is only usable from server side. If this function
* is invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called from client side session
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The sum of |origin_len| and |field_value_len| is larger than
* 16382; or |origin_len| is 0 while |stream_id| is 0; or
* |origin_len| is not 0 while |stream_id| is not 0.
@@ -4607,8 +4797,8 @@ typedef struct {
* If this frame is received, and
* `nghttp2_option_set_user_recv_extension_type()` is not set, and
* `nghttp2_option_set_builtin_recv_extension_type()` is set for
- * :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to
- * this struct.
+ * :enum:`nghttp2_frame_type.NGHTTP2_ORIGIN`,
+ * ``nghttp2_extension.payload`` will point to this struct.
*
* It has the following members:
*/
@@ -4632,7 +4822,7 @@ typedef struct {
* `RFC 8336 <https://tools.ietf.org/html/rfc8336>`_.
*
* The |flags| is currently ignored and should be
- * :enum:`NGHTTP2_FLAG_NONE`.
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
*
* The |ov| points to the array of origins. The |nov| specifies the
* number of origins included in |ov|. This function creates copies
@@ -4640,13 +4830,13 @@ typedef struct {
*
* The ORIGIN frame is only usable by a server. If this function is
* invoked with client side session, this function returns
- * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`.
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called from client side session.
- * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* There are too many origins, or an origin is too large to fit
* into a default frame payload.
*/
@@ -4656,6 +4846,108 @@ NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session,
size_t nov);
/**
+ * @struct
+ *
+ * The payload of PRIORITY_UPDATE frame. PRIORITY_UPDATE frame is a
+ * non-critical extension to HTTP/2. If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`nghttp2_frame_type.NGHTTP2_PRIORITY_UPDATE`,
+ * ``nghttp2_extension.payload`` will point to this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+ /**
+ * The stream ID of the stream whose priority is updated.
+ */
+ int32_t stream_id;
+ /**
+ * The pointer to Priority field value. It is not necessarily
+ * NULL-terminated.
+ */
+ uint8_t *field_value;
+ /**
+ * The length of the :member:`field_value`.
+ */
+ size_t field_value_len;
+} nghttp2_ext_priority_update;
+
+/**
+ * @function
+ *
+ * Submits PRIORITY_UPDATE frame.
+ *
+ * PRIORITY_UPDATE frame is a non-critical extension to HTTP/2, and
+ * defined in :rfc:`9218#section-7.1`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the ID of stream which is prioritized. The
+ * |field_value| points to the Priority field value. The
+ * |field_value_len| is the length of the Priority field value.
+ *
+ * If this function is called by server,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` is returned.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 0 is received by a remote endpoint (or it is omitted),
+ * this function does nothing and returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The function is called from server side session
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * The |field_value_len| is larger than 16380; or |stream_id| is
+ * 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session,
+ uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Changes the priority of the existing stream denoted by |stream_id|.
+ * The new priority is |extpri|. This function is meant to be used by
+ * server for :rfc:`9218` extensible prioritization scheme.
+ *
+ * If |session| is initialized as client, this function returns
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. For client, use
+ * `nghttp2_submit_priority_update()` instead.
+ *
+ * If :member:`extpri->urgency <nghttp2_extpri.urgency>` is out of
+ * bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`.
+ *
+ * If |ignore_client_signal| is nonzero, server starts to ignore
+ * client priority signals for this stream.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is not submitted via `nghttp2_submit_settings()`,
+ * this function does nothing and returns 0.
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The |session| is initialized as client.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * |stream_id| is zero; or a stream denoted by |stream_id| is not
+ * found.
+ */
+NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri,
+ int ignore_client_signal);
+
+/**
* @function
*
* Compares ``lhs->name`` of length ``lhs->namelen`` bytes and
@@ -4766,13 +5058,51 @@ NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
* Returns nonzero if HTTP header field value |value| of length |len|
* is valid according to
* http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * This function is considered obsolete, and application should
+ * consider to use `nghttp2_check_header_value_rfc9113()` instead.
*/
NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
/**
* @function
*
- * Returns nonzero if the |value| which is supposed to the value of
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2, plus
+ * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value,
+ size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :method header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7231#section-4 and
+ * https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
+ */
+NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of
+ * the :path header field is valid according to
+ * https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3
+ *
+ * |value| is valid if it merely consists of the allowed characters.
+ * In particular, it does not check whether |value| follows the syntax
+ * of path. The allowed characters are all characters valid by
+ * `nghttp2_check_header_value` minus SPC and HT.
+ */
+NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |value| which is supposed to be the value of the
* :authority or host header field is valid according to
* https://tools.ietf.org/html/rfc3986#section-3.2
*
@@ -4806,7 +5136,7 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4860,7 +5190,7 @@ NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int
@@ -4874,24 +5204,24 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
* the |buf| of length |buflen|.
*
* If |buf| is not large enough to store the deflated header block,
- * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The
- * caller should use `nghttp2_hd_deflate_bound()` to know the upper
- * bound of buffer size required to deflate given header name/value
- * pairs.
+ * this function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
+ * should use `nghttp2_hd_deflate_bound()` to know the upper bound of
+ * buffer size required to deflate given header name/value pairs.
*
* Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
*
* After this function returns, it is safe to delete the |nva|.
*
* This function returns the number of bytes written to |buf| if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
@@ -4907,23 +5237,24 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
* must be set in len field of :type:`nghttp2_vec`. If and only if
* one chunk is filled up completely, next chunk will be used. If
* |vec| is not large enough to store the deflated header block, this
- * function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
+ * function fails with
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller
* should use `nghttp2_hd_deflate_bound()` to know the upper bound of
* buffer size required to deflate given header name/value pairs.
*
* Once this function fails, subsequent call of this function always
- * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`.
*
* After this function returns, it is safe to delete the |nva|.
*
* This function returns the number of bytes written to |vec| if it
* succeeds, or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Deflation process has failed.
- * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`
* The provided |buflen| size is too small to hold the output.
*/
NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
@@ -5003,7 +5334,7 @@ typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
@@ -5052,9 +5383,9 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
* The function is called while header block is being inflated.
* Probably, application missed to call
* `nghttp2_hd_inflate_end_headers()`.
@@ -5092,7 +5423,8 @@ typedef enum {
*
* Inflates name/value block stored in |in| with length |inlen|. This
* function performs decompression. For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
* |*inflate_flags| and name/value pair is assigned to the |nv_out|
* and the function returns. The caller must not free the members of
* |nv_out|.
@@ -5115,11 +5447,11 @@ typedef enum {
* This function returns the number of bytes processed if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
* The header field name or value is too large.
*
* Example follows::
@@ -5174,7 +5506,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
*
* Inflates name/value block stored in |in| with length |inlen|. This
* function performs decompression. For each successful emission of
- * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * header name/value pair,
+ * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in
* |*inflate_flags| and name/value pair is assigned to the |nv_out|
* and the function returns. The caller must not free the members of
* |nv_out|.
@@ -5190,8 +5523,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
* for the next header block input.
*
* In other words, if |in_final| is nonzero, and this function returns
- * |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is
- * set in |*inflate_flags|.
+ * |inlen|, you can assert that
+ * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in
+ * |*inflate_flags|.
*
* The caller can feed complete compressed header block. It also can
* feed it in several chunks. The caller must set |in_final| to
@@ -5201,11 +5535,11 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
* This function returns the number of bytes processed if it succeeds,
* or one of the following negative error codes:
*
- * :enum:`NGHTTP2_ERR_NOMEM`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
- * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`
* Inflation process has failed.
- * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR`
* The header field name or value is too large.
*
* Example follows::
@@ -5376,7 +5710,7 @@ typedef enum {
*
* Returns state of |stream|. The root stream retrieved by
* `nghttp2_session_get_root_stream()` will have stream state
- * :enum:`NGHTTP2_STREAM_STATE_IDLE`.
+ * :enum:`nghttp2_stream_proto_state.NGHTTP2_STREAM_STATE_IDLE`.
*/
NGHTTP2_EXTERN nghttp2_stream_proto_state
nghttp2_stream_get_state(nghttp2_stream *stream);
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.c b/Utilities/cmnghttp2/lib/nghttp2_buf.c
index 2a435bebf9..a32844712e 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.c
@@ -82,8 +82,10 @@ void nghttp2_buf_reset(nghttp2_buf *buf) {
}
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
- buf->begin = buf->pos = buf->last = buf->mark = begin;
- buf->end = begin + len;
+ buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
+ if (len) {
+ buf->end += len;
+ }
}
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_buf.h b/Utilities/cmnghttp2/lib/nghttp2_buf.h
index 06cce67a11..45f62f16e2 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_buf.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_buf.h
@@ -99,7 +99,7 @@ void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
* |new_cap|. If extensions took place, buffer pointers in |buf| will
* change.
*
- * This function returns 0 if it succeeds, or one of the followings
+ * This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.c b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
new file mode 100644
index 0000000000..3fd9b78163
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.c
@@ -0,0 +1,35 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_extpri.h"
+
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
+ return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
+}
+
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
+ extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
+ extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_extpri.h b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
new file mode 100644
index 0000000000..23c6ddc0c0
--- /dev/null
+++ b/Utilities/cmnghttp2/lib/nghttp2_extpri.h
@@ -0,0 +1,65 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_EXTPRI_H
+#define NGHTTP2_EXTPRI_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
+ * from a value produced by nghttp2_extpri_to_uint8.
+ */
+#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
+
+/*
+ * nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
+ */
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
+
+/*
+ * nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
+ * nghttp2_extpri_to_uint8, intto |extpri|.
+ */
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
+
+/*
+ * nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
+ * supposed to be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_urgency(PRI) \
+ ((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
+
+/*
+ * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
+ * be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
+
+#endif /* NGHTTP2_EXTPRI_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.c b/Utilities/cmnghttp2/lib/nghttp2_frame.c
index 4821de4088..35072c15fc 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.c
@@ -253,6 +253,31 @@ void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
nghttp2_mem_free(mem, origin->ov);
}
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_ext_priority_update *priority_update;
+
+ nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
+ NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
+
+ priority_update = frame->payload;
+ priority_update->stream_id = stream_id;
+ priority_update->field_value = field_value;
+ priority_update->field_value_len = field_value_len;
+}
+
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem) {
+ nghttp2_ext_priority_update *priority_update;
+
+ priority_update = frame->payload;
+ if (priority_update == NULL) {
+ return;
+ }
+ nghttp2_mem_free(mem, priority_update->field_value);
+}
+
size_t nghttp2_frame_priority_len(uint8_t flags) {
if (flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_PRIORITY_SPECLEN;
@@ -654,8 +679,6 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
var_gift_payloadlen = 0;
}
- payloadlen -= var_gift_payloadlen;
-
if (!var_gift_payloadlen) {
var_gift_payload = NULL;
} else {
@@ -818,8 +841,10 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
size_t len = 0;
origin = frame->payload;
- p = payload;
- end = p + payloadlen;
+ p = end = payload;
+ if (payloadlen) {
+ end += payloadlen;
+ }
for (; p != end;) {
if (end - p < 2) {
@@ -876,6 +901,57 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
return 0;
}
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *frame) {
+ int rv;
+ nghttp2_buf *buf;
+ nghttp2_ext_priority_update *priority_update;
+
+ /* This is required with --disable-assert. */
+ (void)rv;
+
+ priority_update = frame->payload;
+
+ buf = &bufs->head->buf;
+
+ assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
+
+ buf->pos -= NGHTTP2_FRAME_HDLEN;
+
+ nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
+
+ nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
+ buf->last += 4;
+
+ rv = nghttp2_bufs_add(bufs, priority_update->field_value,
+ priority_update->field_value_len);
+
+ assert(rv == 0);
+
+ return 0;
+}
+
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen) {
+ nghttp2_ext_priority_update *priority_update;
+
+ assert(payloadlen >= 4);
+
+ priority_update = frame->payload;
+
+ priority_update->stream_id =
+ nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
+
+ if (payloadlen > 4) {
+ priority_update->field_value = payload + 4;
+ priority_update->field_value_len = payloadlen - 4;
+ } else {
+ priority_update->field_value = NULL;
+ priority_update->field_value_len = 0;
+ }
+}
+
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem) {
nghttp2_settings_entry *iv_copy;
@@ -897,9 +973,25 @@ nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
}
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
- return a->namelen == b->namelen && a->valuelen == b->valuelen &&
- memcmp(a->name, b->name, a->namelen) == 0 &&
- memcmp(a->value, b->value, a->valuelen) == 0;
+ if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
+ return 0;
+ }
+
+ if (a->name == NULL || b->name == NULL) {
+ assert(a->namelen == 0);
+ assert(b->namelen == 0);
+ } else if (memcmp(a->name, b->name, a->namelen) != 0) {
+ return 0;
+ }
+
+ if (a->value == NULL || b->value == NULL) {
+ assert(a->valuelen == 0);
+ assert(b->valuelen == 0);
+ } else if (memcmp(a->value, b->value, a->valuelen) != 0) {
+ return 0;
+ }
+
+ return 1;
}
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
@@ -1055,6 +1147,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
return 0;
}
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ if (iv[i].value != 0 && iv[i].value != 1) {
+ return 0;
+ }
+ break;
}
}
return 1;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_frame.h b/Utilities/cmnghttp2/lib/nghttp2_frame.h
index 615bbf31f5..5f6152b745 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_frame.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_frame.h
@@ -46,7 +46,7 @@
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
#define NGHTTP2_MAX_PAYLOADLEN 16384
-/* The one frame buffer length for tranmission. We may use several of
+/* The one frame buffer length for transmission. We may use several of
them to support CONTINUATION. To account for Pad Length field, we
allocate extra 1 byte, which saves extra large memcopying. */
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
@@ -57,7 +57,7 @@
/* Maximum headers block size to send, calculated using
nghttp2_hd_deflate_bound(). This is the default value, and can be
- overridden by nghttp2_option_set_max_send_header_block_size(). */
+ overridden by nghttp2_option_set_max_send_header_block_length(). */
#define NGHTTP2_MAX_HEADERSLEN 65536
/* The number of bytes for each SETTINGS entry */
@@ -73,6 +73,7 @@
typedef union {
nghttp2_ext_altsvc altsvc;
nghttp2_ext_origin origin;
+ nghttp2_ext_priority_update priority_update;
} nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
@@ -423,6 +424,31 @@ int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PRIORITY_UPDATE frame |frame| in wire frame format and store
+ * it in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *ext);
+
+/*
+ * Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of
+ * |payloadlen| bytes contains frame payload. This function assumes
+ * that frame->payload points to the nghttp2_ext_priority_update
+ * object.
+ *
+ * This function always succeeds and returns 0.
+ */
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen);
+
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
@@ -539,6 +565,25 @@ void nghttp2_frame_origin_init(nghttp2_extension *frame,
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
/*
+ * Initializes PRIORITY_UPDATE frame |frame| with given values. This
+ * function assumes that frame->payload points to
+ * nghttp2_ext_priority_update object. On success, this function
+ * takes ownership of |field_value|, so caller must not free it.
+ */
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|. This function does not free
+ * nghttp2_ext_priority_update object pointed by frame->payload. This
+ * function only frees field_value pointed by
+ * nghttp2_ext_priority_update.field_value.
+ */
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem);
+
+/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
* not include the Pad Length field. If |padlen| is 0, this function
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.c b/Utilities/cmnghttp2/lib/nghttp2_hd.c
index 5e86931525..8a2bda64c1 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.c
@@ -269,6 +269,11 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_LOCATION;
}
break;
+ case 'y':
+ if (memeq("priorit", name, 7)) {
+ return NGHTTP2_TOKEN_PRIORITY;
+ }
+ break;
}
break;
case 9:
@@ -1263,6 +1268,8 @@ int nghttp2_hd_inflate_change_table_size(
return NGHTTP2_ERR_INVALID_STATE;
}
+ inflater->settings_hd_table_bufsize_max = settings_max_dynamic_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
@@ -1275,13 +1282,12 @@ int nghttp2_hd_inflate_change_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_max_dynamic_table_size;
- }
- inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
+ inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
- inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
+ hd_context_shrink_table_size(&inflater->ctx, NULL);
+ }
- hd_context_shrink_table_size(&inflater->ctx, NULL);
return 0;
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_hd.h b/Utilities/cmnghttp2/lib/nghttp2_hd.h
index 267402881f..6de0052aae 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_hd.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_hd.h
@@ -112,6 +112,7 @@ typedef enum {
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN__PROTOCOL,
+ NGHTTP2_TOKEN_PRIORITY,
} nghttp2_token;
struct nghttp2_hd_entry;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_helper.c b/Utilities/cmnghttp2/lib/nghttp2_helper.c
index 91136a6198..93dd4754b7 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_helper.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_helper.c
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
case NGHTTP2_ERR_FLOODED:
return "Flooding was detected in this HTTP/2 session, and it must be "
"closed";
+ case NGHTTP2_ERR_TOO_MANY_SETTINGS:
+ return "SETTINGS frame contained more than the maximum allowed entries";
default:
return "Unknown error code";
}
@@ -505,7 +507,179 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
return 1;
}
-/* Generated by genauthroitychartbl.py */
+int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
+ if (len == 0) {
+ return 1;
+ }
+
+ if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
+ *(value + len - 1) == '\t') {
+ return 0;
+ }
+
+ return nghttp2_check_header_value(value, len);
+}
+
+/* Generated by genmethodchartbl.py */
+static char VALID_METHOD_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
+ 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
+ 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
+ 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
+ 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
+ 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
+ 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
+ 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
+ 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
+ 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
+ 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
+ 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
+ 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
+ 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
+ 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
+ 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
+ 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
+ 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
+ 1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
+ 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
+ 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
+ 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
+ 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
+ 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
+ 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
+ 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
+ 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
+ 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
+ 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
+ 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
+ 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
+ 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
+ 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
+ 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
+ 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
+ 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
+ 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
+ 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
+ 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
+ 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
+ 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
+ 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
+ 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
+ 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
+ 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
+ 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
+ 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
+ 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
+ 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
+ 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
+ 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
+ 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
+};
+
+int nghttp2_check_method(const uint8_t *value, size_t len) {
+ const uint8_t *last;
+ if (len == 0) {
+ return 0;
+ }
+ for (last = value + len; value != last; ++value) {
+ if (!VALID_METHOD_CHARS[*value]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Generated by genpathchartbl.py */
+static char VALID_PATH_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
+ 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
+ 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
+ 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
+ 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
+ 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
+ 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
+ 0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
+ 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
+ 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
+ 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
+ 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
+ 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
+ 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
+ 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
+ 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
+ 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
+ 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
+ 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
+ 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
+ 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
+ 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
+ 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
+ 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
+ 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
+ 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
+ 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
+ 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
+ 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
+ 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
+ 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
+ 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
+ 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
+ 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
+ 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
+ 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
+ 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
+ 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
+ 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
+ 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
+ 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
+ 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
+ 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
+ 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
+ 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
+ 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
+ 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
+ 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
+ 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
+ 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
+ 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
+ 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
+ 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
+ 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
+ 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
+ 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
+ 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
+ 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
+ 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
+};
+
+int nghttp2_check_path(const uint8_t *value, size_t len) {
+ const uint8_t *last;
+ for (last = value + len; value != last; ++value) {
+ if (!VALID_PATH_CHARS[*value]) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Generated by genauthoritychartbl.py */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.c b/Utilities/cmnghttp2/lib/nghttp2_http.c
index 62f57b6aec..83e5e6685f 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.c
@@ -30,6 +30,7 @@
#include "nghttp2_hd.h"
#include "nghttp2_helper.h"
+#include "nghttp2_extpri.h"
static uint8_t downcase(uint8_t c) {
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
@@ -72,25 +73,12 @@ static int64_t parse_uint(const uint8_t *s, size_t len) {
return n;
}
-static int lws(const uint8_t *s, size_t n) {
- size_t i;
- for (i = 0; i < n; ++i) {
- if (s[i] != ' ' && s[i] != '\t') {
- return 0;
- }
- }
- return 1;
-}
-
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
- int flag) {
- if (stream->http_flags & flag) {
- return 0;
- }
- if (lws(nv->value->base, nv->value->len)) {
+ uint32_t flag) {
+ if ((stream->http_flags & flag) || nv->value->len == 0) {
return 0;
}
- stream->http_flags = (uint16_t)(stream->http_flags | flag);
+ stream->http_flags = stream->http_flags | flag;
return 1;
}
@@ -114,6 +102,8 @@ static int check_path(nghttp2_stream *stream) {
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer, int connect_protocol) {
+ nghttp2_extpri extpri;
+
if (nv->name->base[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -212,6 +202,23 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
+ case NGHTTP2_TOKEN_PRIORITY:
+ if (!trailer &&
+ /* Do not parse the header field in PUSH_PROMISE. */
+ (stream->stream_id & 1) &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
+ nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
+ if (nghttp2_http_parse_priority(&extpri, nv->value->base,
+ nv->value->len) == 0) {
+ stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
+ } else {
+ stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
+ }
+ }
+ break;
default:
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
@@ -329,6 +336,16 @@ static int check_scheme(const uint8_t *value, size_t len) {
return 1;
}
+static int lws(const uint8_t *s, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ if (s[i] != ' ' && s[i] != '\t') {
+ return 0;
+ }
+ }
+ return 1;
+}
+
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer) {
@@ -360,13 +377,46 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
- if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
- nv->token == NGHTTP2_TOKEN_HOST) {
- rv = nghttp2_check_authority(nv->value->base, nv->value->len);
- } else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
+ switch (nv->token) {
+ case NGHTTP2_TOKEN__METHOD:
+ rv = nghttp2_check_method(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__PATH:
+ rv = nghttp2_check_path(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__AUTHORITY:
+ case NGHTTP2_TOKEN_HOST:
+ if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+ rv = nghttp2_check_authority(nv->value->base, nv->value->len);
+ } else if (
+ stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
+ break;
+ case NGHTTP2_TOKEN__SCHEME:
rv = check_scheme(nv->value->base, nv->value->len);
- } else {
- rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ break;
+ case NGHTTP2_TOKEN__PROTOCOL:
+ /* Check the value consists of just white spaces, which was done
+ in check_pseudo_header before
+ nghttp2_check_header_value_rfc9113 has been introduced. */
+ if ((stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ lws(nv->value->base, nv->value->len)) {
+ rv = 0;
+ break;
+ }
+ /* fall through */
+ default:
+ if (stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
}
if (rv == 0) {
@@ -434,16 +484,15 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
if (stream->status_code / 100 == 1) {
/* non-final response */
- stream->http_flags =
- (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
- NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
+ NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
stream->content_length = -1;
stream->status_code = -1;
return 0;
}
stream->http_flags =
- (uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
if (!expect_response_body(stream)) {
stream->content_length = 0;
@@ -528,3 +577,715 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
return;
}
}
+
+/* Generated by genchartbl.py */
+static const int SF_KEY_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
+ 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */,
+ 1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
+ 0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
+ 0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
+ 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
+ 0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
+ 0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
+ 1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
+ 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if ((*p < 'a' || 'z' < *p) && *p != '*') {
+ return -1;
+ }
+
+ for (; p != end && SF_KEY_CHARS[*p]; ++p)
+ ;
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
+ const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ int sign = 1;
+ int64_t value = 0;
+ int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
+ size_t len = 0;
+ size_t fpos = 0;
+ size_t i;
+
+ if (*p == '-') {
+ if (++p == end) {
+ return -1;
+ }
+
+ sign = -1;
+ }
+
+ if (*p < '0' || '9' < *p) {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ value *= 10;
+ value += *p - '0';
+
+ if (++len > 15) {
+ return -1;
+ }
+
+ break;
+ case '.':
+ if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
+ goto fin;
+ }
+
+ if (len > 12) {
+ return -1;
+ }
+ fpos = len;
+ type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
+
+ break;
+ default:
+ goto fin;
+ };
+ }
+
+fin:
+ switch (type) {
+ case NGHTTP2_SF_VALUE_TYPE_INTEGER:
+ if (dest) {
+ dest->type = (uint8_t)type;
+ dest->i = value * sign;
+ }
+
+ return p - begin;
+ case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
+ if (fpos == len || len - fpos > 3) {
+ return -1;
+ }
+
+ if (dest) {
+ dest->type = (uint8_t)type;
+ dest->d = (double)value;
+ for (i = len - fpos; i > 0; --i) {
+ dest->d /= (double)10;
+ }
+ dest->d *= sign;
+ }
+
+ return p - begin;
+ default:
+ assert(0);
+ abort();
+ }
+}
+
+/* Generated by genchartbl.py */
+static const int SF_DQUOTE_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */,
+ 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
+ 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
+ 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */,
+ 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
+ 1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if (*p++ != '"') {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case '\\':
+ if (++p == end) {
+ return -1;
+ }
+
+ switch (*p) {
+ case '"':
+ case '\\':
+ break;
+ default:
+ return -1;
+ }
+
+ break;
+ case '"':
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
+ dest->s.base = begin + 1;
+ dest->s.len = (size_t)(p - dest->s.base);
+ }
+
+ ++p;
+
+ return p - begin;
+ default:
+ if (!SF_DQUOTE_CHARS[*p]) {
+ return -1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_TOKEN_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
+ 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
+ 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
+ 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */,
+ 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
+ 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
+ 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
+ return -1;
+ }
+
+ for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
+ ;
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
+ dest->s.base = begin;
+ dest->s.len = (size_t)(p - begin);
+ }
+
+ return p - begin;
+}
+
+/* Generated by genchartbl.py */
+static const int SF_BYTESEQ_CHARS[] = {
+ 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
+ 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
+ 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
+ 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
+ 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
+ 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
+ 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
+ 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
+ 0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */,
+ 0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
+ 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
+ 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
+ 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
+ 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
+ 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
+ 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
+ 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
+ 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
+ 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
+ 0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
+ 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
+ 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
+ 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
+ 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
+ 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
+ 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
+ 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
+ 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
+ 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
+ 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
+ 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
+ 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
+ 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
+ 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
+ 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
+ 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
+ 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
+ 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
+ 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
+ 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
+ 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
+ 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
+ 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
+ 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
+ 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
+ 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
+ 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
+ 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
+ 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
+ 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
+ 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
+ 0 /* 0xff */,
+};
+
+static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+
+ if (*p++ != ':') {
+ return -1;
+ }
+
+ for (; p != end; ++p) {
+ switch (*p) {
+ case ':':
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
+ dest->s.base = begin + 1;
+ dest->s.len = (size_t)(p - dest->s.base);
+ }
+
+ ++p;
+
+ return p - begin;
+ default:
+ if (!SF_BYTESEQ_CHARS[*p]) {
+ return -1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ int b;
+
+ if (*p++ != '?') {
+ return -1;
+ }
+
+ if (p == end) {
+ return -1;
+ }
+
+ switch (*p++) {
+ case '0':
+ b = 0;
+ break;
+ case '1':
+ b = 1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+ dest->b = b;
+ }
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ switch (*begin) {
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return sf_parse_integer_or_decimal(dest, begin, end);
+ case '"':
+ return sf_parse_string(dest, begin, end);
+ case '*':
+ return sf_parse_token(dest, begin, end);
+ case ':':
+ return sf_parse_byteseq(dest, begin, end);
+ case '?':
+ return sf_parse_boolean(dest, begin, end);
+ default:
+ if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
+ return sf_parse_token(dest, begin, end);
+ }
+ return -1;
+ }
+}
+
+#define sf_discard_sp_end_err(BEGIN, END, ERR) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ return (ERR); \
+ } \
+ if (*(BEGIN) != ' ') { \
+ break; \
+ } \
+ }
+
+static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ for (; p != end && *p == ';';) {
+ ++p;
+
+ sf_discard_sp_end_err(p, end, -1);
+
+ slen = sf_parse_key(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (p == end || *p != '=') {
+ /* Boolean true */
+ } else if (++p == end) {
+ return -1;
+ } else {
+ slen = sf_parse_bare_item(NULL, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+ }
+ }
+
+ return p - begin;
+}
+
+static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ slen = sf_parse_bare_item(dest, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ return p - begin;
+}
+
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ return sf_parse_item(dest, begin, end);
+}
+
+static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end) {
+ const uint8_t *p = begin;
+ ssize_t slen;
+
+ if (*p++ != '(') {
+ return -1;
+ }
+
+ for (;;) {
+ sf_discard_sp_end_err(p, end, -1);
+
+ if (*p == ')') {
+ ++p;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (dest) {
+ dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
+ }
+
+ return p - begin;
+ }
+
+ slen = sf_parse_item(NULL, p, end);
+ if (slen < 0) {
+ return -1;
+ }
+
+ p += slen;
+
+ if (p == end || (*p != ' ' && *p != ')')) {
+ return -1;
+ }
+ }
+}
+
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin, const uint8_t *end) {
+ return sf_parse_inner_list(dest, begin, end);
+}
+
+static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin,
+ const uint8_t *end) {
+ if (*begin == '(') {
+ return sf_parse_inner_list(dest, begin, end);
+ }
+
+ return sf_parse_item(dest, begin, end);
+}
+
+#define sf_discard_ows(BEGIN, END) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ goto fin; \
+ } \
+ if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
+ break; \
+ } \
+ }
+
+#define sf_discard_ows_end_err(BEGIN, END, ERR) \
+ for (;; ++(BEGIN)) { \
+ if ((BEGIN) == (END)) { \
+ return (ERR); \
+ } \
+ if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
+ break; \
+ } \
+ }
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+ size_t valuelen) {
+ const uint8_t *p = value, *end = value + valuelen;
+ ssize_t slen;
+ nghttp2_sf_value val;
+ nghttp2_extpri pri = *dest;
+ const uint8_t *key;
+ size_t keylen;
+
+ for (; p != end && *p == ' '; ++p)
+ ;
+
+ for (; p != end;) {
+ slen = sf_parse_key(p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ key = p;
+ keylen = (size_t)slen;
+
+ p += slen;
+
+ if (p == end || *p != '=') {
+ /* Boolean true */
+ val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
+ val.b = 1;
+
+ slen = sf_parse_params(p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ } else if (++p == end) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ } else {
+ slen = sf_parse_item_or_inner_list(&val, p, end);
+ if (slen < 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ }
+
+ p += slen;
+
+ if (keylen == 1) {
+ switch (key[0]) {
+ case 'i':
+ if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.inc = val.b;
+
+ break;
+ case 'u':
+ if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
+ val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
+ NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.urgency = (uint32_t)val.i;
+
+ break;
+ }
+ }
+
+ sf_discard_ows(p, end);
+
+ if (*p++ != ',') {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
+ }
+
+fin:
+ *dest = pri;
+
+ return 0;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_http.h b/Utilities/cmnghttp2/lib/nghttp2_http.h
index dd057cdb60..0c3a78eeef 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_http.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_http.h
@@ -94,4 +94,55 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
void nghttp2_http_record_request_method(nghttp2_stream *stream,
nghttp2_frame *frame);
+/*
+ * RFC 8941 Structured Field Values.
+ */
+typedef enum nghttp2_sf_value_type {
+ NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
+ NGHTTP2_SF_VALUE_TYPE_INTEGER,
+ NGHTTP2_SF_VALUE_TYPE_DECIMAL,
+ NGHTTP2_SF_VALUE_TYPE_STRING,
+ NGHTTP2_SF_VALUE_TYPE_TOKEN,
+ NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
+ NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
+} nghttp2_sf_value_type;
+
+/*
+ * nghttp2_sf_value stores Structured Field Values item. For Inner
+ * List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
+ */
+typedef struct nghttp2_sf_value {
+ uint8_t type;
+ union {
+ int b;
+ int64_t i;
+ double d;
+ struct {
+ const uint8_t *base;
+ size_t len;
+ } s;
+ };
+} nghttp2_sf_value;
+
+/*
+ * nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Item in |dest|. It returns the number of
+ * bytes consumed if it succeeds, or -1. This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
+ const uint8_t *end);
+
+/*
+ * nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
+ * and stores the parsed an Inner List in |dest|. It returns the number of
+ * bytes consumed if it succeeds, or -1. This function is declared
+ * here for unit tests.
+ */
+ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
+ const uint8_t *begin, const uint8_t *end);
+
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+ size_t valuelen);
+
#endif /* NGHTTP2_HTTP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.c b/Utilities/cmnghttp2/lib/nghttp2_map.c
index 4d9f97b47e..e5db168ca2 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.c
@@ -1,7 +1,8 @@
/*
* nghttp2 - HTTP/2 C Library
*
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -25,14 +26,19 @@
#include "nghttp2_map.h"
#include <string.h>
+#include <assert.h>
+#include <stdio.h>
-#define INITIAL_TABLE_LENGTH 256
+#include "nghttp2_helper.h"
+
+#define NGHTTP2_INITIAL_TABLE_LENBITS 8
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
- map->tablelen = INITIAL_TABLE_LENGTH;
+ map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
+ map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
map->table =
- nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *));
+ nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
if (map->table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
@@ -43,112 +49,188 @@ int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
}
void nghttp2_map_free(nghttp2_map *map) {
+ if (!map) {
+ return;
+ }
+
nghttp2_mem_free(map->mem, map->table);
}
-void nghttp2_map_each_free(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
uint32_t i;
+ nghttp2_map_bucket *bkt;
+
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- nghttp2_map_entry *next = entry->next;
- func(entry, ptr);
- entry = next;
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ continue;
}
- map->table[i] = NULL;
+
+ func(bkt->data, ptr);
}
}
-int nghttp2_map_each(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
uint32_t i;
+ nghttp2_map_bucket *bkt;
+
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry; entry = entry->next) {
- rv = func(entry, ptr);
- if (rv != 0) {
- return rv;
- }
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ continue;
+ }
+
+ rv = func(bkt->data, ptr);
+ if (rv != 0) {
+ return rv;
}
}
+
return 0;
}
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
- entry->key = key;
- entry->next = NULL;
+static uint32_t hash(nghttp2_map_key_type key) {
+ return (uint32_t)key * 2654435769u;
}
-/* Same hash function in android HashMap source code. */
-/* The |mod| must be power of 2 */
-static uint32_t hash(int32_t key, uint32_t mod) {
- uint32_t h = (uint32_t)key;
- h ^= (h >> 20) ^ (h >> 12);
- h ^= (h >> 7) ^ (h >> 4);
- return h & (mod - 1);
+static size_t h2idx(uint32_t hash, uint32_t bits) {
+ return hash >> (32 - bits);
}
-static int insert(nghttp2_map_entry **table, uint32_t tablelen,
- nghttp2_map_entry *entry) {
- uint32_t h = hash(entry->key, tablelen);
- if (table[h] == NULL) {
- table[h] = entry;
- } else {
- nghttp2_map_entry *p;
- /* We won't allow duplicated key, so check it out. */
- for (p = table[h]; p; p = p->next) {
- if (p->key == entry->key) {
- return NGHTTP2_ERR_INVALID_ARGUMENT;
- }
+static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
+ nghttp2_map_bucket *bkt, size_t idx) {
+ return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
+}
+
+static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
+ nghttp2_map_key_type *pkey, void **pdata) {
+ uint32_t h = bkt->hash;
+ nghttp2_map_key_type key = bkt->key;
+ void *data = bkt->data;
+
+ bkt->hash = *phash;
+ bkt->key = *pkey;
+ bkt->data = *pdata;
+
+ *phash = h;
+ *pkey = key;
+ *pdata = data;
+}
+
+static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
+ nghttp2_map_key_type key, void *data) {
+ bkt->hash = hash;
+ bkt->key = key;
+ bkt->data = data;
+}
+
+void nghttp2_map_print_distance(nghttp2_map *map) {
+ uint32_t i;
+ size_t idx;
+ nghttp2_map_bucket *bkt;
+
+ for (i = 0; i < map->tablelen; ++i) {
+ bkt = &map->table[i];
+
+ if (bkt->data == NULL) {
+ fprintf(stderr, "@%u <EMPTY>\n", i);
+ continue;
}
- entry->next = table[h];
- table[h] = entry;
+
+ idx = h2idx(bkt->hash, map->tablelenbits);
+ fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
+ bkt->hash, bkt->key, idx,
+ distance(map->tablelen, map->tablelenbits, bkt, idx));
+ }
+}
+
+static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
+ uint32_t tablelenbits, uint32_t hash,
+ nghttp2_map_key_type key, void *data) {
+ size_t idx = h2idx(hash, tablelenbits);
+ size_t d = 0, dd;
+ nghttp2_map_bucket *bkt;
+
+ for (;;) {
+ bkt = &table[idx];
+
+ if (bkt->data == NULL) {
+ map_bucket_set_data(bkt, hash, key, data);
+ return 0;
+ }
+
+ dd = distance(tablelen, tablelenbits, bkt, idx);
+ if (d > dd) {
+ map_bucket_swap(bkt, &hash, &key, &data);
+ d = dd;
+ } else if (bkt->key == key) {
+ /* TODO This check is just a waste after first swap or if this
+ function is called from map_resize. That said, there is no
+ difference with or without this conditional in performance
+ wise. */
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ ++d;
+ idx = (idx + 1) & (tablelen - 1);
}
- return 0;
}
-/* new_tablelen must be power of 2 */
-static int resize(nghttp2_map *map, uint32_t new_tablelen) {
+/* new_tablelen must be power of 2 and new_tablelen == (1 <<
+ new_tablelenbits) must hold. */
+static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
+ uint32_t new_tablelenbits) {
uint32_t i;
- nghttp2_map_entry **new_table;
+ nghttp2_map_bucket *new_table;
+ nghttp2_map_bucket *bkt;
+ int rv;
+ (void)rv;
new_table =
- nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *));
+ nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
if (new_table == NULL) {
return NGHTTP2_ERR_NOMEM;
}
for (i = 0; i < map->tablelen; ++i) {
- nghttp2_map_entry *entry;
- for (entry = map->table[i]; entry;) {
- nghttp2_map_entry *next = entry->next;
- entry->next = NULL;
- /* This function must succeed */
- insert(new_table, new_tablelen, entry);
- entry = next;
+ bkt = &map->table[i];
+ if (bkt->data == NULL) {
+ continue;
}
+ rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
+ bkt->data);
+
+ assert(0 == rv);
}
+
nghttp2_mem_free(map->mem, map->table);
map->tablelen = new_tablelen;
+ map->tablelenbits = new_tablelenbits;
map->table = new_table;
return 0;
}
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
int rv;
+
+ assert(data);
+
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
- rv = resize(map, map->tablelen * 2);
+ rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
if (rv != 0) {
return rv;
}
}
- rv = insert(map->table, map->tablelen, new_entry);
+
+ rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
+ data);
if (rv != 0) {
return rv;
}
@@ -156,34 +238,76 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
return 0;
}
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
- uint32_t h;
- nghttp2_map_entry *entry;
- h = hash(key, map->tablelen);
- for (entry = map->table[h]; entry; entry = entry->next) {
- if (entry->key == key) {
- return entry;
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
+ uint32_t h = hash(key);
+ size_t idx = h2idx(h, map->tablelenbits);
+ nghttp2_map_bucket *bkt;
+ size_t d = 0;
+
+ for (;;) {
+ bkt = &map->table[idx];
+
+ if (bkt->data == NULL ||
+ d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+ return NULL;
}
+
+ if (bkt->key == key) {
+ return bkt->data;
+ }
+
+ ++d;
+ idx = (idx + 1) & (map->tablelen - 1);
}
- return NULL;
}
-int nghttp2_map_remove(nghttp2_map *map, key_type key) {
- uint32_t h;
- nghttp2_map_entry **dst;
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
+ uint32_t h = hash(key);
+ size_t idx = h2idx(h, map->tablelenbits), didx;
+ nghttp2_map_bucket *bkt;
+ size_t d = 0;
- h = hash(key, map->tablelen);
+ for (;;) {
+ bkt = &map->table[idx];
- for (dst = &map->table[h]; *dst; dst = &(*dst)->next) {
- if ((*dst)->key != key) {
- continue;
+ if (bkt->data == NULL ||
+ d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (bkt->key == key) {
+ map_bucket_set_data(bkt, 0, 0, NULL);
+
+ didx = idx;
+ idx = (idx + 1) & (map->tablelen - 1);
+
+ for (;;) {
+ bkt = &map->table[idx];
+ if (bkt->data == NULL ||
+ distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
+ break;
+ }
+
+ map->table[didx] = *bkt;
+ map_bucket_set_data(bkt, 0, 0, NULL);
+ didx = idx;
+
+ idx = (idx + 1) & (map->tablelen - 1);
+ }
+
+ --map->size;
+
+ return 0;
}
- *dst = (*dst)->next;
- --map->size;
- return 0;
+ ++d;
+ idx = (idx + 1) & (map->tablelen - 1);
}
- return NGHTTP2_ERR_INVALID_ARGUMENT;
+}
+
+void nghttp2_map_clear(nghttp2_map *map) {
+ memset(map->table, 0, sizeof(*map->table) * map->tablelen);
+ map->size = 0;
}
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
diff --git a/Utilities/cmnghttp2/lib/nghttp2_map.h b/Utilities/cmnghttp2/lib/nghttp2_map.h
index f6e29e35f2..1419a09a35 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_map.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_map.h
@@ -1,7 +1,8 @@
/*
* nghttp2 - HTTP/2 C Library
*
- * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ * Copyright (c) 2017 ngtcp2 contributors
+ * Copyright (c) 2012 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -30,27 +31,25 @@
#endif /* HAVE_CONFIG_H */
#include <nghttp2/nghttp2.h>
-#include "nghttp2_int.h"
+
#include "nghttp2_mem.h"
/* Implementation of unordered map */
-typedef int32_t key_type;
+typedef int32_t nghttp2_map_key_type;
-typedef struct nghttp2_map_entry {
- struct nghttp2_map_entry *next;
- key_type key;
-#if SIZEOF_INT_P == 4
- /* we requires 8 bytes aligment */
- int64_t pad;
-#endif
-} nghttp2_map_entry;
+typedef struct nghttp2_map_bucket {
+ uint32_t hash;
+ nghttp2_map_key_type key;
+ void *data;
+} nghttp2_map_bucket;
-typedef struct {
- nghttp2_map_entry **table;
+typedef struct nghttp2_map {
+ nghttp2_map_bucket *table;
nghttp2_mem *mem;
size_t size;
uint32_t tablelen;
+ uint32_t tablelenbits;
} nghttp2_map;
/*
@@ -74,21 +73,14 @@ void nghttp2_map_free(nghttp2_map *map);
/*
* Deallocates each entries using |func| function and any resources
* allocated for |map|. The |func| function is responsible for freeing
- * given the |entry| object. The |ptr| will be passed to the |func| as
+ * given the |data| object. The |ptr| will be passed to the |func| as
* send argument. The return value of the |func| will be ignored.
*/
-void nghttp2_map_each_free(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
/*
- * Initializes the |entry| with the |key|. All entries to be inserted
- * to the map must be initialized with this function.
- */
-void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
-
-/*
- * Inserts the new |entry| with the key |entry->key| to the map |map|.
+ * Inserts the new |data| with the |key| to the map |map|.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@@ -98,25 +90,30 @@ void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
-int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
/*
- * Returns the entry associated by the key |key|. If there is no such
- * entry, this function returns NULL.
+ * Returns the data associated by the key |key|. If there is no such
+ * data, this function returns NULL.
*/
-nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
+void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
/*
- * Removes the entry associated by the key |key| from the |map|. The
- * removed entry is not freed by this function.
+ * Removes the data associated by the key |key| from the |map|. The
+ * removed data is not freed by this function.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
- * The entry associated by |key| does not exist.
+ * The data associated by |key| does not exist.
*/
-int nghttp2_map_remove(nghttp2_map *map, key_type key);
+int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
+
+/*
+ * Removes all entries from |map|.
+ */
+void nghttp2_map_clear(nghttp2_map *map);
/*
* Returns the number of items stored in the map |map|.
@@ -124,21 +121,22 @@ int nghttp2_map_remove(nghttp2_map *map, key_type key);
size_t nghttp2_map_size(nghttp2_map *map);
/*
- * Applies the function |func| to each entry in the |map| with the
+ * Applies the function |func| to each data in the |map| with the
* optional user supplied pointer |ptr|.
*
* If the |func| returns 0, this function calls the |func| with the
- * next entry. If the |func| returns nonzero, it will not call the
+ * next data. If the |func| returns nonzero, it will not call the
* |func| for further entries and return the return value of the
* |func| immediately. Thus, this function returns 0 if all the
* invocations of the |func| return 0, or nonzero value which the last
* invocation of |func| returns.
*
- * Don't use this function to free each entry. Use
+ * Don't use this function to free each data. Use
* nghttp2_map_each_free() instead.
*/
-int nghttp2_map_each(nghttp2_map *map,
- int (*func)(nghttp2_map_entry *entry, void *ptr),
+int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr);
+void nghttp2_map_print_distance(nghttp2_map *map);
+
#endif /* NGHTTP2_MAP_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_net.h b/Utilities/cmnghttp2/lib/nghttp2_net.h
index 95ffee74a1..345f6c834f 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_net.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_net.h
@@ -42,7 +42,7 @@
#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. */
+ dependency on that lib. */
# ifdef _MSC_VER
# define STIN static __inline
@@ -53,7 +53,7 @@
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostlong >> 24;
+ *p++ = (unsigned char)(hostlong >> 24);
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
@@ -63,7 +63,7 @@ STIN uint32_t htonl(uint32_t hostlong) {
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostshort >> 8;
+ *p++ = (unsigned char)(hostshort >> 8);
*p = hostshort & 0xffu;
return res;
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.c b/Utilities/cmnghttp2/lib/nghttp2_option.c
index e53f22d367..ee0cd0f022 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.c
@@ -90,6 +90,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
return;
+ case NGHTTP2_PRIORITY_UPDATE:
+ option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
+ option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE;
+ return;
default:
return;
}
@@ -121,3 +125,21 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
option->max_outbound_ack = val;
}
+
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
+ option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
+ option->max_settings = val;
+}
+
+void nghttp2_option_set_server_fallback_rfc7540_priorities(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ option->server_fallback_rfc7540_priorities = val;
+}
+
+void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |=
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ option->no_rfc9113_leading_and_trailing_ws_validation = val;
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_option.h b/Utilities/cmnghttp2/lib/nghttp2_option.h
index 1f740aaa6e..b228a0754c 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_option.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_option.h
@@ -67,6 +67,9 @@ typedef enum {
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
+ NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
} nghttp2_option_flag;
/**
@@ -86,6 +89,10 @@ struct nghttp2_option {
*/
size_t max_outbound_ack;
/**
+ * NGHTTP2_OPT_MAX_SETTINGS
+ */
+ size_t max_settings;
+ /**
* Bitwise OR of nghttp2_option_flag to determine that which fields
* are specified.
*/
@@ -123,6 +130,14 @@ struct nghttp2_option {
*/
int no_closed_streams;
/**
+ * NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES
+ */
+ int server_fallback_rfc7540_priorities;
+ /**
+ * NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION
+ */
+ int no_rfc9113_leading_and_trailing_ws_validation;
+ /**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
uint8_t user_recv_ext_types[32];
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
index f651c8029a..2a3041db19 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.c
@@ -89,6 +89,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
case NGHTTP2_ORIGIN:
nghttp2_frame_origin_free(&frame->ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ break;
default:
assert(0);
break;
diff --git a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
index b5f503a312..bd4611b551 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_outbound_item.h
@@ -111,7 +111,7 @@ struct nghttp2_outbound_item {
to this structure to avoid frequent memory allocation. */
nghttp2_ext_frame_payload ext_frame_payload;
nghttp2_aux_data aux_data;
- /* The priority used in priority comparion. Smaller is served
+ /* The priority used in priority comparison. Smaller is served
earlier. For PING, SETTINGS and non-DATA frames (excluding
response HEADERS frame) have dedicated cycle value defined above.
For DATA frame, cycle is computed by taking into account of
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.c b/Utilities/cmnghttp2/lib/nghttp2_pq.c
index bebccc7606..64353acc96 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.c
@@ -29,13 +29,12 @@
#include "nghttp2_helper.h"
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
pq->mem = mem;
pq->capacity = 0;
pq->q = NULL;
pq->length = 0;
pq->less = less;
- return 0;
}
void nghttp2_pq_free(nghttp2_pq *pq) {
diff --git a/Utilities/cmnghttp2/lib/nghttp2_pq.h b/Utilities/cmnghttp2/lib/nghttp2_pq.h
index 2d7b702ac1..c8d90ef2cc 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_pq.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_pq.h
@@ -55,14 +55,8 @@ typedef struct {
/*
* Initializes priority queue |pq| with compare function |cmp|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
*/
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are
@@ -114,7 +108,7 @@ typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
/*
- * Applys |fun| to each item in |pq|. The |arg| is passed as arg
+ * Applies |fun| to each item in |pq|. The |arg| is passed as arg
* parameter to callback function. This function must not change the
* ordering key. If the return value from callback is nonzero, this
* function returns 1 immediately without iterating remaining items.
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.c b/Utilities/cmnghttp2/lib/nghttp2_session.c
index 9df3d6f329..93f3f07cf7 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.c
@@ -36,6 +36,7 @@
#include "nghttp2_option.h"
#include "nghttp2_http.h"
#include "nghttp2_pq.h"
+#include "nghttp2_extpri.h"
#include "nghttp2_debug.h"
/*
@@ -143,6 +144,11 @@ static int session_detect_idle_stream(nghttp2_session *session,
return 0;
}
+static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) {
+ return session->pending_no_rfc7540_priorities == 1 &&
+ !session->fallback_rfc7540_priorities;
+}
+
static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) {
return (ext_types[type / 8] & (1 << (type & 0x7))) > 0;
}
@@ -354,6 +360,14 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
}
nghttp2_frame_origin_free(&iframe->frame.ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ break;
+ }
+ /* Do not call nghttp2_frame_priority_update_free, because all
+ fields point to sbuf. */
+ break;
}
}
@@ -385,6 +399,7 @@ static void init_settings(nghttp2_settings_storage *settings) {
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
settings->max_header_list_size = UINT32_MAX;
+ settings->no_rfc7540_priorities = UINT32_MAX;
}
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
@@ -398,6 +413,21 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
aob->state = NGHTTP2_OB_POP_ITEM;
}
+#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX)
+
+static int stream_less(const void *lhsx, const void *rhsx) {
+ const nghttp2_stream *lhs, *rhs;
+
+ lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
+ rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
+
+ if (lhs->cycle == rhs->cycle) {
+ return lhs->seq < rhs->seq;
+ }
+
+ return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP;
+}
+
int nghttp2_enable_strict_preface = 1;
static int session_new(nghttp2_session **session_ptr,
@@ -408,6 +438,7 @@ static int session_new(nghttp2_session **session_ptr,
size_t nbuffer;
size_t max_deflate_dynamic_table_size =
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
+ size_t i;
if (mem == NULL) {
mem = nghttp2_mem_default();
@@ -442,6 +473,7 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->pending_local_max_concurrent_stream =
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
(*session_ptr)->pending_enable_push = 1;
+ (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
if (server) {
(*session_ptr)->server = 1;
@@ -458,6 +490,7 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
(*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
+ (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
if (option) {
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -521,6 +554,25 @@ static int session_new(nghttp2_session **session_ptr,
if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
(*session_ptr)->max_outbound_ack = option->max_outbound_ack;
}
+
+ if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
+ option->max_settings) {
+ (*session_ptr)->max_settings = option->max_settings;
+ }
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) &&
+ option->server_fallback_rfc7540_priorities) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ }
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ option->no_rfc9113_leading_and_trailing_ws_validation) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -578,6 +630,10 @@ static int session_new(nghttp2_session **session_ptr,
}
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem);
+ }
+
return 0;
fail_aob_framebuf:
@@ -660,7 +716,7 @@ int nghttp2_session_server_new3(nghttp2_session **session_ptr,
return 0;
}
-static int free_streams(nghttp2_map_entry *entry, void *ptr) {
+static int free_streams(void *entry, void *ptr) {
nghttp2_session *session;
nghttp2_stream *stream;
nghttp2_outbound_item *item;
@@ -729,6 +785,7 @@ static void inflight_settings_del(nghttp2_inflight_settings *settings,
void nghttp2_session_del(nghttp2_session *session) {
nghttp2_mem *mem;
nghttp2_inflight_settings *settings;
+ size_t i;
if (session == NULL) {
return;
@@ -742,6 +799,9 @@ void nghttp2_session_del(nghttp2_session *session) {
settings = next;
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_free(&session->sched[i].ob_data);
+ }
nghttp2_stream_free(&session->root);
/* Have to free streams first, so that we can check
@@ -769,6 +829,8 @@ int nghttp2_session_reprioritize_stream(
nghttp2_priority_spec pri_spec_default;
const nghttp2_priority_spec *pri_spec = pri_spec_in;
+ assert((!session->server && session->pending_no_rfc7540_priorities != 1) ||
+ (session->server && !session_no_rfc7540_pri_no_fallback(session)));
assert(pri_spec->stream_id != stream->stream_id);
if (!nghttp2_stream_in_dep_tree(stream)) {
@@ -836,6 +898,214 @@ int nghttp2_session_reprioritize_stream(
return 0;
}
+static uint64_t pq_get_first_cycle(nghttp2_pq *pq) {
+ nghttp2_stream *stream;
+
+ if (nghttp2_pq_empty(pq)) {
+ return 0;
+ }
+
+ stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry);
+ return stream->cycle;
+}
+
+static int session_ob_data_push(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ int rv;
+ uint32_t urgency;
+ int inc;
+ nghttp2_pq *pq;
+
+ assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+ assert(stream->queued == 0);
+
+ urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ inc = nghttp2_extpri_uint8_inc(stream->extpri);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ stream->cycle = pq_get_first_cycle(pq);
+ if (inc) {
+ stream->cycle += stream->last_writelen;
+ }
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+ if (rv != 0) {
+ return rv;
+ }
+
+ stream->queued = 1;
+
+ return 0;
+}
+
+static int session_ob_data_remove(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ uint32_t urgency;
+
+ assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+ assert(stream->queued == 1);
+
+ urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
+
+ stream->queued = 0;
+
+ return 0;
+}
+
+static int session_attach_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ nghttp2_outbound_item *item) {
+ int rv;
+
+ rv = nghttp2_stream_attach_item(stream, item);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static int session_detach_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ int rv;
+
+ rv = nghttp2_stream_detach_item(stream);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ !stream->queued) {
+ return 0;
+ }
+
+ return session_ob_data_remove(session, stream);
+}
+
+static int session_defer_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream, uint8_t flags) {
+ int rv;
+
+ rv = nghttp2_stream_defer_item(stream, flags);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ !stream->queued) {
+ return 0;
+ }
+
+ return session_ob_data_remove(session, stream);
+}
+
+static int session_resume_deferred_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t flags) {
+ int rv;
+
+ rv = nghttp2_stream_resume_deferred_item(stream, flags);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static nghttp2_outbound_item *
+session_sched_get_next_outbound_item(nghttp2_session *session) {
+ size_t i;
+ nghttp2_pq_entry *ent;
+ nghttp2_stream *stream;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ ent = nghttp2_pq_top(&session->sched[i].ob_data);
+ if (!ent) {
+ continue;
+ }
+
+ stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
+ return stream->item;
+ }
+
+ return NULL;
+}
+
+static int session_sched_empty(nghttp2_session *session) {
+ size_t i;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ if (!nghttp2_pq_empty(&session->sched[i].ob_data)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void session_sched_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ nghttp2_pq *pq;
+ uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ int inc = nghttp2_extpri_uint8_inc(stream->extpri);
+ uint64_t penalty = (uint64_t)stream->last_writelen;
+ int rv;
+
+ (void)rv;
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ if (!inc || nghttp2_pq_size(pq) == 1) {
+ return;
+ }
+
+ nghttp2_pq_remove(pq, &stream->pq_entry);
+
+ stream->cycle += penalty;
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+
+ assert(0 == rv);
+}
+
+static int session_update_stream_priority(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t u8extpri) {
+ if (stream->extpri == u8extpri) {
+ return 0;
+ }
+
+ if (stream->queued) {
+ session_ob_data_remove(session, stream);
+
+ stream->extpri = u8extpri;
+
+ return session_ob_data_push(session, stream);
+ }
+
+ stream->extpri = u8extpri;
+
+ return 0;
+}
+
int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item) {
/* TODO Return error if stream is not found for the frame requiring
@@ -857,7 +1127,7 @@ int nghttp2_session_add_item(nghttp2_session *session,
return NGHTTP2_ERR_DATA_EXIST;
}
- rv = nghttp2_stream_attach_item(stream, item);
+ rv = session_attach_stream_item(session, stream, item);
if (rv != 0) {
return rv;
@@ -953,6 +1223,18 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
return 0;
}
+ /* Sending RST_STREAM to an idle stream is subject to protocol
+ violation. Historically, nghttp2 allows this. In order not to
+ disrupt the existing applications, we don't error out this case
+ and simply ignore it. */
+ if (nghttp2_session_is_my_stream_id(session, stream_id)) {
+ if ((uint32_t)stream_id >= session->next_stream_id) {
+ return 0;
+ }
+ } else if (session->last_recv_stream_id < stream_id) {
+ return 0;
+ }
+
/* Cancel pending request HEADERS in ob_syn if this RST_STREAM
refers to that stream. */
if (!session->server && nghttp2_session_is_my_stream_id(session, stream_id) &&
@@ -963,8 +1245,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
headers_frame = &nghttp2_outbound_queue_top(&session->ob_syn)->frame;
assert(headers_frame->hd.type == NGHTTP2_HEADERS);
- if (headers_frame->hd.stream_id <= stream_id &&
- (uint32_t)stream_id < session->next_stream_id) {
+ if (headers_frame->hd.stream_id <= stream_id) {
for (item = session->ob_syn.head; item; item = item->qnext) {
aux_data = &item->aux_data.headers;
@@ -1022,13 +1303,27 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
mem = &session->mem;
stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (session->opt_flags &
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
+
if (stream) {
assert(stream->state == NGHTTP2_STREAM_IDLE);
- assert(nghttp2_stream_in_dep_tree(stream));
- nghttp2_session_detach_idle_stream(session, stream);
- rv = nghttp2_stream_dep_remove(stream);
- if (rv != 0) {
- return NULL;
+ assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ nghttp2_stream_in_dep_tree(stream));
+
+ if (nghttp2_stream_in_dep_tree(stream)) {
+ assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
+ nghttp2_session_detach_idle_stream(session, stream);
+ rv = nghttp2_stream_dep_remove(stream);
+ if (rv != 0) {
+ return NULL;
+ }
+
+ if (session_no_rfc7540_pri_no_fallback(session)) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
}
} else {
stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream));
@@ -1039,7 +1334,21 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
stream_alloc = 1;
}
- if (pri_spec->stream_id != 0) {
+ if (session_no_rfc7540_pri_no_fallback(session) ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ /* For client which has not received server
+ SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal
+ opportunistically. */
+ if (session->server ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ nghttp2_priority_spec_default_init(&pri_spec_default);
+ pri_spec = &pri_spec_default;
+ }
+
+ if (session->pending_no_rfc7540_priorities == 1) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
+ } else if (pri_spec->stream_id != 0) {
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
if (!dep_stream &&
@@ -1085,7 +1394,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
(int32_t)session->local_settings.initial_window_size,
stream_user_data, mem);
- rv = nghttp2_map_insert(&session->streams, &stream->map_entry);
+ if (session_no_rfc7540_pri_no_fallback(session)) {
+ stream->seq = session->stream_seq++;
+ }
+
+ rv = nghttp2_map_insert(&session->streams, stream_id, stream);
if (rv != 0) {
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
@@ -1124,6 +1437,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
}
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return stream;
+ }
+
if (pri_spec->stream_id == 0) {
dep_stream = &session->root;
}
@@ -1163,7 +1480,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
item = stream->item;
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (rv != 0) {
return rv;
@@ -1213,6 +1530,10 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
/* Closes both directions just in case they are not closed yet */
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return nghttp2_session_destroy_stream(session, stream);
+ }
+
if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 &&
session->server && !is_my_stream_id &&
nghttp2_stream_in_dep_tree(stream)) {
@@ -1767,6 +2088,28 @@ static int session_predicate_origin_send(nghttp2_session *session) {
return 0;
}
+static int session_predicate_priority_update_send(nghttp2_session *session,
+ int32_t stream_id) {
+ nghttp2_stream *stream;
+
+ if (session_is_closing(session)) {
+ return NGHTTP2_ERR_SESSION_CLOSING;
+ }
+
+ stream = nghttp2_session_get_stream(session, stream_id);
+ if (stream == NULL) {
+ return 0;
+ }
+ if (stream->state == NGHTTP2_STREAM_CLOSING) {
+ return NGHTTP2_ERR_STREAM_CLOSING;
+ }
+ if (stream->shut_flags & NGHTTP2_SHUT_RD) {
+ return NGHTTP2_ERR_INVALID_STREAM_STATE;
+ }
+
+ return 0;
+}
+
/* Take into account settings max frame size and both connection-level
flow control here */
static ssize_t
@@ -1996,7 +2339,7 @@ static int session_prep_frame(nghttp2_session *session,
if (stream) {
int rv2;
- rv2 = nghttp2_stream_detach_item(stream);
+ rv2 = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv2)) {
return rv2;
@@ -2015,7 +2358,7 @@ static int session_prep_frame(nghttp2_session *session,
queue when session->remote_window_size > 0 */
assert(session->remote_window_size > 0);
- rv = nghttp2_stream_defer_item(stream,
+ rv = session_defer_stream_item(session, stream,
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
@@ -2034,7 +2377,8 @@ static int session_prep_frame(nghttp2_session *session,
return rv;
}
if (rv == NGHTTP2_ERR_DEFERRED) {
- rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
+ rv = session_defer_stream_item(session, stream,
+ NGHTTP2_STREAM_FLAG_DEFERRED_USER);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -2045,7 +2389,7 @@ static int session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_DEFERRED;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -2061,7 +2405,7 @@ static int session_prep_frame(nghttp2_session *session,
if (rv != 0) {
int rv2;
- rv2 = nghttp2_stream_detach_item(stream);
+ rv2 = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv2)) {
return rv2;
@@ -2311,6 +2655,18 @@ static int session_prep_frame(nghttp2_session *session,
}
return 0;
+ case NGHTTP2_PRIORITY_UPDATE: {
+ nghttp2_ext_priority_update *priority_update = frame->ext.payload;
+ rv = session_predicate_priority_update_send(session,
+ priority_update->stream_id);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext);
+
+ return 0;
+ }
default:
/* Unreachable here */
assert(0);
@@ -2322,6 +2678,8 @@ static int session_prep_frame(nghttp2_session *session,
nghttp2_outbound_item *
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
+ nghttp2_outbound_item *item;
+
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
return nghttp2_outbound_queue_top(&session->ob_urgent);
}
@@ -2337,7 +2695,12 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2371,7 +2734,12 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2407,7 +2775,7 @@ static int session_call_on_frame_send(nghttp2_session *session,
return 0;
}
-static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) {
+static int find_stream_on_goaway_func(void *entry, void *ptr) {
nghttp2_close_stream_on_goaway_arg *arg;
nghttp2_stream *stream;
@@ -2481,10 +2849,20 @@ static int session_close_stream_on_goaway(nghttp2_session *session,
return 0;
}
-static void reschedule_stream(nghttp2_stream *stream) {
+static void session_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
stream->last_writelen = stream->item->frame.hd.length;
- nghttp2_stream_reschedule(stream);
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ nghttp2_stream_reschedule(stream);
+ return;
+ }
+
+ if (!session->server) {
+ return;
+ }
+
+ session_sched_reschedule_stream(session, stream);
}
static int session_update_stream_consumed_size(nghttp2_session *session,
@@ -2494,14 +2872,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
static int session_update_connection_consumed_size(nghttp2_session *session,
size_t delta_size);
-static int session_update_recv_connection_window_size(nghttp2_session *session,
- size_t delta_size);
-
-static int session_update_recv_stream_window_size(nghttp2_session *session,
- nghttp2_stream *stream,
- size_t delta_size,
- int send_window_update);
-
/*
* Called after a frame is sent. This function runs
* on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2541,7 +2911,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
if (stream && aux_data->eof) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -2666,9 +3036,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
}
case NGHTTP2_PRIORITY:
- if (session->server) {
+ if (session->server || session->pending_no_rfc7540_priorities == 1) {
return 0;
- ;
}
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
@@ -2735,7 +3104,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_connection_consumed_size(session, 0);
} else {
- rv = session_update_recv_connection_window_size(session, 0);
+ rv = nghttp2_session_update_recv_connection_window_size(session, 0);
}
if (nghttp2_is_fatal(rv)) {
@@ -2761,7 +3130,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
rv = session_update_stream_consumed_size(session, stream, 0);
} else {
- rv = session_update_recv_stream_window_size(session, stream, 0, 1);
+ rv =
+ nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1);
}
if (nghttp2_is_fatal(rv)) {
@@ -2842,7 +3212,7 @@ static int session_after_frame_sent2(nghttp2_session *session) {
further data. */
if (nghttp2_session_predicate_data_send(session, stream) != 0) {
if (stream) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -3140,7 +3510,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
+ rv = session_detach_stream_item(session, stream);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -3720,6 +4090,21 @@ static int session_end_stream_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream) {
int rv;
+
+ assert(frame->hd.type == NGHTTP2_HEADERS);
+
+ if (session->server && session_enforce_http_messaging(session) &&
+ frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) &&
+ (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) {
+ rv = session_update_stream_priority(session, stream, stream->http_extpri);
+ if (rv != 0) {
+ assert(nghttp2_is_fatal(rv));
+ return rv;
+ }
+ }
+
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
return 0;
}
@@ -4081,6 +4466,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
int rv;
nghttp2_stream *stream;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
if (frame->hd.stream_id == 0) {
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PRIORITY: stream_id == 0");
@@ -4138,6 +4525,8 @@ static int session_process_priority_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
return nghttp2_session_on_priority_received(session, frame);
@@ -4184,8 +4573,7 @@ static int session_process_rst_stream_frame(nghttp2_session *session) {
return nghttp2_session_on_rst_stream_received(session, frame);
}
-static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
- void *ptr) {
+static int update_remote_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -4205,8 +4593,8 @@ static int update_remote_initial_window_size_func(nghttp2_map_entry *entry,
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4238,8 +4626,7 @@ session_update_remote_initial_window_size(nghttp2_session *session,
update_remote_initial_window_size_func, &arg);
}
-static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
- void *ptr) {
+static int update_local_initial_window_size_func(void *entry, void *ptr) {
int rv;
nghttp2_update_window_size_arg *arg;
nghttp2_stream *stream;
@@ -4251,9 +4638,16 @@ static int update_local_initial_window_size_func(nghttp2_map_entry *entry,
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
NGHTTP2_FLOW_CONTROL_ERROR);
}
- if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) &&
- stream->window_update_queued == 0 &&
- nghttp2_should_send_window_update(stream->local_window_size,
+
+ if (stream->window_update_queued) {
+ return 0;
+ }
+
+ if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
+ return session_update_stream_consumed_size(arg->session, stream, 0);
+ }
+
+ if (nghttp2_should_send_window_update(stream->local_window_size,
stream->recv_window_size)) {
rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE,
@@ -4374,6 +4768,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
session->local_settings.enable_connect_protocol = iv[i].value;
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ session->local_settings.no_rfc7540_priorities = iv[i].value;
+ break;
}
}
@@ -4533,6 +4930,34 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
session->remote_settings.enable_connect_protocol = entry->value;
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+
+ if (entry->value != 0 && entry->value != 1) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES");
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX &&
+ session->remote_settings.no_rfc7540_priorities != entry->value) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed");
+ }
+
+ session->remote_settings.no_rfc7540_priorities = entry->value;
+
+ break;
+ }
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) {
+ session->remote_settings.no_rfc7540_priorities = 0;
+
+ if (session->server && session->pending_no_rfc7540_priorities &&
+ (session->opt_flags &
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) {
+ session->fallback_rfc7540_priorities = 1;
}
}
@@ -4818,8 +5243,8 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4890,6 +5315,80 @@ int nghttp2_session_on_origin_received(nghttp2_session *session,
return session_call_on_frame_received(session, frame);
}
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame) {
+ nghttp2_ext_priority_update *priority_update;
+ nghttp2_stream *stream;
+ nghttp2_priority_spec pri_spec;
+ nghttp2_extpri extpri;
+ int rv;
+
+ assert(session->server);
+
+ priority_update = frame->ext.payload;
+
+ if (frame->hd.stream_id != 0) {
+ return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: stream_id == 0");
+ }
+
+ if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) {
+ if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: prioritizing idle push is not allowed");
+ }
+
+ /* TODO Ignore priority signal to a push stream for now */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id);
+ if (stream) {
+ /* Stream already exists. */
+ if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) {
+ return session_call_on_frame_received(session, frame);
+ }
+ } else if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ if (session->num_idle_streams + session->num_incoming_streams >=
+ session->local_settings.max_concurrent_streams) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: max concurrent streams exceeded");
+ }
+
+ nghttp2_priority_spec_default_init(&pri_spec);
+ stream = nghttp2_session_open_stream(session, priority_update->stream_id,
+ NGHTTP2_FLAG_NONE, &pri_spec,
+ NGHTTP2_STREAM_IDLE, NULL);
+ if (!stream) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+ } else {
+ return session_call_on_frame_received(session, frame);
+ }
+
+ extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
+ extpri.inc = 0;
+
+ rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value,
+ priority_update->field_value_len);
+ if (rv != 0) {
+ /* Just ignore field_value if it cannot be parsed. */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ rv = session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+ if (rv != 0) {
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ }
+
+ return session_call_on_frame_received(session, frame);
+}
+
static int session_process_altsvc_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
@@ -4924,6 +5423,16 @@ static int session_process_origin_frame(nghttp2_session *session) {
return nghttp2_session_on_origin_received(session, frame);
}
+static int session_process_priority_update_frame(nghttp2_session *session) {
+ nghttp2_inbound_frame *iframe = &session->iframe;
+ nghttp2_frame *frame = &iframe->frame;
+
+ nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos,
+ nghttp2_buf_len(&iframe->sbuf));
+
+ return nghttp2_session_on_priority_update_received(session, frame);
+}
+
static int session_process_extension_frame(nghttp2_session *session) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
@@ -5019,22 +5528,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
return 0;
}
-/*
- * Accumulates received bytes |delta_size| for stream-level flow
- * control and decides whether to send WINDOW_UPDATE to that stream.
- * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
- * be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- */
-static int session_update_recv_stream_window_size(nghttp2_session *session,
- nghttp2_stream *stream,
- size_t delta_size,
- int send_window_update) {
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+ nghttp2_stream *stream,
+ size_t delta_size,
+ int send_window_update) {
int rv;
rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
stream->local_window_size);
@@ -5063,20 +5560,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
return 0;
}
-/*
- * Accumulates received bytes |delta_size| for connection-level flow
- * control and decides whether to send WINDOW_UPDATE to the
- * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
- * WINDOW_UPDATE will not be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- */
-static int session_update_recv_connection_window_size(nghttp2_session *session,
- size_t delta_size) {
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+ size_t delta_size) {
int rv;
rv = adjust_recv_window_size(&session->recv_window_size, delta_size,
session->local_window_size);
@@ -5285,6 +5770,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
break;
default:
DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
@@ -5357,7 +5843,7 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
/*
* This function returns the effective payload length in the data of
- * length |readlen| when the remaning payload is |payloadleft|. The
+ * length |readlen| when the remaining payload is |payloadleft|. The
* |payloadleft| does not include |readlen|. If padding was started
* strictly before this data chunk, this function returns -1.
*/
@@ -5378,9 +5864,11 @@ static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
return (ssize_t)(readlen);
}
+static const uint8_t static_in[] = {0};
+
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
size_t inlen) {
- const uint8_t *first = in, *last = in + inlen;
+ const uint8_t *first, *last;
nghttp2_inbound_frame *iframe = &session->iframe;
size_t readlen;
ssize_t padlen;
@@ -5391,6 +5879,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
size_t pri_fieldlen;
nghttp2_mem *mem;
+ if (in == NULL) {
+ assert(inlen == 0);
+ in = static_in;
+ }
+
+ first = in;
+ last = in + inlen;
+
DEBUGF("recv: connection recv_window_size=%d, local_window=%d\n",
session->recv_window_size, session->local_window_size);
@@ -5678,6 +6174,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
}
+ /* Check the settings flood counter early to be safe */
+ if (session->obq_flood_counter_ >= session->max_outbound_ack &&
+ !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
+ return NGHTTP2_ERR_FLOODED;
+ }
+
iframe->state = NGHTTP2_IB_READ_SETTINGS;
if (iframe->payloadleft) {
@@ -5688,6 +6190,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->max_niv =
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
+ if (iframe->max_niv - 1 > session->max_settings) {
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_ENHANCE_YOUR_CALM,
+ "SETTINGS: too many setting entries");
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ return (ssize_t)inlen;
+ }
+
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
iframe->max_niv);
@@ -5873,6 +6385,49 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD;
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ DEBUGF("recv: PRIORITY_UPDATE\n");
+
+ iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
+ iframe->frame.ext.payload =
+ &iframe->ext_frame_payload.priority_update;
+
+ if (!session->server) {
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_PROTOCOL_ERROR,
+ "PRIORITY_UPDATE is received from server");
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ return (ssize_t)inlen;
+ }
+
+ if (iframe->payloadleft < 4) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
+ break;
+ }
+
+ if (!session_no_rfc7540_pri_no_fallback(session) ||
+ iframe->payloadleft > sizeof(iframe->raw_sbuf)) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ busy = 1;
+
+ iframe->state = NGHTTP2_IB_READ_NBYTE;
+ inbound_frame_set_mark(iframe, iframe->payloadleft);
+
+ break;
default:
busy = 1;
@@ -5978,13 +6533,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
case NGHTTP2_PRIORITY:
- rv = session_process_priority_frame(session);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ if (!session_no_rfc7540_pri_no_fallback(session) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
+ rv = session_process_priority_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (ssize_t)inlen;
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return (ssize_t)inlen;
+ }
}
session_inbound_frame_reset(session);
@@ -6141,6 +6699,18 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD;
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ DEBUGF("recv: prioritized_stream_id=%d\n",
+ nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK);
+
+ rv = session_process_priority_update_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ session_inbound_frame_reset(session);
+
+ break;
}
default:
/* This is unknown frame */
@@ -6420,8 +6990,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
/* CONTINUATION won't bear NGHTTP2_PADDED flag */
- iframe->frame.hd.flags = (uint8_t)(
- iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
+ iframe->frame.hd.flags =
+ (uint8_t)(iframe->frame.hd.flags |
+ (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS));
iframe->frame.hd.length += cont_hd.length;
busy = 1;
@@ -6454,7 +7025,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
}
/* Pad Length field is subject to flow control */
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6477,7 +7048,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) {
- rv = session_update_recv_stream_window_size(
+ rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6524,7 +7095,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
ssize_t data_readlen;
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session,
+ readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6533,7 +7105,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return (ssize_t)inlen;
}
- rv = session_update_recv_stream_window_size(
+ rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6634,7 +7206,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
if (readlen > 0) {
/* Update connection-level flow control window for ignored
DATA frame too */
- rv = session_update_recv_connection_window_size(session, readlen);
+ rv = nghttp2_session_update_recv_connection_window_size(session,
+ readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -6850,7 +7423,8 @@ int nghttp2_session_want_write(nghttp2_session *session) {
*/
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
nghttp2_outbound_queue_top(&session->ob_reg) ||
- (!nghttp2_pq_empty(&session->root.obq) &&
+ ((!nghttp2_pq_empty(&session->root.obq) ||
+ !session_sched_empty(session)) &&
session->remote_window_size > 0) ||
(nghttp2_outbound_queue_top(&session->ob_syn) &&
!session_is_outgoing_concurrent_streams_max(session));
@@ -7003,6 +7577,7 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
int rv;
nghttp2_mem *mem;
nghttp2_inflight_settings *inflight_settings = NULL;
+ uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities;
mem = &session->mem;
@@ -7020,6 +7595,21 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
+ for (i = 0; i < niv; ++i) {
+ if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) {
+ continue;
+ }
+
+ if (no_rfc7540_pri == UINT8_MAX) {
+ no_rfc7540_pri = (uint8_t)iv[i].value;
+ continue;
+ }
+
+ if (iv[i].value != (uint32_t)no_rfc7540_pri) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ }
+
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
return NGHTTP2_ERR_NOMEM;
@@ -7094,6 +7684,12 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
}
}
+ if (no_rfc7540_pri == UINT8_MAX) {
+ session->pending_no_rfc7540_priorities = 0;
+ } else {
+ session->pending_no_rfc7540_priorities = no_rfc7540_pri;
+ }
+
return 0;
}
@@ -7222,7 +7818,7 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
return rv;
}
- reschedule_stream(stream);
+ session_reschedule_stream(session, stream);
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
@@ -7296,7 +7892,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
- rv = nghttp2_stream_resume_deferred_item(stream,
+ rv = session_resume_deferred_stream_item(session, stream,
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
if (nghttp2_is_fatal(rv)) {
@@ -7404,6 +8000,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
return session->remote_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->remote_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->remote_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7427,6 +8025,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
return session->local_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->local_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->local_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7454,6 +8054,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
+ /* SETTINGS frame contains too many settings */
+ if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH >
+ session->max_settings) {
+ return NGHTTP2_ERR_TOO_MANY_SETTINGS;
+ }
rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
settings_payloadlen, mem);
if (rv != 0) {
@@ -7705,6 +8310,10 @@ int nghttp2_session_change_stream_priority(
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -7737,6 +8346,10 @@ int nghttp2_session_create_idle_stream(nghttp2_session *session,
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id ||
!session_detect_idle_stream(session, stream_id)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
@@ -7778,3 +8391,38 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
session->user_data = user_data;
}
+
+int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id,
+ const nghttp2_extpri *extpri_in, int ignore_client_signal) {
+ nghttp2_stream *stream;
+ nghttp2_extpri extpri = *extpri_in;
+
+ if (!session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->pending_no_rfc7540_priorities != 1) {
+ return 0;
+ }
+
+ if (stream_id == 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (!stream) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) {
+ extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW;
+ }
+
+ if (ignore_client_signal) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES;
+ }
+
+ return session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_session.h b/Utilities/cmnghttp2/lib/nghttp2_session.h
index 90ead9c039..34d2d58528 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_session.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_session.h
@@ -52,7 +52,9 @@ typedef enum {
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
- NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
+ NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
} nghttp2_optmask;
/*
@@ -62,7 +64,8 @@ typedef enum {
typedef enum {
NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
- NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
+ NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
} nghttp2_typemask;
typedef enum {
@@ -151,10 +154,8 @@ typedef struct {
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
- /* Small buffer. Currently the largest contiguous chunk to buffer
- is frame header. We buffer part of payload, but they are smaller
- than frame header. */
- uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+ /* Small fixed sized buffer. */
+ uint8_t raw_sbuf[32];
} nghttp2_inbound_frame;
typedef struct {
@@ -165,6 +166,7 @@ typedef struct {
uint32_t max_frame_size;
uint32_t max_header_list_size;
uint32_t enable_connect_protocol;
+ uint32_t no_rfc7540_priorities;
} nghttp2_settings_storage;
typedef enum {
@@ -202,6 +204,12 @@ struct nghttp2_session {
response) frame, which are subject to
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
nghttp2_outbound_queue ob_syn;
+ /* Queues for DATA frames which is used when
+ SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC
+ 9218 extensible prioritization scheme. */
+ struct {
+ nghttp2_pq ob_data;
+ } sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater;
@@ -227,6 +235,9 @@ struct nghttp2_session {
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
considered as in-flight. */
nghttp2_inflight_settings *inflight_settings_head;
+ /* Sequential number across all streams to process streams in
+ FIFO. */
+ uint64_t stream_seq;
/* The number of outgoing streams. This will be capped by
remote_settings.max_concurrent_streams. */
size_t num_outgoing_streams;
@@ -267,6 +278,8 @@ struct nghttp2_session {
/* The maximum length of header block to send. Calculated by the
same way as nghttp2_hd_deflate_bound() does. */
size_t max_send_header_block_length;
+ /* The maximum number of settings accepted per SETTINGS frame. */
+ size_t max_settings;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The last stream ID this session initiated. For client session,
@@ -326,6 +339,11 @@ struct nghttp2_session {
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
accept :protocol header field before SETTINGS_ACK is received. */
uint8_t pending_enable_connect_protocol;
+ /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
+ effective before it is acknowledged. */
+ uint8_t pending_no_rfc7540_priorities;
+ /* Turn on fallback to RFC 7540 priorities; for server use only. */
+ uint8_t fallback_rfc7540_priorities;
/* Nonzero if the session is server side. */
uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -406,7 +424,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
uint32_t error_code);
/*
- * Adds PING frame. This is a convenient functin built on top of
+ * Adds PING frame. This is a convenient function built on top of
* nghttp2_session_add_frame() to add PING easily.
*
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
@@ -772,6 +790,19 @@ int nghttp2_session_on_origin_received(nghttp2_session *session,
nghttp2_frame *frame);
/*
+ * Called when PRIORITY_UPDATE is received, assuming |frame| is
+ * properly initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ * The callback function failed.
+ */
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame);
+
+/*
* Called when DATA is received, assuming |frame| is properly
* initialized.
*
@@ -898,4 +929,36 @@ int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
uint32_t error_code,
const char *reason);
+/*
+ * Accumulates received bytes |delta_size| for connection-level flow
+ * control and decides whether to send WINDOW_UPDATE to the
+ * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
+ * WINDOW_UPDATE will not be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ * Out of memory.
+ */
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+ size_t delta_size);
+
+/*
+ * Accumulates received bytes |delta_size| for stream-level flow
+ * control and decides whether to send WINDOW_UPDATE to that stream.
+ * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
+ * be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ * Out of memory.
+ */
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+ nghttp2_stream *stream,
+ size_t delta_size,
+ int send_window_update);
+
#endif /* NGHTTP2_SESSION_H */
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.c b/Utilities/cmnghttp2/lib/nghttp2_stream.c
index dc3a6b11cc..b3614a0b02 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.c
@@ -33,7 +33,7 @@
#include "nghttp2_frame.h"
/* Maximum distance between any two stream's cycle in the same
- prirority queue. Imagine stream A's cycle is A, and stream B's
+ priority queue. Imagine stream A's cycle is A, and stream B's
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
may get overflow. Because of how we calculate the next cycle
value, if B - A is less than or equals to
@@ -62,7 +62,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
int32_t weight, int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data, nghttp2_mem *mem) {
- nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
nghttp2_pq_init(&stream->obq, stream_less, mem);
stream->stream_id = stream_id;
@@ -101,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->descendant_next_seq = 0;
stream->seq = 0;
stream->last_writelen = 0;
+
+ stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
}
void nghttp2_stream_free(nghttp2_stream *stream) {
@@ -485,6 +486,10 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
stream->item = item;
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
rv = stream_update_dep_on_attach_item(stream);
if (rv != 0) {
/* This may relave stream->queued == 1, but stream->item == NULL.
@@ -504,6 +509,10 @@ int nghttp2_stream_detach_item(nghttp2_stream *stream) {
stream->item = NULL;
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_detach_item(stream);
}
@@ -515,6 +524,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
stream->flags |= flags;
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_detach_item(stream);
}
@@ -530,6 +543,10 @@ int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
return 0;
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_attach_item(stream);
}
diff --git a/Utilities/cmnghttp2/lib/nghttp2_stream.h b/Utilities/cmnghttp2/lib/nghttp2_stream.h
index a1b807d295..7a8e4c6c1d 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_stream.h
+++ b/Utilities/cmnghttp2/lib/nghttp2_stream.h
@@ -90,8 +90,15 @@ typedef enum {
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
- NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
-
+ NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
+ /* Indicates that this stream is not subject to RFC7540
+ priorities scheme. */
+ NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
+ /* Ignore client RFC 9218 priority signal. */
+ NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
+ /* Indicates that RFC 9113 leading and trailing white spaces
+ validation against a field value is not performed. */
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40,
} nghttp2_stream_flag;
/* HTTP related flags to enforce HTTP semantics */
@@ -132,11 +139,14 @@ typedef enum {
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
+ /* set if priority header field is received */
+ NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16,
+ /* set if an error is encountered while parsing priority header
+ field */
+ NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17,
} nghttp2_http_flag;
struct nghttp2_stream {
- /* Intrusive Map */
- nghttp2_map_entry map_entry;
/* Entry for dep_prev->obq */
nghttp2_pq_entry pq_entry;
/* Priority Queue storing direct descendant (nghttp2_stream). Only
@@ -206,7 +216,7 @@ struct nghttp2_stream {
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
- uint16_t http_flags;
+ uint32_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
@@ -220,6 +230,12 @@ struct nghttp2_stream {
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
is not queued. */
uint8_t window_update_queued;
+ /* extpri is a stream priority produced by nghttp2_extpri_to_uint8
+ used by RFC 9218 extensible priorities. */
+ uint8_t extpri;
+ /* http_extpri is a stream priority received in HTTP request header
+ fields and produced by nghttp2_extpri_to_uint8. */
+ uint8_t http_extpri;
};
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
diff --git a/Utilities/cmnghttp2/lib/nghttp2_submit.c b/Utilities/cmnghttp2/lib/nghttp2_submit.c
index f604eff5c9..f5554eb564 100644
--- a/Utilities/cmnghttp2/lib/nghttp2_submit.c
+++ b/Utilities/cmnghttp2/lib/nghttp2_submit.c
@@ -196,7 +196,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
flags &= NGHTTP2_FLAG_END_STREAM;
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, stream_id, pri_spec);
if (rv != 0) {
return rv;
@@ -229,6 +230,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
mem = &session->mem;
+ if (session->remote_settings.no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || pri_spec == NULL) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -450,6 +455,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (rv != 0) {
return rv;
}
+
+ if (window_size_increment > 0) {
+ return nghttp2_session_add_window_update(session, 0, stream_id,
+ window_size_increment);
+ }
+
+ return nghttp2_session_update_recv_connection_window_size(session, 0);
} else {
stream = nghttp2_session_get_stream(session, stream_id);
@@ -476,14 +488,15 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
if (rv != 0) {
return rv;
}
- }
- if (window_size_increment > 0) {
- return nghttp2_session_add_window_update(session, 0, stream_id,
- window_size_increment);
- }
+ if (window_size_increment > 0) {
+ return nghttp2_session_add_window_update(session, 0, stream_id,
+ window_size_increment);
+ }
- return 0;
+ return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
+ 1);
+ }
}
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
@@ -654,6 +667,78 @@ fail_item_malloc:
return rv;
}
+int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_mem *mem;
+ uint8_t *buf, *p;
+ nghttp2_outbound_item *item;
+ nghttp2_frame *frame;
+ nghttp2_ext_priority_update *priority_update;
+ int rv;
+ (void)flags;
+
+ mem = &session->mem;
+
+ if (session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities == 0) {
+ return 0;
+ }
+
+ if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (field_value_len) {
+ buf = nghttp2_mem_malloc(mem, field_value_len + 1);
+ if (buf == NULL) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+
+ p = nghttp2_cpymem(buf, field_value, field_value_len);
+ *p = '\0';
+ } else {
+ buf = NULL;
+ }
+
+ item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
+ if (item == NULL) {
+ rv = NGHTTP2_ERR_NOMEM;
+ goto fail_item_malloc;
+ }
+
+ nghttp2_outbound_item_init(item);
+
+ item->aux_data.ext.builtin = 1;
+
+ priority_update = &item->ext_frame_payload.priority_update;
+
+ frame = &item->frame;
+ frame->ext.payload = priority_update;
+
+ nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
+ field_value_len);
+
+ rv = nghttp2_session_add_item(session, item);
+ if (rv != 0) {
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ nghttp2_mem_free(mem, item);
+
+ return rv;
+ }
+
+ return 0;
+
+fail_item_malloc:
+ free(buf);
+
+ return rv;
+}
+
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) {
uint8_t flags = NGHTTP2_FLAG_NONE;
@@ -680,7 +765,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
return NGHTTP2_ERR_PROTO;
}
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, -1, pri_spec);
if (rv != 0) {
return rv;