From 2ce0be970c6e9df5131fbf25de43b1987cabed28 Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Mon, 6 Jul 2026 10:36:29 -0400 Subject: [PATCH] import UBI nodejs-22.23.1-1.module+el9.8.0+24457+996af7aa --- .gitignore | 2 +- .nodejs.metadata | 2 +- .../0001-deps-update-nghttp2-to-1.68.1.patch | 7712 ----------------- ...26-42338-npm-ip-address-security-fix.patch | 166 + SPECS/nodejs.spec | 32 +- 5 files changed, 187 insertions(+), 7727 deletions(-) delete mode 100644 SOURCES/0001-deps-update-nghttp2-to-1.68.1.patch create mode 100644 SOURCES/0002-CVE-2026-42338-npm-ip-address-security-fix.patch diff --git a/.gitignore b/.gitignore index a262ca4..da72bdc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ SOURCES/icu4c-78.2-data-bin-b.zip SOURCES/icu4c-78.2-data-bin-l.zip -SOURCES/node-v22.22.2-stripped.tar.gz +SOURCES/node-v22.23.1-stripped.tar.gz diff --git a/.nodejs.metadata b/.nodejs.metadata index 4395c78..b5af359 100644 --- a/.nodejs.metadata +++ b/.nodejs.metadata @@ -1,3 +1,3 @@ 7a91e81c4f2c8368d80285a5bbdfe278d68e4a84 SOURCES/icu4c-78.2-data-bin-b.zip b9f5918e2118ef8531b0ffc04b3d50e951e3a166 SOURCES/icu4c-78.2-data-bin-l.zip -99fded7e2ca8329a6bcdba962599c9c8f2f3b689 SOURCES/node-v22.22.2-stripped.tar.gz +8751335622db226d57c19ed444575147f0b62396 SOURCES/node-v22.23.1-stripped.tar.gz diff --git a/SOURCES/0001-deps-update-nghttp2-to-1.68.1.patch b/SOURCES/0001-deps-update-nghttp2-to-1.68.1.patch deleted file mode 100644 index 10a5ae1..0000000 --- a/SOURCES/0001-deps-update-nghttp2-to-1.68.1.patch +++ /dev/null @@ -1,7712 +0,0 @@ -From f6b6d56d3b5eac6a9dfa65ba55fc5d978f952759 Mon Sep 17 00:00:00 2001 -From: Andrei Radchenko -Date: Thu, 26 Mar 2026 12:11:26 +0100 -Subject: [PATCH] deps: update nghttp2 to 1.68.1 - ---- - deps/nghttp2/lib/CMakeLists.txt | 40 +- - deps/nghttp2/lib/Makefile.am | 2 +- - deps/nghttp2/lib/Makefile.in | 6 +- - deps/nghttp2/lib/config.cmake.in | 3 + - deps/nghttp2/lib/includes/Makefile.in | 4 + - deps/nghttp2/lib/includes/nghttp2/nghttp2.h | 315 ++--- - .../nghttp2/lib/includes/nghttp2/nghttp2ver.h | 4 +- - deps/nghttp2/lib/nghttp2_alpn.h | 4 +- - deps/nghttp2/lib/nghttp2_buf.h | 4 +- - deps/nghttp2/lib/nghttp2_callbacks.c | 5 + - deps/nghttp2/lib/nghttp2_callbacks.h | 5 +- - deps/nghttp2/lib/nghttp2_debug.c | 4 +- - deps/nghttp2/lib/nghttp2_debug.h | 8 +- - deps/nghttp2/lib/nghttp2_extpri.h | 4 +- - deps/nghttp2/lib/nghttp2_frame.c | 10 + - deps/nghttp2/lib/nghttp2_frame.h | 4 +- - deps/nghttp2/lib/nghttp2_hd.c | 11 + - deps/nghttp2/lib/nghttp2_hd.h | 4 +- - deps/nghttp2/lib/nghttp2_hd_huffman.h | 4 +- - deps/nghttp2/lib/nghttp2_helper.h | 4 +- - deps/nghttp2/lib/nghttp2_http.c | 17 +- - deps/nghttp2/lib/nghttp2_http.h | 4 +- - deps/nghttp2/lib/nghttp2_int.h | 10 +- - deps/nghttp2/lib/nghttp2_map.c | 70 +- - deps/nghttp2/lib/nghttp2_map.h | 9 +- - deps/nghttp2/lib/nghttp2_mem.h | 4 +- - deps/nghttp2/lib/nghttp2_net.h | 16 +- - deps/nghttp2/lib/nghttp2_option.c | 7 + - deps/nghttp2/lib/nghttp2_option.h | 10 +- - deps/nghttp2/lib/nghttp2_outbound_item.h | 4 +- - deps/nghttp2/lib/nghttp2_pq.h | 4 +- - deps/nghttp2/lib/nghttp2_priority_spec.h | 4 +- - deps/nghttp2/lib/nghttp2_queue.h | 4 +- - deps/nghttp2/lib/nghttp2_ratelim.h | 4 +- - deps/nghttp2/lib/nghttp2_rcbuf.h | 4 +- - deps/nghttp2/lib/nghttp2_session.c | 1163 ++++++----------- - deps/nghttp2/lib/nghttp2_session.h | 147 +-- - deps/nghttp2/lib/nghttp2_stream.c | 847 +----------- - deps/nghttp2/lib/nghttp2_stream.h | 161 +-- - deps/nghttp2/lib/nghttp2_submit.c | 164 +-- - deps/nghttp2/lib/nghttp2_submit.h | 4 +- - deps/nghttp2/lib/nghttp2_time.c | 15 +- - deps/nghttp2/lib/nghttp2_time.h | 4 +- - deps/nghttp2/lib/nghttp2_version.c | 2 +- - deps/nghttp2/lib/sfparse.c | 1140 ++++++++++++---- - deps/nghttp2/lib/sfparse.h | 313 +++-- - 46 files changed, 1834 insertions(+), 2742 deletions(-) - create mode 100644 deps/nghttp2/lib/config.cmake.in - -diff --git a/deps/nghttp2/lib/CMakeLists.txt b/deps/nghttp2/lib/CMakeLists.txt -index fda8dcb7..98e3dbe7 100644 ---- a/deps/nghttp2/lib/CMakeLists.txt -+++ b/deps/nghttp2/lib/CMakeLists.txt -@@ -47,7 +47,29 @@ if(WIN32) - set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) - endif() - --set(EXPORT_SET "${PROJECT_NAME}-targets") -+set(NGHTTP2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") -+set(NGHTTP2_VERSION_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") -+set(NGHTTP2_PROJECT_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}Config.cmake") -+set(NGHTTP2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") -+set(NGHTTP2_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") -+set(NGHTTP2_NAMESPACE "${PROJECT_NAME}::") -+set(NGHTTP2_VERSION ${PROJECT_VERSION}) -+ -+include(CMakePackageConfigHelpers) -+write_basic_package_version_file( -+ "${NGHTTP2_VERSION_CONFIG}" VERSION ${NGHTTP2_VERSION} COMPATIBILITY SameMajorVersion -+) -+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.cmake.in" "${NGHTTP2_PROJECT_CONFIG}" @ONLY) -+ -+# Install cmake config files -+install( -+ FILES "${NGHTTP2_PROJECT_CONFIG}" "${NGHTTP2_VERSION_CONFIG}" -+ DESTINATION "${NGHTTP2_CONFIG_INSTALL_DIR}") -+ -+install( -+ EXPORT "${NGHTTP2_TARGETS_EXPORT_NAME}" -+ NAMESPACE "${NGHTTP2_NAMESPACE}" -+ DESTINATION "${NGHTTP2_CONFIG_INSTALL_DIR}") - - # Public shared library - if(BUILD_SHARED_LIBS) -@@ -65,7 +87,11 @@ if(BUILD_SHARED_LIBS) - $ - ) - -- install(TARGETS ${SHARED_LIB} EXPORT ${EXPORT_SET}) -+ install(TARGETS ${SHARED_LIB} -+ EXPORT ${NGHTTP2_TARGETS_EXPORT_NAME} -+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" -+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" -+ RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") - list(APPEND nghttp2_exports ${SHARED_LIB}) - endif() - -@@ -87,7 +113,9 @@ if(BUILD_STATIC_LIBS) - - target_compile_definitions(${STATIC_LIB} PUBLIC "-DNGHTTP2_STATICLIB") - -- install(TARGETS ${STATIC_LIB} EXPORT ${EXPORT_SET}) -+ install(TARGETS ${STATIC_LIB} -+ EXPORT ${NGHTTP2_TARGETS_EXPORT_NAME} -+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") - list(APPEND nghttp2_exports ${STATIC_LIB}) - endif() - -@@ -97,11 +125,7 @@ else() - set(LIB_SELECTED ${STATIC_LIB}) - endif() - --add_library(${PROJECT_NAME}::nghttp2 ALIAS ${LIB_SELECTED}) -+add_library(nghttp2 ALIAS ${LIB_SELECTED}) - - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") -- --install(EXPORT ${EXPORT_SET} -- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} -- NAMESPACE ${PROJECT_NAME}::) -diff --git a/deps/nghttp2/lib/Makefile.am b/deps/nghttp2/lib/Makefile.am -index 1168c1e6..3a743df6 100644 ---- a/deps/nghttp2/lib/Makefile.am -+++ b/deps/nghttp2/lib/Makefile.am -@@ -22,7 +22,7 @@ - # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - SUBDIRS = includes - --EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in -+EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in config.cmake.in - - AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) - AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ -diff --git a/deps/nghttp2/lib/Makefile.in b/deps/nghttp2/lib/Makefile.in -index 14686ef1..bb458a18 100644 ---- a/deps/nghttp2/lib/Makefile.in -+++ b/deps/nghttp2/lib/Makefile.in -@@ -360,6 +360,10 @@ LIBNGHTTP3_LIBS = @LIBNGHTTP3_LIBS@ - LIBNGTCP2_CFLAGS = @LIBNGTCP2_CFLAGS@ - LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS = @LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ - LIBNGTCP2_CRYPTO_BORINGSSL_LIBS = @LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ -+LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS = @LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS@ -+LIBNGTCP2_CRYPTO_LIBRESSL_LIBS = @LIBNGTCP2_CRYPTO_LIBRESSL_LIBS@ -+LIBNGTCP2_CRYPTO_OSSL_CFLAGS = @LIBNGTCP2_CRYPTO_OSSL_CFLAGS@ -+LIBNGTCP2_CRYPTO_OSSL_LIBS = @LIBNGTCP2_CRYPTO_OSSL_LIBS@ - LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ - LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ - LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS = @LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS@ -@@ -492,7 +496,7 @@ top_srcdir = @top_srcdir@ - # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - SUBDIRS = includes --EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in -+EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in config.cmake.in - AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) - AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ - @DEFS@ -diff --git a/deps/nghttp2/lib/config.cmake.in b/deps/nghttp2/lib/config.cmake.in -new file mode 100644 -index 00000000..0b677718 ---- /dev/null -+++ b/deps/nghttp2/lib/config.cmake.in -@@ -0,0 +1,3 @@ -+include(CMakeFindDependencyMacro) -+ -+include("${CMAKE_CURRENT_LIST_DIR}/@NGHTTP2_TARGETS_EXPORT_NAME@.cmake") -diff --git a/deps/nghttp2/lib/includes/Makefile.in b/deps/nghttp2/lib/includes/Makefile.in -index 778dcb87..a4687390 100644 ---- a/deps/nghttp2/lib/includes/Makefile.in -+++ b/deps/nghttp2/lib/includes/Makefile.in -@@ -265,6 +265,10 @@ LIBNGHTTP3_LIBS = @LIBNGHTTP3_LIBS@ - LIBNGTCP2_CFLAGS = @LIBNGTCP2_CFLAGS@ - LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS = @LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ - LIBNGTCP2_CRYPTO_BORINGSSL_LIBS = @LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ -+LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS = @LIBNGTCP2_CRYPTO_LIBRESSL_CFLAGS@ -+LIBNGTCP2_CRYPTO_LIBRESSL_LIBS = @LIBNGTCP2_CRYPTO_LIBRESSL_LIBS@ -+LIBNGTCP2_CRYPTO_OSSL_CFLAGS = @LIBNGTCP2_CRYPTO_OSSL_CFLAGS@ -+LIBNGTCP2_CRYPTO_OSSL_LIBS = @LIBNGTCP2_CRYPTO_OSSL_LIBS@ - LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ - LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ - LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS = @LIBNGTCP2_CRYPTO_WOLFSSL_CFLAGS@ -diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h -index 2ef49b8d..19c1874f 100644 ---- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h -+++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h -@@ -2039,18 +2039,19 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, - /** - * @functypedef - * -- * Callback function invoked when a invalid header name/value pair is -+ * Callback function invoked when an invalid header name/value pair is - * received for the |frame|. - * - * The parameter and behaviour are similar to - * :type:`nghttp2_on_header_callback`. The difference is that this -- * callback is only invoked when a invalid header name/value pair is -- * received which is treated as stream error if this callback is not -- * set. Only invalid regular header field are passed to this -- * callback. In other words, invalid pseudo header field is not -- * passed to this callback. Also header fields which includes upper -- * cased latter are also treated as error without passing them to this -- * callback. -+ * callback is only invoked when an invalid header name/value pair is -+ * received which is treated as stream error if this callback returns -+ * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` and -+ * :type:`nghttp2_on_invalid_header_callback2` is not set. Only -+ * invalid regular header field are passed to this callback. In other -+ * words, invalid pseudo header field is not passed to this callback. -+ * Also header fields which includes upper cased latter are also -+ * treated as error without passing them to this callback. - * - * This callback is only considered if HTTP messaging validation is - * turned on (which is on by default, see -@@ -2076,17 +2077,18 @@ typedef int (*nghttp2_on_invalid_header_callback)( - /** - * @functypedef - * -- * Callback function invoked when a invalid header name/value pair is -+ * Callback function invoked when an invalid header name/value pair is - * received for the |frame|. - * - * The parameter and behaviour are similar to - * :type:`nghttp2_on_header_callback2`. The difference is that this -- * callback is only invoked when a invalid header name/value pair is -- * received which is silently ignored if this callback is not set. -- * Only invalid regular header field are passed to this callback. In -- * other words, invalid pseudo header field is not passed to this -- * callback. Also header fields which includes upper cased latter are -- * also treated as error without passing them to this callback. -+ * callback is only invoked when an invalid header name/value pair is -+ * received which is silently ignored if neither this callback nor -+ * :type:`nghttp2_on_invalid_header_callback` is set. Only invalid -+ * regular header field are passed to this callback. In other words, -+ * invalid pseudo header field is not passed to this callback. Also -+ * header fields which includes upper cased latter are also treated as -+ * error without passing them to this callback. - * - * This callback is only considered if HTTP messaging validation is - * turned on (which is on by default, see -@@ -2445,6 +2447,15 @@ typedef int (*nghttp2_error_callback2)(nghttp2_session *session, - int lib_error_code, const char *msg, - size_t len, void *user_data); - -+/** -+ * @functypedef -+ * -+ * Callback function invoked when unpredictable data of |destlen| -+ * bytes are needed. The implementation must write unpredictable data -+ * of |destlen| bytes into the buffer pointed by |dest|. -+ */ -+typedef void (*nghttp2_rand_callback)(uint8_t *dest, size_t destlen); -+ - struct nghttp2_session_callbacks; - - /** -@@ -2649,7 +2660,7 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2( - /** - * @function - * -- * Sets callback function invoked when a invalid header name/value -+ * Sets callback function invoked when an invalid header name/value - * pair is received. If both - * `nghttp2_session_callbacks_set_on_invalid_header_callback()` and - * `nghttp2_session_callbacks_set_on_invalid_header_callback2()` are -@@ -2662,7 +2673,7 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback( - /** - * @function - * -- * Sets callback function invoked when a invalid header name/value -+ * Sets callback function invoked when an invalid header name/value - * pair is received. - */ - NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_invalid_header_callback2( -@@ -2833,6 +2844,18 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback( - NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback2( - nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2); - -+/** -+ * @function -+ * -+ * Sets callback function invoked when unpredictable data is needed. -+ * Although this callback is optional due to the backward -+ * compatibility, it is recommended to specify it to harden the -+ * runtime behavior against suspicious activities of a remote -+ * endpoint. -+ */ -+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_rand_callback( -+ nghttp2_session_callbacks *cbs, nghttp2_rand_callback rand_callback); -+ - /** - * @functypedef - * -@@ -3133,14 +3156,12 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, - /** - * @function - * -- * 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. -+ * .. warning:: - * -- * 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. -+ * Deprecated. Closed streams are not retained anymore. -+ * -+ * This function works as before, but it does not take any effect -+ * against :type:`nghttp2_session`. - */ - NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option, - int val); -@@ -3170,16 +3191,11 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option, - /** - * @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. -+ * .. warning:: -+ * Deprecated. :rfc:`7540` priorities have been removed. - * -- * Client session ignores this option. -+ * This function works as before, but it does not take any effect -+ * against :type:`nghttp2_session`. - */ - NGHTTP2_EXTERN void - nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option, -@@ -3225,6 +3241,23 @@ nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, - NGHTTP2_EXTERN void nghttp2_option_set_max_continuations(nghttp2_option *option, - size_t val); - -+/** -+ * @function -+ * -+ * This function sets the rate limit for the "glitches", the -+ * suspicious activities from a remote endpoint. It is a token-bucket -+ * based rate limiter. |burst| specifies the number of tokens that is -+ * initially available. The maximum number of tokens is capped to -+ * this value. |rate| specifies the number of tokens that are -+ * regenerated per second. When a suspicious activity is detected, -+ * some amount of tokens are consumed. If there is no token -+ * available, GOAWAY is sent to tear down the connection. |burst| and -+ * |rate| default to 1000 and 33 respectively. -+ */ -+NGHTTP2_EXTERN void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option, -+ uint64_t burst, -+ uint64_t rate); -+ - /** - * @function - * -@@ -4179,39 +4212,9 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return 0 without doing anything. -- * -- * Changes priority of existing stream denoted by |stream_id|. The -- * new priority specification is |pri_spec|. -- * -- * The priority is changed silently and instantly, and no PRIORITY -- * frame will be sent to notify the peer of this change. This -- * function may be useful for server to change the priority of pushed -- * stream. -- * -- * If |session| is initialized as server, and ``pri_spec->stream_id`` -- * points to the idle stream, the idle stream is created if it does -- * not exist. The created idle stream will depend on root stream -- * (stream 0) with weight 16. -- * -- * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not -- * found, we use default priority instead of given |pri_spec|. That -- * is make stream depend on root stream with weight 16. -- * -- * 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: -+ * prioritization scheme. - * -- * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` -- * Out of memory. -- * :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 -+ * This function is noop. It always returns 0. - */ - NGHTTP2_EXTERN int - nghttp2_session_change_stream_priority(nghttp2_session *session, -@@ -4225,51 +4228,9 @@ nghttp2_session_change_stream_priority(nghttp2_session *session, - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return 0 without doing anything. -- * -- * Creates idle stream with the given |stream_id|, and priority -- * |pri_spec|. -- * -- * The stream creation is done without sending PRIORITY frame, which -- * means that peer does not know about the existence of this idle -- * stream in the local endpoint. -- * -- * RFC 7540 does not disallow the use of creation of idle stream with -- * odd or even stream ID regardless of client or server. So this -- * function can create odd or even stream ID regardless of client or -- * server. But probably it is a bit safer to use the stream ID the -- * local endpoint can initiate (in other words, use odd stream ID for -- * client, and even stream ID for server), to avoid potential -- * collision from peer's instruction. Also we can use -- * `nghttp2_session_set_next_stream_id()` to avoid to open created -- * idle streams accidentally if we follow this recommendation. -- * -- * If |session| is initialized as server, and ``pri_spec->stream_id`` -- * points to the idle stream, the idle stream is created if it does -- * not exist. The created idle stream will depend on root stream -- * (stream 0) with weight 16. -- * -- * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not -- * found, we use default priority instead of given |pri_spec|. That -- * is make stream depend on root stream with weight 16. -- * -- * 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: -+ * prioritization scheme. - * -- * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` -- * Out of memory. -- * :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 -- * stream ID greater than or equal to the given stream ID; or -- * |stream_id| is 0 -+ * This function is noop. It always returns 0. - */ - NGHTTP2_EXTERN int - nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, -@@ -4505,23 +4466,7 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); - * - * Submits HEADERS frame and optionally one or more DATA frames. - * -- * The |pri_spec| is a deprecated priority specification of this -- * request. ``NULL`` means the default priority (see -- * `nghttp2_priority_spec_default_init()`). To specify the priority, -- * 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 [: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 |pri_spec| is ignored. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include -@@ -4564,9 +4509,6 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. -- * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` -- * Trying to depend on itself (new stream ID equals -- * ``pri_spec->stream_id``). - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is server session. - * -@@ -4594,25 +4536,7 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( - * - * Submits HEADERS frame and optionally one or more DATA frames. - * -- * The |pri_spec| is a deprecated priority specification of this -- * request. ``NULL`` means the default priority (see -- * `nghttp2_priority_spec_default_init()`). To specify the priority, -- * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, -- * this function will copy its data members. In the future release -- * after the end of 2024, this function will ignore |pri_spec| and -- * behave as if ``NULL`` is given. -- * -- * 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 |pri_spec| is ignored. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include -@@ -4655,9 +4579,6 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( - * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` - * No stream ID is available because maximum stream ID was - * reached. -- * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` -- * Trying to depend on itself (new stream ID equals -- * ``pri_spec->stream_id``). - * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` - * The |session| is server session. - * -@@ -4899,24 +4820,7 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, - * assigned stream ID will be returned. Otherwise, specify stream ID - * in |stream_id|. - * -- * The |pri_spec| is a deprecated priority specification of this -- * request. ``NULL`` means the default priority (see -- * `nghttp2_priority_spec_default_init()`). To specify the priority, -- * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, -- * this function will copy its data members. In the future release -- * after the end of 2024, this function will ignore |pri_spec| and -- * behave as if ``NULL`` is given. -- * -- * 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 |pri_spec| is ignored. - * - * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible to include -@@ -4956,8 +4860,7 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, - * No stream ID is available because maximum stream ID was - * reached. - * :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``). -+ * The |stream_id| is 0. - * :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| -@@ -5083,40 +4986,9 @@ NGHTTP2_EXTERN int nghttp2_submit_data2(nghttp2_session *session, uint8_t flags, - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return 0 without doing anything. -- * -- * Submits PRIORITY frame to change the priority of stream |stream_id| -- * to the priority specification |pri_spec|. -- * -- * The |flags| is currently ignored and should be -- * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. -- * -- * The |pri_spec| is a deprecated 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 [: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: -+ * prioritization scheme. - * -- * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` -- * Out of memory. -- * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` -- * The |stream_id| is 0; or the |pri_spec| is NULL; or trying to -- * depend on itself. -+ * This function is noop. It always returns 0. - */ - NGHTTP2_EXTERN int - nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, -@@ -6885,11 +6757,9 @@ nghttp2_session_get_root_stream(nghttp2_session *session); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return NULL. -+ * prioritization scheme. - * -- * Returns the parent stream of |stream| in dependency tree. Returns -- * NULL if there is no such stream. -+ * This function always returns NULL. - */ - NGHTTP2_EXTERN nghttp2_stream * - nghttp2_stream_get_parent(nghttp2_stream *stream); -@@ -6903,11 +6773,9 @@ NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return NULL. -+ * prioritization scheme. - * -- * Returns the next sibling stream of |stream| in dependency tree. -- * Returns NULL if there is no such stream. -+ * This function always returns NULL. - */ - NGHTTP2_EXTERN nghttp2_stream * - nghttp2_stream_get_next_sibling(nghttp2_stream *stream); -@@ -6919,11 +6787,9 @@ nghttp2_stream_get_next_sibling(nghttp2_stream *stream); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return NULL. -+ * prioritization scheme. - * -- * Returns the previous sibling stream of |stream| in dependency tree. -- * Returns NULL if there is no such stream. -+ * This function always returns NULL. - */ - NGHTTP2_EXTERN nghttp2_stream * - nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); -@@ -6935,11 +6801,9 @@ nghttp2_stream_get_previous_sibling(nghttp2_stream *stream); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return NULL. -+ * prioritization scheme. - * -- * Returns the first child stream of |stream| in dependency tree. -- * Returns NULL if there is no such stream. -+ * This function always returns NULL. - */ - NGHTTP2_EXTERN nghttp2_stream * - nghttp2_stream_get_first_child(nghttp2_stream *stream); -@@ -6951,11 +6815,9 @@ nghttp2_stream_get_first_child(nghttp2_stream *stream); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return -- * :macro:`NGHTTP2_DEFAULT_WEIGHT`. -+ * prioritization scheme. - * -- * Returns dependency weight to the parent stream of |stream|. -+ * This function always returns :macro:`NGHTTP2_DEFAULT_WEIGHT`. - */ - NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); - -@@ -6966,10 +6828,9 @@ NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream); - * - * Deprecated. :rfc:`7540` priorities are deprecated by - * :rfc:`9113`. Consider migrating to :rfc:`9218` extensible -- * prioritization scheme. In the future release after the end of -- * 2024, this function will always return 0. -+ * prioritization scheme. - * -- * Returns the sum of the weight for |stream|'s children. -+ * This function always returns 0. - */ - NGHTTP2_EXTERN int32_t - nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream); -diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h -index 827c9989..95acef22 100644 ---- a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h -+++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h -@@ -29,7 +29,7 @@ - * @macro - * Version number of the nghttp2 library release - */ --#define NGHTTP2_VERSION "1.64.0" -+#define NGHTTP2_VERSION "1.68.1" - - /** - * @macro -@@ -37,6 +37,6 @@ - * release. This is a 24 bit number with 8 bits for major number, 8 bits - * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. - */ --#define NGHTTP2_VERSION_NUM 0x014000 -+#define NGHTTP2_VERSION_NUM 0x014401 - - #endif /* NGHTTP2VER_H */ -diff --git a/deps/nghttp2/lib/nghttp2_alpn.h b/deps/nghttp2/lib/nghttp2_alpn.h -index 09810fd8..ecc9ed20 100644 ---- a/deps/nghttp2/lib/nghttp2_alpn.h -+++ b/deps/nghttp2/lib/nghttp2_alpn.h -@@ -27,8 +27,8 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - --#endif /* NGHTTP2_ALPN_H */ -+#endif /* !defined(NGHTTP2_ALPN_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_buf.h b/deps/nghttp2/lib/nghttp2_buf.h -index 95ff3706..636aa619 100644 ---- a/deps/nghttp2/lib/nghttp2_buf.h -+++ b/deps/nghttp2/lib/nghttp2_buf.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -409,4 +409,4 @@ int nghttp2_bufs_next_present(nghttp2_bufs *bufs); - */ - size_t nghttp2_bufs_len(nghttp2_bufs *bufs); - --#endif /* NGHTTP2_BUF_H */ -+#endif /* !defined(NGHTTP2_BUF_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_callbacks.c b/deps/nghttp2/lib/nghttp2_callbacks.c -index 32fedd52..162ca6bd 100644 ---- a/deps/nghttp2/lib/nghttp2_callbacks.c -+++ b/deps/nghttp2/lib/nghttp2_callbacks.c -@@ -201,3 +201,8 @@ void nghttp2_session_callbacks_set_error_callback2( - nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) { - cbs->error_callback2 = error_callback2; - } -+ -+void nghttp2_session_callbacks_set_rand_callback( -+ nghttp2_session_callbacks *cbs, nghttp2_rand_callback rand_callback) { -+ cbs->rand_callback = rand_callback; -+} -diff --git a/deps/nghttp2/lib/nghttp2_callbacks.h b/deps/nghttp2/lib/nghttp2_callbacks.h -index a611f485..4b45e578 100644 ---- a/deps/nghttp2/lib/nghttp2_callbacks.h -+++ b/deps/nghttp2/lib/nghttp2_callbacks.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -151,6 +151,7 @@ struct nghttp2_session_callbacks { - nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback; - nghttp2_error_callback error_callback; - nghttp2_error_callback2 error_callback2; -+ nghttp2_rand_callback rand_callback; - }; - --#endif /* NGHTTP2_CALLBACKS_H */ -+#endif /* !defined(NGHTTP2_CALLBACKS_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_debug.c b/deps/nghttp2/lib/nghttp2_debug.c -index 09dd2b28..b5f33ef3 100644 ---- a/deps/nghttp2/lib/nghttp2_debug.c -+++ b/deps/nghttp2/lib/nghttp2_debug.c -@@ -50,11 +50,11 @@ void nghttp2_set_debug_vprintf_callback( - static_debug_vprintf_callback = debug_vprintf_callback; - } - --#else /* !DEBUGBUILD */ -+#else /* !defined(DEBUGBUILD) */ - - void nghttp2_set_debug_vprintf_callback( - nghttp2_debug_vprintf_callback debug_vprintf_callback) { - (void)debug_vprintf_callback; - } - --#endif /* !DEBUGBUILD */ -+#endif /* !defined(DEBUGBUILD) */ -diff --git a/deps/nghttp2/lib/nghttp2_debug.h b/deps/nghttp2/lib/nghttp2_debug.h -index cbb4dd57..26566a62 100644 ---- a/deps/nghttp2/lib/nghttp2_debug.h -+++ b/deps/nghttp2/lib/nghttp2_debug.h -@@ -27,17 +27,17 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - - #ifdef DEBUGBUILD - # define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__) - void nghttp2_debug_vprintf(const char *format, ...); --#else -+#else /* !defined(DEBUGBUILD) */ - # define DEBUGF(...) \ - do { \ - } while (0) --#endif -+#endif /* !defined(DEBUGBUILD) */ - --#endif /* NGHTTP2_DEBUG_H */ -+#endif /* !defined(NGHTTP2_DEBUG_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_extpri.h b/deps/nghttp2/lib/nghttp2_extpri.h -index db911972..2e039165 100644 ---- a/deps/nghttp2/lib/nghttp2_extpri.h -+++ b/deps/nghttp2/lib/nghttp2_extpri.h -@@ -28,7 +28,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -62,4 +62,4 @@ void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri); - */ - #define nghttp2_extpri_uint8_inc(PRI) (((PRI) & NGHTTP2_EXTPRI_INC_MASK) != 0) - --#endif /* NGHTTP2_EXTPRI_H */ -+#endif /* !defined(NGHTTP2_EXTPRI_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c -index edc2aaaa..264ae9d3 100644 ---- a/deps/nghttp2/lib/nghttp2_frame.c -+++ b/deps/nghttp2/lib/nghttp2_frame.c -@@ -750,6 +750,16 @@ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, - uint8_t *p; - - altsvc = frame->payload; -+ -+ if (payloadlen == 0) { -+ altsvc->origin = NULL; -+ altsvc->origin_len = 0; -+ altsvc->field_value = NULL; -+ altsvc->field_value_len = 0; -+ -+ return; -+ } -+ - p = payload; - - altsvc->origin = p; -diff --git a/deps/nghttp2/lib/nghttp2_frame.h b/deps/nghttp2/lib/nghttp2_frame.h -index d5866880..ed4ab2c6 100644 ---- a/deps/nghttp2/lib/nghttp2_frame.h -+++ b/deps/nghttp2/lib/nghttp2_frame.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_hd.h" -@@ -634,4 +634,4 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); - void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, - size_t padlen, int framehd_only); - --#endif /* NGHTTP2_FRAME_H */ -+#endif /* !defined(NGHTTP2_FRAME_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c -index 55fc2cc6..ad85eed1 100644 ---- a/deps/nghttp2/lib/nghttp2_hd.c -+++ b/deps/nghttp2/lib/nghttp2_hd.c -@@ -594,8 +594,19 @@ static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) { - static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize, - nghttp2_mem *mem) { - size_t size; -+ const size_t max_size = SIZE_MAX / sizeof(nghttp2_hd_entry *); -+ -+ if (bufsize > max_size) { -+ return NGHTTP2_ERR_NOMEM; -+ } -+ - for (size = 1; size < bufsize; size <<= 1) - ; -+ -+ if (size > max_size) { -+ return NGHTTP2_ERR_NOMEM; -+ } -+ - ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size); - if (ringbuf->buffer == NULL) { - return NGHTTP2_ERR_NOMEM; -diff --git a/deps/nghttp2/lib/nghttp2_hd.h b/deps/nghttp2/lib/nghttp2_hd.h -index 38a31a83..bdc7fad5 100644 ---- a/deps/nghttp2/lib/nghttp2_hd.h -+++ b/deps/nghttp2/lib/nghttp2_hd.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -439,4 +439,4 @@ nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, - */ - int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx); - --#endif /* NGHTTP2_HD_H */ -+#endif /* !defined(NGHTTP2_HD_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_hd_huffman.h b/deps/nghttp2/lib/nghttp2_hd_huffman.h -index 2bfd5318..df037a8b 100644 ---- a/deps/nghttp2/lib/nghttp2_hd_huffman.h -+++ b/deps/nghttp2/lib/nghttp2_hd_huffman.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -69,4 +69,4 @@ typedef struct { - extern const nghttp2_huff_sym huff_sym_table[]; - extern const nghttp2_huff_decode huff_decode_table[][16]; - --#endif /* NGHTTP2_HD_HUFFMAN_H */ -+#endif /* !defined(NGHTTP2_HD_HUFFMAN_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_helper.h b/deps/nghttp2/lib/nghttp2_helper.h -index f5de6290..7d640761 100644 ---- a/deps/nghttp2/lib/nghttp2_helper.h -+++ b/deps/nghttp2/lib/nghttp2_helper.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include -@@ -142,4 +142,4 @@ int nghttp2_should_send_window_update(int32_t local_window_size, - */ - uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len); - --#endif /* NGHTTP2_HELPER_H */ -+#endif /* !defined(NGHTTP2_HELPER_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c -index f222fe5e..60a0b01e 100644 ---- a/deps/nghttp2/lib/nghttp2_http.c -+++ b/deps/nghttp2/lib/nghttp2_http.c -@@ -207,7 +207,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, - 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, -@@ -660,17 +659,17 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream, - int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - size_t valuelen) { - nghttp2_extpri pri = *dest; -- sf_parser sfp; -- sf_vec key; -- sf_value val; -+ sfparse_parser sfp; -+ sfparse_vec key; -+ sfparse_value val; - int rv; - -- sf_parser_init(&sfp, value, valuelen); -+ sfparse_parser_init(&sfp, value, valuelen); - - for (;;) { -- rv = sf_parser_dict(&sfp, &key, &val); -+ rv = sfparse_parser_dict(&sfp, &key, &val); - if (rv != 0) { -- if (rv == SF_ERR_EOF) { -+ if (rv == SFPARSE_ERR_EOF) { - break; - } - -@@ -683,7 +682,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - - switch (key.base[0]) { - case 'i': -- if (val.type != SF_TYPE_BOOLEAN) { -+ if (val.type != SFPARSE_TYPE_BOOLEAN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - -@@ -691,7 +690,7 @@ int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - - break; - case 'u': -- if (val.type != SF_TYPE_INTEGER || -+ if (val.type != SFPARSE_TYPE_INTEGER || - val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH || - NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) { - return NGHTTP2_ERR_INVALID_ARGUMENT; -diff --git a/deps/nghttp2/lib/nghttp2_http.h b/deps/nghttp2/lib/nghttp2_http.h -index d9992fe6..2925334c 100644 ---- a/deps/nghttp2/lib/nghttp2_http.h -+++ b/deps/nghttp2/lib/nghttp2_http.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_session.h" -@@ -97,4 +97,4 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream, - int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, - size_t valuelen); - --#endif /* NGHTTP2_HTTP_H */ -+#endif /* !defined(NGHTTP2_HTTP_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_int.h b/deps/nghttp2/lib/nghttp2_int.h -index b23585cc..d89cf154 100644 ---- a/deps/nghttp2/lib/nghttp2_int.h -+++ b/deps/nghttp2/lib/nghttp2_int.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -52,7 +52,11 @@ typedef enum { - * Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke - * nghttp2_on_invalid_header_callback. - */ -- NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106 -+ NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106, -+ /* -+ * Cancel pushed stream. -+ */ -+ NGHTTP2_ERR_PUSH_CANCEL = -107, - } nghttp2_internal_error; - --#endif /* NGHTTP2_INT_H */ -+#endif /* !defined(NGHTTP2_INT_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_map.c b/deps/nghttp2/lib/nghttp2_map.c -index ee6bb196..f89f3103 100644 ---- a/deps/nghttp2/lib/nghttp2_map.c -+++ b/deps/nghttp2/lib/nghttp2_map.c -@@ -31,12 +31,13 @@ - - #include "nghttp2_helper.h" - --#define NGHTTP2_INITIAL_TABLE_LENBITS 4 -+#define NGHTTP2_INITIAL_HASHBITS 4 - --void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) { -+void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem) { - map->mem = mem; - map->hashbits = 0; - map->table = NULL; -+ map->seed = seed; - map->size = 0; - } - -@@ -77,8 +78,13 @@ int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), - return 0; - } - --static size_t hash(nghttp2_map_key_type key, size_t bits) { -- return (size_t)(((uint32_t)key * 2654435769u) >> (32 - bits)); -+static size_t map_hash(const nghttp2_map *map, nghttp2_map_key_type key) { -+ /* hasher from -+ https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs -+ We do not perform finalization here because we use top bits -+ anyway. */ -+ uint32_t h = ((uint32_t)key + map->seed) * 0x93d765dd; -+ return (size_t)((h * 2654435769u) >> (32 - map->hashbits)); - } - - static void map_bucket_swap(nghttp2_map_bucket *a, nghttp2_map_bucket *b) { -@@ -109,24 +115,28 @@ void nghttp2_map_print_distance(const nghttp2_map *map) { - continue; - } - -- idx = hash(bkt->key, map->hashbits); -+ idx = map_hash(map, bkt->key); - fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i, -- hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl); -+ map_hash(map, bkt->key), bkt->key, idx, bkt->psl); - } - } --#endif /* !WIN32 */ -- --static int insert(nghttp2_map_bucket *table, size_t hashbits, -- nghttp2_map_key_type key, void *data) { -- size_t idx = hash(key, hashbits); -- nghttp2_map_bucket b = {0, key, data}, *bkt; -- size_t mask = (1u << hashbits) - 1; -+#endif /* !defined(WIN32) */ -+ -+static int map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { -+ size_t idx = map_hash(map, key); -+ nghttp2_map_bucket b = { -+ .key = key, -+ .data = data, -+ }; -+ nghttp2_map_bucket *bkt; -+ size_t mask = (1u << map->hashbits) - 1; - - for (;;) { -- bkt = &table[idx]; -+ bkt = &map->table[idx]; - - if (bkt->data == NULL) { - *bkt = b; -+ ++map->size; - return 0; - } - -@@ -147,15 +157,19 @@ static int insert(nghttp2_map_bucket *table, size_t hashbits, - - static int map_resize(nghttp2_map *map, size_t new_hashbits) { - size_t i; -- nghttp2_map_bucket *new_table; - nghttp2_map_bucket *bkt; - size_t tablelen; - int rv; -+ nghttp2_map new_map = { -+ .table = nghttp2_mem_calloc(map->mem, 1u << new_hashbits, -+ sizeof(nghttp2_map_bucket)), -+ .mem = map->mem, -+ .seed = map->seed, -+ .hashbits = new_hashbits, -+ }; - (void)rv; - -- new_table = nghttp2_mem_calloc(map->mem, 1u << new_hashbits, -- sizeof(nghttp2_map_bucket)); -- if (new_table == NULL) { -+ if (new_map.table == NULL) { - return NGHTTP2_ERR_NOMEM; - } - -@@ -168,15 +182,15 @@ static int map_resize(nghttp2_map *map, size_t new_hashbits) { - continue; - } - -- rv = insert(new_table, new_hashbits, bkt->key, bkt->data); -+ rv = map_insert(&new_map, bkt->key, bkt->data); - - assert(0 == rv); - } - } - - nghttp2_mem_free(map->mem, map->table); -+ map->table = new_map.table; - map->hashbits = new_hashbits; -- map->table = new_table; - - return 0; - } -@@ -186,30 +200,28 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { - - assert(data); - -- /* Load factor is 0.75 */ -+ /* Load factor is 7/8 */ - /* Under the very initial condition, that is map->size == 0 and -- map->hashbits == 0, 4 > 3 still holds nicely. */ -- if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) { -+ map->hashbits == 0, 8 > 7 still holds nicely. */ -+ if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) { - if (map->hashbits) { - rv = map_resize(map, map->hashbits + 1); - if (rv != 0) { - return rv; - } - } else { -- rv = map_resize(map, NGHTTP2_INITIAL_TABLE_LENBITS); -+ rv = map_resize(map, NGHTTP2_INITIAL_HASHBITS); - if (rv != 0) { - return rv; - } - } - } - -- rv = insert(map->table, map->hashbits, key, data); -+ rv = map_insert(map, key, data); - if (rv != 0) { - return rv; - } - -- ++map->size; -- - return 0; - } - -@@ -223,7 +235,7 @@ void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) { - return NULL; - } - -- idx = hash(key, map->hashbits); -+ idx = map_hash(map, key); - mask = (1u << map->hashbits) - 1; - - for (;;) { -@@ -252,7 +264,7 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - -- idx = hash(key, map->hashbits); -+ idx = map_hash(map, key); - mask = (1u << map->hashbits) - 1; - - for (;;) { -diff --git a/deps/nghttp2/lib/nghttp2_map.h b/deps/nghttp2/lib/nghttp2_map.h -index 5adfb78d..e45685bc 100644 ---- a/deps/nghttp2/lib/nghttp2_map.h -+++ b/deps/nghttp2/lib/nghttp2_map.h -@@ -28,7 +28,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -47,6 +47,7 @@ typedef struct nghttp2_map_bucket { - typedef struct nghttp2_map { - nghttp2_map_bucket *table; - nghttp2_mem *mem; -+ uint32_t seed; - size_t size; - size_t hashbits; - } nghttp2_map; -@@ -54,7 +55,7 @@ typedef struct nghttp2_map { - /* - * nghttp2_map_init initializes the map |map|. - */ --void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem); -+void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem); - - /* - * nghttp2_map_free deallocates any resources allocated for |map|. -@@ -123,6 +124,6 @@ int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr), - - #ifndef WIN32 - void nghttp2_map_print_distance(const nghttp2_map *map); --#endif /* !WIN32 */ -+#endif /* !defined(WIN32) */ - --#endif /* NGHTTP2_MAP_H */ -+#endif /* !defined(NGHTTP2_MAP_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_mem.h b/deps/nghttp2/lib/nghttp2_mem.h -index f83dbcb8..10af7c69 100644 ---- a/deps/nghttp2/lib/nghttp2_mem.h -+++ b/deps/nghttp2/lib/nghttp2_mem.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -42,4 +42,4 @@ void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data); - void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size); - void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size); - --#endif /* NGHTTP2_MEM_H */ -+#endif /* !defined(NGHTTP2_MEM_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_net.h b/deps/nghttp2/lib/nghttp2_net.h -index 521f9814..0c57d947 100644 ---- a/deps/nghttp2/lib/nghttp2_net.h -+++ b/deps/nghttp2/lib/nghttp2_net.h -@@ -27,28 +27,28 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #ifdef HAVE_ARPA_INET_H - # include --#endif /* HAVE_ARPA_INET_H */ -+#endif /* defined(HAVE_ARPA_INET_H) */ - - #ifdef HAVE_NETINET_IN_H - # include --#endif /* HAVE_NETINET_IN_H */ -+#endif /* defined(HAVE_NETINET_IN_H) */ - - #include - --#if defined(WIN32) -+#ifdef WIN32 - /* Windows requires ws2_32 library for ntonl family functions. We - define inline functions for those function so that we don't have - dependency on that lib. */ - - # ifdef _MSC_VER - # define STIN static __inline --# else -+# else /* !defined(_MSC_VER) */ - # define STIN static inline --# endif -+# endif /* !defined(_MSC_VER) */ - - STIN uint32_t htonl(uint32_t hostlong) { - uint32_t res; -@@ -86,6 +86,6 @@ STIN uint16_t ntohs(uint16_t netshort) { - return res; - } - --#endif /* WIN32 */ -+#endif /* defined(WIN32) */ - --#endif /* NGHTTP2_NET_H */ -+#endif /* !defined(NGHTTP2_NET_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_option.c b/deps/nghttp2/lib/nghttp2_option.c -index 02a24eee..7e44a241 100644 ---- a/deps/nghttp2/lib/nghttp2_option.c -+++ b/deps/nghttp2/lib/nghttp2_option.c -@@ -155,3 +155,10 @@ void nghttp2_option_set_max_continuations(nghttp2_option *option, size_t val) { - option->opt_set_mask |= NGHTTP2_OPT_MAX_CONTINUATIONS; - option->max_continuations = val; - } -+ -+void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option, -+ uint64_t burst, uint64_t rate) { -+ option->opt_set_mask |= NGHTTP2_OPT_GLITCH_RATE_LIMIT; -+ option->glitch_burst = burst; -+ option->glitch_rate = rate; -+} -diff --git a/deps/nghttp2/lib/nghttp2_option.h b/deps/nghttp2/lib/nghttp2_option.h -index c89cb97f..711185ba 100644 ---- a/deps/nghttp2/lib/nghttp2_option.h -+++ b/deps/nghttp2/lib/nghttp2_option.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -72,6 +72,7 @@ typedef enum { - NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, - NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, - NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16, -+ NGHTTP2_OPT_GLITCH_RATE_LIMIT = 1 << 17, - } nghttp2_option_flag; - - /** -@@ -83,6 +84,11 @@ struct nghttp2_option { - */ - uint64_t stream_reset_burst; - uint64_t stream_reset_rate; -+ /** -+ * NGHTTP2_OPT_GLITCH_RATE_LIMIT -+ */ -+ uint64_t glitch_burst; -+ uint64_t glitch_rate; - /** - * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH - */ -@@ -154,4 +160,4 @@ struct nghttp2_option { - uint8_t user_recv_ext_types[32]; - }; - --#endif /* NGHTTP2_OPTION_H */ -+#endif /* !defined(NGHTTP2_OPTION_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_outbound_item.h b/deps/nghttp2/lib/nghttp2_outbound_item.h -index 4e917500..6e8e310c 100644 ---- a/deps/nghttp2/lib/nghttp2_outbound_item.h -+++ b/deps/nghttp2/lib/nghttp2_outbound_item.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_frame.h" -@@ -186,4 +186,4 @@ void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q); - /* Returns the size of the queue */ - #define nghttp2_outbound_queue_size(Q) ((Q)->n) - --#endif /* NGHTTP2_OUTBOUND_ITEM_H */ -+#endif /* !defined(NGHTTP2_OUTBOUND_ITEM_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_pq.h b/deps/nghttp2/lib/nghttp2_pq.h -index c8d90ef2..5dd863f8 100644 ---- a/deps/nghttp2/lib/nghttp2_pq.h -+++ b/deps/nghttp2/lib/nghttp2_pq.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_int.h" -@@ -121,4 +121,4 @@ int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); - */ - void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item); - --#endif /* NGHTTP2_PQ_H */ -+#endif /* !defined(NGHTTP2_PQ_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_priority_spec.h b/deps/nghttp2/lib/nghttp2_priority_spec.h -index 92ece822..158e0dcd 100644 ---- a/deps/nghttp2/lib/nghttp2_priority_spec.h -+++ b/deps/nghttp2/lib/nghttp2_priority_spec.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -39,4 +39,4 @@ - */ - void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec); - --#endif /* NGHTTP2_PRIORITY_SPEC_H */ -+#endif /* !defined(NGHTTP2_PRIORITY_SPEC_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_queue.h b/deps/nghttp2/lib/nghttp2_queue.h -index a06fa6c7..c63897c0 100644 ---- a/deps/nghttp2/lib/nghttp2_queue.h -+++ b/deps/nghttp2/lib/nghttp2_queue.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include "config.h" --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -48,4 +48,4 @@ void *nghttp2_queue_front(nghttp2_queue *queue); - void *nghttp2_queue_back(nghttp2_queue *queue); - int nghttp2_queue_empty(nghttp2_queue *queue); - --#endif /* NGHTTP2_QUEUE_H */ -+#endif /* !defined(NGHTTP2_QUEUE_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_ratelim.h b/deps/nghttp2/lib/nghttp2_ratelim.h -index 866ed3f0..d1097f2f 100644 ---- a/deps/nghttp2/lib/nghttp2_ratelim.h -+++ b/deps/nghttp2/lib/nghttp2_ratelim.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -54,4 +54,4 @@ void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp); - succeeds, or -1. */ - int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n); - --#endif /* NGHTTP2_RATELIM_H */ -+#endif /* !defined(NGHTTP2_RATELIM_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_rcbuf.h b/deps/nghttp2/lib/nghttp2_rcbuf.h -index 6814e709..ef82e1b3 100644 ---- a/deps/nghttp2/lib/nghttp2_rcbuf.h -+++ b/deps/nghttp2/lib/nghttp2_rcbuf.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -77,4 +77,4 @@ int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src, - */ - void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf); - --#endif /* NGHTTP2_RCBUF_H */ -+#endif /* !defined(NGHTTP2_RCBUF_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c -index df33a89e..0fbcc930 100644 ---- a/deps/nghttp2/lib/nghttp2_session.c -+++ b/deps/nghttp2/lib/nghttp2_session.c -@@ -41,6 +41,8 @@ - #include "nghttp2_debug.h" - #include "nghttp2_submit.h" - -+nghttp2_stream nghttp2_stream_root; -+ - /* - * Returns non-zero if the number of outgoing opened streams is larger - * than or equal to -@@ -146,11 +148,6 @@ 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; - } -@@ -441,6 +438,7 @@ static int session_new(nghttp2_session **session_ptr, - size_t max_deflate_dynamic_table_size = - NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; - size_t i; -+ uint32_t map_seed; - - if (mem == NULL) { - mem = nghttp2_mem_default(); -@@ -458,10 +456,6 @@ static int session_new(nghttp2_session **session_ptr, - /* next_stream_id is initialized in either - nghttp2_session_client_new2 or nghttp2_session_server_new2 */ - -- nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE, -- NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL, -- mem); -- - (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; - (*session_ptr)->recv_window_size = 0; - (*session_ptr)->consumed_size = 0; -@@ -481,6 +475,10 @@ static int session_new(nghttp2_session **session_ptr, - NGHTTP2_DEFAULT_STREAM_RESET_BURST, - NGHTTP2_DEFAULT_STREAM_RESET_RATE); - -+ nghttp2_ratelim_init(&(*session_ptr)->glitch_ratelim, -+ NGHTTP2_DEFAULT_GLITCH_BURST, -+ NGHTTP2_DEFAULT_GLITCH_RATE); -+ - if (server) { - (*session_ptr)->server = 1; - } -@@ -548,11 +546,6 @@ static int session_new(nghttp2_session **session_ptr, - max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; - } - -- if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && -- option->no_closed_streams) { -- (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; -- } -- - if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) { - (*session_ptr)->max_outbound_ack = option->max_outbound_ack; - } -@@ -562,13 +555,6 @@ static int session_new(nghttp2_session **session_ptr, - (*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) { -@@ -585,6 +571,11 @@ static int session_new(nghttp2_session **session_ptr, - if (option->opt_set_mask & NGHTTP2_OPT_MAX_CONTINUATIONS) { - (*session_ptr)->max_continuations = option->max_continuations; - } -+ -+ if (option->opt_set_mask & NGHTTP2_OPT_GLITCH_RATE_LIMIT) { -+ nghttp2_ratelim_init(&(*session_ptr)->glitch_ratelim, -+ option->glitch_burst, option->glitch_rate); -+ } - } - - rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, -@@ -613,7 +604,13 @@ static int session_new(nghttp2_session **session_ptr, - goto fail_aob_framebuf; - } - -- nghttp2_map_init(&(*session_ptr)->streams, mem); -+ if (callbacks->rand_callback) { -+ callbacks->rand_callback((uint8_t *)&map_seed, sizeof(map_seed)); -+ } else { -+ map_seed = 0; -+ } -+ -+ nghttp2_map_init(&(*session_ptr)->streams, map_seed, mem); - - active_outbound_item_reset(&(*session_ptr)->aob, mem); - -@@ -810,7 +807,6 @@ void nghttp2_session_del(nghttp2_session *session) { - 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 - stream->item->queued */ -@@ -829,82 +825,6 @@ void nghttp2_session_del(nghttp2_session *session) { - nghttp2_mem_free(mem, session); - } - --int nghttp2_session_reprioritize_stream( -- nghttp2_session *session, nghttp2_stream *stream, -- const nghttp2_priority_spec *pri_spec_in) { -- int rv; -- nghttp2_stream *dep_stream = NULL; -- 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)) { -- return 0; -- } -- -- if (pri_spec->stream_id != 0) { -- dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); -- -- if (!dep_stream && -- session_detect_idle_stream(session, pri_spec->stream_id)) { -- nghttp2_priority_spec_default_init(&pri_spec_default); -- -- dep_stream = nghttp2_session_open_stream( -- session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, -- NGHTTP2_STREAM_IDLE, NULL); -- -- if (dep_stream == NULL) { -- return NGHTTP2_ERR_NOMEM; -- } -- } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { -- nghttp2_priority_spec_default_init(&pri_spec_default); -- pri_spec = &pri_spec_default; -- } -- } -- -- if (pri_spec->stream_id == 0) { -- dep_stream = &session->root; -- } else if (nghttp2_stream_dep_find_ancestor(dep_stream, stream)) { -- DEBUGF("stream: cycle detected, dep_stream(%p)=%d stream(%p)=%d\n", -- dep_stream, dep_stream->stream_id, stream, stream->stream_id); -- -- nghttp2_stream_dep_remove_subtree(dep_stream); -- rv = nghttp2_stream_dep_add_subtree(stream->dep_prev, dep_stream); -- if (rv != 0) { -- return rv; -- } -- } -- -- assert(dep_stream); -- -- if (dep_stream == stream->dep_prev && !pri_spec->exclusive) { -- /* This is minor optimization when just weight is changed. */ -- nghttp2_stream_change_weight(stream, pri_spec->weight); -- -- return 0; -- } -- -- nghttp2_stream_dep_remove_subtree(stream); -- -- /* We have to update weight after removing stream from tree */ -- stream->weight = pri_spec->weight; -- -- if (pri_spec->exclusive) { -- rv = nghttp2_stream_dep_insert_subtree(dep_stream, stream); -- } else { -- rv = nghttp2_stream_dep_add_subtree(dep_stream, stream); -- } -- -- if (rv != 0) { -- return rv; -- } -- -- return 0; --} -- - static uint64_t pq_get_first_cycle(nghttp2_pq *pq) { - nghttp2_stream *stream; - -@@ -923,7 +843,6 @@ static int session_ob_data_push(nghttp2_session *session, - 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); -@@ -952,7 +871,6 @@ static void 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); -@@ -969,14 +887,7 @@ static int session_attach_stream_item(nghttp2_session *session, - 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; -- } -+ nghttp2_stream_attach_item(stream, item); - - rv = session_ob_data_push(session, stream); - if (rv != 0) { -@@ -992,8 +903,7 @@ static void session_detach_stream_item(nghttp2_session *session, - nghttp2_stream *stream) { - nghttp2_stream_detach_item(stream); - -- if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || -- !stream->queued) { -+ if (!stream->queued) { - return; - } - -@@ -1004,8 +914,7 @@ static void session_defer_stream_item(nghttp2_session *session, - nghttp2_stream *stream, uint8_t flags) { - nghttp2_stream_defer_item(stream, flags); - -- if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || -- !stream->queued) { -+ if (!stream->queued) { - return; - } - -@@ -1015,15 +924,9 @@ static void session_defer_stream_item(nghttp2_session *session, - static int session_resume_deferred_stream_item(nghttp2_session *session, - nghttp2_stream *stream, - uint8_t flags) { -- int rv; -+ nghttp2_stream_resume_deferred_item(stream, flags); - -- 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)) { -+ if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { - return 0; - } - -@@ -1168,7 +1071,6 @@ int nghttp2_session_add_item(nghttp2_session *session, - return 0; - case NGHTTP2_PUSH_PROMISE: { - nghttp2_headers_aux_data *aux_data; -- nghttp2_priority_spec pri_spec; - - aux_data = &item->aux_data.headers; - -@@ -1176,20 +1078,13 @@ int nghttp2_session_add_item(nghttp2_session *session, - return NGHTTP2_ERR_STREAM_CLOSED; - } - -- nghttp2_priority_spec_init(&pri_spec, stream->stream_id, -- NGHTTP2_DEFAULT_WEIGHT, 0); -- - if (!nghttp2_session_open_stream( - session, frame->push_promise.promised_stream_id, -- NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_RESERVED, -+ NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_STREAM_RESERVED, - aux_data->stream_user_data)) { - return NGHTTP2_ERR_NOMEM; - } - -- /* We don't have to call nghttp2_session_adjust_closed_stream() -- here, since stream->stream_id is local stream_id, and it does -- not affect closed stream count. */ -- - nghttp2_outbound_queue_push(&session->ob_reg, item); - item->queued = 1; - -@@ -1213,6 +1108,15 @@ int nghttp2_session_add_item(nghttp2_session *session, - - int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code) { -+ return nghttp2_session_add_rst_stream_continue( -+ session, stream_id, error_code, -+ /* continue_without_stream = */ 1); -+} -+ -+int nghttp2_session_add_rst_stream_continue(nghttp2_session *session, -+ int32_t stream_id, -+ uint32_t error_code, -+ int continue_without_stream) { - int rv; - nghttp2_outbound_item *item; - nghttp2_frame *frame; -@@ -1269,6 +1173,12 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, - } - } - -+ /* To keep the old behaviour, do not fail if stream was not -+ found. */ -+ if (!continue_without_stream && !stream) { -+ return 0; -+ } -+ - item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); - if (item == NULL) { - return NGHTTP2_ERR_NOMEM; -@@ -1290,15 +1200,11 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, - - nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - int32_t stream_id, uint8_t flags, -- nghttp2_priority_spec *pri_spec_in, - nghttp2_stream_state initial_state, - void *stream_user_data) { - int rv; - nghttp2_stream *stream; -- nghttp2_stream *dep_stream = NULL; - int stream_alloc = 0; -- nghttp2_priority_spec pri_spec_default; -- nghttp2_priority_spec *pri_spec = pri_spec_in; - nghttp2_mem *mem; - - mem = &session->mem; -@@ -1311,23 +1217,9 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - - if (stream) { - assert(stream->state == NGHTTP2_STREAM_IDLE); -- assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || -- nghttp2_stream_in_dep_tree(stream)); -- -- nghttp2_session_detach_idle_stream(session, stream); -- -- if (nghttp2_stream_in_dep_tree(stream)) { -- assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)); -+ assert(initial_state != NGHTTP2_STREAM_IDLE); - -- 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; -- } -- } -+ --session->num_idle_streams; - } else { - stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream)); - if (stream == NULL) { -@@ -1337,69 +1229,16 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - stream_alloc = 1; - } - -- 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 && -- session_detect_idle_stream(session, pri_spec->stream_id)) { -- /* Depends on idle stream, which does not exist in memory. -- Assign default priority for it. */ -- nghttp2_priority_spec_default_init(&pri_spec_default); -- -- dep_stream = nghttp2_session_open_stream( -- session, pri_spec->stream_id, NGHTTP2_FLAG_NONE, &pri_spec_default, -- NGHTTP2_STREAM_IDLE, NULL); -- -- if (dep_stream == NULL) { -- if (stream_alloc) { -- nghttp2_mem_free(mem, stream); -- } -- -- return NULL; -- } -- } else if (!dep_stream || !nghttp2_stream_in_dep_tree(dep_stream)) { -- /* If dep_stream is not part of dependency tree, stream will get -- default priority. This handles the case when -- pri_spec->stream_id == stream_id. This happens because we -- don't check pri_spec->stream_id against new stream ID in -- nghttp2_submit_request. This also handles the case when idle -- stream created by PRIORITY frame was opened. Somehow we -- first remove the idle stream from dependency tree. This is -- done to simplify code base, but ideally we should retain old -- dependency. But I'm not sure this adds values. */ -- nghttp2_priority_spec_default_init(&pri_spec_default); -- pri_spec = &pri_spec_default; -- } -- } -- - if (initial_state == NGHTTP2_STREAM_RESERVED) { - flags |= NGHTTP2_STREAM_FLAG_PUSH; - } - - if (stream_alloc) { - nghttp2_stream_init(stream, stream_id, flags, initial_state, -- pri_spec->weight, - (int32_t)session->remote_settings.initial_window_size, - (int32_t)session->local_settings.initial_window_size, -- stream_user_data, mem); -- -- if (session_no_rfc7540_pri_no_fallback(session)) { -- stream->seq = session->stream_seq++; -- } -+ stream_user_data); -+ stream->seq = session->stream_seq++; - - rv = nghttp2_map_insert(&session->streams, stream_id, stream); - if (rv != 0) { -@@ -1410,7 +1249,6 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - } else { - stream->flags = flags; - stream->state = initial_state; -- stream->weight = pri_spec->weight; - stream->stream_user_data = stream_user_data; - } - -@@ -1428,9 +1266,7 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - limit. That is one of the DOS vector. */ - break; - case NGHTTP2_STREAM_IDLE: -- /* Idle stream does not count toward the concurrent streams limit. -- This is used as anchor node in dependency tree. */ -- nghttp2_session_keep_idle_stream(session, stream); -+ ++session->num_idle_streams; - break; - default: - if (nghttp2_session_is_my_stream_id(session, stream_id)) { -@@ -1440,31 +1276,11 @@ 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; -- } -- -- assert(dep_stream); -- -- if (pri_spec->exclusive) { -- rv = nghttp2_stream_dep_insert(dep_stream, stream); -- if (rv != 0) { -- return NULL; -- } -- } else { -- nghttp2_stream_dep_add(dep_stream, stream); -- } -- - return stream; - } - - int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, - uint32_t error_code) { -- int rv; - nghttp2_stream *stream; - nghttp2_mem *mem; - int is_my_stream_id; -@@ -1528,207 +1344,26 @@ 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)) { -- /* On server side, retain stream at most MAX_CONCURRENT_STREAMS -- combined with the current active incoming streams to make -- dependency tree work better. */ -- nghttp2_session_keep_closed_stream(session, stream); -- } else { -- rv = nghttp2_session_destroy_stream(session, stream); -- if (rv != 0) { -- return rv; -- } -- } -+ nghttp2_session_destroy_stream(session, stream); - - return 0; - } - --int nghttp2_session_destroy_stream(nghttp2_session *session, -- nghttp2_stream *stream) { -+void nghttp2_session_destroy_stream(nghttp2_session *session, -+ nghttp2_stream *stream) { - nghttp2_mem *mem; -- int rv; - - DEBUGF("stream: destroy closed stream(%p)=%d\n", stream, stream->stream_id); - - mem = &session->mem; - -- if (nghttp2_stream_in_dep_tree(stream)) { -- rv = nghttp2_stream_dep_remove(stream); -- if (rv != 0) { -- return rv; -- } -- } -- -- if (stream->queued && -- (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { -+ if (stream->queued) { - session_ob_data_remove(session, stream); - } - - nghttp2_map_remove(&session->streams, stream->stream_id); - nghttp2_stream_free(stream); - nghttp2_mem_free(mem, stream); -- -- return 0; --} -- --void nghttp2_session_keep_closed_stream(nghttp2_session *session, -- nghttp2_stream *stream) { -- DEBUGF("stream: keep closed stream(%p)=%d, state=%d\n", stream, -- stream->stream_id, stream->state); -- -- if (session->closed_stream_tail) { -- session->closed_stream_tail->closed_next = stream; -- stream->closed_prev = session->closed_stream_tail; -- } else { -- session->closed_stream_head = stream; -- } -- session->closed_stream_tail = stream; -- -- ++session->num_closed_streams; --} -- --void nghttp2_session_keep_idle_stream(nghttp2_session *session, -- nghttp2_stream *stream) { -- DEBUGF("stream: keep idle stream(%p)=%d, state=%d\n", stream, -- stream->stream_id, stream->state); -- -- if (session->idle_stream_tail) { -- session->idle_stream_tail->closed_next = stream; -- stream->closed_prev = session->idle_stream_tail; -- } else { -- session->idle_stream_head = stream; -- } -- session->idle_stream_tail = stream; -- -- ++session->num_idle_streams; --} -- --void nghttp2_session_detach_idle_stream(nghttp2_session *session, -- nghttp2_stream *stream) { -- nghttp2_stream *prev_stream, *next_stream; -- -- DEBUGF("stream: detach idle stream(%p)=%d, state=%d\n", stream, -- stream->stream_id, stream->state); -- -- prev_stream = stream->closed_prev; -- next_stream = stream->closed_next; -- -- if (prev_stream) { -- prev_stream->closed_next = next_stream; -- } else { -- session->idle_stream_head = next_stream; -- } -- -- if (next_stream) { -- next_stream->closed_prev = prev_stream; -- } else { -- session->idle_stream_tail = prev_stream; -- } -- -- stream->closed_prev = NULL; -- stream->closed_next = NULL; -- -- --session->num_idle_streams; --} -- --int nghttp2_session_adjust_closed_stream(nghttp2_session *session) { -- size_t num_stream_max; -- int rv; -- -- if (session->local_settings.max_concurrent_streams == -- NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS) { -- num_stream_max = session->pending_local_max_concurrent_stream; -- } else { -- num_stream_max = session->local_settings.max_concurrent_streams; -- } -- -- DEBUGF("stream: adjusting kept closed streams num_closed_streams=%zu, " -- "num_incoming_streams=%zu, max_concurrent_streams=%zu\n", -- session->num_closed_streams, session->num_incoming_streams, -- num_stream_max); -- -- while (session->num_closed_streams > 0 && -- session->num_closed_streams + session->num_incoming_streams > -- num_stream_max) { -- nghttp2_stream *head_stream; -- nghttp2_stream *next; -- -- head_stream = session->closed_stream_head; -- -- assert(head_stream); -- -- next = head_stream->closed_next; -- -- rv = nghttp2_session_destroy_stream(session, head_stream); -- if (rv != 0) { -- return rv; -- } -- -- /* head_stream is now freed */ -- -- session->closed_stream_head = next; -- -- if (session->closed_stream_head) { -- session->closed_stream_head->closed_prev = NULL; -- } else { -- session->closed_stream_tail = NULL; -- } -- -- --session->num_closed_streams; -- } -- -- return 0; --} -- --int nghttp2_session_adjust_idle_stream(nghttp2_session *session) { -- size_t max; -- int rv; -- -- /* Make minimum number of idle streams 16, and maximum 100, which -- are arbitrary chosen numbers. */ -- max = nghttp2_min_uint32( -- 100, -- nghttp2_max_uint32( -- 16, nghttp2_min_uint32(session->local_settings.max_concurrent_streams, -- session->pending_local_max_concurrent_stream))); -- -- DEBUGF("stream: adjusting kept idle streams num_idle_streams=%zu, max=%zu\n", -- session->num_idle_streams, max); -- -- while (session->num_idle_streams > max) { -- nghttp2_stream *head; -- nghttp2_stream *next; -- -- head = session->idle_stream_head; -- assert(head); -- -- next = head->closed_next; -- -- rv = nghttp2_session_destroy_stream(session, head); -- if (rv != 0) { -- return rv; -- } -- -- /* head is now destroyed */ -- -- session->idle_stream_head = next; -- -- if (session->idle_stream_head) { -- session->idle_stream_head->closed_prev = NULL; -- } else { -- session->idle_stream_tail = NULL; -- } -- -- --session->num_idle_streams; -- } -- -- return 0; - } - - /* -@@ -2411,16 +2046,12 @@ static int session_prep_frame(nghttp2_session *session, - - stream = nghttp2_session_open_stream( - session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, -- &frame->headers.pri_spec, NGHTTP2_STREAM_INITIAL, -- aux_data->stream_user_data); -+ NGHTTP2_STREAM_INITIAL, aux_data->stream_user_data); - - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - -- /* We don't call nghttp2_session_adjust_closed_stream() here, -- since we don't keep closed stream in client side */ -- - rv = session_predicate_request_headers_send(session, item); - if (rv != 0) { - return rv; -@@ -2662,8 +2293,6 @@ 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); - } -@@ -2679,11 +2308,6 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) { - } - - if (session->remote_window_size > 0) { -- item = nghttp2_stream_next_outbound_item(&session->root); -- if (item) { -- return item; -- } -- - return session_sched_get_next_outbound_item(session); - } - -@@ -2718,11 +2342,6 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) { - } - - if (session->remote_window_size > 0) { -- item = nghttp2_stream_next_outbound_item(&session->root); -- if (item) { -- return item; -- } -- - return session_sched_get_next_outbound_item(session); - } - -@@ -2781,7 +2400,6 @@ static int find_stream_on_goaway_func(void *entry, void *ptr) { - nghttp2_session_close_stream() inside nghttp2_map_each(). - Reuse closed_next member.. bad choice? */ - assert(stream->closed_next == NULL); -- assert(stream->closed_prev == NULL); - - if (arg->head) { - stream->closed_next = arg->head; -@@ -2837,11 +2455,6 @@ static void session_reschedule_stream(nghttp2_session *session, - nghttp2_stream *stream) { - stream->last_writelen = stream->item->frame.hd.length; - -- if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) { -- nghttp2_stream_reschedule(stream); -- return; -- } -- - if (!session->server) { - return; - } -@@ -3020,37 +2633,6 @@ static int session_after_frame_sent1(nghttp2_session *session) { - } - } - case NGHTTP2_PRIORITY: -- if (session->server || session->pending_no_rfc7540_priorities == 1) { -- return 0; -- } -- -- stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); -- -- if (!stream) { -- if (!session_detect_idle_stream(session, frame->hd.stream_id)) { -- return 0; -- } -- -- stream = nghttp2_session_open_stream( -- session, frame->hd.stream_id, NGHTTP2_FLAG_NONE, -- &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); -- if (!stream) { -- return NGHTTP2_ERR_NOMEM; -- } -- } else { -- rv = nghttp2_session_reprioritize_stream(session, stream, -- &frame->priority.pri_spec); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- } -- -- rv = nghttp2_session_adjust_idle_stream(session); -- -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- - return 0; - case NGHTTP2_RST_STREAM: - rv = nghttp2_session_close_stream(session, frame->hd.stream_id, -@@ -3239,14 +2821,6 @@ static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session, - aob = &session->aob; - framebufs = &aob->framebufs; - -- /* We may have idle streams more than we expect (e.g., -- nghttp2_session_change_stream_priority() or -- nghttp2_session_create_idle_stream()). Adjust them here. */ -- rv = nghttp2_session_adjust_idle_stream(session); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- - for (;;) { - switch (aob->state) { - case NGHTTP2_OB_POP_ITEM: { -@@ -3698,7 +3272,9 @@ static int session_call_on_invalid_header(nghttp2_session *session, - session, frame, nv->name->base, nv->name->len, nv->value->base, - nv->value->len, nv->flags, session->user_data); - } else { -- return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; -+ /* If both callbacks are not set, the invalid field nv is -+ ignored. */ -+ return 0; - } - - if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { -@@ -3783,6 +3359,10 @@ static uint32_t get_error_code_from_lib_error_code(int lib_error_code) { - case NGHTTP2_ERR_HTTP_HEADER: - case NGHTTP2_ERR_HTTP_MESSAGING: - return NGHTTP2_PROTOCOL_ERROR; -+ case NGHTTP2_ERR_INTERNAL: -+ return NGHTTP2_INTERNAL_ERROR; -+ case NGHTTP2_ERR_PUSH_CANCEL: -+ return NGHTTP2_CANCEL; - default: - return NGHTTP2_INTERNAL_ERROR; - } -@@ -3809,17 +3389,32 @@ static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, - return 0; - } - -+static int session_update_glitch_ratelim(nghttp2_session *session) { -+ if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) { -+ return 0; -+ } -+ -+ nghttp2_ratelim_update(&session->glitch_ratelim, nghttp2_time_now_sec()); -+ -+ if (nghttp2_ratelim_drain(&session->glitch_ratelim, 1) == 0) { -+ return 0; -+ } -+ -+ return nghttp2_session_terminate_session(session, NGHTTP2_ENHANCE_YOUR_CALM); -+} -+ - static int session_handle_invalid_stream2(nghttp2_session *session, - int32_t stream_id, - nghttp2_frame *frame, - int lib_error_code) { - int rv; -+ - rv = nghttp2_session_add_rst_stream( - session, stream_id, get_error_code_from_lib_error_code(lib_error_code)); - if (rv != 0) { - return rv; - } -- if (session->callbacks.on_invalid_frame_recv_callback) { -+ if (frame && session->callbacks.on_invalid_frame_recv_callback) { - if (session->callbacks.on_invalid_frame_recv_callback( - session, frame, lib_error_code, session->user_data) != 0) { - return NGHTTP2_ERR_CALLBACK_FAILURE; -@@ -3974,7 +3569,29 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, - - rv2 = session_call_on_invalid_header(session, frame, &nv); - if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { -- rv = NGHTTP2_ERR_HTTP_HEADER; -+ DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", -+ frame->hd.type, frame->hd.stream_id, (int)nv.name->len, -+ nv.name->base, (int)nv.value->len, nv.value->base); -+ -+ rv = session_call_error_callback( -+ session, NGHTTP2_ERR_HTTP_HEADER, -+ "Invalid HTTP header field was received: frame type: " -+ "%u, stream: %d, name: [%.*s], value: [%.*s]", -+ frame->hd.type, frame->hd.stream_id, (int)nv.name->len, -+ nv.name->base, (int)nv.value->len, nv.value->base); -+ -+ if (nghttp2_is_fatal(rv)) { -+ return rv; -+ } -+ -+ rv = session_handle_invalid_stream2( -+ session, subject_stream->stream_id, frame, -+ NGHTTP2_ERR_HTTP_HEADER); -+ if (nghttp2_is_fatal(rv)) { -+ return rv; -+ } -+ -+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } else { - if (rv2 != 0) { - return rv2; -@@ -4014,13 +3631,8 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, - return rv; - } - -- rv = -- session_handle_invalid_stream2(session, subject_stream->stream_id, -- frame, NGHTTP2_ERR_HTTP_HEADER); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; -+ return nghttp2_session_terminate_session(session, -+ NGHTTP2_PROTOCOL_ERROR); - } - } - if (rv == 0) { -@@ -4064,7 +3676,6 @@ static int session_end_stream_headers_received(nghttp2_session *session, - - 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); -@@ -4134,27 +3745,7 @@ static int session_after_header_block_received(nghttp2_session *session) { - } - } - if (rv != 0) { -- int32_t stream_id; -- -- if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { -- stream_id = frame->push_promise.promised_stream_id; -- } else { -- stream_id = frame->hd.stream_id; -- } -- -- rv = session_handle_invalid_stream2(session, stream_id, frame, -- NGHTTP2_ERR_HTTP_MESSAGING); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- -- if (frame->hd.type == NGHTTP2_HEADERS && -- (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { -- nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); -- /* Don't call nghttp2_session_close_stream_if_shut_rdwr -- because RST_STREAM has been submitted. */ -- } -- return 0; -+ return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); - } - } - -@@ -4253,18 +3844,13 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, - NGHTTP2_ERR_REFUSED_STREAM); - } - -- stream = nghttp2_session_open_stream( -- session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, -- &frame->headers.pri_spec, NGHTTP2_STREAM_OPENING, NULL); -+ stream = nghttp2_session_open_stream(session, frame->hd.stream_id, -+ NGHTTP2_STREAM_FLAG_NONE, -+ NGHTTP2_STREAM_OPENING, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } - -- rv = nghttp2_session_adjust_closed_stream(session); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- - session->last_proc_stream_id = session->last_recv_stream_id; - - rv = session_call_on_begin_headers(session, frame); -@@ -4396,104 +3982,33 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, - return NGHTTP2_ERR_IGN_HEADER_BLOCK; - } - --static int session_process_headers_frame(nghttp2_session *session) { -- nghttp2_inbound_frame *iframe = &session->iframe; -- nghttp2_frame *frame = &iframe->frame; -- nghttp2_stream *stream; -- -- nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); -- -- stream = nghttp2_session_get_stream(session, frame->hd.stream_id); -- if (!stream) { -- frame->headers.cat = NGHTTP2_HCAT_REQUEST; -- return nghttp2_session_on_request_headers_received(session, frame); -- } -- -- if (stream->state == NGHTTP2_STREAM_RESERVED) { -- frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; -- return nghttp2_session_on_push_response_headers_received(session, frame, -- stream); -- } -- -- if (stream->state == NGHTTP2_STREAM_OPENING && -- nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { -- frame->headers.cat = NGHTTP2_HCAT_RESPONSE; -- return nghttp2_session_on_response_headers_received(session, frame, stream); -- } -- -- frame->headers.cat = NGHTTP2_HCAT_HEADERS; -- return nghttp2_session_on_headers_received(session, frame, stream); --} -- --int nghttp2_session_on_priority_received(nghttp2_session *session, -- nghttp2_frame *frame) { -- 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"); -- } -- -- if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) { -- return nghttp2_session_terminate_session_with_reason( -- session, NGHTTP2_PROTOCOL_ERROR, "depend on itself"); -- } -- -- if (!session->server) { -- /* Re-prioritization works only in server */ -- return session_call_on_frame_received(session, frame); -- } -- -- stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); -- -- if (!stream) { -- /* PRIORITY against idle stream can create anchor node in -- dependency tree. */ -- if (!session_detect_idle_stream(session, frame->hd.stream_id)) { -- return 0; -- } -- -- stream = nghttp2_session_open_stream( -- session, frame->hd.stream_id, NGHTTP2_STREAM_FLAG_NONE, -- &frame->priority.pri_spec, NGHTTP2_STREAM_IDLE, NULL); -- -- if (stream == NULL) { -- return NGHTTP2_ERR_NOMEM; -- } -- -- rv = nghttp2_session_adjust_idle_stream(session); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- } else { -- rv = nghttp2_session_reprioritize_stream(session, stream, -- &frame->priority.pri_spec); -- -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- -- rv = nghttp2_session_adjust_idle_stream(session); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- } -- -- return session_call_on_frame_received(session, frame); --} -- --static int session_process_priority_frame(nghttp2_session *session) { -+static int session_process_headers_frame(nghttp2_session *session) { - nghttp2_inbound_frame *iframe = &session->iframe; - nghttp2_frame *frame = &iframe->frame; -+ nghttp2_stream *stream; -+ -+ nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); -+ -+ stream = nghttp2_session_get_stream(session, frame->hd.stream_id); -+ if (!stream) { -+ frame->headers.cat = NGHTTP2_HCAT_REQUEST; -+ return nghttp2_session_on_request_headers_received(session, frame); -+ } - -- assert(!session_no_rfc7540_pri_no_fallback(session)); -+ if (stream->state == NGHTTP2_STREAM_RESERVED) { -+ frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; -+ return nghttp2_session_on_push_response_headers_received(session, frame, -+ stream); -+ } - -- nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos); -+ if (stream->state == NGHTTP2_STREAM_OPENING && -+ nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { -+ frame->headers.cat = NGHTTP2_HCAT_RESPONSE; -+ return nghttp2_session_on_response_headers_received(session, frame, stream); -+ } - -- return nghttp2_session_on_priority_received(session, frame); -+ frame->headers.cat = NGHTTP2_HCAT_HEADERS; -+ return nghttp2_session_on_headers_received(session, frame, stream); - } - - static int session_update_stream_reset_ratelim(nghttp2_session *session) { -@@ -4566,8 +4081,7 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) { - rv = nghttp2_stream_update_remote_initial_window_size( - stream, arg->new_window_size, arg->old_window_size); - if (rv != 0) { -- return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, -- NGHTTP2_FLOW_CONTROL_ERROR); -+ return NGHTTP2_ERR_FLOW_CONTROL; - } - - /* If window size gets positive, push deferred DATA frame to -@@ -4593,6 +4107,8 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) { - * - * NGHTTP2_ERR_NOMEM - * Out of memory. -+ * NGHTTP2_ERR_FLOW_CONTROL -+ * Window size gets out of range. - */ - static int - session_update_remote_initial_window_size(nghttp2_session *session, -@@ -4616,8 +4132,7 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) { - rv = nghttp2_stream_update_local_initial_window_size( - stream, arg->new_window_size, arg->old_window_size); - if (rv != 0) { -- return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, -- NGHTTP2_FLOW_CONTROL_ERROR); -+ return NGHTTP2_ERR_FLOW_CONTROL; - } - - if (stream->window_update_queued) { -@@ -4651,6 +4166,8 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) { - * - * NGHTTP2_ERR_NOMEM - * Out of memory. -+ * NGHTTP2_ERR_FLOW_CONTROL -+ * Window size gets out of range. - */ - static int - session_update_local_initial_window_size(nghttp2_session *session, -@@ -4934,12 +4451,6 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, - - 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; -- } - } - - if (!noack && !session_is_closing(session)) { -@@ -5000,7 +4511,6 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, - int rv; - nghttp2_stream *stream; - nghttp2_stream *promised_stream; -- nghttp2_priority_spec pri_spec; - - if (frame->hd.stream_id == 0) { - return session_inflate_handle_invalid_connection( -@@ -5044,9 +4554,9 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, - session->max_incoming_reserved_streams) { - /* Currently, client does not retain closed stream, so we don't - check NGHTTP2_SHUT_RD condition here. */ -- -- rv = nghttp2_session_add_rst_stream( -- session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL); -+ rv = session_handle_invalid_stream2(session, -+ frame->push_promise.promised_stream_id, -+ NULL, NGHTTP2_ERR_PUSH_CANCEL); - if (rv != 0) { - return rv; - } -@@ -5058,20 +4568,14 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, - session, frame, NGHTTP2_ERR_STREAM_CLOSED, "PUSH_PROMISE: stream closed"); - } - -- nghttp2_priority_spec_init(&pri_spec, stream->stream_id, -- NGHTTP2_DEFAULT_WEIGHT, 0); -- - promised_stream = nghttp2_session_open_stream( - session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE, -- &pri_spec, NGHTTP2_STREAM_RESERVED, NULL); -+ NGHTTP2_STREAM_RESERVED, NULL); - - if (!promised_stream) { - return NGHTTP2_ERR_NOMEM; - } - -- /* We don't call nghttp2_session_adjust_closed_stream(), since we -- don't keep closed stream in client side */ -- - session->last_proc_stream_id = session->last_recv_stream_id; - rv = session_call_on_begin_headers(session, frame); - if (rv != 0) { -@@ -5209,8 +4713,9 @@ static int session_on_stream_window_update_received(nghttp2_session *session, - } - if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < - stream->remote_window_size) { -- return session_handle_invalid_stream(session, frame, -- NGHTTP2_ERR_FLOW_CONTROL); -+ return session_handle_invalid_connection( -+ session, frame, NGHTTP2_ERR_FLOW_CONTROL, -+ "WINDOW_UPDATE: window size overflow"); - } - stream->remote_window_size += frame->window_update.window_size_increment; - -@@ -5292,7 +4797,6 @@ 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; - -@@ -5330,10 +4834,9 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session, - "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); -+ stream = -+ nghttp2_session_open_stream(session, priority_update->stream_id, -+ NGHTTP2_FLAG_NONE, NGHTTP2_STREAM_IDLE, NULL); - if (!stream) { - return NGHTTP2_ERR_NOMEM; - } -@@ -5442,16 +4945,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session, - if (session_enforce_http_messaging(session) && - (frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { - if (nghttp2_http_on_remote_end_stream(stream) != 0) { -- rv = nghttp2_session_add_rst_stream(session, stream->stream_id, -- NGHTTP2_PROTOCOL_ERROR); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- -- nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); -- /* Don't call nghttp2_session_close_stream_if_shut_rdwr because -- RST_STREAM has been submitted. */ -- return 0; -+ return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); - } - } - -@@ -5509,8 +5003,8 @@ int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session, - rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, - stream->local_window_size); - if (rv != 0) { -- return nghttp2_session_add_rst_stream(session, stream->stream_id, -- NGHTTP2_FLOW_CONTROL_ERROR); -+ return nghttp2_session_terminate_session(session, -+ NGHTTP2_FLOW_CONTROL_ERROR); - } - /* We don't have to send WINDOW_UPDATE if the data received is the - last chunk in the incoming stream. */ -@@ -5869,14 +5363,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - - mem = &session->mem; - -- /* We may have idle streams more than we expect (e.g., -- nghttp2_session_change_stream_priority() or -- nghttp2_session_create_idle_stream()). Adjust them here. */ -- rv = nghttp2_session_adjust_idle_stream(session); -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- - if (!nghttp2_session_want_read(session)) { - return (nghttp2_ssize)inlen; - } -@@ -5980,20 +5466,30 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - busy = 1; - - rv = session_on_data_received_fail_fast(session); -+ if (nghttp2_is_fatal(rv)) { -+ return rv; -+ } -+ - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } - if (rv == NGHTTP2_ERR_IGN_PAYLOAD) { - DEBUGF("recv: DATA not allowed stream_id=%d\n", - iframe->frame.hd.stream_id); -+ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - iframe->state = NGHTTP2_IB_IGN_DATA; - break; - } - -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- - rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); - if (rv < 0) { - rv = nghttp2_session_terminate_session_with_reason( -@@ -6011,6 +5507,20 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - break; - } - -+ /* Empty DATA frame without END_STREAM flag set is -+ suspicious. */ -+ if (iframe->payloadleft == 0 && -+ (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ } -+ - iframe->state = NGHTTP2_IB_READ_DATA; - break; - } -@@ -6063,6 +5573,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - on_begin_frame_called = 1; - - rv = session_process_headers_frame(session); -@@ -6077,8 +5591,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { -- rv = nghttp2_session_add_rst_stream( -- session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); -+ rv = session_handle_invalid_stream2( -+ session, iframe->frame.hd.stream_id, NULL, NGHTTP2_ERR_INTERNAL); - if (nghttp2_is_fatal(rv)) { - return rv; - } -@@ -6087,6 +5601,15 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } - - if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } -@@ -6107,6 +5630,18 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - break; - } - -+ /* This is deprecated RFC 7540 priorities mechanism which is -+ very unpopular. We do not expect it is received so -+ frequently. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - iframe->state = NGHTTP2_IB_READ_NBYTE; - - inbound_frame_set_mark(iframe, NGHTTP2_PRIORITY_SPECLEN); -@@ -6123,7 +5658,7 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - DEBUGF("recv: WINDOW_UPDATE\n"); - break; - } --#endif /* DEBUGBUILD */ -+#endif /* defined(DEBUGBUILD) */ - - iframe->frame.hd.flags = NGHTTP2_FLAG_NONE; - -@@ -6279,8 +5814,17 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (check_ext_type_set(session->user_recv_ext_types, - iframe->frame.hd.type)) { - if (!session->callbacks.unpack_extension_callback) { -- /* Silently ignore unknown frame type. */ -+ /* Receiving too frequent unknown frames is suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } - -+ /* Silently ignore unknown frame type. */ - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; -@@ -6298,6 +5842,16 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - case NGHTTP2_ALTSVC: - if ((session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ALTSVC) == - 0) { -+ /* Receiving too frequent unknown frames is suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6309,6 +5863,17 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - iframe->frame.ext.payload = &iframe->ext_frame_payload.altsvc; - - if (session->server) { -+ /* Receiving too frequent ALTSVC from client is -+ suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6328,6 +5893,16 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - break; - case NGHTTP2_ORIGIN: - if (!(session->builtin_recv_ext_types & NGHTTP2_TYPEMASK_ORIGIN)) { -+ /* Receiving too frequent unknown frames is suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6339,6 +5914,17 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - - if (session->server || iframe->frame.hd.stream_id || - (iframe->frame.hd.flags & 0xf0)) { -+ /* Receiving too frequent invalid frames is -+ suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6365,6 +5951,16 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - case NGHTTP2_PRIORITY_UPDATE: - if ((session->builtin_recv_ext_types & - NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) { -+ /* Receiving too frequent unknown frames is suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6392,8 +5988,18 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - break; - } - -- if (!session_no_rfc7540_pri_no_fallback(session) || -- iframe->payloadleft > sizeof(iframe->raw_sbuf)) { -+ /* Receiving too frequent PRIORITY_UPDATE is -+ suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ -+ if (iframe->payloadleft > sizeof(iframe->raw_sbuf)) { - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; -@@ -6406,6 +6012,16 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - - break; - default: -+ /* Receiving too frequent unknown frames is suspicious. */ -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - busy = 1; - - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; -@@ -6429,6 +6045,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (nghttp2_is_fatal(rv)) { - return rv; - } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } - } - } - -@@ -6492,8 +6112,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { -- rv = nghttp2_session_add_rst_stream( -- session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); -+ rv = session_handle_invalid_stream2( -+ session, iframe->frame.hd.stream_id, NULL, NGHTTP2_ERR_INTERNAL); - if (nghttp2_is_fatal(rv)) { - return rv; - } -@@ -6502,26 +6122,23 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } - - if (rv == NGHTTP2_ERR_IGN_HEADER_BLOCK) { -- iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; -- break; -- } -- -- iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; -- -- break; -- case NGHTTP2_PRIORITY: -- 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)) { -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { - return rv; - } - - if (iframe->state == NGHTTP2_IB_IGN_ALL) { - return (nghttp2_ssize)inlen; - } -+ -+ iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; -+ break; - } - -+ iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; -+ -+ break; -+ case NGHTTP2_PRIORITY: - session_inbound_frame_reset(session); - - break; -@@ -6579,9 +6196,9 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } - - if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { -- rv = nghttp2_session_add_rst_stream( -- session, iframe->frame.push_promise.promised_stream_id, -- NGHTTP2_INTERNAL_ERROR); -+ rv = session_handle_invalid_stream2( -+ session, iframe->frame.push_promise.promised_stream_id, NULL, -+ NGHTTP2_ERR_INTERNAL); - if (nghttp2_is_fatal(rv)) { - return rv; - } -@@ -6684,6 +6301,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - session_inbound_frame_reset(session); - - break; -@@ -6706,7 +6327,7 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } else { - DEBUGF("recv: [IB_IGN_HEADER_BLOCK]\n"); - } --#endif /* DEBUGBUILD */ -+#endif /* defined(DEBUGBUILD) */ - - readlen = inbound_frame_payload_readlen(iframe, in, last); - -@@ -6759,12 +6380,12 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - iframe->payloadleft -= hd_proclen; - - /* Use promised stream ID for PUSH_PROMISE */ -- rv = nghttp2_session_add_rst_stream( -+ rv = session_handle_invalid_stream2( - session, - iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE - ? iframe->frame.push_promise.promised_stream_id - : iframe->frame.hd.stream_id, -- NGHTTP2_INTERNAL_ERROR); -+ NULL, NGHTTP2_ERR_INTERNAL); - if (nghttp2_is_fatal(rv)) { - return rv; - } -@@ -6811,6 +6432,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (nghttp2_is_fatal(rv)) { - return rv; - } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } - } - session_inbound_frame_reset(session); - -@@ -6934,7 +6559,7 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - } else { - fprintf(stderr, "recv: [IB_IGN_CONTINUATION]\n"); - } --#endif /* DEBUGBUILD */ -+#endif /* defined(DEBUGBUILD) */ - - if (++session->num_continuations > session->max_continuations) { - return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS; -@@ -6986,6 +6611,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (nghttp2_is_fatal(rv)) { - return rv; - } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } - } else { - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - } -@@ -7036,6 +6665,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (nghttp2_is_fatal(rv)) { - return rv; - } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } - } - - busy = 1; -@@ -7052,6 +6685,20 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - - iframe->frame.data.padlen = (size_t)padlen; - -+ /* Empty DATA frame without END_STREAM flag set is -+ suspicious. */ -+ if (iframe->payloadleft == 0 && -+ (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { -+ rv = session_update_glitch_ratelim(session); -+ if (rv != 0) { -+ return rv; -+ } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ } -+ - iframe->state = NGHTTP2_IB_READ_DATA; - - break; -@@ -7094,6 +6741,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - data_readlen = - inbound_frame_effective_readlen(iframe, iframe->payloadleft, readlen); - -@@ -7123,41 +6774,30 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - if (data_readlen > 0) { - if (session_enforce_http_messaging(session)) { - if (nghttp2_http_on_data_chunk(stream, (size_t)data_readlen) != 0) { -- if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { -- /* Consume all data for connection immediately here */ -- rv = session_update_connection_consumed_size( -- session, (size_t)data_readlen); -- -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -- -- if (iframe->state == NGHTTP2_IB_IGN_DATA) { -- return (nghttp2_ssize)inlen; -- } -- } -- -- rv = nghttp2_session_add_rst_stream( -- session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR); -+ rv = nghttp2_session_terminate_session(session, -+ NGHTTP2_PROTOCOL_ERROR); - if (nghttp2_is_fatal(rv)) { - return rv; - } -- busy = 1; -- iframe->state = NGHTTP2_IB_IGN_DATA; -- break; -+ -+ return (nghttp2_ssize)inlen; - } - } - if (session->callbacks.on_data_chunk_recv_callback) { - rv = session->callbacks.on_data_chunk_recv_callback( - session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, - in - readlen, (size_t)data_readlen, session->user_data); -- if (rv == NGHTTP2_ERR_PAUSE) { -- return (nghttp2_ssize)(in - first); -- } -- - if (nghttp2_is_fatal(rv)) { - return NGHTTP2_ERR_CALLBACK_FAILURE; - } -+ -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ -+ if (rv == NGHTTP2_ERR_PAUSE) { -+ return (nghttp2_ssize)(in - first); -+ } - } - } - } -@@ -7171,6 +6811,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - session_inbound_frame_reset(session); - - break; -@@ -7237,6 +6881,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - if (rv != 0) { - busy = 1; - -@@ -7255,6 +6903,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - session_inbound_frame_reset(session); - - break; -@@ -7283,6 +6935,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session, - return rv; - } - -+ if (iframe->state == NGHTTP2_IB_IGN_ALL) { -+ return (nghttp2_ssize)inlen; -+ } -+ - session_inbound_frame_reset(session); - - break; -@@ -7404,9 +7060,7 @@ 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) || -- !session_sched_empty(session)) && -- session->remote_window_size > 0) || -+ (!session_sched_empty(session) && session->remote_window_size > 0) || - (nghttp2_outbound_queue_top(&session->ob_syn) && - !session_is_outgoing_concurrent_streams_max(session)); - } -@@ -8046,7 +7700,6 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session, - nghttp2_settings_entry *iv; - size_t niv; - int rv; -- nghttp2_priority_spec pri_spec; - nghttp2_mem *mem; - - mem = &session->mem; -@@ -8083,18 +7736,13 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session, - return rv; - } - -- nghttp2_priority_spec_default_init(&pri_spec); -- - stream = nghttp2_session_open_stream( -- session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec, NGHTTP2_STREAM_OPENING, -+ session, 1, NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_STREAM_OPENING, - session->server ? NULL : stream_user_data); - if (stream == NULL) { - return NGHTTP2_ERR_NOMEM; - } - -- /* We don't call nghttp2_session_adjust_closed_stream(), since this -- should be the first stream open. */ -- - if (session->server) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); - session->last_recv_stream_id = 1; -@@ -8293,14 +7941,16 @@ int32_t nghttp2_session_get_last_proc_stream_id(nghttp2_session *session) { - nghttp2_stream *nghttp2_session_find_stream(nghttp2_session *session, - int32_t stream_id) { - if (stream_id == 0) { -- return &session->root; -+ return &nghttp2_stream_root; - } - - return nghttp2_session_get_stream_raw(session, stream_id); - } - - nghttp2_stream *nghttp2_session_get_root_stream(nghttp2_session *session) { -- return &session->root; -+ (void)session; -+ -+ return &nghttp2_stream_root; - } - - int nghttp2_session_check_server_session(nghttp2_session *session) { -@@ -8310,75 +7960,20 @@ int nghttp2_session_check_server_session(nghttp2_session *session) { - int nghttp2_session_change_stream_priority( - nghttp2_session *session, int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { -- int rv; -- 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; -- } -- -- stream = nghttp2_session_get_stream_raw(session, stream_id); -- if (!stream) { -- return NGHTTP2_ERR_INVALID_ARGUMENT; -- } -- -- pri_spec_copy = *pri_spec; -- nghttp2_priority_spec_normalize_weight(&pri_spec_copy); -- -- rv = nghttp2_session_reprioritize_stream(session, stream, &pri_spec_copy); -- -- if (nghttp2_is_fatal(rv)) { -- return rv; -- } -+ (void)session; -+ (void)stream_id; -+ (void)pri_spec; - -- /* We don't intentionally call nghttp2_session_adjust_idle_stream() -- so that idle stream created by this function, and existing ones -- are kept for application. We will adjust number of idle stream -- in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is -- called. */ - return 0; - } - - int nghttp2_session_create_idle_stream(nghttp2_session *session, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { -- 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; -- } -- -- stream = nghttp2_session_get_stream_raw(session, stream_id); -- if (stream) { -- return NGHTTP2_ERR_INVALID_ARGUMENT; -- } -- -- pri_spec_copy = *pri_spec; -- nghttp2_priority_spec_normalize_weight(&pri_spec_copy); -- -- stream = -- nghttp2_session_open_stream(session, stream_id, NGHTTP2_STREAM_FLAG_NONE, -- &pri_spec_copy, NGHTTP2_STREAM_IDLE, NULL); -- if (!stream) { -- return NGHTTP2_ERR_NOMEM; -- } -+ (void)session; -+ (void)stream_id; -+ (void)pri_spec; - -- /* We don't intentionally call nghttp2_session_adjust_idle_stream() -- so that idle stream created by this function, and existing ones -- are kept for application. We will adjust number of idle stream -- in nghttp2_session_mem_send2 or nghttp2_session_mem_recv2 is -- called. */ - return 0; - } - -diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h -index ef8f7b27..edbef80d 100644 ---- a/deps/nghttp2/lib/nghttp2_session.h -+++ b/deps/nghttp2/lib/nghttp2_session.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_map.h" -@@ -45,6 +45,8 @@ - preface handling. */ - extern int nghttp2_enable_strict_preface; - -+extern nghttp2_stream nghttp2_stream_root; -+ - /* - * Option flags. - */ -@@ -53,8 +55,6 @@ 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_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5, - NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6, - } nghttp2_optmask; - -@@ -89,10 +89,6 @@ typedef struct { - /* The default maximum number of incoming reserved streams */ - #define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200 - --/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this -- number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */ --#define NGHTTP2_MIN_IDLE_STREAMS 16 -- - /* The maximum number of items in outbound queue, which is considered - as flooding caused by peer. All frames are not considered here. - We only consider PING + ACK and SETTINGS + ACK. This is because -@@ -110,6 +106,10 @@ typedef struct { - #define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 - #define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 - -+/* The default values for glitch rate limiter. */ -+#define NGHTTP2_DEFAULT_GLITCH_BURST 1000 -+#define NGHTTP2_DEFAULT_GLITCH_RATE 33 -+ - /* The default max number of CONTINUATION frames following an incoming - HEADER frame. */ - #define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8 -@@ -205,8 +205,6 @@ typedef struct nghttp2_inflight_settings nghttp2_inflight_settings; - - struct nghttp2_session { - nghttp2_map /* */ streams; -- /* root of dependency tree*/ -- nghttp2_stream root; - /* Queue for outbound urgent frames (PING and SETTINGS) */ - nghttp2_outbound_queue ob_urgent; - /* Queue for non-DATA frames */ -@@ -229,26 +227,14 @@ struct nghttp2_session { - /* Memory allocator */ - nghttp2_mem mem; - void *user_data; -- /* Points to the latest incoming closed stream. NULL if there is no -- closed stream. Only used when session is initialized as -- server. */ -- nghttp2_stream *closed_stream_head; -- /* Points to the oldest incoming closed stream. NULL if there is no -- closed stream. Only used when session is initialized as -- server. */ -- nghttp2_stream *closed_stream_tail; -- /* Points to the latest idle stream. NULL if there is no idle -- stream. Only used when session is initialized as server .*/ -- nghttp2_stream *idle_stream_head; -- /* Points to the oldest idle stream. NULL if there is no idle -- stream. Only used when session is initialized as erver. */ -- nghttp2_stream *idle_stream_tail; - /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not - considered as in-flight. */ - nghttp2_inflight_settings *inflight_settings_head; - /* Stream reset rate limiter. If receiving excessive amount of - stream resets, GOAWAY will be sent. */ - nghttp2_ratelim stream_reset_ratelim; -+ /* Rate limiter for all kinds of glitches. */ -+ nghttp2_ratelim glitch_ratelim; - /* Sequential number across all streams to process streams in - FIFO. */ - uint64_t stream_seq; -@@ -276,10 +262,9 @@ struct nghttp2_session { - |closed_stream_head|. The current implementation only keeps - incoming streams and session is initialized as server. */ - size_t num_closed_streams; -- /* The number of idle streams kept in |streams| hash. The idle -- streams can be accessed through doubly linked list -- |idle_stream_head|. The current implementation only keeps idle -- streams if session is initialized as server. */ -+ /* The number of idle streams kept in |streams| hash. The current -+ implementation only keeps idle streams if session is initialized -+ as server. */ - size_t num_idle_streams; - /* The number of bytes allocated for nvbuf */ - size_t nvbuflen; -@@ -362,8 +347,6 @@ struct nghttp2_session { - /* 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 -@@ -425,6 +408,13 @@ int nghttp2_session_is_my_stream_id(nghttp2_session *session, - int nghttp2_session_add_item(nghttp2_session *session, - nghttp2_outbound_item *item); - -+/* -+ * This function wraps around nghttp2_session_add_rst_stream_continue -+ * with continue_without_stream = 1. -+ */ -+int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, -+ uint32_t error_code); -+ - /* - * Adds RST_STREAM frame for the stream |stream_id| with the error - * code |error_code|. This is a convenient function built on top of -@@ -432,7 +422,9 @@ int nghttp2_session_add_item(nghttp2_session *session, - * - * This function simply returns 0 without adding RST_STREAM frame if - * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple -- * RST_STREAM for a stream is redundant. -+ * RST_STREAM for a stream is redundant. It also returns 0 without -+ * adding the frame if |continue_without_stream| is nonzero, and -+ * stream was already gone. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: -@@ -440,8 +432,10 @@ int nghttp2_session_add_item(nghttp2_session *session, - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ --int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, -- uint32_t error_code); -+int nghttp2_session_add_rst_stream_continue(nghttp2_session *session, -+ int32_t stream_id, -+ uint32_t error_code, -+ int continue_without_stream); - - /* - * Adds PING frame. This is a convenient function built on top of -@@ -527,15 +521,9 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, - * - * This function returns a pointer to created new stream object, or - * NULL. -- * -- * This function adjusts neither the number of closed streams or idle -- * streams. The caller should manually call -- * nghttp2_session_adjust_closed_stream() or -- * nghttp2_session_adjust_idle_stream() respectively. - */ - nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - int32_t stream_id, uint8_t flags, -- nghttp2_priority_spec *pri_spec, - nghttp2_stream_state initial_state, - void *stream_user_data); - -@@ -544,11 +532,6 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, - * is indicated by the |error_code|. When closing the stream, - * on_stream_close_callback will be called. - * -- * If the session is initialized as server and |stream| is incoming -- * stream, stream is just marked closed and this function calls -- * nghttp2_session_keep_closed_stream() with |stream|. Otherwise, -- * |stream| will be deleted from memory. -- * - * This function returns 0 if it succeeds, or one the following - * negative error codes: - * -@@ -565,63 +548,9 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, - /* - * Deletes |stream| from memory. After this function returns, stream - * cannot be accessed. -- * -- * This function returns 0 if it succeeds, or one the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_session_destroy_stream(nghttp2_session *session, -- nghttp2_stream *stream); -- --/* -- * Tries to keep incoming closed stream |stream|. Due to the -- * limitation of maximum number of streams in memory, |stream| is not -- * closed and just deleted from memory (see -- * nghttp2_session_destroy_stream). -- */ --void nghttp2_session_keep_closed_stream(nghttp2_session *session, -- nghttp2_stream *stream); -- --/* -- * Appends |stream| to linked list |session->idle_stream_head|. We -- * apply fixed limit for list size. To fit into that limit, one or -- * more oldest streams are removed from list as necessary. - */ --void nghttp2_session_keep_idle_stream(nghttp2_session *session, -- nghttp2_stream *stream); -- --/* -- * Detaches |stream| from idle streams linked list. -- */ --void nghttp2_session_detach_idle_stream(nghttp2_session *session, -- nghttp2_stream *stream); -- --/* -- * Deletes closed stream to ensure that number of incoming streams -- * including active and closed is in the maximum number of allowed -- * stream. -- * -- * This function returns 0 if it succeeds, or one the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_session_adjust_closed_stream(nghttp2_session *session); -- --/* -- * Deletes idle stream to ensure that number of idle streams is in -- * certain limit. -- * -- * This function returns 0 if it succeeds, or one the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_session_adjust_idle_stream(nghttp2_session *session); -+void nghttp2_session_destroy_stream(nghttp2_session *session, -+ nghttp2_stream *stream); - - /* - * If further receptions and transmissions over the stream |stream_id| -@@ -915,24 +844,6 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, - nghttp2_settings_entry *iv, - size_t niv); - --/* -- * Re-prioritize |stream|. The new priority specification is -- * |pri_spec|. Caller must ensure that stream->hd.stream_id != -- * pri_spec->stream_id. -- * -- * This function does not adjust the number of idle streams. The -- * caller should call nghttp2_session_adjust_idle_stream() later. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_session_reprioritize_stream(nghttp2_session *session, -- nghttp2_stream *stream, -- const nghttp2_priority_spec *pri_spec); -- - /* - * Terminates current |session| with the |error_code|. The |reason| - * is NULL-terminated debug string. -@@ -981,4 +892,4 @@ int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session, - size_t delta_size, - int send_window_update); - --#endif /* NGHTTP2_SESSION_H */ -+#endif /* !defined(NGHTTP2_SESSION_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_stream.c b/deps/nghttp2/lib/nghttp2_stream.c -index f2362447..0f2d3658 100644 ---- a/deps/nghttp2/lib/nghttp2_stream.c -+++ b/deps/nghttp2/lib/nghttp2_stream.c -@@ -25,45 +25,17 @@ - #include "nghttp2_stream.h" - - #include --#include - - #include "nghttp2_session.h" - #include "nghttp2_helper.h" - #include "nghttp2_debug.h" - #include "nghttp2_frame.h" - --/* Maximum distance between any two stream's cycle in the same -- 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 -- NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other -- words, B is really greater than or equal to A. Otherwise, A is a -- result of overflow, and it is actually A > B if we consider that -- fact. */ --#define NGHTTP2_MAX_CYCLE_DISTANCE \ -- ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255) -- --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_MAX_CYCLE_DISTANCE; --} -- - void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, - uint8_t flags, nghttp2_stream_state initial_state, -- int32_t weight, int32_t remote_initial_window_size, -+ int32_t remote_initial_window_size, - int32_t local_initial_window_size, -- void *stream_user_data, nghttp2_mem *mem) { -- nghttp2_pq_init(&stream->obq, stream_less, mem); -- -+ void *stream_user_data) { - stream->stream_id = stream_id; - stream->flags = flags; - stream->state = initial_state; -@@ -77,428 +49,36 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, - stream->recv_reduction = 0; - stream->window_update_queued = 0; - -- stream->dep_prev = NULL; -- stream->dep_next = NULL; -- stream->sib_prev = NULL; -- stream->sib_next = NULL; -- -- stream->closed_prev = NULL; - stream->closed_next = NULL; - -- stream->weight = weight; -- stream->sum_dep_weight = 0; -- - stream->http_flags = NGHTTP2_HTTP_FLAG_NONE; - stream->content_length = -1; - stream->recv_content_length = 0; - stream->status_code = -1; - - stream->queued = 0; -- stream->descendant_last_cycle = 0; - stream->cycle = 0; - stream->pending_penalty = 0; -- 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) { -- nghttp2_pq_free(&stream->obq); -- /* We don't free stream->item. If it is assigned to aob, then -- active_outbound_item_reset() will delete it. Otherwise, -- nghttp2_stream_close() or session_del() will delete it. */ --} -+void nghttp2_stream_free(nghttp2_stream *stream) { (void)stream; } - - void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) { - stream->shut_flags = (uint8_t)(stream->shut_flags | flag); - } - --/* -- * Returns nonzero if |stream| is active. This function does not take -- * into account its descendants. -- */ --static int stream_active(nghttp2_stream *stream) { -- return stream->item && -- (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0; --} -- --/* -- * Returns nonzero if |stream| or one of its descendants is active -- */ --static int stream_subtree_active(nghttp2_stream *stream) { -- return stream_active(stream) || !nghttp2_pq_empty(&stream->obq); --} -- --/* -- * Returns next cycle for |stream|. -- */ --static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) { -- uint64_t penalty; -- -- penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT + -- stream->pending_penalty; -- -- stream->cycle = last_cycle + penalty / (uint32_t)stream->weight; -- stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight); --} -- --static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) { -- int rv; -- -- for (; dep_stream && !stream->queued; -- stream = dep_stream, dep_stream = dep_stream->dep_prev) { -- stream_next_cycle(stream, dep_stream->descendant_last_cycle); -- stream->seq = dep_stream->descendant_next_seq++; -- -- DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id, -- stream->cycle); -- -- DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id, -- dep_stream->stream_id); -- -- rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); -- if (rv != 0) { -- return rv; -- } -- stream->queued = 1; -- } -- -- return 0; --} -- --/* -- * Removes |stream| from parent's obq. If removal of |stream| makes -- * parent's obq empty, and parent is not active, then parent is also -- * removed. This process is repeated recursively. -- */ --static void stream_obq_remove(nghttp2_stream *stream) { -- nghttp2_stream *dep_stream; -- -- dep_stream = stream->dep_prev; -- -- if (!stream->queued) { -- return; -- } -- -- for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { -- DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id, -- dep_stream->stream_id); -- -- nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); -- -- assert(stream->queued); -- -- stream->queued = 0; -- stream->cycle = 0; -- stream->pending_penalty = 0; -- stream->descendant_last_cycle = 0; -- stream->last_writelen = 0; -- -- if (stream_subtree_active(dep_stream)) { -- return; -- } -- } --} -- --/* -- * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from -- * |src|'s obq is just done calling nghttp2_pq_remove(), so it does -- * not recursively remove |src| and ancestors, like -- * stream_obq_remove(). -- */ --static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src, -- nghttp2_stream *stream) { -- if (!stream->queued) { -- return 0; -- } -- -- DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id, -- src->stream_id); -- -- nghttp2_pq_remove(&src->obq, &stream->pq_entry); -- stream->queued = 0; -- -- return stream_obq_push(dest, stream); --} -- --void nghttp2_stream_reschedule(nghttp2_stream *stream) { -- nghttp2_stream *dep_stream; -- -- assert(stream->queued); -- -- dep_stream = stream->dep_prev; -- -- for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) { -- nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); -- -- stream_next_cycle(stream, dep_stream->descendant_last_cycle); -- stream->seq = dep_stream->descendant_next_seq++; -- -- nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); -- -- DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, -- stream->cycle); -- -- dep_stream->last_writelen = stream->last_writelen; -- } --} -- --void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) { -- nghttp2_stream *dep_stream; -- uint64_t last_cycle; -- int32_t old_weight; -- uint64_t wlen_penalty; -- -- if (stream->weight == weight) { -- return; -- } -- -- old_weight = stream->weight; -- stream->weight = weight; -- -- dep_stream = stream->dep_prev; -- -- if (!dep_stream) { -- return; -- } -- -- dep_stream->sum_dep_weight += weight - old_weight; -- -- if (!stream->queued) { -- return; -- } -- -- nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry); -- -- wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT; -- -- /* Compute old stream->pending_penalty we used to calculate -- stream->cycle */ -- stream->pending_penalty = -- (uint32_t)((stream->pending_penalty + (uint32_t)old_weight - -- (wlen_penalty % (uint32_t)old_weight)) % -- (uint32_t)old_weight); -- -- last_cycle = stream->cycle - -- (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight; -- -- /* Now we have old stream->pending_penalty and new stream->weight in -- place */ -- stream_next_cycle(stream, last_cycle); -- -- if (dep_stream->descendant_last_cycle - stream->cycle <= -- NGHTTP2_MAX_CYCLE_DISTANCE) { -- stream->cycle = dep_stream->descendant_last_cycle; -- } -- -- /* Continue to use same stream->seq */ -- -- nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry); -- -- DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id, -- stream->cycle); --} -- --static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { -- for (; stream->sib_next; stream = stream->sib_next) -- ; -- -- return stream; --} -- --int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, -- int32_t weight) { -- weight = stream->weight * weight / stream->sum_dep_weight; -- -- return nghttp2_max_int32(1, weight); --} -- --#ifdef STREAM_DEP_DEBUG -- --static void ensure_inactive(nghttp2_stream *stream) { -- nghttp2_stream *si; -- -- if (stream->queued) { -- fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream, -- stream->stream_id); -- assert(0); -- } -- -- if (stream_active(stream)) { -- fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n", -- stream, stream->stream_id); -- assert(0); -- } -- -- if (!nghttp2_pq_empty(&stream->obq)) { -- fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream, -- stream->stream_id, nghttp2_pq_size(&stream->obq)); -- assert(0); -- } -- -- for (si = stream->dep_next; si; si = si->sib_next) { -- ensure_inactive(si); -- } --} -- --static void check_queued(nghttp2_stream *stream) { -- nghttp2_stream *si; -- int queued; -- -- if (stream->queued) { -- if (!stream_subtree_active(stream)) { -- fprintf(stderr, -- "stream(%p)=%d, stream->queued == 1, but " -- "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n", -- stream, stream->stream_id, stream_active(stream), -- nghttp2_pq_size(&stream->obq)); -- assert(0); -- } -- if (!stream_active(stream)) { -- queued = 0; -- for (si = stream->dep_next; si; si = si->sib_next) { -- if (si->queued) { -- ++queued; -- } -- } -- if (queued == 0) { -- fprintf(stderr, -- "stream(%p)=%d, stream->queued == 1, and " -- "!stream_active(), but no descendants is queued\n", -- stream, stream->stream_id); -- assert(0); -- } -- } -- -- for (si = stream->dep_next; si; si = si->sib_next) { -- check_queued(si); -- } -- } else { -- if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) { -- fprintf(stderr, -- "stream(%p) = %d, stream->queued == 0, but " -- "stream_active(stream) == %d and " -- "nghttp2_pq_size(&stream->obq) = %zu\n", -- stream, stream->stream_id, stream_active(stream), -- nghttp2_pq_size(&stream->obq)); -- assert(0); -- } -- for (si = stream->dep_next; si; si = si->sib_next) { -- ensure_inactive(si); -- } -- } --} -- --static void check_sum_dep(nghttp2_stream *stream) { -- nghttp2_stream *si; -- int32_t n = 0; -- for (si = stream->dep_next; si; si = si->sib_next) { -- n += si->weight; -- } -- if (n != stream->sum_dep_weight) { -- fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream, -- stream->stream_id, n, stream->sum_dep_weight); -- assert(0); -- } -- for (si = stream->dep_next; si; si = si->sib_next) { -- check_sum_dep(si); -- } --} -- --static void check_dep_prev(nghttp2_stream *stream) { -- nghttp2_stream *si; -- for (si = stream->dep_next; si; si = si->sib_next) { -- if (si->dep_prev != stream) { -- fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream); -- assert(0); -- } -- check_dep_prev(si); -- } --} -- --#endif /* STREAM_DEP_DEBUG */ -- --#ifdef STREAM_DEP_DEBUG --static void validate_tree(nghttp2_stream *stream) { -- nghttp2_stream *si; -- -- if (!stream) { -- return; -- } -- -- for (; stream->dep_prev; stream = stream->dep_prev) -- ; -- -- assert(stream->stream_id == 0); -- assert(!stream->queued); -- -- fprintf(stderr, "checking...\n"); -- if (nghttp2_pq_empty(&stream->obq)) { -- fprintf(stderr, "root obq empty\n"); -- for (si = stream->dep_next; si; si = si->sib_next) { -- ensure_inactive(si); -- } -- } else { -- for (si = stream->dep_next; si; si = si->sib_next) { -- check_queued(si); -- } -- } -- -- check_sum_dep(stream); -- check_dep_prev(stream); --} --#else /* !STREAM_DEP_DEBUG */ --static void validate_tree(nghttp2_stream *stream) { (void)stream; } --#endif /* !STREAM_DEP_DEBUG*/ -- --static int stream_update_dep_on_attach_item(nghttp2_stream *stream) { -- int rv; -- -- rv = stream_obq_push(stream->dep_prev, stream); -- if (rv != 0) { -- return rv; -- } -- -- validate_tree(stream); -- return 0; --} -- --static void stream_update_dep_on_detach_item(nghttp2_stream *stream) { -- if (nghttp2_pq_empty(&stream->obq)) { -- stream_obq_remove(stream); -- } -- -- validate_tree(stream); --} -- --int nghttp2_stream_attach_item(nghttp2_stream *stream, -- nghttp2_outbound_item *item) { -- int rv; -- -+void nghttp2_stream_attach_item(nghttp2_stream *stream, -+ nghttp2_outbound_item *item) { - assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0); - assert(stream->item == NULL); - - DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item); - - 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. -- But only consequence of this error is fatal one, and session -- destruction. In that execution path, these inconsistency does -- not matter. */ -- stream->item = NULL; -- return rv; -- } -- -- return 0; - } - - void nghttp2_stream_detach_item(nghttp2_stream *stream) { -@@ -506,12 +86,6 @@ void 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; -- } -- -- stream_update_dep_on_detach_item(stream); - } - - void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { -@@ -521,31 +95,16 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { - stream->item, flags); - - stream->flags |= flags; -- -- if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { -- return; -- } -- -- stream_update_dep_on_detach_item(stream); - } - --int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) { -+void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, -+ uint8_t flags) { - assert(stream->item); - - DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id, - stream->item, flags); - - stream->flags = (uint8_t)(stream->flags & ~flags); -- -- if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) { -- return 0; -- } -- -- if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { -- return 0; -- } -- -- return stream_update_dep_on_attach_item(stream); - } - - int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) { -@@ -591,373 +150,11 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) { - stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH); - } - --int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, -- nghttp2_stream *target) { -- for (; stream; stream = stream->dep_prev) { -- if (stream == target) { -- return 1; -- } -- } -- return 0; --} -- --int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, -- nghttp2_stream *stream) { -- nghttp2_stream *si; -- int rv; -- -- DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, -- dep_stream->stream_id, stream, stream->stream_id); -- -- stream->sum_dep_weight = dep_stream->sum_dep_weight; -- dep_stream->sum_dep_weight = stream->weight; -- -- if (dep_stream->dep_next) { -- for (si = dep_stream->dep_next; si; si = si->sib_next) { -- si->dep_prev = stream; -- if (si->queued) { -- rv = stream_obq_move(stream, dep_stream, si); -- if (rv != 0) { -- return rv; -- } -- } -- } -- -- if (stream_subtree_active(stream)) { -- rv = stream_obq_push(dep_stream, stream); -- if (rv != 0) { -- return rv; -- } -- } -- -- stream->dep_next = dep_stream->dep_next; -- } -- -- dep_stream->dep_next = stream; -- stream->dep_prev = dep_stream; -- -- validate_tree(stream); -- -- return 0; --} -- --static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) { -- for (; stream; stream = stream->sib_next) { -- stream->dep_prev = dep; -- } --} -- --static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { -- dep_stream->dep_next = stream; -- if (stream) { -- stream->dep_prev = dep_stream; -- } --} -- --static void link_sib(nghttp2_stream *a, nghttp2_stream *b) { -- a->sib_next = b; -- if (b) { -- b->sib_prev = a; -- } --} -- --static void insert_link_dep(nghttp2_stream *dep_stream, -- nghttp2_stream *stream) { -- nghttp2_stream *sib_next; -- -- assert(stream->sib_prev == NULL); -- -- sib_next = dep_stream->dep_next; -- -- link_sib(stream, sib_next); -- -- link_dep(dep_stream, stream); --} -- --static void unlink_sib(nghttp2_stream *stream) { -- nghttp2_stream *prev, *next, *dep_next; -- -- prev = stream->sib_prev; -- dep_next = stream->dep_next; -- -- assert(prev); -- -- if (dep_next) { -- /* -- * prev--stream(--sib_next--...) -- * | -- * dep_next -- */ -- -- link_sib(prev, dep_next); -- -- set_dep_prev(dep_next, stream->dep_prev); -- -- if (stream->sib_next) { -- link_sib(stream_last_sib(dep_next), stream->sib_next); -- } -- } else { -- /* -- * prev--stream(--sib_next--...) -- */ -- next = stream->sib_next; -- -- prev->sib_next = next; -- -- if (next) { -- next->sib_prev = prev; -- } -- } --} -- --static void unlink_dep(nghttp2_stream *stream) { -- nghttp2_stream *prev, *next, *dep_next; -- -- prev = stream->dep_prev; -- dep_next = stream->dep_next; -- -- assert(prev); -- -- if (dep_next) { -- /* -- * prev -- * | -- * stream(--sib_next--...) -- * | -- * dep_next -- */ -- link_dep(prev, dep_next); -- -- set_dep_prev(dep_next, stream->dep_prev); -- -- if (stream->sib_next) { -- link_sib(stream_last_sib(dep_next), stream->sib_next); -- } -- -- } else if (stream->sib_next) { -- /* -- * prev -- * | -- * stream--sib_next -- */ -- next = stream->sib_next; -- -- next->sib_prev = NULL; -- -- link_dep(prev, next); -- } else { -- prev->dep_next = NULL; -- } --} -- --void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, -- nghttp2_stream *stream) { -- DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream, -- dep_stream->stream_id, stream, stream->stream_id); -- -- dep_stream->sum_dep_weight += stream->weight; -- -- if (dep_stream->dep_next == NULL) { -- link_dep(dep_stream, stream); -- } else { -- insert_link_dep(dep_stream, stream); -- } -- -- validate_tree(stream); --} -- --int nghttp2_stream_dep_remove(nghttp2_stream *stream) { -- nghttp2_stream *dep_prev, *si; -- int32_t sum_dep_weight_delta; -- int rv; -- -- DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id); -- -- /* Distribute weight of |stream| to direct descendants */ -- sum_dep_weight_delta = -stream->weight; -- -- for (si = stream->dep_next; si; si = si->sib_next) { -- si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); -- -- sum_dep_weight_delta += si->weight; -- -- if (si->queued) { -- rv = stream_obq_move(stream->dep_prev, stream, si); -- if (rv != 0) { -- return rv; -- } -- } -- } -- -- assert(stream->dep_prev); -- -- dep_prev = stream->dep_prev; -- -- dep_prev->sum_dep_weight += sum_dep_weight_delta; -- -- if (stream->queued) { -- stream_obq_remove(stream); -- } -- -- if (stream->sib_prev) { -- unlink_sib(stream); -- } else { -- unlink_dep(stream); -- } -- -- stream->sum_dep_weight = 0; -- -- stream->dep_prev = NULL; -- stream->dep_next = NULL; -- stream->sib_prev = NULL; -- stream->sib_next = NULL; -- -- validate_tree(dep_prev); -- -- return 0; --} -- --int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, -- nghttp2_stream *stream) { -- nghttp2_stream *last_sib; -- nghttp2_stream *dep_next; -- nghttp2_stream *si; -- int rv; -- -- DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n", -- dep_stream, dep_stream->stream_id, stream, stream->stream_id); -- -- stream->sum_dep_weight += dep_stream->sum_dep_weight; -- dep_stream->sum_dep_weight = stream->weight; -- -- if (dep_stream->dep_next) { -- dep_next = dep_stream->dep_next; -- -- link_dep(dep_stream, stream); -- -- if (stream->dep_next) { -- last_sib = stream_last_sib(stream->dep_next); -- -- link_sib(last_sib, dep_next); -- } else { -- link_dep(stream, dep_next); -- } -- -- for (si = dep_next; si; si = si->sib_next) { -- si->dep_prev = stream; -- if (si->queued) { -- rv = stream_obq_move(stream, dep_stream, si); -- if (rv != 0) { -- return rv; -- } -- } -- } -- } else { -- link_dep(dep_stream, stream); -- } -- -- if (stream_subtree_active(stream)) { -- rv = stream_obq_push(dep_stream, stream); -- if (rv != 0) { -- return rv; -- } -- } -- -- validate_tree(dep_stream); -- -- return 0; --} -- --int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, -- nghttp2_stream *stream) { -- int rv; -- -- DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n", -- dep_stream, dep_stream->stream_id, stream, stream->stream_id); -- -- dep_stream->sum_dep_weight += stream->weight; -- -- if (dep_stream->dep_next) { -- insert_link_dep(dep_stream, stream); -- } else { -- link_dep(dep_stream, stream); -- } -- -- if (stream_subtree_active(stream)) { -- rv = stream_obq_push(dep_stream, stream); -- if (rv != 0) { -- return rv; -- } -- } -- -- validate_tree(dep_stream); -- -- return 0; --} -- --void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { -- nghttp2_stream *next, *dep_prev; -- -- DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream, -- stream->stream_id); -- -- assert(stream->dep_prev); -- -- dep_prev = stream->dep_prev; -- -- if (stream->sib_prev) { -- link_sib(stream->sib_prev, stream->sib_next); -- } else { -- next = stream->sib_next; -- -- link_dep(dep_prev, next); -- -- if (next) { -- next->sib_prev = NULL; -- } -- } -- -- dep_prev->sum_dep_weight -= stream->weight; -- -- if (stream->queued) { -- stream_obq_remove(stream); -- } -- -- validate_tree(dep_prev); -- -- stream->sib_prev = NULL; -- stream->sib_next = NULL; -- stream->dep_prev = NULL; --} -- --int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) { -- return stream->dep_prev || stream->dep_next || stream->sib_prev || -- stream->sib_next; --} -- --nghttp2_outbound_item * --nghttp2_stream_next_outbound_item(nghttp2_stream *stream) { -- nghttp2_pq_entry *ent; -- nghttp2_stream *si; -- -- for (;;) { -- if (stream_active(stream)) { -- /* Update ascendant's descendant_last_cycle here, so that we can -- assure that new stream is scheduled based on it. */ -- for (si = stream; si->dep_prev; si = si->dep_prev) { -- si->dep_prev->descendant_last_cycle = si->cycle; -- } -- return stream->item; -- } -- ent = nghttp2_pq_top(&stream->obq); -- if (!ent) { -- return NULL; -- } -- stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry); -+nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { -+ if (stream == &nghttp2_stream_root) { -+ return NGHTTP2_STREAM_STATE_IDLE; - } --} - --nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { - if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) { - return NGHTTP2_STREAM_STATE_CLOSED; - } -@@ -988,27 +185,39 @@ nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) { - } - - nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) { -- return stream->dep_prev; -+ (void)stream; -+ -+ return NULL; - } - - nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) { -- return stream->sib_next; -+ (void)stream; -+ -+ return NULL; - } - - nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) { -- return stream->sib_prev; -+ (void)stream; -+ -+ return NULL; - } - - nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) { -- return stream->dep_next; -+ (void)stream; -+ -+ return NULL; - } - - int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) { -- return stream->weight; -+ (void)stream; -+ -+ return NGHTTP2_DEFAULT_WEIGHT; - } - - int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) { -- return stream->sum_dep_weight; -+ (void)stream; -+ -+ return 0; - } - - int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) { -diff --git a/deps/nghttp2/lib/nghttp2_stream.h b/deps/nghttp2/lib/nghttp2_stream.h -index 28add165..603209ec 100644 ---- a/deps/nghttp2/lib/nghttp2_stream.h -+++ b/deps/nghttp2/lib/nghttp2_stream.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - #include "nghttp2_outbound_item.h" -@@ -91,9 +91,6 @@ typedef enum { - /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and - NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ - 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 -@@ -146,39 +143,18 @@ typedef enum { - } nghttp2_http_flag; - - struct nghttp2_stream { -- /* Entry for dep_prev->obq */ -+ nghttp2_stream_state state; - nghttp2_pq_entry pq_entry; -- /* Priority Queue storing direct descendant (nghttp2_stream). Only -- streams which itself has some data to send, or has a descendant -- which has some data to sent. */ -- nghttp2_pq obq; - /* Content-Length of request/response body. -1 if unknown. */ - int64_t content_length; - /* Received body so far */ - int64_t recv_content_length; -- /* Base last_cycle for direct descendent streams. */ -- uint64_t descendant_last_cycle; - /* Next scheduled time to sent item */ - uint64_t cycle; -- /* Next seq used for direct descendant streams */ -- uint64_t descendant_next_seq; - /* Secondary key for prioritization to break a tie for cycle. This - value is monotonically increased for single parent stream. */ - uint64_t seq; -- /* pointers to form dependency tree. If multiple streams depend on -- a stream, only one stream (left most) has non-NULL dep_prev which -- points to the stream it depends on. The remaining streams are -- linked using sib_prev and sib_next. The stream which has -- non-NULL dep_prev always NULL sib_prev. The right most stream -- has NULL sib_next. If this stream is a root of dependency tree, -- dep_prev and sib_prev are NULL. */ -- nghttp2_stream *dep_prev, *dep_next; -- nghttp2_stream *sib_prev, *sib_next; -- /* When stream is kept after closure, it may be kept in doubly -- linked list pointed by nghttp2_session closed_stream_head. -- closed_next points to the next stream object if it is the element -- of the list. */ -- nghttp2_stream *closed_prev, *closed_next; -+ nghttp2_stream *closed_next; - /* The arbitrary data provided by user for this stream. */ - void *stream_user_data; - /* Item to send */ -@@ -205,13 +181,8 @@ struct nghttp2_stream { - NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by - submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ - int32_t local_window_size; -- /* weight of this stream */ -- int32_t weight; - /* This is unpaid penalty (offset) when calculating cycle. */ - uint32_t pending_penalty; -- /* sum of weight of direct descendants */ -- int32_t sum_dep_weight; -- nghttp2_stream_state state; - /* status code from remote server */ - int16_t status_code; - /* Bitwise OR of zero or more nghttp2_http_flag values */ -@@ -239,9 +210,9 @@ struct nghttp2_stream { - - void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, - uint8_t flags, nghttp2_stream_state initial_state, -- int32_t weight, int32_t remote_initial_window_size, -+ int32_t remote_initial_window_size, - int32_t local_initial_window_size, -- void *stream_user_data, nghttp2_mem *mem); -+ void *stream_user_data); - - void nghttp2_stream_free(nghttp2_stream *stream); - -@@ -267,14 +238,8 @@ void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); - * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are - * cleared if they are set. So even if this function is called, if - * one of flag is still set, data does not become active. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory - */ --int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); -+void nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); - - /* - * Returns nonzero if item is deferred by whatever reason. -@@ -317,57 +282,11 @@ int nghttp2_stream_update_local_initial_window_size( - */ - void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); - --/* -- * Returns nonzero if |target| is an ancestor of |stream|. -- */ --int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, -- nghttp2_stream *target); -- --/* -- * Computes distributed weight of a stream of the |weight| under the -- * |stream| if |stream| is removed from a dependency tree. -- */ --int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, -- int32_t weight); -- --/* -- * Makes the |stream| depend on the |dep_stream|. This dependency is -- * exclusive. All existing direct descendants of |dep_stream| become -- * the descendants of the |stream|. This function assumes -- * |stream->item| is NULL. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, -- nghttp2_stream *stream); -- --/* -- * Makes the |stream| depend on the |dep_stream|. This dependency is -- * not exclusive. This function assumes |stream->item| is NULL. -- */ --void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); -- --/* -- * Removes the |stream| from the current dependency tree. This -- * function assumes |stream->item| is NULL. -- */ --int nghttp2_stream_dep_remove(nghttp2_stream *stream); -- - /* - * Attaches |item| to |stream|. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory - */ --int nghttp2_stream_attach_item(nghttp2_stream *stream, -- nghttp2_outbound_item *item); -+void nghttp2_stream_attach_item(nghttp2_stream *stream, -+ nghttp2_outbound_item *item); - - /* - * Detaches |stream->item|. This function does not free -@@ -375,66 +294,4 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream, - */ - void nghttp2_stream_detach_item(nghttp2_stream *stream); - --/* -- * Makes the |stream| depend on the |dep_stream|. This dependency is -- * exclusive. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, -- nghttp2_stream *stream); -- --/* -- * Makes the |stream| depend on the |dep_stream|. This dependency is -- * not exclusive. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, -- nghttp2_stream *stream); -- --/* -- * Removes subtree whose root stream is |stream|. The -- * effective_weight of streams in removed subtree is not updated. -- * -- * This function returns 0 if it succeeds, or one of the following -- * negative error codes: -- * -- * NGHTTP2_ERR_NOMEM -- * Out of memory -- */ --void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); -- --/* -- * Returns nonzero if |stream| is in any dependency tree. -- */ --int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); -- --/* -- * Schedules transmission of |stream|'s item, assuming stream->item is -- * attached, and stream->last_writelen was updated. -- */ --void nghttp2_stream_reschedule(nghttp2_stream *stream); -- --/* -- * Changes |stream|'s weight to |weight|. If |stream| is queued, it -- * will be rescheduled based on new weight. -- */ --void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); -- --/* -- * Returns a stream which has highest priority, updating -- * descendant_last_cycle of selected stream's ancestors. -- */ --nghttp2_outbound_item * --nghttp2_stream_next_outbound_item(nghttp2_stream *stream); -- --#endif /* NGHTTP2_STREAM */ -+#endif /* !defined(NGHTTP2_STREAM_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_submit.c b/deps/nghttp2/lib/nghttp2_submit.c -index 81c1ab70..8a90f714 100644 ---- a/deps/nghttp2/lib/nghttp2_submit.c -+++ b/deps/nghttp2/lib/nghttp2_submit.c -@@ -32,42 +32,12 @@ - #include "nghttp2_helper.h" - #include "nghttp2_priority_spec.h" - --/* -- * Detects the dependency error, that is stream attempted to depend on -- * itself. If |stream_id| is -1, we use session->next_stream_id as -- * stream ID. -- * -- * This function returns 0 if it succeeds, or one of the following -- * error codes: -- * -- * NGHTTP2_ERR_INVALID_ARGUMENT -- * Stream attempted to depend on itself. -- */ --static int detect_self_dependency(nghttp2_session *session, int32_t stream_id, -- const nghttp2_priority_spec *pri_spec) { -- assert(pri_spec); -- -- if (stream_id == -1) { -- if ((int32_t)session->next_stream_id == pri_spec->stream_id) { -- return NGHTTP2_ERR_INVALID_ARGUMENT; -- } -- return 0; -- } -- -- if (stream_id == pri_spec->stream_id) { -- return NGHTTP2_ERR_INVALID_ARGUMENT; -- } -- -- return 0; --} -- - /* This function takes ownership of |nva_copy|. Regardless of the - return value, the caller must not free |nva_copy| after this - function returns. */ - static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, -- int32_t stream_id, -- const nghttp2_priority_spec *pri_spec, -- nghttp2_nv *nva_copy, size_t nvlen, -+ int32_t stream_id, nghttp2_nv *nva_copy, -+ size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - int rv; -@@ -114,8 +84,8 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags, - - frame = &item->frame; - -- nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, -- pri_spec, nva_copy, nvlen); -+ nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat, NULL, -+ nva_copy, nvlen); - - rv = nghttp2_session_add_item(session, item); - -@@ -141,31 +111,22 @@ fail2: - - static int32_t submit_headers_shared_nva(nghttp2_session *session, - uint8_t flags, int32_t stream_id, -- const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - int rv; - nghttp2_nv *nva_copy; -- nghttp2_priority_spec copy_pri_spec; - nghttp2_mem *mem; - - mem = &session->mem; - -- if (pri_spec) { -- copy_pri_spec = *pri_spec; -- nghttp2_priority_spec_normalize_weight(©_pri_spec); -- } else { -- nghttp2_priority_spec_default_init(©_pri_spec); -- } -- - rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem); - if (rv < 0) { - return rv; - } - -- return submit_headers_shared(session, flags, stream_id, ©_pri_spec, -- nva_copy, nvlen, dpw, stream_user_data); -+ return submit_headers_shared(session, flags, stream_id, nva_copy, nvlen, dpw, -+ stream_user_data); - } - - int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, -@@ -174,8 +135,8 @@ int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id, - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - -- return (int)submit_headers_shared_nva( -- session, NGHTTP2_FLAG_END_STREAM, stream_id, NULL, nva, nvlen, NULL, NULL); -+ return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM, -+ stream_id, nva, nvlen, NULL, NULL); - } - - int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, -@@ -183,7 +144,7 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags, - const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - void *stream_user_data) { -- int rv; -+ (void)pri_spec; - - if (stream_id == -1) { - if (session->server) { -@@ -195,20 +156,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) && -- session->remote_settings.no_rfc7540_priorities != 1) { -- rv = detect_self_dependency(session, stream_id, pri_spec); -- if (rv != 0) { -- return rv; -- } -- -- flags |= NGHTTP2_FLAG_PRIORITY; -- } else { -- pri_spec = NULL; -- } -- -- return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva, -- nvlen, NULL, stream_user_data); -+ return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, NULL, -+ stream_user_data); - } - - int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, -@@ -220,51 +169,10 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, - int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_priority_spec *pri_spec) { -- int rv; -- nghttp2_outbound_item *item; -- nghttp2_frame *frame; -- nghttp2_priority_spec copy_pri_spec; -- nghttp2_mem *mem; -+ (void)session; - (void)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; -- } -- -- if (stream_id == pri_spec->stream_id) { -- return NGHTTP2_ERR_INVALID_ARGUMENT; -- } -- -- copy_pri_spec = *pri_spec; -- -- nghttp2_priority_spec_normalize_weight(©_pri_spec); -- -- item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); -- -- if (item == NULL) { -- return NGHTTP2_ERR_NOMEM; -- } -- -- nghttp2_outbound_item_init(item); -- -- frame = &item->frame; -- -- nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec); -- -- rv = nghttp2_session_add_item(session, item); -- -- if (rv != 0) { -- nghttp2_frame_priority_free(&frame->priority); -- nghttp2_mem_free(mem, item); -- -- return rv; -- } -+ (void)stream_id; -+ (void)pri_spec; - - return 0; - } -@@ -277,7 +185,8 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags, - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - -- return nghttp2_session_add_rst_stream(session, stream_id, error_code); -+ return nghttp2_session_add_rst_stream_continue( -+ session, stream_id, error_code, /* continue_without_stream = */ 0); - } - - int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags, -@@ -578,7 +487,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, - return 0; - - fail_item_malloc: -- free(buf); -+ nghttp2_mem_free(mem, buf); - - return rv; - } -@@ -661,7 +570,7 @@ int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags, - return 0; - - fail_item_malloc: -- free(ov_copy); -+ nghttp2_mem_free(mem, ov_copy); - - return rv; - } -@@ -733,51 +642,34 @@ int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags, - return 0; - - fail_item_malloc: -- free(buf); -+ nghttp2_mem_free(mem, buf); - - return rv; - } - --static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec, -- const nghttp2_data_provider_wrap *dpw) { -+static uint8_t set_request_flags(const nghttp2_data_provider_wrap *dpw) { - uint8_t flags = NGHTTP2_FLAG_NONE; - if (dpw == NULL || dpw->data_prd.read_callback == NULL) { - flags |= NGHTTP2_FLAG_END_STREAM; - } - -- if (pri_spec) { -- flags |= NGHTTP2_FLAG_PRIORITY; -- } -- - return flags; - } - - static int32_t submit_request_shared(nghttp2_session *session, -- const nghttp2_priority_spec *pri_spec, - const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider_wrap *dpw, - void *stream_user_data) { - uint8_t flags; -- int rv; - - if (session->server) { - return NGHTTP2_ERR_PROTO; - } - -- 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; -- } -- } else { -- pri_spec = NULL; -- } -- -- flags = set_request_flags(pri_spec, dpw); -+ flags = set_request_flags(dpw); - -- return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen, -- dpw, stream_user_data); -+ return submit_headers_shared_nva(session, flags, -1, nva, nvlen, dpw, -+ stream_user_data); - } - - int32_t nghttp2_submit_request(nghttp2_session *session, -@@ -786,8 +678,9 @@ int32_t nghttp2_submit_request(nghttp2_session *session, - const nghttp2_data_provider *data_prd, - void *stream_user_data) { - nghttp2_data_provider_wrap dpw; -+ (void)pri_spec; - -- return submit_request_shared(session, pri_spec, nva, nvlen, -+ return submit_request_shared(session, nva, nvlen, - nghttp2_data_provider_wrap_v1(&dpw, data_prd), - stream_user_data); - } -@@ -798,8 +691,9 @@ int32_t nghttp2_submit_request2(nghttp2_session *session, - const nghttp2_data_provider2 *data_prd, - void *stream_user_data) { - nghttp2_data_provider_wrap dpw; -+ (void)pri_spec; - -- return submit_request_shared(session, pri_spec, nva, nvlen, -+ return submit_request_shared(session, nva, nvlen, - nghttp2_data_provider_wrap_v2(&dpw, data_prd), - stream_user_data); - } -@@ -826,8 +720,8 @@ static int submit_response_shared(nghttp2_session *session, int32_t stream_id, - } - - flags = set_response_flags(dpw); -- return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen, -- dpw, NULL); -+ return submit_headers_shared_nva(session, flags, stream_id, nva, nvlen, dpw, -+ NULL); - } - - int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, -diff --git a/deps/nghttp2/lib/nghttp2_submit.h b/deps/nghttp2/lib/nghttp2_submit.h -index 350ee022..decf803d 100644 ---- a/deps/nghttp2/lib/nghttp2_submit.h -+++ b/deps/nghttp2/lib/nghttp2_submit.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -37,4 +37,4 @@ int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags, - int32_t stream_id, - const nghttp2_data_provider_wrap *dpw); - --#endif /* NGHTTP2_SUBMIT_H */ -+#endif /* !defined(NGHTTP2_SUBMIT_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_time.c b/deps/nghttp2/lib/nghttp2_time.c -index 148ccfdc..18fd7bca 100644 ---- a/deps/nghttp2/lib/nghttp2_time.c -+++ b/deps/nghttp2/lib/nghttp2_time.c -@@ -26,7 +26,7 @@ - - #ifdef HAVE_WINDOWS_H - # include --#endif /* HAVE_WINDOWS_H */ -+#endif /* defined(HAVE_WINDOWS_H) */ - - #include - -@@ -40,12 +40,11 @@ static uint64_t time_now_sec(void) { - - return (uint64_t)t; - } --#endif /* !HAVE_GETTICKCOUNT64 || __CYGWIN__ */ -+#endif /* !defined(HAVE_GETTICKCOUNT64) || defined(__CYGWIN__) */ - - #if defined(HAVE_GETTICKCOUNT64) && !defined(__CYGWIN__) - uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; } --#elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_DECL_CLOCK_MONOTONIC) && \ -- HAVE_DECL_CLOCK_MONOTONIC -+#elif defined(HAVE_CLOCK_GETTIME) && HAVE_DECL_CLOCK_MONOTONIC - uint64_t nghttp2_time_now_sec(void) { - struct timespec tp; - int rv = clock_gettime(CLOCK_MONOTONIC, &tp); -@@ -56,8 +55,8 @@ uint64_t nghttp2_time_now_sec(void) { - - return (uint64_t)tp.tv_sec; - } --#else /* (!HAVE_CLOCK_GETTIME || !HAVE_DECL_CLOCK_MONOTONIC) && \ -- (!HAVE_GETTICKCOUNT64 || __CYGWIN__)) */ -+#else /* (!defined(HAVE_GETTICKCOUNT64) || !defined(__CYGWIN__)) && \ -+ (!defined(HAVE_CLOCK_GETTIME) || !HAVE_DECL_CLOCK_MONOTONIC) */ - uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); } --#endif /* (!HAVE_CLOCK_GETTIME || !HAVE_DECL_CLOCK_MONOTONIC) && \ -- (!HAVE_GETTICKCOUNT64 || __CYGWIN__)) */ -+#endif /* (!defined(HAVE_GETTICKCOUNT64) || !defined(__CYGWIN__)) && \ -+ (!defined(HAVE_CLOCK_GETTIME) || !HAVE_DECL_CLOCK_MONOTONIC) */ -diff --git a/deps/nghttp2/lib/nghttp2_time.h b/deps/nghttp2/lib/nghttp2_time.h -index 03c0bbe9..a91e62ad 100644 ---- a/deps/nghttp2/lib/nghttp2_time.h -+++ b/deps/nghttp2/lib/nghttp2_time.h -@@ -27,7 +27,7 @@ - - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -@@ -35,4 +35,4 @@ - timepoint. If it is unable to get seconds, it returns 0. */ - uint64_t nghttp2_time_now_sec(void); - --#endif /* NGHTTP2_TIME_H */ -+#endif /* !defined(NGHTTP2_TIME_H) */ -diff --git a/deps/nghttp2/lib/nghttp2_version.c b/deps/nghttp2/lib/nghttp2_version.c -index 4211f2cf..39a49ff3 100644 ---- a/deps/nghttp2/lib/nghttp2_version.c -+++ b/deps/nghttp2/lib/nghttp2_version.c -@@ -24,7 +24,7 @@ - */ - #ifdef HAVE_CONFIG_H - # include --#endif /* HAVE_CONFIG_H */ -+#endif /* defined(HAVE_CONFIG_H) */ - - #include - -diff --git a/deps/nghttp2/lib/sfparse.c b/deps/nghttp2/lib/sfparse.c -index b5e94cc2..cee089d3 100644 ---- a/deps/nghttp2/lib/sfparse.c -+++ b/deps/nghttp2/lib/sfparse.c -@@ -30,38 +30,46 @@ - #include - #include - --#define SF_STATE_DICT 0x08u --#define SF_STATE_LIST 0x10u --#define SF_STATE_ITEM 0x18u -+#ifdef __AVX2__ -+# include -+#endif /* __AVX2__ */ - --#define SF_STATE_INNER_LIST 0x04u -+#define SFPARSE_STATE_DICT 0x08u -+#define SFPARSE_STATE_LIST 0x10u -+#define SFPARSE_STATE_ITEM 0x18u - --#define SF_STATE_BEFORE 0x00u --#define SF_STATE_BEFORE_PARAMS 0x01u --#define SF_STATE_PARAMS 0x02u --#define SF_STATE_AFTER 0x03u -+#define SFPARSE_STATE_INNER_LIST 0x04u - --#define SF_STATE_OP_MASK 0x03u -+#define SFPARSE_STATE_BEFORE 0x00u -+#define SFPARSE_STATE_BEFORE_PARAMS 0x01u -+#define SFPARSE_STATE_PARAMS 0x02u -+#define SFPARSE_STATE_AFTER 0x03u - --#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) --#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ -- (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) --#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ -- (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) -+#define SFPARSE_STATE_OP_MASK 0x03u - --#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) --#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) --#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) -+#define SFPARSE_SET_STATE_AFTER(NAME) \ -+ (SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER) -+#define SFPARSE_SET_STATE_BEFORE_PARAMS(NAME) \ -+ (SFPARSE_STATE_##NAME | SFPARSE_STATE_BEFORE_PARAMS) -+#define SFPARSE_SET_STATE_INNER_LIST_BEFORE(NAME) \ -+ (SFPARSE_STATE_##NAME | SFPARSE_STATE_INNER_LIST | SFPARSE_STATE_BEFORE) - --#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) --#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) --#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) -+#define SFPARSE_STATE_DICT_AFTER SFPARSE_SET_STATE_AFTER(DICT) -+#define SFPARSE_STATE_DICT_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(DICT) -+#define SFPARSE_STATE_DICT_INNER_LIST_BEFORE \ -+ SFPARSE_SET_STATE_INNER_LIST_BEFORE(DICT) - --#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) --#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) --#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) -+#define SFPARSE_STATE_LIST_AFTER SFPARSE_SET_STATE_AFTER(LIST) -+#define SFPARSE_STATE_LIST_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(LIST) -+#define SFPARSE_STATE_LIST_INNER_LIST_BEFORE \ -+ SFPARSE_SET_STATE_INNER_LIST_BEFORE(LIST) - --#define SF_STATE_INITIAL 0x00u -+#define SFPARSE_STATE_ITEM_AFTER SFPARSE_SET_STATE_AFTER(ITEM) -+#define SFPARSE_STATE_ITEM_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(ITEM) -+#define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \ -+ SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM) -+ -+#define SFPARSE_STATE_INITIAL 0x00u - - #define DIGIT_CASES \ - case '0': \ -@@ -135,6 +143,70 @@ - UCALPHA_CASES: \ - LCALPHA_CASES - -+#define TOKEN_CASES \ -+ case '!': \ -+ case '#': \ -+ case '$': \ -+ case '%': \ -+ case '&': \ -+ case '\'': \ -+ case '*': \ -+ case '+': \ -+ case '-': \ -+ case '.': \ -+ case '/': \ -+ DIGIT_CASES: \ -+ case ':': \ -+ UCALPHA_CASES: \ -+ case '^': \ -+ case '_': \ -+ case '`': \ -+ LCALPHA_CASES: \ -+ case '|': \ -+ case '~' -+ -+#define LCHEXALPHA_CASES \ -+ case 'a': \ -+ case 'b': \ -+ case 'c': \ -+ case 'd': \ -+ case 'e': \ -+ case 'f' -+ -+#define X00_1F_CASES \ -+ case 0x00: \ -+ case 0x01: \ -+ case 0x02: \ -+ case 0x03: \ -+ case 0x04: \ -+ case 0x05: \ -+ case 0x06: \ -+ case 0x07: \ -+ case 0x08: \ -+ case 0x09: \ -+ case 0x0a: \ -+ case 0x0b: \ -+ case 0x0c: \ -+ case 0x0d: \ -+ case 0x0e: \ -+ case 0x0f: \ -+ case 0x10: \ -+ case 0x11: \ -+ case 0x12: \ -+ case 0x13: \ -+ case 0x14: \ -+ case 0x15: \ -+ case 0x16: \ -+ case 0x17: \ -+ case 0x18: \ -+ case 0x19: \ -+ case 0x1a: \ -+ case 0x1b: \ -+ case 0x1c: \ -+ case 0x1d: \ -+ case 0x1e: \ -+ case 0x1f -+ - #define X20_21_CASES \ - case ' ': \ - case '!' -@@ -175,6 +247,137 @@ - case '}': \ - case '~' - -+#define X7F_FF_CASES \ -+ case 0x7f: \ -+ case 0x80: \ -+ case 0x81: \ -+ case 0x82: \ -+ case 0x83: \ -+ case 0x84: \ -+ case 0x85: \ -+ case 0x86: \ -+ case 0x87: \ -+ case 0x88: \ -+ case 0x89: \ -+ case 0x8a: \ -+ case 0x8b: \ -+ case 0x8c: \ -+ case 0x8d: \ -+ case 0x8e: \ -+ case 0x8f: \ -+ case 0x90: \ -+ case 0x91: \ -+ case 0x92: \ -+ case 0x93: \ -+ case 0x94: \ -+ case 0x95: \ -+ case 0x96: \ -+ case 0x97: \ -+ case 0x98: \ -+ case 0x99: \ -+ case 0x9a: \ -+ case 0x9b: \ -+ case 0x9c: \ -+ case 0x9d: \ -+ case 0x9e: \ -+ case 0x9f: \ -+ case 0xa0: \ -+ case 0xa1: \ -+ case 0xa2: \ -+ case 0xa3: \ -+ case 0xa4: \ -+ case 0xa5: \ -+ case 0xa6: \ -+ case 0xa7: \ -+ case 0xa8: \ -+ case 0xa9: \ -+ case 0xaa: \ -+ case 0xab: \ -+ case 0xac: \ -+ case 0xad: \ -+ case 0xae: \ -+ case 0xaf: \ -+ case 0xb0: \ -+ case 0xb1: \ -+ case 0xb2: \ -+ case 0xb3: \ -+ case 0xb4: \ -+ case 0xb5: \ -+ case 0xb6: \ -+ case 0xb7: \ -+ case 0xb8: \ -+ case 0xb9: \ -+ case 0xba: \ -+ case 0xbb: \ -+ case 0xbc: \ -+ case 0xbd: \ -+ case 0xbe: \ -+ case 0xbf: \ -+ case 0xc0: \ -+ case 0xc1: \ -+ case 0xc2: \ -+ case 0xc3: \ -+ case 0xc4: \ -+ case 0xc5: \ -+ case 0xc6: \ -+ case 0xc7: \ -+ case 0xc8: \ -+ case 0xc9: \ -+ case 0xca: \ -+ case 0xcb: \ -+ case 0xcc: \ -+ case 0xcd: \ -+ case 0xce: \ -+ case 0xcf: \ -+ case 0xd0: \ -+ case 0xd1: \ -+ case 0xd2: \ -+ case 0xd3: \ -+ case 0xd4: \ -+ case 0xd5: \ -+ case 0xd6: \ -+ case 0xd7: \ -+ case 0xd8: \ -+ case 0xd9: \ -+ case 0xda: \ -+ case 0xdb: \ -+ case 0xdc: \ -+ case 0xdd: \ -+ case 0xde: \ -+ case 0xdf: \ -+ case 0xe0: \ -+ case 0xe1: \ -+ case 0xe2: \ -+ case 0xe3: \ -+ case 0xe4: \ -+ case 0xe5: \ -+ case 0xe6: \ -+ case 0xe7: \ -+ case 0xe8: \ -+ case 0xe9: \ -+ case 0xea: \ -+ case 0xeb: \ -+ case 0xec: \ -+ case 0xed: \ -+ case 0xee: \ -+ case 0xef: \ -+ case 0xf0: \ -+ case 0xf1: \ -+ case 0xf2: \ -+ case 0xf3: \ -+ case 0xf4: \ -+ case 0xf5: \ -+ case 0xf6: \ -+ case 0xf7: \ -+ case 0xf8: \ -+ case 0xf9: \ -+ case 0xfa: \ -+ case 0xfb: \ -+ case 0xfc: \ -+ case 0xfd: \ -+ case 0xfe: \ -+ case 0xff -+ - static int is_ws(uint8_t c) { - switch (c) { - case ' ': -@@ -185,40 +388,108 @@ static int is_ws(uint8_t c) { - } - } - --static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } -+#ifdef __AVX2__ -+# ifdef _MSC_VER -+# include -+ -+static int ctz(unsigned int v) { -+ unsigned long n; -+ -+ /* Assume that v is not 0. */ -+ _BitScanForward(&n, v); -+ -+ return (int)n; -+} -+# else /* !_MSC_VER */ -+# define ctz __builtin_ctz -+# endif /* !_MSC_VER */ -+#endif /* __AVX2__ */ -+ -+static int parser_eof(sfparse_parser *sfp) { return sfp->pos == sfp->end; } - --static void parser_discard_ows(sf_parser *sfp) { -+static void parser_discard_ows(sfparse_parser *sfp) { - for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) - ; - } - --static void parser_discard_sp(sf_parser *sfp) { -+static void parser_discard_sp(sfparse_parser *sfp) { - for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) - ; - } - --static void parser_set_op_state(sf_parser *sfp, uint32_t op) { -- sfp->state &= ~SF_STATE_OP_MASK; -+static void parser_set_op_state(sfparse_parser *sfp, uint32_t op) { -+ sfp->state &= ~SFPARSE_STATE_OP_MASK; - sfp->state |= op; - } - --static void parser_unset_inner_list_state(sf_parser *sfp) { -- sfp->state &= ~SF_STATE_INNER_LIST; -+static void parser_unset_inner_list_state(sfparse_parser *sfp) { -+ sfp->state &= ~SFPARSE_STATE_INNER_LIST; - } - --static int parser_key(sf_parser *sfp, sf_vec *dest) { -+#ifdef __AVX2__ -+static const uint8_t *find_char_key(const uint8_t *first, const uint8_t *last) { -+ const __m256i us = _mm256_set1_epi8('_'); -+ const __m256i ds = _mm256_set1_epi8('-'); -+ const __m256i dot = _mm256_set1_epi8('.'); -+ const __m256i ast = _mm256_set1_epi8('*'); -+ const __m256i r0l = _mm256_set1_epi8('0' - 1); -+ const __m256i r0r = _mm256_set1_epi8('9' + 1); -+ const __m256i r1l = _mm256_set1_epi8('a' - 1); -+ const __m256i r1r = _mm256_set1_epi8('z' + 1); -+ __m256i s, x; -+ uint32_t m; -+ -+ for (; first != last; first += 32) { -+ s = _mm256_loadu_si256((void *)first); -+ -+ x = _mm256_cmpeq_epi8(s, us); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ds), x); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dot), x); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ast), x); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), -+ x); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), -+ x); -+ -+ m = ~(uint32_t)_mm256_movemask_epi8(x); -+ if (m) { -+ return first + ctz(m); -+ } -+ } -+ -+ return last; -+} -+#endif /* __AVX2__ */ -+ -+static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) { - const uint8_t *base; -+#ifdef __AVX2__ -+ const uint8_t *last; -+#endif /* __AVX2__ */ - - switch (*sfp->pos) { - case '*': - LCALPHA_CASES: - break; - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - base = sfp->pos++; - -+#ifdef __AVX2__ -+ if (sfp->end - sfp->pos >= 32) { -+ last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); -+ -+ sfp->pos = find_char_key(sfp->pos, last); -+ if (sfp->pos != last) { -+ goto fin; -+ } -+ } -+#endif /* __AVX2__ */ -+ - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - case '_': -@@ -233,6 +504,9 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { - break; - } - -+#ifdef __AVX2__ -+fin: -+#endif /* __AVX2__ */ - if (dest) { - dest->base = (uint8_t *)base; - dest->len = (size_t)(sfp->pos - dest->base); -@@ -241,7 +515,7 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { - return 0; - } - --static int parser_number(sf_parser *sfp, sf_value *dest) { -+static int parser_number(sfparse_parser *sfp, sfparse_value *dest) { - int sign = 1; - int64_t value = 0; - size_t len = 0; -@@ -250,7 +524,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - if (*sfp->pos == '-') { - ++sfp->pos; - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - sign = -1; -@@ -262,7 +536,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - switch (*sfp->pos) { - DIGIT_CASES: - if (++len > 15) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - value *= 10; -@@ -275,13 +549,13 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - } - - if (len == 0) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - if (parser_eof(sfp) || *sfp->pos != '.') { - if (dest) { -- dest->type = SF_TYPE_INTEGER; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_INTEGER; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->integer = value * sign; - } - -@@ -291,7 +565,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - /* decimal */ - - if (len > 12) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - fpos = len; -@@ -302,7 +576,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - switch (*sfp->pos) { - DIGIT_CASES: - if (++len > 15) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - value *= 10; -@@ -315,12 +589,12 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - } - - if (fpos == len || len - fpos > 3) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - if (dest) { -- dest->type = SF_TYPE_DECIMAL; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_DECIMAL; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->decimal.numer = value * sign; - - switch (len - fpos) { -@@ -342,9 +616,9 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { - return 0; - } - --static int parser_date(sf_parser *sfp, sf_value *dest) { -+static int parser_date(sfparse_parser *sfp, sfparse_value *dest) { - int rv; -- sf_value val; -+ sfparse_value val; - - /* The first byte has already been validated by the caller. */ - assert('@' == *sfp->pos); -@@ -352,7 +626,7 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { - ++sfp->pos; - - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - rv = parser_number(sfp, &val); -@@ -360,27 +634,93 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { - return rv; - } - -- if (val.type != SF_TYPE_INTEGER) { -- return SF_ERR_PARSE_ERROR; -+ if (val.type != SFPARSE_TYPE_INTEGER) { -+ return SFPARSE_ERR_PARSE; - } - - if (dest) { - *dest = val; -- dest->type = SF_TYPE_DATE; -+ dest->type = SFPARSE_TYPE_DATE; - } - - return 0; - } - --static int parser_string(sf_parser *sfp, sf_value *dest) { -+#ifdef __AVX2__ -+static const uint8_t *find_char_string(const uint8_t *first, -+ const uint8_t *last) { -+ const __m256i bs = _mm256_set1_epi8('\\'); -+ const __m256i dq = _mm256_set1_epi8('"'); -+ const __m256i del = _mm256_set1_epi8(0x7f); -+ const __m256i sp = _mm256_set1_epi8(' '); -+ __m256i s, x; -+ uint32_t m; -+ -+ for (; first != last; first += 32) { -+ s = _mm256_loadu_si256((void *)first); -+ -+ x = _mm256_cmpgt_epi8(sp, s); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, bs), x); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dq), x); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, del), x); -+ -+ m = (uint32_t)_mm256_movemask_epi8(x); -+ if (m) { -+ return first + ctz(m); -+ } -+ } -+ -+ return last; -+} -+#endif /* __AVX2__ */ -+ -+static int parser_string(sfparse_parser *sfp, sfparse_value *dest) { - const uint8_t *base; -- uint32_t flags = SF_VALUE_FLAG_NONE; -+#ifdef __AVX2__ -+ const uint8_t *last; -+#endif /* __AVX2__ */ -+ uint32_t flags = SFPARSE_VALUE_FLAG_NONE; - - /* The first byte has already been validated by the caller. */ - assert('"' == *sfp->pos); - - base = ++sfp->pos; - -+#ifdef __AVX2__ -+ for (; sfp->end - sfp->pos >= 32; ++sfp->pos) { -+ last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); -+ -+ sfp->pos = find_char_string(sfp->pos, last); -+ if (sfp->pos == last) { -+ break; -+ } -+ -+ switch (*sfp->pos) { -+ case '\\': -+ ++sfp->pos; -+ if (parser_eof(sfp)) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ switch (*sfp->pos) { -+ case '"': -+ case '\\': -+ flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; -+ -+ break; -+ default: -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ break; -+ case '"': -+ goto fin; -+ default: -+ return SFPARSE_ERR_PARSE; -+ } -+ } -+#endif /* __AVX2__ */ -+ - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - X20_21_CASES: -@@ -390,75 +730,131 @@ static int parser_string(sf_parser *sfp, sf_value *dest) { - case '\\': - ++sfp->pos; - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - switch (*sfp->pos) { - case '"': - case '\\': -- flags = SF_VALUE_FLAG_ESCAPED_STRING; -+ flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; - - break; - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - break; - case '"': -- if (dest) { -- dest->type = SF_TYPE_STRING; -- dest->flags = flags; -- dest->vec.len = (size_t)(sfp->pos - base); -- dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; -- } -+ goto fin; -+ default: -+ return SFPARSE_ERR_PARSE; -+ } -+ } - -- ++sfp->pos; -+ return SFPARSE_ERR_PARSE; - -- return 0; -- default: -- return SF_ERR_PARSE_ERROR; -+fin: -+ if (dest) { -+ dest->type = SFPARSE_TYPE_STRING; -+ dest->flags = flags; -+ dest->vec.len = (size_t)(sfp->pos - base); -+ dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; -+ } -+ -+ ++sfp->pos; -+ -+ return 0; -+} -+ -+#ifdef __AVX2__ -+static const uint8_t *find_char_token(const uint8_t *first, -+ const uint8_t *last) { -+ /* r0: !..:, excluding "(), -+ r1: A..Z -+ r2: ^..~, excluding {} */ -+ const __m256i r0l = _mm256_set1_epi8('!' - 1); -+ const __m256i r0r = _mm256_set1_epi8(':' + 1); -+ const __m256i dq = _mm256_set1_epi8('"'); -+ const __m256i prl = _mm256_set1_epi8('('); -+ const __m256i prr = _mm256_set1_epi8(')'); -+ const __m256i comma = _mm256_set1_epi8(','); -+ const __m256i r1l = _mm256_set1_epi8('A' - 1); -+ const __m256i r1r = _mm256_set1_epi8('Z' + 1); -+ const __m256i r2l = _mm256_set1_epi8('^' - 1); -+ const __m256i r2r = _mm256_set1_epi8('~' + 1); -+ const __m256i cbl = _mm256_set1_epi8('{'); -+ const __m256i cbr = _mm256_set1_epi8('}'); -+ __m256i s, x; -+ uint32_t m; -+ -+ for (; first != last; first += 32) { -+ s = _mm256_loadu_si256((void *)first); -+ -+ x = _mm256_andnot_si256( -+ _mm256_cmpeq_epi8(s, comma), -+ _mm256_andnot_si256( -+ _mm256_cmpeq_epi8(s, prr), -+ _mm256_andnot_si256( -+ _mm256_cmpeq_epi8(s, prl), -+ _mm256_andnot_si256(_mm256_cmpeq_epi8(s, dq), -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), -+ _mm256_cmpgt_epi8(r0r, s)))))); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), -+ x); -+ x = _mm256_or_si256( -+ _mm256_andnot_si256( -+ _mm256_cmpeq_epi8(s, cbr), -+ _mm256_andnot_si256(_mm256_cmpeq_epi8(s, cbl), -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), -+ _mm256_cmpgt_epi8(r2r, s)))), -+ x); -+ -+ m = ~(uint32_t)_mm256_movemask_epi8(x); -+ if (m) { -+ return first + ctz(m); - } - } - -- return SF_ERR_PARSE_ERROR; -+ return last; - } -+#endif /* __AVX2__ */ - --static int parser_token(sf_parser *sfp, sf_value *dest) { -+static int parser_token(sfparse_parser *sfp, sfparse_value *dest) { - const uint8_t *base; -+#ifdef __AVX2__ -+ const uint8_t *last; -+#endif /* __AVX2__ */ - - /* The first byte has already been validated by the caller. */ - base = sfp->pos++; - -+#ifdef __AVX2__ -+ if (sfp->end - sfp->pos >= 32) { -+ last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); -+ -+ sfp->pos = find_char_token(sfp->pos, last); -+ if (sfp->pos != last) { -+ goto fin; -+ } -+ } -+#endif /* __AVX2__ */ -+ - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { -- case '!': -- case '#': -- case '$': -- case '%': -- case '&': -- case '\'': -- case '*': -- case '+': -- case '-': -- case '.': -- case '^': -- case '_': -- case '`': -- case '|': -- case '~': -- case ':': -- case '/': -- DIGIT_CASES: -- ALPHA_CASES: -+ TOKEN_CASES: - continue; - } - - break; - } - -+#ifdef __AVX2__ -+fin: -+#endif /* __AVX2__ */ - if (dest) { -- dest->type = SF_TYPE_TOKEN; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_TOKEN; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->vec.base = (uint8_t *)base; - dest->vec.len = (size_t)(sfp->pos - base); - } -@@ -466,14 +862,63 @@ static int parser_token(sf_parser *sfp, sf_value *dest) { - return 0; - } - --static int parser_byteseq(sf_parser *sfp, sf_value *dest) { -+#ifdef __AVX2__ -+static const uint8_t *find_char_byteseq(const uint8_t *first, -+ const uint8_t *last) { -+ const __m256i pls = _mm256_set1_epi8('+'); -+ const __m256i fs = _mm256_set1_epi8('/'); -+ const __m256i r0l = _mm256_set1_epi8('0' - 1); -+ const __m256i r0r = _mm256_set1_epi8('9' + 1); -+ const __m256i r1l = _mm256_set1_epi8('A' - 1); -+ const __m256i r1r = _mm256_set1_epi8('Z' + 1); -+ const __m256i r2l = _mm256_set1_epi8('a' - 1); -+ const __m256i r2r = _mm256_set1_epi8('z' + 1); -+ __m256i s, x; -+ uint32_t m; -+ -+ for (; first != last; first += 32) { -+ s = _mm256_loadu_si256((void *)first); -+ -+ x = _mm256_cmpeq_epi8(s, pls); -+ x = _mm256_or_si256(_mm256_cmpeq_epi8(s, fs), x); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), -+ x); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), -+ x); -+ x = _mm256_or_si256( -+ _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), _mm256_cmpgt_epi8(r2r, s)), -+ x); -+ -+ m = ~(uint32_t)_mm256_movemask_epi8(x); -+ if (m) { -+ return first + ctz(m); -+ } -+ } -+ -+ return last; -+} -+#endif /* __AVX2__ */ -+ -+static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) { - const uint8_t *base; -+#ifdef __AVX2__ -+ const uint8_t *last; -+#endif /* __AVX2__ */ - - /* The first byte has already been validated by the caller. */ - assert(':' == *sfp->pos); - - base = ++sfp->pos; - -+#ifdef __AVX2__ -+ if (sfp->end - sfp->pos >= 32) { -+ last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); -+ sfp->pos = find_char_byteseq(sfp->pos, last); -+ } -+#endif /* __AVX2__ */ -+ - for (; !parser_eof(sfp); ++sfp->pos) { - switch (*sfp->pos) { - case '+': -@@ -485,75 +930,47 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { - switch ((sfp->pos - base) & 0x3) { - case 0: - case 1: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - case 2: -- switch (*(sfp->pos - 1)) { -- case 'A': -- case 'Q': -- case 'g': -- case 'w': -- break; -- default: -- return SF_ERR_PARSE_ERROR; -- } -- - ++sfp->pos; - -- if (parser_eof(sfp) || *sfp->pos != '=') { -- return SF_ERR_PARSE_ERROR; -+ if (parser_eof(sfp)) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ if (*sfp->pos == '=') { -+ ++sfp->pos; - } - - break; - case 3: -- switch (*(sfp->pos - 1)) { -- case 'A': -- case 'E': -- case 'I': -- case 'M': -- case 'Q': -- case 'U': -- case 'Y': -- case 'c': -- case 'g': -- case 'k': -- case 'o': -- case 's': -- case 'w': -- case '0': -- case '4': -- case '8': -- break; -- default: -- return SF_ERR_PARSE_ERROR; -- } -+ ++sfp->pos; - - break; - } - -- ++sfp->pos; -- - if (parser_eof(sfp) || *sfp->pos != ':') { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - goto fin; - case ':': -- if ((sfp->pos - base) & 0x3) { -- return SF_ERR_PARSE_ERROR; -+ if (((sfp->pos - base) & 0x3) == 1) { -+ return SFPARSE_ERR_PARSE; - } - - goto fin; - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - } - -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - - fin: - if (dest) { -- dest->type = SF_TYPE_BYTESEQ; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_BYTESEQ; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->vec.len = (size_t)(sfp->pos - base); - dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; - } -@@ -563,7 +980,7 @@ fin: - return 0; - } - --static int parser_boolean(sf_parser *sfp, sf_value *dest) { -+static int parser_boolean(sfparse_parser *sfp, sfparse_value *dest) { - int b; - - /* The first byte has already been validated by the caller. */ -@@ -572,7 +989,7 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { - ++sfp->pos; - - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - switch (*sfp->pos) { -@@ -585,21 +1002,184 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { - - break; - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - ++sfp->pos; - - if (dest) { -- dest->type = SF_TYPE_BOOLEAN; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_BOOLEAN; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->boolean = b; - } - - return 0; - } - --static int parser_bare_item(sf_parser *sfp, sf_value *dest) { -+static int pctdecode(uint8_t *pc, const uint8_t **ppos) { -+ uint8_t c, b = **ppos; -+ -+ switch (b) { -+ DIGIT_CASES: -+ c = (uint8_t)((b - '0') << 4); -+ -+ break; -+ LCHEXALPHA_CASES: -+ c = (uint8_t)((b - 'a' + 10) << 4); -+ -+ break; -+ default: -+ return -1; -+ } -+ -+ b = *++*ppos; -+ -+ switch (b) { -+ DIGIT_CASES: -+ c |= (uint8_t)(b - '0'); -+ -+ break; -+ LCHEXALPHA_CASES: -+ c |= (uint8_t)(b - 'a' + 10); -+ -+ break; -+ default: -+ return -1; -+ } -+ -+ *pc = c; -+ ++*ppos; -+ -+ return 0; -+} -+ -+/* Start of utf8 dfa */ -+/* Copyright (c) 2008-2010 Bjoern Hoehrmann -+ * See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. -+ * -+ * Copyright (c) 2008-2009 Bjoern Hoehrmann -+ * -+ * 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. -+ */ -+#define UTF8_ACCEPT 0 -+#define UTF8_REJECT 12 -+ -+/* clang-format off */ -+static const uint8_t utf8d[] = { -+ /* -+ * The first part of the table maps bytes to character classes that -+ * to reduce the size of the transition table and create bitmasks. -+ */ -+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, -+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, -+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, -+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, -+ -+ /* -+ * The second part is a transition table that maps a combination -+ * of a state of the automaton and a character class to a state. -+ */ -+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, -+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, -+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, -+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, -+ 12,36,12,12,12,12,12,12,12,12,12,12, -+}; -+/* clang-format on */ -+ -+static void utf8_decode(uint32_t *state, uint8_t byte) { -+ *state = utf8d[256 + *state + utf8d[byte]]; -+} -+ -+/* End of utf8 dfa */ -+ -+static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) { -+ const uint8_t *base; -+ uint8_t c; -+ uint32_t utf8state = UTF8_ACCEPT; -+ -+ assert('%' == *sfp->pos); -+ -+ ++sfp->pos; -+ -+ if (parser_eof(sfp) || *sfp->pos != '"') { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ base = ++sfp->pos; -+ -+ for (; !parser_eof(sfp);) { -+ switch (*sfp->pos) { -+ X00_1F_CASES: -+ X7F_FF_CASES: -+ return SFPARSE_ERR_PARSE; -+ case '%': -+ ++sfp->pos; -+ -+ if (sfp->pos + 2 > sfp->end) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ if (pctdecode(&c, &sfp->pos) != 0) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ utf8_decode(&utf8state, c); -+ if (utf8state == UTF8_REJECT) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ break; -+ case '"': -+ if (utf8state != UTF8_ACCEPT) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ if (dest) { -+ dest->type = SFPARSE_TYPE_DISPSTRING; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; -+ dest->vec.len = (size_t)(sfp->pos - base); -+ dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; -+ } -+ -+ ++sfp->pos; -+ -+ return 0; -+ default: -+ if (utf8state != UTF8_ACCEPT) { -+ return SFPARSE_ERR_PARSE; -+ } -+ -+ ++sfp->pos; -+ } -+ } -+ -+ return SFPARSE_ERR_PARSE; -+} -+ -+static int parser_bare_item(sfparse_parser *sfp, sfparse_value *dest) { - switch (*sfp->pos) { - case '"': - return parser_string(sfp, dest); -@@ -615,29 +1195,32 @@ static int parser_bare_item(sf_parser *sfp, sf_value *dest) { - case '*': - ALPHA_CASES: - return parser_token(sfp, dest); -+ case '%': -+ return parser_dispstring(sfp, dest); - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - } - --static int parser_skip_inner_list(sf_parser *sfp); -+static int parser_skip_inner_list(sfparse_parser *sfp); - --int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { -+int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, -+ sfparse_value *dest_value) { - int rv; - -- switch (sfp->state & SF_STATE_OP_MASK) { -- case SF_STATE_BEFORE: -+ switch (sfp->state & SFPARSE_STATE_OP_MASK) { -+ case SFPARSE_STATE_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_BEFORE_PARAMS: -- parser_set_op_state(sfp, SF_STATE_PARAMS); -+ case SFPARSE_STATE_BEFORE_PARAMS: -+ parser_set_op_state(sfp, SFPARSE_STATE_PARAMS); - - break; -- case SF_STATE_PARAMS: -+ case SFPARSE_STATE_PARAMS: - break; - default: - assert(0); -@@ -645,16 +1228,16 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - } - - if (parser_eof(sfp) || *sfp->pos != ';') { -- parser_set_op_state(sfp, SF_STATE_AFTER); -+ parser_set_op_state(sfp, SFPARSE_STATE_AFTER); - -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - } - - ++sfp->pos; - - parser_discard_sp(sfp); - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - rv = parser_key(sfp, dest_key); -@@ -664,8 +1247,8 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - - if (parser_eof(sfp) || *sfp->pos != '=') { - if (dest_value) { -- dest_value->type = SF_TYPE_BOOLEAN; -- dest_value->flags = SF_VALUE_FLAG_NONE; -+ dest_value->type = SFPARSE_TYPE_BOOLEAN; -+ dest_value->flags = SFPARSE_VALUE_FLAG_NONE; - dest_value->boolean = 1; - } - -@@ -675,23 +1258,23 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - ++sfp->pos; - - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - return parser_bare_item(sfp, dest_value); - } - --static int parser_skip_params(sf_parser *sfp) { -+static int parser_skip_params(sfparse_parser *sfp) { - int rv; - - for (;;) { -- rv = sf_parser_param(sfp, NULL, NULL); -+ rv = sfparse_parser_param(sfp, NULL, NULL); - switch (rv) { - case 0: - break; -- case SF_ERR_EOF: -+ case SFPARSE_ERR_EOF: - return 0; -- case SF_ERR_PARSE_ERROR: -+ case SFPARSE_ERR_PARSE: - return rv; - default: - assert(0); -@@ -700,45 +1283,45 @@ static int parser_skip_params(sf_parser *sfp) { - } - } - --int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { -+int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest) { - int rv; - -- switch (sfp->state & SF_STATE_OP_MASK) { -- case SF_STATE_BEFORE: -+ switch (sfp->state & SFPARSE_STATE_OP_MASK) { -+ case SFPARSE_STATE_BEFORE: - parser_discard_sp(sfp); - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - break; -- case SF_STATE_BEFORE_PARAMS: -+ case SFPARSE_STATE_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - -- /* Technically, we are entering SF_STATE_AFTER, but we will set -+ /* Technically, we are entering SFPARSE_STATE_AFTER, but we will set - another state without reading the state. */ -- /* parser_set_op_state(sfp, SF_STATE_AFTER); */ -+ /* parser_set_op_state(sfp, SFPARSE_STATE_AFTER); */ - - /* fall through */ -- case SF_STATE_AFTER: -+ case SFPARSE_STATE_AFTER: - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - switch (*sfp->pos) { - case ' ': - parser_discard_sp(sfp); - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - break; - case ')': - break; - default: -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - break; -@@ -751,9 +1334,9 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { - ++sfp->pos; - - parser_unset_inner_list_state(sfp); -- parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); -+ parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); - -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - } - - rv = parser_bare_item(sfp, dest); -@@ -761,22 +1344,22 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { - return rv; - } - -- parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); -+ parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); - - return 0; - } - --static int parser_skip_inner_list(sf_parser *sfp) { -+static int parser_skip_inner_list(sfparse_parser *sfp) { - int rv; - - for (;;) { -- rv = sf_parser_inner_list(sfp, NULL); -+ rv = sfparse_parser_inner_list(sfp, NULL); - switch (rv) { - case 0: - break; -- case SF_ERR_EOF: -+ case SFPARSE_ERR_EOF: - return 0; -- case SF_ERR_PARSE_ERROR: -+ case SFPARSE_ERR_PARSE: - return rv; - default: - assert(0); -@@ -785,39 +1368,39 @@ static int parser_skip_inner_list(sf_parser *sfp) { - } - } - --static int parser_next_key_or_item(sf_parser *sfp) { -+static int parser_next_key_or_item(sfparse_parser *sfp) { - parser_discard_ows(sfp); - - if (parser_eof(sfp)) { -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - } - - if (*sfp->pos != ',') { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - ++sfp->pos; - - parser_discard_ows(sfp); - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - return 0; - } - --static int parser_dict_value(sf_parser *sfp, sf_value *dest) { -+static int parser_dict_value(sfparse_parser *sfp, sfparse_value *dest) { - int rv; - - if (parser_eof(sfp) || *(sfp->pos) != '=') { - /* Boolean true */ - if (dest) { -- dest->type = SF_TYPE_BOOLEAN; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_BOOLEAN; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - dest->boolean = 1; - } - -- sfp->state = SF_STATE_DICT_BEFORE_PARAMS; -+ sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; - - return 0; - } -@@ -825,18 +1408,18 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { - ++sfp->pos; - - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - if (*sfp->pos == '(') { - if (dest) { -- dest->type = SF_TYPE_INNER_LIST; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_INNER_LIST; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - } - - ++sfp->pos; - -- sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; -+ sfp->state = SFPARSE_STATE_DICT_INNER_LIST_BEFORE; - - return 0; - } -@@ -846,41 +1429,42 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { - return rv; - } - -- sfp->state = SF_STATE_DICT_BEFORE_PARAMS; -+ sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; - - return 0; - } - --int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { -+int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, -+ sfparse_value *dest_value) { - int rv; - - switch (sfp->state) { -- case SF_STATE_DICT_INNER_LIST_BEFORE: -+ case SFPARSE_STATE_DICT_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_DICT_BEFORE_PARAMS: -+ case SFPARSE_STATE_DICT_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_DICT_AFTER: -+ case SFPARSE_STATE_DICT_AFTER: - rv = parser_next_key_or_item(sfp); - if (rv != 0) { - return rv; - } - - break; -- case SF_STATE_INITIAL: -+ case SFPARSE_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - } - - break; -@@ -897,36 +1481,36 @@ int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { - return parser_dict_value(sfp, dest_value); - } - --int sf_parser_list(sf_parser *sfp, sf_value *dest) { -+int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest) { - int rv; - - switch (sfp->state) { -- case SF_STATE_LIST_INNER_LIST_BEFORE: -+ case SFPARSE_STATE_LIST_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_LIST_BEFORE_PARAMS: -+ case SFPARSE_STATE_LIST_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_LIST_AFTER: -+ case SFPARSE_STATE_LIST_AFTER: - rv = parser_next_key_or_item(sfp); - if (rv != 0) { - return rv; - } - - break; -- case SF_STATE_INITIAL: -+ case SFPARSE_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - } - - break; -@@ -937,13 +1521,13 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { - - if (*sfp->pos == '(') { - if (dest) { -- dest->type = SF_TYPE_INNER_LIST; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_INNER_LIST; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - } - - ++sfp->pos; - -- sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; -+ sfp->state = SFPARSE_STATE_LIST_INNER_LIST_BEFORE; - - return 0; - } -@@ -953,45 +1537,45 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { - return rv; - } - -- sfp->state = SF_STATE_LIST_BEFORE_PARAMS; -+ sfp->state = SFPARSE_STATE_LIST_BEFORE_PARAMS; - - return 0; - } - --int sf_parser_item(sf_parser *sfp, sf_value *dest) { -+int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest) { - int rv; - - switch (sfp->state) { -- case SF_STATE_INITIAL: -+ case SFPARSE_STATE_INITIAL: - parser_discard_sp(sfp); - - if (parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - - break; -- case SF_STATE_ITEM_INNER_LIST_BEFORE: -+ case SFPARSE_STATE_ITEM_INNER_LIST_BEFORE: - rv = parser_skip_inner_list(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_ITEM_BEFORE_PARAMS: -+ case SFPARSE_STATE_ITEM_BEFORE_PARAMS: - rv = parser_skip_params(sfp); - if (rv != 0) { - return rv; - } - - /* fall through */ -- case SF_STATE_ITEM_AFTER: -+ case SFPARSE_STATE_ITEM_AFTER: - parser_discard_sp(sfp); - - if (!parser_eof(sfp)) { -- return SF_ERR_PARSE_ERROR; -+ return SFPARSE_ERR_PARSE; - } - -- return SF_ERR_EOF; -+ return SFPARSE_ERR_EOF; - default: - assert(0); - abort(); -@@ -999,13 +1583,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { - - if (*sfp->pos == '(') { - if (dest) { -- dest->type = SF_TYPE_INNER_LIST; -- dest->flags = SF_VALUE_FLAG_NONE; -+ dest->type = SFPARSE_TYPE_INNER_LIST; -+ dest->flags = SFPARSE_VALUE_FLAG_NONE; - } - - ++sfp->pos; - -- sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; -+ sfp->state = SFPARSE_STATE_ITEM_INNER_LIST_BEFORE; - - return 0; - } -@@ -1015,12 +1599,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { - return rv; - } - -- sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; -+ sfp->state = SFPARSE_STATE_ITEM_BEFORE_PARAMS; - - return 0; - } - --void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { -+void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, -+ size_t datalen) { - if (datalen == 0) { - sfp->pos = sfp->end = NULL; - } else { -@@ -1028,16 +1613,16 @@ void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { - sfp->end = data + datalen; - } - -- sfp->state = SF_STATE_INITIAL; -+ sfp->state = SFPARSE_STATE_INITIAL; - } - --void sf_unescape(sf_vec *dest, const sf_vec *src) { -+void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src) { - const uint8_t *p, *q; - uint8_t *o; - size_t len, slen; - - if (src->len == 0) { -- *dest = *src; -+ dest->len = 0; - - return; - } -@@ -1049,16 +1634,12 @@ void sf_unescape(sf_vec *dest, const sf_vec *src) { - for (;;) { - q = memchr(p, '\\', len); - if (q == NULL) { -- if (len == src->len) { -- *dest = *src; -- -- return; -- } -- - memcpy(o, p, len); - o += len; - -- break; -+ dest->len = (size_t)(o - dest->base); -+ -+ return; - } - - slen = (size_t)(q - p); -@@ -1069,11 +1650,9 @@ void sf_unescape(sf_vec *dest, const sf_vec *src) { - *o++ = *p++; - len -= slen + 2; - } -- -- dest->len = (size_t)(o - dest->base); - } - --void sf_base64decode(sf_vec *dest, const sf_vec *src) { -+void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) { - static const int index_tbl[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -@@ -1092,20 +1671,22 @@ void sf_base64decode(sf_vec *dest, const sf_vec *src) { - uint8_t *o; - const uint8_t *p, *end; - uint32_t n; -- size_t i; -+ size_t i, left; - int idx; - -- assert((src->len & 0x3) == 0); -- - if (src->len == 0) { -- *dest = *src; -+ dest->len = 0; - - return; - } - - o = dest->base; - p = src->base; -- end = src->base + src->len; -+ left = src->len & 0x3; -+ if (left == 0 && src->base[src->len - 1] == '=') { -+ left = 4; -+ } -+ end = src->base + src->len - left; - - for (; p != end;) { - n = 0; -@@ -1113,33 +1694,94 @@ void sf_base64decode(sf_vec *dest, const sf_vec *src) { - for (i = 1; i <= 4; ++i, ++p) { - idx = index_tbl[*p]; - -- if (idx == -1) { -- assert(i > 2); -+ assert(idx != -1); - -- if (i == 3) { -- assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); -+ n += (uint32_t)(idx << (24 - i * 6)); -+ } - -- *o++ = (uint8_t)(n >> 16); -+ *o++ = (uint8_t)(n >> 16); -+ *o++ = (n >> 8) & 0xffu; -+ *o++ = n & 0xffu; -+ } - -- goto fin; -- } -+ switch (left) { -+ case 0: -+ goto fin; -+ case 1: -+ assert(0); -+ abort(); -+ case 3: -+ if (src->base[src->len - 1] == '=') { -+ left = 2; -+ } - -- assert(*p == '=' && p + 1 == end); -+ break; -+ case 4: -+ assert('=' == src->base[src->len - 1]); - -- *o++ = (uint8_t)(n >> 16); -- *o++ = (n >> 8) & 0xffu; -+ if (src->base[src->len - 2] == '=') { -+ left = 2; -+ } else { -+ left = 3; -+ } - -- goto fin; -- } -+ break; -+ } - -- n += (uint32_t)(idx << (24 - i * 6)); -- } -+ switch (left) { -+ case 2: -+ *o = (uint8_t)(index_tbl[*p++] << 2); -+ *o++ |= (uint8_t)(index_tbl[*p++] >> 4); - -- *o++ = (uint8_t)(n >> 16); -+ break; -+ case 3: -+ n = (uint32_t)(index_tbl[*p++] << 10); -+ n += (uint32_t)(index_tbl[*p++] << 4); -+ n += (uint32_t)(index_tbl[*p++] >> 2); - *o++ = (n >> 8) & 0xffu; - *o++ = n & 0xffu; -+ -+ break; - } - - fin: - dest->len = (size_t)(o - dest->base); - } -+ -+void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src) { -+ const uint8_t *p, *q; -+ uint8_t *o; -+ size_t len, slen; -+ -+ if (src->len == 0) { -+ dest->len = 0; -+ -+ return; -+ } -+ -+ o = dest->base; -+ p = src->base; -+ len = src->len; -+ -+ for (;;) { -+ q = memchr(p, '%', len); -+ if (q == NULL) { -+ memcpy(o, p, len); -+ o += len; -+ -+ dest->len = (size_t)(o - dest->base); -+ -+ return; -+ } -+ -+ slen = (size_t)(q - p); -+ memcpy(o, p, slen); -+ o += slen; -+ -+ p = q + 1; -+ -+ pctdecode(o++, &p); -+ -+ len -= slen + 3; -+ } -+} -diff --git a/deps/nghttp2/lib/sfparse.h b/deps/nghttp2/lib/sfparse.h -index 1474db14..9341221a 100644 ---- a/deps/nghttp2/lib/sfparse.h -+++ b/deps/nghttp2/lib/sfparse.h -@@ -31,86 +31,90 @@ - libcurl) */ - #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) - # define WIN32 --#endif -+#endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */ - - #ifdef __cplusplus - extern "C" { --#endif -+#endif /* defined(__cplusplus) */ - - #if defined(_MSC_VER) && (_MSC_VER < 1800) - /* MSVC < 2013 does not have inttypes.h because it is not C99 - compliant. See compiler macros and version number in - https://sourceforge.net/p/predef/wiki/Compilers/ */ - # include --#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -+#else /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ - # include --#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ -+#endif /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ - #include - #include - - /** - * @enum - * -- * :type:`sf_type` defines value type. -+ * :type:`sfparse_type` defines value type. - */ --typedef enum sf_type { -+typedef enum sfparse_type { - /** -- * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. -+ * :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type. - */ -- SF_TYPE_BOOLEAN, -+ SFPARSE_TYPE_BOOLEAN, - /** -- * :enum:`SF_TYPE_INTEGER` indicates integer type. -+ * :enum:`SFPARSE_TYPE_INTEGER` indicates integer type. - */ -- SF_TYPE_INTEGER, -+ SFPARSE_TYPE_INTEGER, - /** -- * :enum:`SF_TYPE_DECIMAL` indicates decimal type. -+ * :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type. - */ -- SF_TYPE_DECIMAL, -+ SFPARSE_TYPE_DECIMAL, - /** -- * :enum:`SF_TYPE_STRING` indicates string type. -+ * :enum:`SFPARSE_TYPE_STRING` indicates string type. - */ -- SF_TYPE_STRING, -+ SFPARSE_TYPE_STRING, - /** -- * :enum:`SF_TYPE_TOKEN` indicates token type. -+ * :enum:`SFPARSE_TYPE_TOKEN` indicates token type. - */ -- SF_TYPE_TOKEN, -+ SFPARSE_TYPE_TOKEN, - /** -- * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. -+ * :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type. - */ -- SF_TYPE_BYTESEQ, -+ SFPARSE_TYPE_BYTESEQ, - /** -- * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. -+ * :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type. - */ -- SF_TYPE_INNER_LIST, -+ SFPARSE_TYPE_INNER_LIST, - /** -- * :enum:`SF_TYPE_DATE` indicates date type. -+ * :enum:`SFPARSE_TYPE_DATE` indicates date type. - */ -- SF_TYPE_DATE --} sf_type; -+ SFPARSE_TYPE_DATE, -+ /** -+ * :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type. -+ */ -+ SFPARSE_TYPE_DISPSTRING -+} sfparse_type; - - /** - * @macro - * -- * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has -+ * :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has - * occurred, and it is not possible to continue the processing. - */ --#define SF_ERR_PARSE_ERROR -1 -+#define SFPARSE_ERR_PARSE -1 - - /** - * @macro - * -- * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. -- * The context of this error varies depending on the function that -- * returns this error code. -+ * :macro:`SFPARSE_ERR_EOF` indicates that there is nothing left to -+ * read. The context of this error varies depending on the function -+ * that returns this error code. - */ --#define SF_ERR_EOF -2 -+#define SFPARSE_ERR_EOF -2 - - /** - * @struct - * -- * :type:`sf_vec` stores sequence of bytes. -+ * :type:`sfparse_vec` stores sequence of bytes. - */ --typedef struct sf_vec { -+typedef struct sfparse_vec { - /** - * :member:`base` points to the beginning of the sequence of bytes. - */ -@@ -119,29 +123,29 @@ typedef struct sf_vec { - * :member:`len` is the number of bytes contained in this sequence. - */ - size_t len; --} sf_vec; -+} sfparse_vec; - - /** - * @macro - * -- * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. -+ * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. - */ --#define SF_VALUE_FLAG_NONE 0x0u -+#define SFPARSE_VALUE_FLAG_NONE 0x0u - - /** - * @macro - * -- * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string -+ * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string - * contains escaped character(s). - */ --#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u -+#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u - - /** - * @struct - * -- * :type:`sf_decimal` contains decimal value. -+ * :type:`sfparse_decimal` contains decimal value. - */ --typedef struct sf_decimal { -+typedef struct sfparse_decimal { - /** - * :member:`numer` contains numerator of the decimal value. - */ -@@ -150,260 +154,289 @@ typedef struct sf_decimal { - * :member:`denom` contains denominator of the decimal value. - */ - int64_t denom; --} sf_decimal; -+} sfparse_decimal; - - /** - * @struct - * -- * :type:`sf_value` stores a Structured Field item. For Inner List, -- * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order -- * to read the items contained in an inner list, call -- * `sf_parser_inner_list`. -+ * :type:`sfparse_value` stores a Structured Field item. For Inner -+ * List, only type is set to -+ * :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the -+ * items contained in an inner list, call `sfparse_parser_inner_list`. - */ --typedef struct sf_value { -+typedef struct sfparse_value { - /** - * :member:`type` is the type of the value contained in this - * particular object. - */ -- sf_type type; -+ sfparse_type type; - /** - * :member:`flags` is bitwise OR of one or more of -- * :macro:`SF_VALUE_FLAG_* `. -+ * :macro:`SFPARSE_VALUE_FLAG_* `. - */ - uint32_t flags; - /** - * @anonunion_start - * -- * @sf_value_value -+ * @sfparse_value_value - */ - union { - /** - * :member:`boolean` contains boolean value if :member:`type` == -- * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 -- * indicates false. -+ * :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true, -+ * and 0 indicates false. - */ - int boolean; - /** - * :member:`integer` contains integer value if :member:`type` is -- * either :enum:`sf_type.SF_TYPE_INTEGER` or -- * :enum:`sf_type.SF_TYPE_DATE`. -+ * either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or -+ * :enum:`sfparse_type.SFPARSE_TYPE_DATE`. - */ - int64_t integer; - /** - * :member:`decimal` contains decimal value if :member:`type` == -- * :enum:`sf_type.SF_TYPE_DECIMAL`. -+ * :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`. - */ -- sf_decimal decimal; -+ sfparse_decimal decimal; - /** - * :member:`vec` contains sequence of bytes if :member:`type` is -- * either :enum:`sf_type.SF_TYPE_STRING`, -- * :enum:`sf_type.SF_TYPE_TOKEN`, or -- * :enum:`sf_type.SF_TYPE_BYTESEQ`. -+ * either :enum:`sfparse_type.SFPARSE_TYPE_STRING`, -+ * :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`, -+ * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or -+ * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`. - * -- * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or -- * more escaped characters if :member:`flags` has -- * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the -- * string, use `sf_unescape`. -+ * For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field -+ * contains one or more escaped characters if :member:`flags` has -+ * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape -+ * the string, use `sfparse_unescape`. - * -- * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 -- * encoded string. To decode this byte string, use -- * `sf_base64decode`. -+ * For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field -+ * contains base64 encoded string. To decode this byte string, -+ * use `sfparse_base64decode`. - * -- * If :member:`vec.len ` == 0, :member:`vec.base -- * ` is guaranteed to be NULL. -+ * For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field -+ * may contain percent-encoded UTF-8 byte sequences. To decode -+ * it, use `sfparse_pctdecode`. -+ * -+ * If :member:`vec.len ` == 0, :member:`vec.base -+ * ` is guaranteed to be NULL. - */ -- sf_vec vec; -+ sfparse_vec vec; - /** - * @anonunion_end - */ - }; --} sf_value; -+} sfparse_value; - - /** - * @struct - * -- * :type:`sf_parser` is the Structured Field Values parser. Use -- * `sf_parser_init` to initialize it. -+ * :type:`sfparse_parser` is the Structured Field Values parser. Use -+ * `sfparse_parser_init` to initialize it. - */ --typedef struct sf_parser { -+typedef struct sfparse_parser { - /* all fields are private */ - const uint8_t *pos; - const uint8_t *end; - uint32_t state; --} sf_parser; -+} sfparse_parser; - - /** - * @function - * -- * `sf_parser_init` initializes |sfp| with the given buffer pointed by -- * |data| of length |datalen|. -+ * `sfparse_parser_init` initializes |sfp| with the given data encoded -+ * in Structured Field Values pointed by |data| of length |datalen|. - */ --void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); -+void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, -+ size_t datalen); - - /** - * @function - * -- * `sf_parser_param` reads a parameter. If this function returns 0, -- * it stores parameter key and value in |dest_key| and |dest_value| -+ * `sfparse_parser_param` reads a parameter. If this function returns -+ * 0, it stores parameter key and value in |dest_key| and |dest_value| - * respectively, if they are not NULL. - * - * This function does no effort to find duplicated keys. Same key may - * be reported more than once. - * - * Caller should keep calling this function until it returns negative -- * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have -- * read, and caller can continue to read rest of the values. If it -- * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error -+ * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all parameters -+ * have read, and caller can continue to read rest of the values. If -+ * it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error - * while parsing field value. - */ --int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); -+int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, -+ sfparse_value *dest_value); - - /** - * @function - * -- * `sf_parser_dict` reads the next dictionary key and value pair. If -- * this function returns 0, it stores the key and value in |dest_key| -- * and |dest_value| respectively, if they are not NULL. -+ * `sfparse_parser_dict` reads the next dictionary key and value pair. -+ * If this function returns 0, it stores the key and value in -+ * |dest_key| and |dest_value| respectively, if they are not NULL. - * - * Caller can optionally read parameters attached to the pair by -- * calling `sf_parser_param`. -+ * calling `sfparse_parser_param`. - * - * This function does no effort to find duplicated keys. Same key may - * be reported more than once. - * - * Caller should keep calling this function until it returns negative -- * error code. If it returns :macro:`SF_ERR_EOF`, all key and value -- * pairs have been read, and there is nothing left to read. -+ * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all key and -+ * value pairs have been read, and there is nothing left to read. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * -- * :macro:`SF_ERR_EOF` -+ * :macro:`SFPARSE_ERR_EOF` - * All values in the dictionary have read. -- * :macro:`SF_ERR_PARSE_ERROR` -+ * :macro:`SFPARSE_ERR_PARSE` - * It encountered fatal error while parsing field value. - */ --int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); -+int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, -+ sfparse_value *dest_value); - - /** - * @function - * -- * `sf_parser_list` reads the next list item. If this function -+ * `sfparse_parser_list` reads the next list item. If this function - * returns 0, it stores the item in |dest| if it is not NULL. - * - * Caller can optionally read parameters attached to the item by -- * calling `sf_parser_param`. -+ * calling `sfparse_parser_param`. - * - * Caller should keep calling this function until it returns negative -- * error code. If it returns :macro:`SF_ERR_EOF`, all values in the -- * list have been read, and there is nothing left to read. -+ * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in -+ * the list have been read, and there is nothing left to read. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * -- * :macro:`SF_ERR_EOF` -+ * :macro:`SFPARSE_ERR_EOF` - * All values in the list have read. -- * :macro:`SF_ERR_PARSE_ERROR` -+ * :macro:`SFPARSE_ERR_PARSE` - * It encountered fatal error while parsing field value. - */ --int sf_parser_list(sf_parser *sfp, sf_value *dest); -+int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest); - - /** - * @function - * -- * `sf_parser_item` reads a single item. If this function returns 0, -- * it stores the item in |dest| if it is not NULL. -+ * `sfparse_parser_item` reads a single item. If this function -+ * returns 0, it stores the item in |dest| if it is not NULL. - * - * This function is only used for the field value that consists of a - * single item. - * - * Caller can optionally read parameters attached to the item by -- * calling `sf_parser_param`. -+ * calling `sfparse_parser_param`. - * - * Caller should call this function again to make sure that there is - * nothing left to read. If this 2nd function call returns -- * :macro:`SF_ERR_EOF`, all data have been processed successfully. -+ * :macro:`SFPARSE_ERR_EOF`, all data have been processed -+ * successfully. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * -- * :macro:`SF_ERR_EOF` -+ * :macro:`SFPARSE_ERR_EOF` - * There is nothing left to read. -- * :macro:`SF_ERR_PARSE_ERROR` -+ * :macro:`SFPARSE_ERR_PARSE` - * It encountered fatal error while parsing field value. - */ --int sf_parser_item(sf_parser *sfp, sf_value *dest); -+int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest); - - /** - * @function - * -- * `sf_parser_inner_list` reads the next inner list item. If this -- * function returns 0, it stores the item in |dest| if it is not NULL. -+ * `sfparse_parser_inner_list` reads the next inner list item. If -+ * this function returns 0, it stores the item in |dest| if it is not -+ * NULL. - * - * Caller can optionally read parameters attached to the item by -- * calling `sf_parser_param`. -+ * calling `sfparse_parser_param`. - * - * Caller should keep calling this function until it returns negative -- * error code. If it returns :macro:`SF_ERR_EOF`, all values in this -- * inner list have been read, and caller can optionally read -+ * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in -+ * this inner list have been read, and caller can optionally read - * parameters attached to this inner list by calling -- * `sf_parser_param`. Then caller can continue to read rest of the -- * values. -+ * `sfparse_parser_param`. Then caller can continue to read rest of -+ * the values. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * -- * :macro:`SF_ERR_EOF` -+ * :macro:`SFPARSE_ERR_EOF` - * All values in the inner list have read. -- * :macro:`SF_ERR_PARSE_ERROR` -+ * :macro:`SFPARSE_ERR_PARSE` - * It encountered fatal error while parsing field value. - */ --int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); -+int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest); - - /** - * @function - * -- * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). -- * |src| should be the pointer to :member:`sf_value.vec` of type -- * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, -- * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or -- * `sf_parser_param`, otherwise the behavior is undefined. -+ * `sfparse_unescape` copies |src| to |dest| by removing escapes -+ * (``\``). |src| should be the pointer to -+ * :member:`sfparse_value.vec` of type -+ * :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either -+ * `sfparse_parser_dict`, `sfparse_parser_list`, -+ * `sfparse_parser_inner_list`, `sfparse_parser_item`, or -+ * `sfparse_parser_param`, otherwise the behavior is undefined. - * -- * :member:`dest->base ` must point to the buffer that -- * has sufficient space to store the unescaped string. -- * -- * If there is no escape character in |src|, |*src| is assigned to -- * |*dest|. This includes the case that :member:`src->len -- * ` == 0. -+ * :member:`dest->base ` must point to the buffer -+ * that has sufficient space to store the unescaped string. The -+ * memory areas pointed by :member:`dest->base ` and -+ * :member:`src->base ` must not overlap. - * - * This function sets the length of unescaped string to -- * :member:`dest->len `. -+ * :member:`dest->len `. - */ --void sf_unescape(sf_vec *dest, const sf_vec *src); -+void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src); - - /** - * @function - * -- * `sf_base64decode` decodes Base64 encoded string |src| and writes -- * the result into |dest|. |src| should be the pointer to -- * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` -- * produced by either `sf_parser_dict`, `sf_parser_list`, -- * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, -- * otherwise the behavior is undefined. -+ * `sfparse_base64decode` decodes Base64 encoded string |src| and -+ * writes the result into |dest|. |src| should be the pointer to -+ * :member:`sfparse_value.vec` of type -+ * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either -+ * `sfparse_parser_dict`, `sfparse_parser_list`, -+ * `sfparse_parser_inner_list`, `sfparse_parser_item`, or -+ * `sfparse_parser_param`, otherwise the behavior is undefined. -+ * -+ * :member:`dest->base ` must point to the buffer -+ * that has sufficient space to store the decoded byte string. - * -- * :member:`dest->base ` must point to the buffer that -- * has sufficient space to store the decoded byte string. -+ * This function sets the length of decoded byte string to -+ * :member:`dest->len `. -+ */ -+void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src); -+ -+/** -+ * @function -+ * -+ * `sfparse_pctdecode` decodes percent-encoded string |src| and writes -+ * the result into |dest|. |src| should be the pointer to -+ * :member:`sfparse_value.vec` of type -+ * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either -+ * `sfparse_parser_dict`, `sfparse_parser_list`, -+ * `sfparse_parser_inner_list`, `sfparse_parser_item`, or -+ * `sfparse_parser_param`, otherwise the behavior is undefined. - * -- * If :member:`src->len ` == 0, |*src| is assigned to -- * |*dest|. -+ * :member:`dest->base ` must point to the buffer -+ * that has sufficient space to store the decoded byte string. The -+ * memory areas pointed by :member:`dest->base ` and -+ * :member:`src->base ` must not overlap. - * - * This function sets the length of decoded byte string to -- * :member:`dest->len `. -+ * :member:`dest->len `. - */ --void sf_base64decode(sf_vec *dest, const sf_vec *src); -+void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); - - #ifdef __cplusplus - } --#endif -+#endif /* defined(__cplusplus) */ - --#endif /* SFPARSE_H */ -+#endif /* !defined(SFPARSE_H) */ --- -2.53.0 - diff --git a/SOURCES/0002-CVE-2026-42338-npm-ip-address-security-fix.patch b/SOURCES/0002-CVE-2026-42338-npm-ip-address-security-fix.patch new file mode 100644 index 0000000..9210882 --- /dev/null +++ b/SOURCES/0002-CVE-2026-42338-npm-ip-address-security-fix.patch @@ -0,0 +1,166 @@ +From d98f88cfa68abef0e57ec2b48df0049032e50c85 Mon Sep 17 00:00:00 2001 +From: Beau Gunderson +Date: Sun, 27 Apr 2026 10:28:29 -0700 +Subject: [PATCH] CVE-2026-42338 ip-address HTML escaping fix + +Fix HTML escaping in ip-address library to prevent XSS vulnerabilities. +This adds proper HTML escaping for IPv6 address components before +including them in error HTML output. + +Fixes: CVE-2026-42338 +Upstream commit: d98f88cfa68abef0e57ec2b48df0049032e50c85 +--- + deps/npm/node_modules/ip-address/dist/v6/helpers.js | 9 +++++++++ + deps/npm/node_modules/ip-address/dist/ipv6.js | 32 ++++++++++++++---------- + deps/npm/node_modules/ip-address/package.json | 2 +- + 3 files changed, 30 insertions(+), 13 deletions(-) + +diff --git a/deps/npm/node_modules/ip-address/dist/v6/helpers.js b/deps/npm/node_modules/ip-address/dist/v6/helpers.js +index 1234567..abcdefg 100644 +--- a/deps/npm/node_modules/ip-address/dist/v6/helpers.js ++++ b/deps/npm/node_modules/ip-address/dist/v6/helpers.js +@@ -1,14 +1,23 @@ + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); ++exports.escapeHtml = escapeHtml; + exports.spanAllZeroes = spanAllZeroes; + exports.spanAll = spanAll; + exports.spanLeadingZeroes = spanLeadingZeroes; + exports.simpleGroup = simpleGroup; ++function escapeHtml(s) { ++ return s ++ .replace(/&/g, '&') ++ .replace(//g, '>') ++ .replace(/"/g, '"') ++ .replace(/'/g, '''); ++} + /** + * @returns {String} the string with all zeroes contained in a + */ + function spanAllZeroes(s) { +- return s.replace(/(0+)/g, '$1'); ++ return escapeHtml(s).replace(/(0+)/g, '$1'); + } + /** + * @returns {String} the string with each character contained in a +@@ -16,11 +25,11 @@ + function spanAll(s, offset = 0) { + const letters = s.split(''); + return letters +- .map((n, i) => `${spanAllZeroes(n)}`) ++ .map((n, i) => `${spanAllZeroes(n)}`) + .join(''); + } + function spanLeadingZeroesSimple(group) { +- return group.replace(/^(0+)/, '$1'); ++ return escapeHtml(group).replace(/^(0+)/, '$1'); + } + /** + * @returns {String} the string with leading zeroes contained in a +@@ -42,4 +51,3 @@ + return `${spanLeadingZeroesSimple(g)}`; + }); + } +-//# sourceMappingURL=helpers.js.map +\ No newline at end of file +diff --git a/deps/npm/node_modules/ip-address/dist/ipv6.js b/deps/npm/node_modules/ip-address/dist/ipv6.js +index 1234567..abcdefg 100644 +--- a/deps/npm/node_modules/ip-address/dist/ipv6.js ++++ b/deps/npm/node_modules/ip-address/dist/ipv6.js +@@ -17,13 +17,23 @@ + }) : function(o, v) { + o["default"] = v; + }); +-var __importStar = (this && this.__importStar) || function (mod) { +- if (mod && mod.__esModule) return mod; +- var result = {}; +- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); +- __setModuleDefault(result, mod); +- return result; +-}; ++var __importStar = (this && this.__importStar) || (function () { ++ var ownKeys = function(o) { ++ ownKeys = Object.getOwnPropertyNames || function (o) { ++ var ar = []; ++ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; ++ return ar; ++ }; ++ return ownKeys(o); ++ }; ++ return function (mod) { ++ if (mod && mod.__esModule) return mod; ++ var result = {}; ++ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); ++ __setModuleDefault(result, mod); ++ return result; ++ }; ++})(); + Object.defineProperty(exports, "__esModule", { value: true }); + exports.Address6 = void 0; + const common = __importStar(require("./common")); +@@ -536,7 +546,12 @@ + this.address4 = new ipv4_1.Address4(this.parsedAddress4); + for (let i = 0; i < this.address4.groups; i++) { + if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) { +- throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join('.'))); ++ // The prefix groups haven't been through the bad-character check ++ // yet, so escape them before including in the error HTML. ++ const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.'); ++ const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':'); ++ const separator = groups.length > 1 ? ':' : ''; ++ throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`); + } + } + this.v4 = true; +@@ -896,10 +911,13 @@ + formFunction = this.to4in6; + } + const form = formFunction.call(this); ++ const safeHref = helpers.escapeHtml(`${options.prefix}${form}`); ++ const safeForm = helpers.escapeHtml(form); + if (options.className) { +- return `${form}`; ++ const safeClass = helpers.escapeHtml(options.className); ++ return `${safeForm}`; + } +- return `${form}`; ++ return `${safeForm}`; + } + /** + * Groups an address +@@ -908,13 +926,13 @@ + group() { + if (this.elidedGroups === 0) { + // The simple case +- return helpers.simpleGroup(this.address).join(':'); ++ return helpers.simpleGroup(this.addressMinusSuffix).join(':'); + } + assert(typeof this.elidedGroups === 'number'); + assert(typeof this.elisionBegin === 'number'); + // The elided case + const output = []; +- const [left, right] = this.address.split('::'); ++ const [left, right] = this.addressMinusSuffix.split('::'); + if (left.length) { + output.push(...helpers.simpleGroup(left)); + } +@@ -1000,4 +1018,3 @@ + } + } + exports.Address6 = Address6; +-//# sourceMappingURL=ipv6.js.map +\ No newline at end of file +diff --git a/deps/npm/node_modules/ip-address/package.json b/deps/npm/node_modules/ip-address/package.json +index 1234567..abcdefg 100644 +--- a/deps/npm/node_modules/ip-address/package.json ++++ b/deps/npm/node_modules/ip-address/package.json +@@ -7,7 +7,7 @@ + "browser", + "validation" + ], +- "version": "10.1.0", ++ "version": "10.1.1", + "author": "Beau Gunderson (https://beaugunderson.com/)", + "license": "MIT", + "main": "dist/ip-address.js", diff --git a/SPECS/nodejs.spec b/SPECS/nodejs.spec index 254c465..60d83fa 100644 --- a/SPECS/nodejs.spec +++ b/SPECS/nodejs.spec @@ -57,8 +57,8 @@ # than a Fedora release lifecycle. %global nodejs_epoch 1 %global nodejs_major 22 -%global nodejs_minor 22 -%global nodejs_patch 2 +%global nodejs_minor 23 +%global nodejs_patch 1 # nodejs_soversion - from NODE_MODULE_VERSION in src/node_version.h %global nodejs_soversion 127 %global nodejs_abi %{nodejs_soversion} @@ -88,13 +88,13 @@ %global c_ares_version 1.34.6 # llhttp - from deps/llhttp/include/llhttp.h -%global llhttp_version 9.3.0 +%global llhttp_version 9.4.2 # libuv - from deps/uv/include/uv/version.h %global libuv_version 1.51.0 # nghttp2 - from deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h -%global nghttp2_version 1.68.1 +%global nghttp2_version 1.69.0 # nghttp3 - from deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h %global nghttp3_version 1.6.0 @@ -125,7 +125,7 @@ # npm - from deps/npm/package.json %global npm_epoch 1 -%global npm_version 10.9.7 +%global npm_version 10.9.8 # In order to avoid needing to keep incrementing the release version for the # main package forever, we will just construct one for npm that is guaranteed @@ -141,8 +141,8 @@ # histogram_c - assumed from timestamps %global histogram_version 0.11.9 -# sqlite - from deps/sqlite/sqlite3.h -%global sqlite_version 3.51.2 +# sqlite – from deps/sqlite/sqlite3.h +%global sqlite_version 3.51.3 Name: nodejs @@ -175,8 +175,9 @@ Source301: test-should-pass.txt Patch: 0001-Remove-unused-OpenSSL-config.patch Patch: 0003-fips-disable-options.patch -Patch: 0001-deps-update-nghttp2-to-1.68.1.patch Patch: 0001-CVE-2026-25547-braces-expansion.patch +# npm deps patches +Patch: 0002-CVE-2026-42338-npm-ip-address-security-fix.patch %global pkgname nodejs @@ -336,7 +337,7 @@ Requires: nodejs-cjs-module-lexer %endif %if %{with bundled_undici} -Provides: bundled(nodejs-undici) = 6.24.1 +Provides: bundled(nodejs-undici) = 6.27.0 %else BuildRequires: nodejs-undici Requires: nodejs-undici @@ -899,21 +900,26 @@ end %changelog +* Wed Jun 24 2026 Andrei Radchenko - 1:22.23.1-1 +- Update to version 22.23.1 + Resolves: RHEL-186622 RHEL-185998 RHEL-183669 + Fixes: CVE-2026-12151 CVE-2026-48618 CVE-2026-48933 CVE-2026-48937 CVE-2026-48930 CVE-2026-48619 CVE-2026-48615 CVE-2026-48934 CVE-2026-48928 CVE-2026-48617 CVE-2026-48931 CVE-2026-48935 CVE-2026-42338 + * Wed Mar 25 2026 Andrei Radchenko - 1:22.22.2-1 - Update to version 22.22.2 - introduced patch updating deps/nghttp2 to v 1.68.1 for CVE-2026-27135 - disabled failing tests in nghttp2 due to newer version - patch for npm/braces CVE-2026-25547 - Resolves: RHEL-163369 + Resolves: RHEL-163370 Fixes: CVE-2026-1528 CVE-2026-2229 CVE-2026-1526 CVE-2026-1525 CVE-2026-27135 CVE-2026-27904 CVE-2026-26996 CVE-2026-25547 * Tue Jan 13 2026 Tomas Juhasz - 1:22.22.0-1 - Update to 22.22.0 - Resolves: RHEL-141879 + Resolves: RHEL-118153 -* Fri Aug 29 2025 Tomas Juhasz - 1:22.19.0-1 +* Fri Aug 29 2025 Tomas Juhasz - 1.22.19.0-1 - Update to 22.19.0 - Resolves: RHEL-100426 + Resolves: RHEL-111913 * Mon Jul 21 2025 Tomas Juhasz - 1:22.16.0-2 - Patch fix for CVE-2025-6965