nodejs/0003-deps-nghttp2-update-to...

5803 lines
186 KiB
Diff

From 3cdb8a61ff25e4d299d9d47284da5134bc5f1072 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 12 Oct 2023 14:18:12 +0200
Subject: [PATCH] deps(nghttp2): update to 1.57.0
Resolves: CVE-2023-44487
Signed-off-by: rpm-build <rpm-build>
---
deps/nghttp2/lib/CMakeLists.txt | 4 +
deps/nghttp2/lib/Makefile.am | 12 +-
deps/nghttp2/lib/Makefile.in | 66 +-
deps/nghttp2/lib/includes/Makefile.in | 26 +-
deps/nghttp2/lib/includes/config.h | 92 --
deps/nghttp2/lib/includes/nghttp2/nghttp2.h | 266 +++-
.../nghttp2/lib/includes/nghttp2/nghttp2ver.h | 4 +-
deps/nghttp2/lib/nghttp2_extpri.c | 35 +
deps/nghttp2/lib/nghttp2_extpri.h | 65 +
deps/nghttp2/lib/nghttp2_frame.c | 122 +-
deps/nghttp2/lib/nghttp2_frame.h | 95 +-
deps/nghttp2/lib/nghttp2_hd.c | 5 +
deps/nghttp2/lib/nghttp2_hd.h | 1 +
deps/nghttp2/lib/nghttp2_helper.c | 13 +
deps/nghttp2/lib/nghttp2_http.c | 136 +-
deps/nghttp2/lib/nghttp2_http.h | 3 +
deps/nghttp2/lib/nghttp2_map.c | 61 +-
deps/nghttp2/lib/nghttp2_map.h | 8 +-
deps/nghttp2/lib/nghttp2_net.h | 12 +-
deps/nghttp2/lib/nghttp2_option.c | 24 +
deps/nghttp2/lib/nghttp2_option.h | 16 +
deps/nghttp2/lib/nghttp2_outbound_item.c | 3 +
deps/nghttp2/lib/nghttp2_pq.c | 3 +-
deps/nghttp2/lib/nghttp2_pq.h | 8 +-
deps/nghttp2/lib/nghttp2_ratelim.c | 75 ++
deps/nghttp2/lib/nghttp2_ratelim.h | 57 +
deps/nghttp2/lib/nghttp2_session.c | 870 ++++++++++---
deps/nghttp2/lib/nghttp2_session.h | 53 +-
deps/nghttp2/lib/nghttp2_stream.c | 30 +-
deps/nghttp2/lib/nghttp2_stream.h | 40 +-
deps/nghttp2/lib/nghttp2_submit.c | 82 +-
deps/nghttp2/lib/nghttp2_time.c | 62 +
deps/nghttp2/lib/nghttp2_time.h | 38 +
deps/nghttp2/lib/sfparse.c | 1146 +++++++++++++++++
deps/nghttp2/lib/sfparse.h | 409 ++++++
deps/nghttp2/nghttp2.gyp | 7 +-
36 files changed, 3477 insertions(+), 472 deletions(-)
delete mode 100644 deps/nghttp2/lib/includes/config.h
create mode 100644 deps/nghttp2/lib/nghttp2_extpri.c
create mode 100644 deps/nghttp2/lib/nghttp2_extpri.h
create mode 100644 deps/nghttp2/lib/nghttp2_ratelim.c
create mode 100644 deps/nghttp2/lib/nghttp2_ratelim.h
create mode 100644 deps/nghttp2/lib/nghttp2_time.c
create mode 100644 deps/nghttp2/lib/nghttp2_time.h
create mode 100644 deps/nghttp2/lib/sfparse.c
create mode 100644 deps/nghttp2/lib/sfparse.h
diff --git a/deps/nghttp2/lib/CMakeLists.txt b/deps/nghttp2/lib/CMakeLists.txt
index 4dc2fcd..7adba3a 100644
--- a/deps/nghttp2/lib/CMakeLists.txt
+++ b/deps/nghttp2/lib/CMakeLists.txt
@@ -23,7 +23,11 @@ set(NGHTTP2_SOURCES
nghttp2_mem.c
nghttp2_http.c
nghttp2_rcbuf.c
+ nghttp2_extpri.c
+ nghttp2_ratelim.c
+ nghttp2_time.c
nghttp2_debug.c
+ sfparse.c
)
set(NGHTTP2_RES "")
diff --git a/deps/nghttp2/lib/Makefile.am b/deps/nghttp2/lib/Makefile.am
index 1e1f248..c3ace40 100644
--- a/deps/nghttp2/lib/Makefile.am
+++ b/deps/nghttp2/lib/Makefile.am
@@ -50,7 +50,11 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_mem.c \
nghttp2_http.c \
nghttp2_rcbuf.c \
- nghttp2_debug.c
+ nghttp2_extpri.c \
+ nghttp2_ratelim.c \
+ nghttp2_time.c \
+ nghttp2_debug.c \
+ sfparse.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@@ -66,7 +70,11 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_mem.h \
nghttp2_http.h \
nghttp2_rcbuf.h \
- nghttp2_debug.h
+ nghttp2_extpri.h \
+ nghttp2_ratelim.h \
+ nghttp2_time.h \
+ nghttp2_debug.h \
+ sfparse.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
diff --git a/deps/nghttp2/lib/Makefile.in b/deps/nghttp2/lib/Makefile.in
index 5653774..0b95613 100644
--- a/deps/nghttp2/lib/Makefile.in
+++ b/deps/nghttp2/lib/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.16.4 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2021 Free Software Foundation, Inc.
@@ -107,13 +107,8 @@ host_triplet = @host@
target_triplet = @target@
subdir = lib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_asio.m4 \
- $(top_srcdir)/m4/ax_boost_base.m4 \
- $(top_srcdir)/m4/ax_boost_system.m4 \
- $(top_srcdir)/m4/ax_boost_thread.m4 \
- $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
- $(top_srcdir)/m4/ax_python_devel.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -162,7 +157,8 @@ am__objects_2 = nghttp2_pq.lo nghttp2_map.lo nghttp2_queue.lo \
nghttp2_hd_huffman.lo nghttp2_hd_huffman_data.lo \
nghttp2_version.lo nghttp2_priority_spec.lo nghttp2_option.lo \
nghttp2_callbacks.lo nghttp2_mem.lo nghttp2_http.lo \
- nghttp2_rcbuf.lo nghttp2_debug.lo
+ nghttp2_rcbuf.lo nghttp2_extpri.lo nghttp2_ratelim.lo \
+ nghttp2_time.lo nghttp2_debug.lo sfparse.lo
am_libnghttp2_la_OBJECTS = $(am__objects_1) $(am__objects_2)
libnghttp2_la_OBJECTS = $(am_libnghttp2_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -189,8 +185,9 @@ depcomp = $(SHELL) $(top_srcdir)/depcomp
am__maybe_remake_depfiles = depfiles
am__depfiles_remade = ./$(DEPDIR)/nghttp2_buf.Plo \
./$(DEPDIR)/nghttp2_callbacks.Plo \
- ./$(DEPDIR)/nghttp2_debug.Plo ./$(DEPDIR)/nghttp2_frame.Plo \
- ./$(DEPDIR)/nghttp2_hd.Plo ./$(DEPDIR)/nghttp2_hd_huffman.Plo \
+ ./$(DEPDIR)/nghttp2_debug.Plo ./$(DEPDIR)/nghttp2_extpri.Plo \
+ ./$(DEPDIR)/nghttp2_frame.Plo ./$(DEPDIR)/nghttp2_hd.Plo \
+ ./$(DEPDIR)/nghttp2_hd_huffman.Plo \
./$(DEPDIR)/nghttp2_hd_huffman_data.Plo \
./$(DEPDIR)/nghttp2_helper.Plo ./$(DEPDIR)/nghttp2_http.Plo \
./$(DEPDIR)/nghttp2_map.Plo ./$(DEPDIR)/nghttp2_mem.Plo \
@@ -198,9 +195,11 @@ am__depfiles_remade = ./$(DEPDIR)/nghttp2_buf.Plo \
./$(DEPDIR)/nghttp2_outbound_item.Plo \
./$(DEPDIR)/nghttp2_pq.Plo \
./$(DEPDIR)/nghttp2_priority_spec.Plo \
- ./$(DEPDIR)/nghttp2_queue.Plo ./$(DEPDIR)/nghttp2_rcbuf.Plo \
- ./$(DEPDIR)/nghttp2_session.Plo ./$(DEPDIR)/nghttp2_stream.Plo \
- ./$(DEPDIR)/nghttp2_submit.Plo ./$(DEPDIR)/nghttp2_version.Plo
+ ./$(DEPDIR)/nghttp2_queue.Plo ./$(DEPDIR)/nghttp2_ratelim.Plo \
+ ./$(DEPDIR)/nghttp2_rcbuf.Plo ./$(DEPDIR)/nghttp2_session.Plo \
+ ./$(DEPDIR)/nghttp2_stream.Plo ./$(DEPDIR)/nghttp2_submit.Plo \
+ ./$(DEPDIR)/nghttp2_time.Plo ./$(DEPDIR)/nghttp2_version.Plo \
+ ./$(DEPDIR)/sfparse.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -299,11 +298,6 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
-BOOST_ASIO_LIB = @BOOST_ASIO_LIB@
-BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
-BOOST_LDFLAGS = @BOOST_LDFLAGS@
-BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@
-BOOST_THREAD_LIB = @BOOST_THREAD_LIB@
BPFCFLAGS = @BPFCFLAGS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
@@ -320,7 +314,6 @@ CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
-CYTHON = @CYTHON@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
@@ -336,6 +329,7 @@ EXTRABPFCFLAGS = @EXTRABPFCFLAGS@
EXTRACFLAG = @EXTRACFLAG@
EXTRA_DEFS = @EXTRA_DEFS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
GREP = @GREP@
HAVE_CXX14 = @HAVE_CXX14@
INSTALL = @INSTALL@
@@ -364,8 +358,8 @@ 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_OPENSSL_CFLAGS = @LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@
-LIBNGTCP2_CRYPTO_OPENSSL_LIBS = @LIBNGTCP2_CRYPTO_OPENSSL_LIBS@
+LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@
+LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@
LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
@@ -404,15 +398,9 @@ PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PYTHON = @PYTHON@
-PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
-PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
-PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
-PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
-PYTHON_PLATFORM_SITE_PKG = @PYTHON_PLATFORM_SITE_PKG@
PYTHON_PREFIX = @PYTHON_PREFIX@
-PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
PYTHON_VERSION = @PYTHON_VERSION@
RANLIB = @RANLIB@
SED = @SED@
@@ -523,7 +511,11 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_mem.c \
nghttp2_http.c \
nghttp2_rcbuf.c \
- nghttp2_debug.c
+ nghttp2_extpri.c \
+ nghttp2_ratelim.c \
+ nghttp2_time.c \
+ nghttp2_debug.c \
+ sfparse.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@@ -539,7 +531,11 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_mem.h \
nghttp2_http.h \
nghttp2_rcbuf.h \
- nghttp2_debug.h
+ nghttp2_extpri.h \
+ nghttp2_ratelim.h \
+ nghttp2_time.h \
+ nghttp2_debug.h \
+ sfparse.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \
@@ -628,6 +624,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_buf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_callbacks.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_debug.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_extpri.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_frame.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd_huffman.Plo@am__quote@ # am--include-marker
@@ -642,11 +639,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_pq.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_priority_spec.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_queue.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_ratelim.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_rcbuf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_session.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_stream.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_submit.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_time.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_version.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sfparse.Plo@am__quote@ # am--include-marker
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
@@ -909,6 +909,7 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/nghttp2_buf.Plo
-rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo
-rm -f ./$(DEPDIR)/nghttp2_debug.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_extpri.Plo
-rm -f ./$(DEPDIR)/nghttp2_frame.Plo
-rm -f ./$(DEPDIR)/nghttp2_hd.Plo
-rm -f ./$(DEPDIR)/nghttp2_hd_huffman.Plo
@@ -923,11 +924,14 @@ distclean: distclean-recursive
-rm -f ./$(DEPDIR)/nghttp2_pq.Plo
-rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo
-rm -f ./$(DEPDIR)/nghttp2_queue.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo
-rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo
-rm -f ./$(DEPDIR)/nghttp2_session.Plo
-rm -f ./$(DEPDIR)/nghttp2_stream.Plo
-rm -f ./$(DEPDIR)/nghttp2_submit.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_time.Plo
-rm -f ./$(DEPDIR)/nghttp2_version.Plo
+ -rm -f ./$(DEPDIR)/sfparse.Plo
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
@@ -976,6 +980,7 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/nghttp2_buf.Plo
-rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo
-rm -f ./$(DEPDIR)/nghttp2_debug.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_extpri.Plo
-rm -f ./$(DEPDIR)/nghttp2_frame.Plo
-rm -f ./$(DEPDIR)/nghttp2_hd.Plo
-rm -f ./$(DEPDIR)/nghttp2_hd_huffman.Plo
@@ -990,11 +995,14 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/nghttp2_pq.Plo
-rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo
-rm -f ./$(DEPDIR)/nghttp2_queue.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo
-rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo
-rm -f ./$(DEPDIR)/nghttp2_session.Plo
-rm -f ./$(DEPDIR)/nghttp2_stream.Plo
-rm -f ./$(DEPDIR)/nghttp2_submit.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_time.Plo
-rm -f ./$(DEPDIR)/nghttp2_version.Plo
+ -rm -f ./$(DEPDIR)/sfparse.Plo
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
diff --git a/deps/nghttp2/lib/includes/Makefile.in b/deps/nghttp2/lib/includes/Makefile.in
index 327e523..3de90d7 100644
--- a/deps/nghttp2/lib/includes/Makefile.in
+++ b/deps/nghttp2/lib/includes/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.16.4 from Makefile.am.
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2021 Free Software Foundation, Inc.
@@ -114,13 +114,8 @@ host_triplet = @host@
target_triplet = @target@
subdir = lib/includes
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_asio.m4 \
- $(top_srcdir)/m4/ax_boost_base.m4 \
- $(top_srcdir)/m4/ax_boost_system.m4 \
- $(top_srcdir)/m4/ax_boost_thread.m4 \
- $(top_srcdir)/m4/ax_check_compile_flag.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
- $(top_srcdir)/m4/ax_python_devel.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -208,11 +203,6 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
-BOOST_ASIO_LIB = @BOOST_ASIO_LIB@
-BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
-BOOST_LDFLAGS = @BOOST_LDFLAGS@
-BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@
-BOOST_THREAD_LIB = @BOOST_THREAD_LIB@
BPFCFLAGS = @BPFCFLAGS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
@@ -229,7 +219,6 @@ CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
-CYTHON = @CYTHON@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
@@ -245,6 +234,7 @@ EXTRABPFCFLAGS = @EXTRABPFCFLAGS@
EXTRACFLAG = @EXTRACFLAG@
EXTRA_DEFS = @EXTRA_DEFS@
FGREP = @FGREP@
+FILECMD = @FILECMD@
GREP = @GREP@
HAVE_CXX14 = @HAVE_CXX14@
INSTALL = @INSTALL@
@@ -273,8 +263,8 @@ 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_OPENSSL_CFLAGS = @LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@
-LIBNGTCP2_CRYPTO_OPENSSL_LIBS = @LIBNGTCP2_CRYPTO_OPENSSL_LIBS@
+LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@
+LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@
LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
@@ -313,15 +303,9 @@ PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PYTHON = @PYTHON@
-PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
-PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
-PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
-PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
-PYTHON_PLATFORM_SITE_PKG = @PYTHON_PLATFORM_SITE_PKG@
PYTHON_PREFIX = @PYTHON_PREFIX@
-PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
PYTHON_VERSION = @PYTHON_VERSION@
RANLIB = @RANLIB@
SED = @SED@
diff --git a/deps/nghttp2/lib/includes/config.h b/deps/nghttp2/lib/includes/config.h
deleted file mode 100644
index 12a816e..0000000
--- a/deps/nghttp2/lib/includes/config.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Hint to the compiler that a function never returns */
-#define NGHTTP2_NORETURN
-
-/* Edited to match src/node.h. */
-#include <stdint.h>
-
-#ifdef _WIN32
-#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
-typedef intptr_t ssize_t;
-# define _SSIZE_T_
-# define _SSIZE_T_DEFINED
-#endif
-#else // !_WIN32
-# include <sys/types.h> // size_t, ssize_t
-#endif // _WIN32
-
-/* Define to 1 if you have the `std::map::emplace`. */
-#define HAVE_STD_MAP_EMPLACE 1
-
-/* Define to 1 if you have `libjansson` library. */
-/* #undef HAVE_JANSSON */
-
-/* Define to 1 if you have `libxml2` library. */
-/* #undef HAVE_LIBXML2 */
-
-/* Define to 1 if you have `spdylay` library. */
-/* #undef HAVE_SPDYLAY */
-
-/* Define to 1 if you have `mruby` library. */
-/* #undef HAVE_MRUBY */
-
-/* Define to 1 if you have `neverbleed` library. */
-/* #undef HAVE_NEVERBLEED */
-
-/* sizeof(int *) */
-#define SIZEOF_INT_P 4
-
-/* sizeof(time_t) */
-#define SIZEOF_TIME_T 8
-
-/* Define to 1 if you have the `_Exit` function. */
-#define HAVE__EXIT 1
-
-/* Define to 1 if you have the `accept4` function. */
-/* #undef HAVE_ACCEPT4 */
-
-/* Define to 1 if you have the `initgroups` function. */
-#define HAVE_DECL_INITGROUPS 0
-
-/* Define to 1 to enable debug output. */
-/* #undef DEBUGBUILD */
-
-/* Define to 1 if you want to disable threads. */
-/* #undef NOTHREADS */
-
-/* Define to 1 if you have the <arpa/inet.h> header file. */
-#ifndef _WIN32
-# define HAVE_ARPA_INET_H 1
-#endif
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the <limits.h> header file. */
-#define HAVE_LIMITS_H 1
-
-/* Define to 1 if you have the <netdb.h> header file. */
-/* #undef HAVE_NETDB_H */
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-/* #undef HAVE_NETINET_IN_H */
-
-/* Define to 1 if you have the <pwd.h> header file. */
-/* #undef HAVE_PWD_H */
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-/* #undef HAVE_SYS_SOCKET_H */
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-/* #undef HAVE_SYS_TIME_H */
-
-/* Define to 1 if you have the <syslog.h> header file. */
-/* #undef HAVE_SYSLOG_H */
-
-/* Define to 1 if you have the <time.h> header file. */
-#define HAVE_TIME_H 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-/* #undef HAVE_UNISTD_H */
diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
index 04321a6..fa22081 100644
--- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
+++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
@@ -634,7 +634,11 @@ typedef enum {
* The ORIGIN frame, which is defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*/
- NGHTTP2_ORIGIN = 0x0c
+ NGHTTP2_ORIGIN = 0x0c,
+ /**
+ * The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`.
+ */
+ NGHTTP2_PRIORITY_UPDATE = 0x10
} nghttp2_frame_type;
/**
@@ -703,7 +707,11 @@ typedef enum {
* SETTINGS_ENABLE_CONNECT_PROTOCOL
* (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
*/
- NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
+ NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
+ /**
+ * SETTINGS_NO_RFC7540_PRIORITIES (:rfc:`9218`)
+ */
+ NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
} nghttp2_settings_id;
/* Note: If we add SETTINGS, update the capacity of
NGHTTP2_INBOUND_NUM_IV as well */
@@ -1422,12 +1430,6 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
* respectively. The header name/value pairs are emitted via
* :type:`nghttp2_on_header_callback`.
*
- * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
- * called after stream is closed (see
- * :type:`nghttp2_on_stream_close_callback`). The application should
- * check that stream is still alive using its own stream management or
- * :func:`nghttp2_session_get_stream_user_data()`.
- *
* Only HEADERS and DATA frame can signal the end of incoming data.
* If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
* |frame| is the last frame from the remote peer in this stream.
@@ -2693,6 +2695,11 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
* This option prevents the library from retaining closed streams to
* maintain the priority tree. If this option is set to nonzero,
* applications can discard closed stream completely to save memory.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, any
+ * closed streams are not retained regardless of this option.
*/
NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
int val);
@@ -2719,6 +2726,53 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
size_t val);
+/**
+ * @function
+ *
+ * This option, if set to nonzero, allows server to fallback to
+ * :rfc:`7540` priorities if SETTINGS_NO_RFC7540_PRIORITIES was not
+ * received from client, and server submitted
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * = 1 via `nghttp2_submit_settings()`. Most of the advanced
+ * functionality for RFC 7540 priorities are still disabled. This
+ * fallback only enables the minimal feature set of RFC 7540
+ * priorities to deal with priority signaling from client.
+ *
+ * Client session ignores this option.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_server_fallback_rfc7540_priorities(nghttp2_option *option,
+ int val);
+
+/**
+ * @function
+ *
+ * This option, if set to nonzero, turns off RFC 9113 leading and
+ * trailing white spaces validation against HTTP field value. Some
+ * important fields, such as HTTP/2 pseudo header fields, are
+ * validated more strictly and this option does not apply to them.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
+ * This function sets the rate limit for the incoming stream reset
+ * (RST_STREAM frame). It is server use only. 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. An incoming RST_STREAM consumes one token.
+ * 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_stream_reset_rate_limit(nghttp2_option *option,
+ uint64_t burst, uint64_t rate);
+
/**
* @function
*
@@ -3589,6 +3643,11 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
@@ -3632,6 +3691,11 @@ nghttp2_session_change_stream_priority(nghttp2_session *session,
* found, we use default priority instead of given |pri_spec|. That
* is make stream depend on root stream with weight 16.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is submitted via `nghttp2_submit_settings()`, this
+ * function does nothing and returns 0.
+ *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
@@ -3837,6 +3901,11 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
* :macro:`NGHTTP2_MAX_WEIGHT`.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
+ *
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
* required pseudo-header fields (header field whose name starts with
@@ -4057,6 +4126,11 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
* :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`.
*
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is received by a remote endpoint, |pri_spec| is
+ * ignored, and treated as if ``NULL`` is specified.
+ *
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
* |nvlen| elements. The application is responsible to include
* required pseudo-header fields (header field whose name starts with
@@ -4184,6 +4258,11 @@ NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
* :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:
*
@@ -4198,6 +4277,61 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const nghttp2_priority_spec *pri_spec);
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_DEFAULT_URGENCY` is the default urgency
+ * level for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_DEFAULT_URGENCY 3
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_HIGH` is the highest urgency level
+ * for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_HIGH 0
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW` is the lowest urgency level for
+ * :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LOW 7
+
+/**
+ * @macro
+ *
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LEVELS` is the number of urgency
+ * levels for :rfc:`9218` extensible priorities.
+ */
+#define NGHTTP2_EXTPRI_URGENCY_LEVELS (NGHTTP2_EXTPRI_URGENCY_LOW + 1)
+
+/**
+ * @struct
+ *
+ * :type:`nghttp2_extpri` is :rfc:`9218` extensible priorities
+ * specification for a stream.
+ */
+typedef struct nghttp2_extpri {
+ /**
+ * :member:`urgency` is the urgency of a stream, it must be in
+ * [:macro:`NGHTTP2_EXTPRI_URGENCY_HIGH`,
+ * :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`], inclusive, and 0 is the
+ * highest urgency.
+ */
+ uint32_t urgency;
+ /**
+ * :member:`inc` indicates that a content can be processed
+ * incrementally or not. If inc is 0, it cannot be processed
+ * incrementally. If inc is 1, it can be processed incrementally.
+ * Other value is not permitted.
+ */
+ int inc;
+} nghttp2_extpri;
+
/**
* @function
*
@@ -4722,6 +4856,108 @@ NGHTTP2_EXTERN int nghttp2_submit_origin(nghttp2_session *session,
const nghttp2_origin_entry *ov,
size_t nov);
+/**
+ * @struct
+ *
+ * The payload of PRIORITY_UPDATE frame. PRIORITY_UPDATE frame is a
+ * non-critical extension to HTTP/2. If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`nghttp2_frame_type.NGHTTP2_PRIORITY_UPDATE`,
+ * ``nghttp2_extension.payload`` will point to this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+ /**
+ * The stream ID of the stream whose priority is updated.
+ */
+ int32_t stream_id;
+ /**
+ * The pointer to Priority field value. It is not necessarily
+ * NULL-terminated.
+ */
+ uint8_t *field_value;
+ /**
+ * The length of the :member:`field_value`.
+ */
+ size_t field_value_len;
+} nghttp2_ext_priority_update;
+
+/**
+ * @function
+ *
+ * Submits PRIORITY_UPDATE frame.
+ *
+ * PRIORITY_UPDATE frame is a non-critical extension to HTTP/2, and
+ * defined in :rfc:`9218#section-7.1`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the ID of stream which is prioritized. The
+ * |field_value| points to the Priority field value. The
+ * |field_value_len| is the length of the Priority field value.
+ *
+ * If this function is called by server,
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` is returned.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 0 is received by a remote endpoint (or it is omitted),
+ * this function does nothing and returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The function is called from server side session
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * The |field_value_len| is larger than 16380; or |stream_id| is
+ * 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session,
+ uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Changes the priority of the existing stream denoted by |stream_id|.
+ * The new priority is |extpri|. This function is meant to be used by
+ * server for :rfc:`9218` extensible prioritization scheme.
+ *
+ * If |session| is initialized as client, this function returns
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. For client, use
+ * `nghttp2_submit_priority_update()` instead.
+ *
+ * If :member:`extpri->urgency <nghttp2_extpri.urgency>` is out of
+ * bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`.
+ *
+ * If |ignore_client_signal| is nonzero, server starts to ignore
+ * client priority signals for this stream.
+ *
+ * If
+ * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
+ * of value of 1 is not submitted via `nghttp2_submit_settings()`,
+ * this function does nothing and returns 0.
+ *
+ * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
+ * Out of memory.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
+ * The |session| is initialized as client.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * |stream_id| is zero; or a stream denoted by |stream_id| is not
+ * found.
+ */
+NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri,
+ int ignore_client_signal);
+
/**
* @function
*
@@ -4833,9 +5069,23 @@ NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
* Returns nonzero if HTTP header field value |value| of length |len|
* is valid according to
* http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * This function is considered obsolete, and application should
+ * consider to use `nghttp2_check_header_value_rfc9113()` instead.
*/
NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
+/**
+ * @function
+ *
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2, plus
+ * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value,
+ size_t len);
+
/**
* @function
*
diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h
index c608251..f56954e 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.47.0"
+#define NGHTTP2_VERSION "1.57.0"
/**
* @macro
@@ -37,6 +37,6 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define NGHTTP2_VERSION_NUM 0x012f00
+#define NGHTTP2_VERSION_NUM 0x013900
#endif /* NGHTTP2VER_H */
diff --git a/deps/nghttp2/lib/nghttp2_extpri.c b/deps/nghttp2/lib/nghttp2_extpri.c
new file mode 100644
index 0000000..3fd9b78
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_extpri.c
@@ -0,0 +1,35 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_extpri.h"
+
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
+ return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
+}
+
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
+ extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
+ extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
+}
diff --git a/deps/nghttp2/lib/nghttp2_extpri.h b/deps/nghttp2/lib/nghttp2_extpri.h
new file mode 100644
index 0000000..23c6ddc
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_extpri.h
@@ -0,0 +1,65 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2022 nghttp3 contributors
+ * Copyright (c) 2022 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_EXTPRI_H
+#define NGHTTP2_EXTPRI_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
+ * from a value produced by nghttp2_extpri_to_uint8.
+ */
+#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
+
+/*
+ * nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
+ */
+uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
+
+/*
+ * nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
+ * nghttp2_extpri_to_uint8, intto |extpri|.
+ */
+void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
+
+/*
+ * nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
+ * supposed to be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_urgency(PRI) \
+ ((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
+
+/*
+ * nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
+ * be constructed by nghttp2_extpri_to_uint8.
+ */
+#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
+
+#endif /* NGHTTP2_EXTPRI_H */
diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c
index 3648b23..77cb463 100644
--- a/deps/nghttp2/lib/nghttp2_frame.c
+++ b/deps/nghttp2/lib/nghttp2_frame.c
@@ -253,6 +253,31 @@ void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
nghttp2_mem_free(mem, origin->ov);
}
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_ext_priority_update *priority_update;
+
+ nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
+ NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
+
+ priority_update = frame->payload;
+ priority_update->stream_id = stream_id;
+ priority_update->field_value = field_value;
+ priority_update->field_value_len = field_value_len;
+}
+
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem) {
+ nghttp2_ext_priority_update *priority_update;
+
+ priority_update = frame->payload;
+ if (priority_update == NULL) {
+ return;
+ }
+ nghttp2_mem_free(mem, priority_update->field_value);
+}
+
size_t nghttp2_frame_priority_len(uint8_t flags) {
if (flags & NGHTTP2_FLAG_PRIORITY) {
return NGHTTP2_PRIORITY_SPECLEN;
@@ -393,8 +418,8 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
}
-int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
- const uint8_t *payload) {
+void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
+ const uint8_t *payload) {
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
} else {
@@ -403,11 +428,9 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
frame->nva = NULL;
frame->nvlen = 0;
-
- return 0;
}
-int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
+void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
nghttp2_buf *buf;
assert(bufs->head == bufs->cur);
@@ -423,8 +446,6 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
buf->last += NGHTTP2_PRIORITY_SPECLEN;
-
- return 0;
}
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
@@ -432,8 +453,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
}
-int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
- nghttp2_rst_stream *frame) {
+void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
+ nghttp2_rst_stream *frame) {
nghttp2_buf *buf;
assert(bufs->head == bufs->cur);
@@ -448,8 +469,6 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
nghttp2_put_uint32be(buf->last, frame->error_code);
buf->last += 4;
-
- return 0;
}
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
@@ -567,16 +586,15 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
return frame_pack_headers_shared(bufs, &frame->hd);
}
-int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
- const uint8_t *payload) {
+void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
+ const uint8_t *payload) {
frame->promised_stream_id =
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
frame->nva = NULL;
frame->nvlen = 0;
- return 0;
}
-int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
+void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
nghttp2_buf *buf;
assert(bufs->head == bufs->cur);
@@ -591,8 +609,6 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
buf->last =
nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
-
- return 0;
}
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
@@ -672,8 +688,8 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
return 0;
}
-int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
- nghttp2_window_update *frame) {
+void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
+ nghttp2_window_update *frame) {
nghttp2_buf *buf;
assert(bufs->head == bufs->cur);
@@ -688,8 +704,6 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment);
buf->last += 4;
-
- return 0;
}
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
@@ -698,7 +712,7 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
}
-int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
+void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
int rv;
nghttp2_buf *buf;
nghttp2_ext_altsvc *altsvc;
@@ -727,8 +741,6 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len);
assert(rv == 0);
-
- return 0;
}
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
@@ -876,6 +888,55 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
return 0;
}
+void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *frame) {
+ int rv;
+ nghttp2_buf *buf;
+ nghttp2_ext_priority_update *priority_update;
+
+ /* This is required with --disable-assert. */
+ (void)rv;
+
+ priority_update = frame->payload;
+
+ buf = &bufs->head->buf;
+
+ assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
+
+ buf->pos -= NGHTTP2_FRAME_HDLEN;
+
+ nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
+
+ nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
+ buf->last += 4;
+
+ rv = nghttp2_bufs_add(bufs, priority_update->field_value,
+ priority_update->field_value_len);
+
+ assert(rv == 0);
+}
+
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen) {
+ nghttp2_ext_priority_update *priority_update;
+
+ assert(payloadlen >= 4);
+
+ priority_update = frame->payload;
+
+ priority_update->stream_id =
+ nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
+
+ if (payloadlen > 4) {
+ priority_update->field_value = payload + 4;
+ priority_update->field_value_len = payloadlen - 4;
+ } else {
+ priority_update->field_value = NULL;
+ priority_update->field_value_len = 0;
+ }
+}
+
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv, nghttp2_mem *mem) {
nghttp2_settings_entry *iv_copy;
@@ -1071,6 +1132,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
return 0;
}
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ if (iv[i].value != 0 && iv[i].value != 1) {
+ return 0;
+ }
+ break;
}
}
return 1;
@@ -1105,14 +1171,14 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
buf->last += trail_padlen;
}
-int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
- size_t padlen, int framehd_only) {
+void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
+ size_t padlen, int framehd_only) {
nghttp2_buf *buf;
if (padlen == 0) {
DEBUGF("send: padlen = 0, nothing to do\n");
- return 0;
+ return;
}
/*
@@ -1145,6 +1211,4 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
hd->flags |= NGHTTP2_FLAG_PADDED;
DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen);
-
- return 0;
}
diff --git a/deps/nghttp2/lib/nghttp2_frame.h b/deps/nghttp2/lib/nghttp2_frame.h
index 3859926..d586688 100644
--- a/deps/nghttp2/lib/nghttp2_frame.h
+++ b/deps/nghttp2/lib/nghttp2_frame.h
@@ -73,6 +73,7 @@
typedef union {
nghttp2_ext_altsvc altsvc;
nghttp2_ext_origin origin;
+ nghttp2_ext_priority_update priority_update;
} nghttp2_ext_frame_payload;
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
@@ -142,11 +143,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
* Unpacks HEADERS frame byte sequence into |frame|. This function
* only unapcks bytes that come before name/value header block and
* after possible Pad Length field.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
- const uint8_t *payload);
+void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
+ const uint8_t *payload);
/*
* Packs PRIORITY frame |frame| in wire format and store it in
@@ -154,10 +153,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
+void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
/*
* Unpacks PRIORITY wire format into |frame|.
@@ -171,11 +168,9 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
- nghttp2_rst_stream *frame);
+void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
+ nghttp2_rst_stream *frame);
/*
* Unpacks RST_STREAM frame byte sequence into |frame|.
@@ -264,15 +259,9 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This
* function only unapcks bytes that come before name/value header
* block and after possible Pad Length field.
- *
- * This function returns 0 if it succeeds or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_PROTO
- * TODO END_HEADERS flag is not set
*/
-int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
- const uint8_t *payload);
+void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
+ const uint8_t *payload);
/*
* Packs PING frame |frame| in wire format and store it in
@@ -280,10 +269,8 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
+void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
/*
* Unpacks PING wire format into |frame|.
@@ -342,11 +329,9 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
- nghttp2_window_update *frame);
+void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
+ nghttp2_window_update *frame);
/*
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
@@ -360,17 +345,13 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
*
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
* before calling this function.
- *
- * This function always succeeds and returns 0.
*/
-int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
+void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
/*
* Unpacks ALTSVC wire format into |frame|. The |payload| of
* |payloadlen| bytes contains frame payload. This function assumes
* that frame->payload points to the nghttp2_ext_altsvc object.
- *
- * This function always succeeds and returns 0.
*/
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
size_t origin_len, uint8_t *payload,
@@ -423,6 +404,27 @@ int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
const uint8_t *payload,
size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PRIORITY_UPDATE frame |frame| in wire frame format and store
+ * it in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ */
+void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
+ nghttp2_extension *ext);
+
+/*
+ * Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of
+ * |payloadlen| bytes contains frame payload. This function assumes
+ * that frame->payload points to the nghttp2_ext_priority_update
+ * object.
+ */
+void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
+ uint8_t *payload,
+ size_t payloadlen);
+
/*
* Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is
@@ -538,6 +540,25 @@ void nghttp2_frame_origin_init(nghttp2_extension *frame,
*/
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
+/*
+ * Initializes PRIORITY_UPDATE frame |frame| with given values. This
+ * function assumes that frame->payload points to
+ * nghttp2_ext_priority_update object. On success, this function
+ * takes ownership of |field_value|, so caller must not free it.
+ */
+void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
+ int32_t stream_id, uint8_t *field_value,
+ size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|. This function does not free
+ * nghttp2_ext_priority_update object pointed by frame->payload. This
+ * function only frees field_value pointed by
+ * nghttp2_ext_priority_update.field_value.
+ */
+void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
+ nghttp2_mem *mem);
+
/*
* Returns the number of padding bytes after payload. The total
* padding length is given in the |padlen|. The returned value does
@@ -609,16 +630,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
* |padlen| including Pad Length field. The |hd| is the frame header
* for the serialized data. This function fills zeros padding region
* unless framehd_only is nonzero.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- * NGHTTP2_ERR_FRAME_SIZE_ERROR
- * The length of the resulting frame is too large.
*/
-int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
- size_t padlen, int framehd_only);
+void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
+ size_t padlen, int framehd_only);
#endif /* NGHTTP2_FRAME_H */
diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c
index 30ee9b8..8a2bda6 100644
--- a/deps/nghttp2/lib/nghttp2_hd.c
+++ b/deps/nghttp2/lib/nghttp2_hd.c
@@ -269,6 +269,11 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
return NGHTTP2_TOKEN_LOCATION;
}
break;
+ case 'y':
+ if (memeq("priorit", name, 7)) {
+ return NGHTTP2_TOKEN_PRIORITY;
+ }
+ break;
}
break;
case 9:
diff --git a/deps/nghttp2/lib/nghttp2_hd.h b/deps/nghttp2/lib/nghttp2_hd.h
index 2674028..6de0052 100644
--- a/deps/nghttp2/lib/nghttp2_hd.h
+++ b/deps/nghttp2/lib/nghttp2_hd.h
@@ -112,6 +112,7 @@ typedef enum {
NGHTTP2_TOKEN_PROXY_CONNECTION,
NGHTTP2_TOKEN_UPGRADE,
NGHTTP2_TOKEN__PROTOCOL,
+ NGHTTP2_TOKEN_PRIORITY,
} nghttp2_token;
struct nghttp2_hd_entry;
diff --git a/deps/nghttp2/lib/nghttp2_helper.c b/deps/nghttp2/lib/nghttp2_helper.c
index 588e269..93dd475 100644
--- a/deps/nghttp2/lib/nghttp2_helper.c
+++ b/deps/nghttp2/lib/nghttp2_helper.c
@@ -507,6 +507,19 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
return 1;
}
+int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
+ if (len == 0) {
+ return 1;
+ }
+
+ if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
+ *(value + len - 1) == '\t') {
+ return 0;
+ }
+
+ return nghttp2_check_header_value(value, len);
+}
+
/* Generated by genmethodchartbl.py */
static char VALID_METHOD_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c
index a2bcd2c..ecdeb21 100644
--- a/deps/nghttp2/lib/nghttp2_http.c
+++ b/deps/nghttp2/lib/nghttp2_http.c
@@ -30,6 +30,8 @@
#include "nghttp2_hd.h"
#include "nghttp2_helper.h"
+#include "nghttp2_extpri.h"
+#include "sfparse.h"
static uint8_t downcase(uint8_t c) {
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
@@ -72,25 +74,12 @@ static int64_t parse_uint(const uint8_t *s, size_t len) {
return n;
}
-static int lws(const uint8_t *s, size_t n) {
- size_t i;
- for (i = 0; i < n; ++i) {
- if (s[i] != ' ' && s[i] != '\t') {
- return 0;
- }
- }
- return 1;
-}
-
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
- int flag) {
- if (stream->http_flags & flag) {
- return 0;
- }
- if (lws(nv->value->base, nv->value->len)) {
+ uint32_t flag) {
+ if ((stream->http_flags & flag) || nv->value->len == 0) {
return 0;
}
- stream->http_flags = (uint16_t)(stream->http_flags | flag);
+ stream->http_flags = stream->http_flags | flag;
return 1;
}
@@ -114,6 +103,8 @@ static int check_path(nghttp2_stream *stream) {
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer, int connect_protocol) {
+ nghttp2_extpri extpri;
+
if (nv->name->base[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
@@ -212,6 +203,23 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
+ case NGHTTP2_TOKEN_PRIORITY:
+ if (!trailer &&
+ /* Do not parse the header field in PUSH_PROMISE. */
+ (stream->stream_id & 1) &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
+ nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
+ if (nghttp2_http_parse_priority(&extpri, nv->value->base,
+ nv->value->len) == 0) {
+ stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
+ } else {
+ stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
+ stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
+ }
+ }
+ break;
default:
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
@@ -329,6 +337,16 @@ static int check_scheme(const uint8_t *value, size_t len) {
return 1;
}
+static int lws(const uint8_t *s, size_t n) {
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ if (s[i] != ' ' && s[i] != '\t') {
+ return 0;
+ }
+ }
+ return 1;
+}
+
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer) {
@@ -369,13 +387,37 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
break;
case NGHTTP2_TOKEN__AUTHORITY:
case NGHTTP2_TOKEN_HOST:
- rv = nghttp2_check_authority(nv->value->base, nv->value->len);
+ if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+ rv = nghttp2_check_authority(nv->value->base, nv->value->len);
+ } else if (
+ stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
break;
case NGHTTP2_TOKEN__SCHEME:
rv = check_scheme(nv->value->base, nv->value->len);
break;
+ case NGHTTP2_TOKEN__PROTOCOL:
+ /* Check the value consists of just white spaces, which was done
+ in check_pseudo_header before
+ nghttp2_check_header_value_rfc9113 has been introduced. */
+ if ((stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ lws(nv->value->base, nv->value->len)) {
+ rv = 0;
+ break;
+ }
+ /* fall through */
default:
- rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ if (stream->flags &
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
+ } else {
+ rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
+ }
}
if (rv == 0) {
@@ -443,16 +485,15 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
if (stream->status_code / 100 == 1) {
/* non-final response */
- stream->http_flags =
- (uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
- NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
+ NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
stream->content_length = -1;
stream->status_code = -1;
return 0;
}
stream->http_flags =
- (uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
+ stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
if (!expect_response_body(stream)) {
stream->content_length = 0;
@@ -537,3 +578,54 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
return;
}
}
+
+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;
+ int rv;
+
+ sf_parser_init(&sfp, value, valuelen);
+
+ for (;;) {
+ rv = sf_parser_dict(&sfp, &key, &val);
+ if (rv != 0) {
+ if (rv == SF_ERR_EOF) {
+ break;
+ }
+
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (key.len != 1) {
+ continue;
+ }
+
+ switch (key.base[0]) {
+ case 'i':
+ if (val.type != SF_TYPE_BOOLEAN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.inc = val.boolean;
+
+ break;
+ case 'u':
+ if (val.type != SF_TYPE_INTEGER ||
+ val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH ||
+ NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ pri.urgency = (uint32_t)val.integer;
+
+ break;
+ }
+ }
+
+ *dest = pri;
+
+ return 0;
+}
diff --git a/deps/nghttp2/lib/nghttp2_http.h b/deps/nghttp2/lib/nghttp2_http.h
index dd057cd..d9992fe 100644
--- a/deps/nghttp2/lib/nghttp2_http.h
+++ b/deps/nghttp2/lib/nghttp2_http.h
@@ -94,4 +94,7 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
void nghttp2_http_record_request_method(nghttp2_stream *stream,
nghttp2_frame *frame);
+int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
+ size_t valuelen);
+
#endif /* NGHTTP2_HTTP_H */
diff --git a/deps/nghttp2/lib/nghttp2_map.c b/deps/nghttp2/lib/nghttp2_map.c
index e5db168..5f63fc2 100644
--- a/deps/nghttp2/lib/nghttp2_map.c
+++ b/deps/nghttp2/lib/nghttp2_map.c
@@ -31,21 +31,14 @@
#include "nghttp2_helper.h"
-#define NGHTTP2_INITIAL_TABLE_LENBITS 8
+#define NGHTTP2_INITIAL_TABLE_LENBITS 4
-int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
+void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
- map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
- map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
- map->table =
- nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
- if (map->table == NULL) {
- return NGHTTP2_ERR_NOMEM;
- }
-
+ map->tablelen = 0;
+ map->tablelenbits = 0;
+ map->table = NULL;
map->size = 0;
-
- return 0;
}
void nghttp2_map_free(nghttp2_map *map) {
@@ -78,6 +71,10 @@ int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
uint32_t i;
nghttp2_map_bucket *bkt;
+ if (map->size == 0) {
+ return 0;
+ }
+
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
@@ -223,9 +220,17 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
- rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
- if (rv != 0) {
- return rv;
+ if (map->tablelen) {
+ rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
+ if (rv != 0) {
+ return rv;
+ }
+ } else {
+ rv = map_resize(map, 1 << NGHTTP2_INITIAL_TABLE_LENBITS,
+ NGHTTP2_INITIAL_TABLE_LENBITS);
+ if (rv != 0) {
+ return rv;
+ }
}
}
@@ -239,11 +244,18 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
}
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
- uint32_t h = hash(key);
- size_t idx = h2idx(h, map->tablelenbits);
+ uint32_t h;
+ size_t idx;
nghttp2_map_bucket *bkt;
size_t d = 0;
+ if (map->size == 0) {
+ return NULL;
+ }
+
+ h = hash(key);
+ idx = h2idx(h, map->tablelenbits);
+
for (;;) {
bkt = &map->table[idx];
@@ -262,11 +274,18 @@ void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
}
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
- uint32_t h = hash(key);
- size_t idx = h2idx(h, map->tablelenbits), didx;
+ uint32_t h;
+ size_t idx, didx;
nghttp2_map_bucket *bkt;
size_t d = 0;
+ if (map->size == 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ h = hash(key);
+ idx = h2idx(h, map->tablelenbits);
+
for (;;) {
bkt = &map->table[idx];
@@ -306,6 +325,10 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
}
void nghttp2_map_clear(nghttp2_map *map) {
+ if (map->tablelen == 0) {
+ return;
+ }
+
memset(map->table, 0, sizeof(*map->table) * map->tablelen);
map->size = 0;
}
diff --git a/deps/nghttp2/lib/nghttp2_map.h b/deps/nghttp2/lib/nghttp2_map.h
index 1419a09..d90245a 100644
--- a/deps/nghttp2/lib/nghttp2_map.h
+++ b/deps/nghttp2/lib/nghttp2_map.h
@@ -54,14 +54,8 @@ typedef struct nghttp2_map {
/*
* Initializes the map |map|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory
*/
-int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
+void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |map|. The stored entries
diff --git a/deps/nghttp2/lib/nghttp2_net.h b/deps/nghttp2/lib/nghttp2_net.h
index 582099b..521f981 100644
--- a/deps/nghttp2/lib/nghttp2_net.h
+++ b/deps/nghttp2/lib/nghttp2_net.h
@@ -53,7 +53,7 @@
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostlong >> 24;
+ *p++ = (unsigned char)(hostlong >> 24);
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
@@ -63,7 +63,7 @@ STIN uint32_t htonl(uint32_t hostlong) {
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
- *p++ = hostshort >> 8;
+ *p++ = (unsigned char)(hostshort >> 8);
*p = hostshort & 0xffu;
return res;
}
@@ -71,9 +71,9 @@ STIN uint16_t htons(uint16_t hostshort) {
STIN uint32_t ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
- res = *p++ << 24;
- res += *p++ << 16;
- res += *p++ << 8;
+ res = (uint32_t)(*p++ << 24);
+ res += (uint32_t)(*p++ << 16);
+ res += (uint32_t)(*p++ << 8);
res += *p;
return res;
}
@@ -81,7 +81,7 @@ STIN uint32_t ntohl(uint32_t netlong) {
STIN uint16_t ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
- res = *p++ << 8;
+ res = (uint16_t)(*p++ << 8);
res += *p;
return res;
}
diff --git a/deps/nghttp2/lib/nghttp2_option.c b/deps/nghttp2/lib/nghttp2_option.c
index 34348e6..43d4e95 100644
--- a/deps/nghttp2/lib/nghttp2_option.c
+++ b/deps/nghttp2/lib/nghttp2_option.c
@@ -90,6 +90,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
return;
+ case NGHTTP2_PRIORITY_UPDATE:
+ option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
+ option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE;
+ return;
default:
return;
}
@@ -126,3 +130,23 @@ void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
option->max_settings = val;
}
+
+void nghttp2_option_set_server_fallback_rfc7540_priorities(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ option->server_fallback_rfc7540_priorities = val;
+}
+
+void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
+ nghttp2_option *option, int val) {
+ option->opt_set_mask |=
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ option->no_rfc9113_leading_and_trailing_ws_validation = val;
+}
+
+void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option,
+ uint64_t burst, uint64_t rate) {
+ option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT;
+ option->stream_reset_burst = burst;
+ option->stream_reset_rate = rate;
+}
diff --git a/deps/nghttp2/lib/nghttp2_option.h b/deps/nghttp2/lib/nghttp2_option.h
index 939729f..2259e18 100644
--- a/deps/nghttp2/lib/nghttp2_option.h
+++ b/deps/nghttp2/lib/nghttp2_option.h
@@ -68,12 +68,20 @@ typedef enum {
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
+ NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15,
} nghttp2_option_flag;
/**
* Struct to store option values for nghttp2_session.
*/
struct nghttp2_option {
+ /**
+ * NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT
+ */
+ uint64_t stream_reset_burst;
+ uint64_t stream_reset_rate;
/**
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
*/
@@ -127,6 +135,14 @@ struct nghttp2_option {
* NGHTTP2_OPT_NO_CLOSED_STREAMS
*/
int no_closed_streams;
+ /**
+ * NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES
+ */
+ int server_fallback_rfc7540_priorities;
+ /**
+ * NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION
+ */
+ int no_rfc9113_leading_and_trailing_ws_validation;
/**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
diff --git a/deps/nghttp2/lib/nghttp2_outbound_item.c b/deps/nghttp2/lib/nghttp2_outbound_item.c
index f651c80..2a3041d 100644
--- a/deps/nghttp2/lib/nghttp2_outbound_item.c
+++ b/deps/nghttp2/lib/nghttp2_outbound_item.c
@@ -89,6 +89,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
case NGHTTP2_ORIGIN:
nghttp2_frame_origin_free(&frame->ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ break;
default:
assert(0);
break;
diff --git a/deps/nghttp2/lib/nghttp2_pq.c b/deps/nghttp2/lib/nghttp2_pq.c
index bebccc7..64353ac 100644
--- a/deps/nghttp2/lib/nghttp2_pq.c
+++ b/deps/nghttp2/lib/nghttp2_pq.c
@@ -29,13 +29,12 @@
#include "nghttp2_helper.h"
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
pq->mem = mem;
pq->capacity = 0;
pq->q = NULL;
pq->length = 0;
pq->less = less;
- return 0;
}
void nghttp2_pq_free(nghttp2_pq *pq) {
diff --git a/deps/nghttp2/lib/nghttp2_pq.h b/deps/nghttp2/lib/nghttp2_pq.h
index 7b7b739..c8d90ef 100644
--- a/deps/nghttp2/lib/nghttp2_pq.h
+++ b/deps/nghttp2/lib/nghttp2_pq.h
@@ -55,14 +55,8 @@ typedef struct {
/*
* Initializes priority queue |pq| with compare function |cmp|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
*/
-int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |pq|. The stored items are
diff --git a/deps/nghttp2/lib/nghttp2_ratelim.c b/deps/nghttp2/lib/nghttp2_ratelim.c
new file mode 100644
index 0000000..7011655
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_ratelim.c
@@ -0,0 +1,75 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_ratelim.h"
+#include "nghttp2_helper.h"
+
+void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) {
+ rl->val = rl->burst = burst;
+ rl->rate = rate;
+ rl->tstamp = 0;
+}
+
+void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) {
+ uint64_t d, gain;
+
+ if (tstamp == rl->tstamp) {
+ return;
+ }
+
+ if (tstamp > rl->tstamp) {
+ d = tstamp - rl->tstamp;
+ } else {
+ d = 1;
+ }
+
+ rl->tstamp = tstamp;
+
+ if (UINT64_MAX / d < rl->rate) {
+ rl->val = rl->burst;
+
+ return;
+ }
+
+ gain = rl->rate * d;
+
+ if (UINT64_MAX - gain < rl->val) {
+ rl->val = rl->burst;
+
+ return;
+ }
+
+ rl->val += gain;
+ rl->val = nghttp2_min(rl->val, rl->burst);
+}
+
+int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) {
+ if (rl->val < n) {
+ return -1;
+ }
+
+ rl->val -= n;
+
+ return 0;
+}
diff --git a/deps/nghttp2/lib/nghttp2_ratelim.h b/deps/nghttp2/lib/nghttp2_ratelim.h
new file mode 100644
index 0000000..866ed3f
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_ratelim.h
@@ -0,0 +1,57 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_RATELIM_H
+#define NGHTTP2_RATELIM_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+typedef struct nghttp2_ratelim {
+ /* burst is the maximum value of val. */
+ uint64_t burst;
+ /* rate is the amount of value that is regenerated per 1 tstamp. */
+ uint64_t rate;
+ /* val is the amount of value available to drain. */
+ uint64_t val;
+ /* tstamp is the last timestamp in second resolution that is known
+ to this object. */
+ uint64_t tstamp;
+} nghttp2_ratelim;
+
+/* nghttp2_ratelim_init initializes |rl| with the given parameters. */
+void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate);
+
+/* nghttp2_ratelim_update updates rl->val with the current |tstamp|
+ given in second resolution. */
+void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp);
+
+/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it
+ succeeds, or -1. */
+int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n);
+
+#endif /* NGHTTP2_RATELIM_H */
diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c
index 380a47c..ec5024d 100644
--- a/deps/nghttp2/lib/nghttp2_session.c
+++ b/deps/nghttp2/lib/nghttp2_session.c
@@ -36,6 +36,8 @@
#include "nghttp2_option.h"
#include "nghttp2_http.h"
#include "nghttp2_pq.h"
+#include "nghttp2_extpri.h"
+#include "nghttp2_time.h"
#include "nghttp2_debug.h"
/*
@@ -143,6 +145,11 @@ static int session_detect_idle_stream(nghttp2_session *session,
return 0;
}
+static int session_no_rfc7540_pri_no_fallback(nghttp2_session *session) {
+ return session->pending_no_rfc7540_priorities == 1 &&
+ !session->fallback_rfc7540_priorities;
+}
+
static int check_ext_type_set(const uint8_t *ext_types, uint8_t type) {
return (ext_types[type / 8] & (1 << (type & 0x7))) > 0;
}
@@ -354,6 +361,14 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
}
nghttp2_frame_origin_free(&iframe->frame.ext, mem);
break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ break;
+ }
+ /* Do not call nghttp2_frame_priority_update_free, because all
+ fields point to sbuf. */
+ break;
}
}
@@ -385,6 +400,7 @@ static void init_settings(nghttp2_settings_storage *settings) {
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
settings->max_header_list_size = UINT32_MAX;
+ settings->no_rfc7540_priorities = UINT32_MAX;
}
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
@@ -398,6 +414,21 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
aob->state = NGHTTP2_OB_POP_ITEM;
}
+#define NGHTTP2_STREAM_MAX_CYCLE_GAP ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX)
+
+static int stream_less(const void *lhsx, const void *rhsx) {
+ const nghttp2_stream *lhs, *rhs;
+
+ lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
+ rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
+
+ if (lhs->cycle == rhs->cycle) {
+ return lhs->seq < rhs->seq;
+ }
+
+ return rhs->cycle - lhs->cycle <= NGHTTP2_STREAM_MAX_CYCLE_GAP;
+}
+
int nghttp2_enable_strict_preface = 1;
static int session_new(nghttp2_session **session_ptr,
@@ -408,6 +439,7 @@ static int session_new(nghttp2_session **session_ptr,
size_t nbuffer;
size_t max_deflate_dynamic_table_size =
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
+ size_t i;
if (mem == NULL) {
mem = nghttp2_mem_default();
@@ -442,6 +474,11 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->pending_local_max_concurrent_stream =
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
(*session_ptr)->pending_enable_push = 1;
+ (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
+
+ nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
+ NGHTTP2_DEFAULT_STREAM_RESET_BURST,
+ NGHTTP2_DEFAULT_STREAM_RESET_RATE);
if (server) {
(*session_ptr)->server = 1;
@@ -527,6 +564,26 @@ static int session_new(nghttp2_session **session_ptr,
option->max_settings) {
(*session_ptr)->max_settings = option->max_settings;
}
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES) &&
+ option->server_fallback_rfc7540_priorities) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES;
+ }
+
+ if ((option->opt_set_mask &
+ NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
+ option->no_rfc9113_leading_and_trailing_ws_validation) {
+ (*session_ptr)->opt_flags |=
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
+
+ if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) {
+ nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
+ option->stream_reset_burst,
+ option->stream_reset_rate);
+ }
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -538,10 +595,6 @@ static int session_new(nghttp2_session **session_ptr,
if (rv != 0) {
goto fail_hd_inflater;
}
- rv = nghttp2_map_init(&(*session_ptr)->streams, mem);
- if (rv != 0) {
- goto fail_map;
- }
nbuffer = ((*session_ptr)->max_send_header_block_length +
NGHTTP2_FRAMEBUF_CHUNKLEN - 1) /
@@ -559,6 +612,8 @@ static int session_new(nghttp2_session **session_ptr,
goto fail_aob_framebuf;
}
+ nghttp2_map_init(&(*session_ptr)->streams, mem);
+
active_outbound_item_reset(&(*session_ptr)->aob, mem);
(*session_ptr)->callbacks = *callbacks;
@@ -584,11 +639,13 @@ static int session_new(nghttp2_session **session_ptr,
}
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_init(&(*session_ptr)->sched[i].ob_data, stream_less, mem);
+ }
+
return 0;
fail_aob_framebuf:
- nghttp2_map_free(&(*session_ptr)->streams);
-fail_map:
nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater);
fail_hd_inflater:
nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater);
@@ -735,6 +792,7 @@ static void inflight_settings_del(nghttp2_inflight_settings *settings,
void nghttp2_session_del(nghttp2_session *session) {
nghttp2_mem *mem;
nghttp2_inflight_settings *settings;
+ size_t i;
if (session == NULL) {
return;
@@ -748,6 +806,9 @@ void nghttp2_session_del(nghttp2_session *session) {
settings = next;
}
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ nghttp2_pq_free(&session->sched[i].ob_data);
+ }
nghttp2_stream_free(&session->root);
/* Have to free streams first, so that we can check
@@ -775,6 +836,8 @@ int nghttp2_session_reprioritize_stream(
nghttp2_priority_spec pri_spec_default;
const nghttp2_priority_spec *pri_spec = pri_spec_in;
+ assert((!session->server && session->pending_no_rfc7540_priorities != 1) ||
+ (session->server && !session_no_rfc7540_pri_no_fallback(session)));
assert(pri_spec->stream_id != stream->stream_id);
if (!nghttp2_stream_in_dep_tree(stream)) {
@@ -842,6 +905,202 @@ int nghttp2_session_reprioritize_stream(
return 0;
}
+static uint64_t pq_get_first_cycle(nghttp2_pq *pq) {
+ nghttp2_stream *stream;
+
+ if (nghttp2_pq_empty(pq)) {
+ return 0;
+ }
+
+ stream = nghttp2_struct_of(nghttp2_pq_top(pq), nghttp2_stream, pq_entry);
+ return stream->cycle;
+}
+
+static int session_ob_data_push(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ int rv;
+ uint32_t urgency;
+ int inc;
+ nghttp2_pq *pq;
+
+ assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
+ assert(stream->queued == 0);
+
+ urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ inc = nghttp2_extpri_uint8_inc(stream->extpri);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ stream->cycle = pq_get_first_cycle(pq);
+ if (inc) {
+ stream->cycle += stream->last_writelen;
+ }
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+ if (rv != 0) {
+ return rv;
+ }
+
+ stream->queued = 1;
+
+ return 0;
+}
+
+static 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);
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
+
+ stream->queued = 0;
+}
+
+static int session_attach_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ nghttp2_outbound_item *item) {
+ int rv;
+
+ rv = nghttp2_stream_attach_item(stream, item);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static 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) {
+ return;
+ }
+
+ session_ob_data_remove(session, stream);
+}
+
+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) {
+ return;
+ }
+
+ session_ob_data_remove(session, stream);
+}
+
+static int session_resume_deferred_stream_item(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t flags) {
+ int rv;
+
+ rv = nghttp2_stream_resume_deferred_item(stream, flags);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) {
+ return 0;
+ }
+
+ return session_ob_data_push(session, stream);
+}
+
+static nghttp2_outbound_item *
+session_sched_get_next_outbound_item(nghttp2_session *session) {
+ size_t i;
+ nghttp2_pq_entry *ent;
+ nghttp2_stream *stream;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ ent = nghttp2_pq_top(&session->sched[i].ob_data);
+ if (!ent) {
+ continue;
+ }
+
+ stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
+ return stream->item;
+ }
+
+ return NULL;
+}
+
+static int session_sched_empty(nghttp2_session *session) {
+ size_t i;
+
+ for (i = 0; i < NGHTTP2_EXTPRI_URGENCY_LEVELS; ++i) {
+ if (!nghttp2_pq_empty(&session->sched[i].ob_data)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void session_sched_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
+ nghttp2_pq *pq;
+ uint32_t urgency = nghttp2_extpri_uint8_urgency(stream->extpri);
+ int inc = nghttp2_extpri_uint8_inc(stream->extpri);
+ uint64_t penalty = (uint64_t)stream->last_writelen;
+ int rv;
+
+ (void)rv;
+
+ assert(urgency < NGHTTP2_EXTPRI_URGENCY_LEVELS);
+
+ pq = &session->sched[urgency].ob_data;
+
+ if (!inc || nghttp2_pq_size(pq) == 1) {
+ return;
+ }
+
+ nghttp2_pq_remove(pq, &stream->pq_entry);
+
+ stream->cycle += penalty;
+
+ rv = nghttp2_pq_push(pq, &stream->pq_entry);
+
+ assert(0 == rv);
+}
+
+static int session_update_stream_priority(nghttp2_session *session,
+ nghttp2_stream *stream,
+ uint8_t u8extpri) {
+ if (stream->extpri == u8extpri) {
+ return 0;
+ }
+
+ if (stream->queued) {
+ session_ob_data_remove(session, stream);
+
+ stream->extpri = u8extpri;
+
+ return session_ob_data_push(session, stream);
+ }
+
+ stream->extpri = u8extpri;
+
+ return 0;
+}
+
int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_item *item) {
/* TODO Return error if stream is not found for the frame requiring
@@ -863,7 +1122,7 @@ int nghttp2_session_add_item(nghttp2_session *session,
return NGHTTP2_ERR_DATA_EXIST;
}
- rv = nghttp2_stream_attach_item(stream, item);
+ rv = session_attach_stream_item(session, stream, item);
if (rv != 0) {
return rv;
@@ -1039,13 +1298,27 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
mem = &session->mem;
stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (session->opt_flags &
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
+ }
+
if (stream) {
assert(stream->state == NGHTTP2_STREAM_IDLE);
- assert(nghttp2_stream_in_dep_tree(stream));
- nghttp2_session_detach_idle_stream(session, stream);
- rv = nghttp2_stream_dep_remove(stream);
- if (rv != 0) {
- return NULL;
+ assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
+ nghttp2_stream_in_dep_tree(stream));
+
+ if (nghttp2_stream_in_dep_tree(stream)) {
+ assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
+ nghttp2_session_detach_idle_stream(session, stream);
+ rv = nghttp2_stream_dep_remove(stream);
+ if (rv != 0) {
+ return NULL;
+ }
+
+ if (session_no_rfc7540_pri_no_fallback(session)) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
}
} else {
stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream));
@@ -1056,7 +1329,21 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
stream_alloc = 1;
}
- if (pri_spec->stream_id != 0) {
+ if (session_no_rfc7540_pri_no_fallback(session) ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ /* For client which has not received server
+ SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal
+ opportunistically. */
+ if (session->server ||
+ session->remote_settings.no_rfc7540_priorities == 1) {
+ nghttp2_priority_spec_default_init(&pri_spec_default);
+ pri_spec = &pri_spec_default;
+ }
+
+ if (session->pending_no_rfc7540_priorities == 1) {
+ flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
+ }
+ } else if (pri_spec->stream_id != 0) {
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
if (!dep_stream &&
@@ -1102,6 +1389,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
(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++;
+ }
+
rv = nghttp2_map_insert(&session->streams, stream_id, stream);
if (rv != 0) {
nghttp2_stream_free(stream);
@@ -1141,6 +1432,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
}
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return stream;
+ }
+
if (pri_spec->stream_id == 0) {
dep_stream = &session->root;
}
@@ -1180,11 +1475,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
item = stream->item;
- rv = nghttp2_stream_detach_item(stream);
-
- if (rv != 0) {
- return rv;
- }
+ session_detach_stream_item(session, stream);
/* If item is queued, it will be deleted when it is popped
(nghttp2_session_prep_frame() will fail). If session->aob.item
@@ -1230,6 +1521,10 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
/* Closes both directions just in case they are not closed yet */
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return nghttp2_session_destroy_stream(session, stream);
+ }
+
if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 &&
session->server && !is_my_stream_id &&
nghttp2_stream_in_dep_tree(stream)) {
@@ -1784,6 +2079,28 @@ static int session_predicate_origin_send(nghttp2_session *session) {
return 0;
}
+static int session_predicate_priority_update_send(nghttp2_session *session,
+ int32_t stream_id) {
+ nghttp2_stream *stream;
+
+ if (session_is_closing(session)) {
+ return NGHTTP2_ERR_SESSION_CLOSING;
+ }
+
+ stream = nghttp2_session_get_stream(session, stream_id);
+ if (stream == NULL) {
+ return 0;
+ }
+ if (stream->state == NGHTTP2_STREAM_CLOSING) {
+ return NGHTTP2_ERR_STREAM_CLOSING;
+ }
+ if (stream->shut_flags & NGHTTP2_SHUT_RD) {
+ return NGHTTP2_ERR_INVALID_STREAM_STATE;
+ }
+
+ return 0;
+}
+
/* Take into account settings max frame size and both connection-level
flow control here */
static ssize_t
@@ -1899,7 +2216,6 @@ static ssize_t session_call_select_padding(nghttp2_session *session,
frame->push_promise has also padlen in the same position. */
static int session_headers_add_pad(nghttp2_session *session,
nghttp2_frame *frame) {
- int rv;
ssize_t padded_payloadlen;
nghttp2_active_outbound_item *aob;
nghttp2_bufs *framebufs;
@@ -1924,11 +2240,7 @@ static int session_headers_add_pad(nghttp2_session *session,
DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n",
padded_payloadlen, padlen);
- rv = nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0);
-
- if (rv != 0) {
- return rv;
- }
+ nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0);
frame->headers.padlen = padlen;
@@ -2011,13 +2323,7 @@ static int session_prep_frame(nghttp2_session *session,
// Search stream including closed again.
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
if (stream) {
- int rv2;
-
- rv2 = nghttp2_stream_detach_item(stream);
-
- if (nghttp2_is_fatal(rv2)) {
- return rv2;
- }
+ session_detach_stream_item(session, stream);
}
return rv;
@@ -2032,12 +2338,8 @@ static int session_prep_frame(nghttp2_session *session,
queue when session->remote_window_size > 0 */
assert(session->remote_window_size > 0);
- rv = nghttp2_stream_defer_item(stream,
- NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
-
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_defer_stream_item(session, stream,
+ NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
session->aob.item = NULL;
active_outbound_item_reset(&session->aob, mem);
@@ -2051,22 +2353,15 @@ static int session_prep_frame(nghttp2_session *session,
return rv;
}
if (rv == NGHTTP2_ERR_DEFERRED) {
- rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
-
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_defer_stream_item(session, stream,
+ NGHTTP2_STREAM_FLAG_DEFERRED_USER);
session->aob.item = NULL;
active_outbound_item_reset(&session->aob, mem);
return NGHTTP2_ERR_DEFERRED;
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
-
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_detach_stream_item(session, stream);
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
@@ -2076,13 +2371,7 @@ static int session_prep_frame(nghttp2_session *session,
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
if (rv != 0) {
- int rv2;
-
- rv2 = nghttp2_stream_detach_item(stream);
-
- if (nghttp2_is_fatal(rv2)) {
- return rv2;
- }
+ session_detach_stream_item(session, stream);
return rv;
}
@@ -2328,6 +2617,18 @@ static int session_prep_frame(nghttp2_session *session,
}
return 0;
+ case NGHTTP2_PRIORITY_UPDATE: {
+ nghttp2_ext_priority_update *priority_update = frame->ext.payload;
+ rv = session_predicate_priority_update_send(session,
+ priority_update->stream_id);
+ if (rv != 0) {
+ return rv;
+ }
+
+ nghttp2_frame_pack_priority_update(&session->aob.framebufs, &frame->ext);
+
+ return 0;
+ }
default:
/* Unreachable here */
assert(0);
@@ -2339,6 +2640,8 @@ static int session_prep_frame(nghttp2_session *session,
nghttp2_outbound_item *
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
+ nghttp2_outbound_item *item;
+
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
return nghttp2_outbound_queue_top(&session->ob_urgent);
}
@@ -2354,7 +2657,12 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2388,7 +2696,12 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
}
if (session->remote_window_size > 0) {
- return nghttp2_stream_next_outbound_item(&session->root);
+ item = nghttp2_stream_next_outbound_item(&session->root);
+ if (item) {
+ return item;
+ }
+
+ return session_sched_get_next_outbound_item(session);
}
return NULL;
@@ -2498,10 +2811,20 @@ static int session_close_stream_on_goaway(nghttp2_session *session,
return 0;
}
-static void reschedule_stream(nghttp2_stream *stream) {
+static void session_reschedule_stream(nghttp2_session *session,
+ nghttp2_stream *stream) {
stream->last_writelen = stream->item->frame.hd.length;
- nghttp2_stream_reschedule(stream);
+ if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
+ nghttp2_stream_reschedule(stream);
+ return;
+ }
+
+ if (!session->server) {
+ return;
+ }
+
+ session_sched_reschedule_stream(session, stream);
}
static int session_update_stream_consumed_size(nghttp2_session *session,
@@ -2550,10 +2873,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
if (stream && aux_data->eof) {
- rv = nghttp2_stream_detach_item(stream);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_detach_stream_item(session, stream);
/* Call on_frame_send_callback after
nghttp2_stream_detach_item(), so that application can issue
@@ -2675,9 +2995,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
}
case NGHTTP2_PRIORITY:
- if (session->server) {
+ if (session->server || session->pending_no_rfc7540_priorities == 1) {
return 0;
- ;
}
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
@@ -2787,17 +3106,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
/*
* Called after a frame is sent and session_after_frame_sent1. This
* function is responsible to reset session->aob.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory.
- * NGHTTP2_ERR_CALLBACK_FAILURE
- * The callback function failed.
*/
-static int session_after_frame_sent2(nghttp2_session *session) {
- int rv;
+static void session_after_frame_sent2(nghttp2_session *session) {
nghttp2_active_outbound_item *aob = &session->aob;
nghttp2_outbound_item *item = aob->item;
nghttp2_bufs *framebufs = &aob->framebufs;
@@ -2820,13 +3130,13 @@ static int session_after_frame_sent2(nghttp2_session *session) {
DEBUGF("send: next CONTINUATION frame, %zu bytes\n",
nghttp2_buf_len(&framebufs->cur->buf));
- return 0;
+ return;
}
}
active_outbound_item_reset(&session->aob, mem);
- return 0;
+ return;
}
/* DATA frame */
@@ -2840,7 +3150,7 @@ static int session_after_frame_sent2(nghttp2_session *session) {
if (aux_data->eof) {
active_outbound_item_reset(aob, mem);
- return 0;
+ return;
}
/* Reset no_copy here because next write may not use this. */
@@ -2852,22 +3162,18 @@ static int session_after_frame_sent2(nghttp2_session *session) {
further data. */
if (nghttp2_session_predicate_data_send(session, stream) != 0) {
if (stream) {
- rv = nghttp2_stream_detach_item(stream);
-
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_detach_stream_item(session, stream);
}
active_outbound_item_reset(aob, mem);
- return 0;
+ return;
}
aob->item = NULL;
active_outbound_item_reset(&session->aob, mem);
- return 0;
+ return;
}
static int session_call_send_data(nghttp2_session *session,
@@ -2940,6 +3246,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
if (rv < 0) {
int32_t opened_stream_id = 0;
uint32_t error_code = NGHTTP2_INTERNAL_ERROR;
+ int rv2 = 0;
DEBUGF("send: frame preparation failed with %s\n",
nghttp2_strerror(rv));
@@ -2982,19 +3289,18 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
}
if (opened_stream_id) {
/* careful not to override rv */
- int rv2;
rv2 = nghttp2_session_close_stream(session, opened_stream_id,
error_code);
-
- if (nghttp2_is_fatal(rv2)) {
- return rv2;
- }
}
nghttp2_outbound_item_free(item, mem);
nghttp2_mem_free(mem, item);
active_outbound_item_reset(aob, mem);
+ if (nghttp2_is_fatal(rv2)) {
+ return rv2;
+ }
+
if (rv == NGHTTP2_ERR_HEADER_COMP) {
/* If header compression error occurred, should terminiate
connection. */
@@ -3098,7 +3404,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
/* Frame has completely sent */
if (fast_cb) {
- rv = session_after_frame_sent2(session);
+ session_after_frame_sent2(session);
} else {
rv = session_after_frame_sent1(session);
if (rv < 0) {
@@ -3106,12 +3412,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
assert(nghttp2_is_fatal(rv));
return rv;
}
- rv = session_after_frame_sent2(session);
- }
- if (rv < 0) {
- /* FATAL */
- assert(nghttp2_is_fatal(rv));
- return rv;
+ session_after_frame_sent2(session);
}
/* We have already adjusted the next state */
break;
@@ -3150,11 +3451,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
- rv = nghttp2_stream_detach_item(stream);
-
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ session_detach_stream_item(session, stream);
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id,
NGHTTP2_INTERNAL_ERROR);
@@ -3178,11 +3475,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
assert(nghttp2_is_fatal(rv));
return rv;
}
- rv = session_after_frame_sent2(session);
- if (rv < 0) {
- assert(nghttp2_is_fatal(rv));
- return rv;
- }
+ session_after_frame_sent2(session);
/* We have already adjusted the next state */
@@ -3730,6 +4023,21 @@ static int session_end_stream_headers_received(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_stream *stream) {
int rv;
+
+ assert(frame->hd.type == NGHTTP2_HEADERS);
+
+ if (session->server && session_enforce_http_messaging(session) &&
+ frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
+ (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
+ !(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) &&
+ (stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) {
+ rv = session_update_stream_priority(session, stream, stream->http_extpri);
+ if (rv != 0) {
+ assert(nghttp2_is_fatal(rv));
+ return rv;
+ }
+ }
+
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
return 0;
}
@@ -4053,17 +4361,12 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
}
static int session_process_headers_frame(nghttp2_session *session) {
- int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
nghttp2_stream *stream;
- rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos);
+ nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos);
- if (rv != 0) {
- return nghttp2_session_terminate_session_with_reason(
- session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: could not unpack");
- }
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if (!stream) {
frame->headers.cat = NGHTTP2_HCAT_REQUEST;
@@ -4091,6 +4394,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
int rv;
nghttp2_stream *stream;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
if (frame->hd.stream_id == 0) {
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
"PRIORITY: stream_id == 0");
@@ -4148,11 +4453,30 @@ static int session_process_priority_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
+ assert(!session_no_rfc7540_pri_no_fallback(session));
+
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
return nghttp2_session_on_priority_received(session, frame);
}
+static int session_update_stream_reset_ratelim(nghttp2_session *session) {
+ if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) {
+ return 0;
+ }
+
+ nghttp2_ratelim_update(&session->stream_reset_ratelim,
+ nghttp2_time_now_sec());
+
+ if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) {
+ return 0;
+ }
+
+ return nghttp2_session_add_goaway(session, session->last_recv_stream_id,
+ NGHTTP2_INTERNAL_ERROR, NULL, 0,
+ NGHTTP2_GOAWAY_AUX_NONE);
+}
+
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
nghttp2_frame *frame) {
int rv;
@@ -4182,7 +4506,8 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
if (nghttp2_is_fatal(rv)) {
return rv;
}
- return 0;
+
+ return session_update_stream_reset_ratelim(session);
}
static int session_process_rst_stream_frame(nghttp2_session *session) {
@@ -4214,8 +4539,8 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) {
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4259,9 +4584,16 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) {
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
NGHTTP2_FLOW_CONTROL_ERROR);
}
- if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) &&
- stream->window_update_queued == 0 &&
- nghttp2_should_send_window_update(stream->local_window_size,
+
+ if (stream->window_update_queued) {
+ return 0;
+ }
+
+ if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
+ return session_update_stream_consumed_size(arg->session, stream, 0);
+ }
+
+ if (nghttp2_should_send_window_update(stream->local_window_size,
stream->recv_window_size)) {
rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE,
@@ -4382,6 +4714,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
session->local_settings.enable_connect_protocol = iv[i].value;
break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ session->local_settings.no_rfc7540_priorities = iv[i].value;
+ break;
}
}
@@ -4540,10 +4875,38 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
session->remote_settings.enable_connect_protocol = entry->value;
+ break;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+
+ if (entry->value != 0 && entry->value != 1) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES");
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX &&
+ session->remote_settings.no_rfc7540_priorities != entry->value) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed");
+ }
+
+ session->remote_settings.no_rfc7540_priorities = entry->value;
+
break;
}
}
+ if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) {
+ session->remote_settings.no_rfc7540_priorities = 0;
+
+ if (session->server && session->pending_no_rfc7540_priorities &&
+ (session->opt_flags &
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES)) {
+ session->fallback_rfc7540_priorities = 1;
+ }
+ }
+
if (!noack && !session_is_closing(session)) {
rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0);
@@ -4684,17 +5047,11 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
}
static int session_process_push_promise_frame(nghttp2_session *session) {
- int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
- rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
- iframe->sbuf.pos);
-
- if (rv != 0) {
- return nghttp2_session_terminate_session_with_reason(
- session, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: could not unpack");
- }
+ nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
+ iframe->sbuf.pos);
return nghttp2_session_on_push_promise_received(session, frame);
}
@@ -4826,8 +5183,8 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
if (stream->remote_window_size > 0 &&
nghttp2_stream_check_deferred_by_flow_control(stream)) {
- rv = nghttp2_stream_resume_deferred_item(
- stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
+ rv = session_resume_deferred_stream_item(
+ session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
if (nghttp2_is_fatal(rv)) {
return rv;
@@ -4898,6 +5255,80 @@ int nghttp2_session_on_origin_received(nghttp2_session *session,
return session_call_on_frame_received(session, frame);
}
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame) {
+ nghttp2_ext_priority_update *priority_update;
+ nghttp2_stream *stream;
+ nghttp2_priority_spec pri_spec;
+ nghttp2_extpri extpri;
+ int rv;
+
+ assert(session->server);
+
+ priority_update = frame->ext.payload;
+
+ if (frame->hd.stream_id != 0) {
+ return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: stream_id == 0");
+ }
+
+ if (nghttp2_session_is_my_stream_id(session, priority_update->stream_id)) {
+ if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: prioritizing idle push is not allowed");
+ }
+
+ /* TODO Ignore priority signal to a push stream for now */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id);
+ if (stream) {
+ /* Stream already exists. */
+ if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) {
+ return session_call_on_frame_received(session, frame);
+ }
+ } else if (session_detect_idle_stream(session, priority_update->stream_id)) {
+ if (session->num_idle_streams + session->num_incoming_streams >=
+ session->local_settings.max_concurrent_streams) {
+ return session_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PRIORITY_UPDATE: max concurrent streams exceeded");
+ }
+
+ nghttp2_priority_spec_default_init(&pri_spec);
+ stream = nghttp2_session_open_stream(session, priority_update->stream_id,
+ NGHTTP2_FLAG_NONE, &pri_spec,
+ NGHTTP2_STREAM_IDLE, NULL);
+ if (!stream) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+ } else {
+ return session_call_on_frame_received(session, frame);
+ }
+
+ extpri.urgency = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
+ extpri.inc = 0;
+
+ rv = nghttp2_http_parse_priority(&extpri, priority_update->field_value,
+ priority_update->field_value_len);
+ if (rv != 0) {
+ /* Just ignore field_value if it cannot be parsed. */
+ return session_call_on_frame_received(session, frame);
+ }
+
+ rv = session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+ if (rv != 0) {
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ }
+
+ return session_call_on_frame_received(session, frame);
+}
+
static int session_process_altsvc_frame(nghttp2_session *session) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_frame *frame = &iframe->frame;
@@ -4932,6 +5363,16 @@ static int session_process_origin_frame(nghttp2_session *session) {
return nghttp2_session_on_origin_received(session, frame);
}
+static int session_process_priority_update_frame(nghttp2_session *session) {
+ nghttp2_inbound_frame *iframe = &session->iframe;
+ nghttp2_frame *frame = &iframe->frame;
+
+ nghttp2_frame_unpack_priority_update_payload(&frame->ext, iframe->sbuf.pos,
+ nghttp2_buf_len(&iframe->sbuf));
+
+ return nghttp2_session_on_priority_update_received(session, frame);
+}
+
static int session_process_extension_frame(nghttp2_session *session) {
int rv;
nghttp2_inbound_frame *iframe = &session->iframe;
@@ -5269,6 +5710,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
break;
default:
DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
@@ -5429,7 +5871,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS ||
@@ -5466,7 +5908,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos);
@@ -5882,6 +6324,49 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ORIGIN_PAYLOAD;
+ break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ if ((session->builtin_recv_ext_types &
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE) == 0) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ DEBUGF("recv: PRIORITY_UPDATE\n");
+
+ iframe->frame.hd.flags = NGHTTP2_FLAG_NONE;
+ iframe->frame.ext.payload =
+ &iframe->ext_frame_payload.priority_update;
+
+ if (!session->server) {
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_PROTOCOL_ERROR,
+ "PRIORITY_UPDATE is received from server");
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ return (ssize_t)inlen;
+ }
+
+ if (iframe->payloadleft < 4) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR;
+ break;
+ }
+
+ if (!session_no_rfc7540_pri_no_fallback(session) ||
+ iframe->payloadleft > sizeof(iframe->raw_sbuf)) {
+ busy = 1;
+ iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
+ break;
+ }
+
+ busy = 1;
+
+ iframe->state = NGHTTP2_IB_READ_NBYTE;
+ inbound_frame_set_mark(iframe, iframe->payloadleft);
+
break;
default:
busy = 1;
@@ -5923,7 +6408,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
switch (iframe->frame.hd.type) {
@@ -5988,13 +6473,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
break;
case NGHTTP2_PRIORITY:
- rv = session_process_priority_frame(session);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
+ if (!session_no_rfc7540_pri_no_fallback(session) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
+ rv = session_process_priority_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (ssize_t)inlen;
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return (ssize_t)inlen;
+ }
}
session_inbound_frame_reset(session);
@@ -6150,6 +6638,18 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->state = NGHTTP2_IB_READ_ALTSVC_PAYLOAD;
+ break;
+ case NGHTTP2_PRIORITY_UPDATE:
+ DEBUGF("recv: prioritized_stream_id=%d\n",
+ nghttp2_get_uint32(iframe->sbuf.pos) & NGHTTP2_STREAM_ID_MASK);
+
+ rv = session_process_priority_update_frame(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ session_inbound_frame_reset(session);
+
break;
}
default:
@@ -6212,7 +6712,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += hd_proclen;
iframe->payloadleft -= hd_proclen;
- return in - first;
+ return (ssize_t)(in - first);
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6403,7 +6903,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos);
@@ -6461,7 +6961,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
/* Pad Length field is subject to flow control */
@@ -6611,7 +7111,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
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 in - first;
+ return (ssize_t)(in - first);
}
if (nghttp2_is_fatal(rv)) {
@@ -6791,7 +7291,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
assert(in == last);
- return in - first;
+ return (ssize_t)(in - first);
}
int nghttp2_session_recv(nghttp2_session *session) {
@@ -6863,7 +7363,8 @@ int nghttp2_session_want_write(nghttp2_session *session) {
*/
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
nghttp2_outbound_queue_top(&session->ob_reg) ||
- (!nghttp2_pq_empty(&session->root.obq) &&
+ ((!nghttp2_pq_empty(&session->root.obq) ||
+ !session_sched_empty(session)) &&
session->remote_window_size > 0) ||
(nghttp2_outbound_queue_top(&session->ob_syn) &&
!session_is_outgoing_concurrent_streams_max(session));
@@ -6962,6 +7463,9 @@ int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
nghttp2_mem_free(mem, item);
return rv;
}
+
+ session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED;
+
return 0;
}
@@ -7016,6 +7520,7 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
int rv;
nghttp2_mem *mem;
nghttp2_inflight_settings *inflight_settings = NULL;
+ uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities;
mem = &session->mem;
@@ -7033,6 +7538,21 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
+ for (i = 0; i < niv; ++i) {
+ if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) {
+ continue;
+ }
+
+ if (no_rfc7540_pri == UINT8_MAX) {
+ no_rfc7540_pri = (uint8_t)iv[i].value;
+ continue;
+ }
+
+ if (iv[i].value != (uint32_t)no_rfc7540_pri) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+ }
+
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
if (item == NULL) {
return NGHTTP2_ERR_NOMEM;
@@ -7107,6 +7627,12 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
}
}
+ if (no_rfc7540_pri == UINT8_MAX) {
+ session->pending_no_rfc7540_priorities = 0;
+ } else {
+ session->pending_no_rfc7540_priorities = no_rfc7540_pri;
+ }
+
return 0;
}
@@ -7229,13 +7755,10 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
- rv = nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen,
- aux_data->no_copy);
- if (rv != 0) {
- return rv;
- }
+ nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen,
+ aux_data->no_copy);
- reschedule_stream(stream);
+ session_reschedule_stream(session, stream);
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
@@ -7309,7 +7832,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
- rv = nghttp2_stream_resume_deferred_item(stream,
+ rv = session_resume_deferred_stream_item(session, stream,
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
if (nghttp2_is_fatal(rv)) {
@@ -7417,6 +7940,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
return session->remote_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->remote_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->remote_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7440,6 +7965,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
return session->local_settings.max_header_list_size;
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
return session->local_settings.enable_connect_protocol;
+ case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
+ return session->local_settings.no_rfc7540_priorities;
}
assert(0);
@@ -7723,6 +8250,10 @@ int nghttp2_session_change_stream_priority(
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -7755,6 +8286,10 @@ int nghttp2_session_create_idle_stream(nghttp2_session *session,
nghttp2_stream *stream;
nghttp2_priority_spec pri_spec_copy;
+ if (session->pending_no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || stream_id == pri_spec->stream_id ||
!session_detect_idle_stream(session, stream_id)) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
@@ -7796,3 +8331,38 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
session->user_data = user_data;
}
+
+int nghttp2_session_change_extpri_stream_priority(
+ nghttp2_session *session, int32_t stream_id,
+ const nghttp2_extpri *extpri_in, int ignore_client_signal) {
+ nghttp2_stream *stream;
+ nghttp2_extpri extpri = *extpri_in;
+
+ if (!session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->pending_no_rfc7540_priorities != 1) {
+ return 0;
+ }
+
+ if (stream_id == 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ stream = nghttp2_session_get_stream_raw(session, stream_id);
+ if (!stream) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) {
+ extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW;
+ }
+
+ if (ignore_client_signal) {
+ stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES;
+ }
+
+ return session_update_stream_priority(session, stream,
+ nghttp2_extpri_to_uint8(&extpri));
+}
diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h
index 907b170..b119329 100644
--- a/deps/nghttp2/lib/nghttp2_session.h
+++ b/deps/nghttp2/lib/nghttp2_session.h
@@ -39,6 +39,7 @@
#include "nghttp2_buf.h"
#include "nghttp2_callbacks.h"
#include "nghttp2_mem.h"
+#include "nghttp2_ratelim.h"
/* The global variable for tests where we want to disable strict
preface handling. */
@@ -52,7 +53,9 @@ typedef enum {
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
- NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
+ NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
+ NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
+ NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
} nghttp2_optmask;
/*
@@ -62,7 +65,8 @@ typedef enum {
typedef enum {
NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
- NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
+ NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
+ NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
} nghttp2_typemask;
typedef enum {
@@ -102,6 +106,10 @@ typedef struct {
/* The default value of maximum number of concurrent streams. */
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
+/* The default values for stream reset rate limiter. */
+#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000
+#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33
+
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
@@ -151,10 +159,8 @@ typedef struct {
/* padding length for the current frame */
size_t padlen;
nghttp2_inbound_state state;
- /* Small buffer. Currently the largest contiguous chunk to buffer
- is frame header. We buffer part of payload, but they are smaller
- than frame header. */
- uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+ /* Small fixed sized buffer. */
+ uint8_t raw_sbuf[32];
} nghttp2_inbound_frame;
typedef struct {
@@ -165,6 +171,7 @@ typedef struct {
uint32_t max_frame_size;
uint32_t max_header_list_size;
uint32_t enable_connect_protocol;
+ uint32_t no_rfc7540_priorities;
} nghttp2_settings_storage;
typedef enum {
@@ -176,7 +183,9 @@ typedef enum {
/* Flag means GOAWAY was sent */
NGHTTP2_GOAWAY_SENT = 0x4,
/* Flag means GOAWAY was received */
- NGHTTP2_GOAWAY_RECV = 0x8
+ NGHTTP2_GOAWAY_RECV = 0x8,
+ /* Flag means GOAWAY has been submitted at least once */
+ NGHTTP2_GOAWAY_SUBMITTED = 0x10
} nghttp2_goaway_flag;
/* nghttp2_inflight_settings stores the SETTINGS entries which local
@@ -202,6 +211,12 @@ struct nghttp2_session {
response) frame, which are subject to
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
nghttp2_outbound_queue ob_syn;
+ /* Queues for DATA frames which is used when
+ SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC
+ 9218 extensible prioritization scheme. */
+ struct {
+ nghttp2_pq ob_data;
+ } sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
nghttp2_active_outbound_item aob;
nghttp2_inbound_frame iframe;
nghttp2_hd_deflater hd_deflater;
@@ -227,6 +242,12 @@ struct nghttp2_session {
/* 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;
+ /* Sequential number across all streams to process streams in
+ FIFO. */
+ uint64_t stream_seq;
/* The number of outgoing streams. This will be capped by
remote_settings.max_concurrent_streams. */
size_t num_outgoing_streams;
@@ -328,6 +349,11 @@ struct nghttp2_session {
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
accept :protocol header field before SETTINGS_ACK is received. */
uint8_t pending_enable_connect_protocol;
+ /* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
+ effective before it is acknowledged. */
+ uint8_t pending_no_rfc7540_priorities;
+ /* Turn on fallback to RFC 7540 priorities; for server use only. */
+ uint8_t fallback_rfc7540_priorities;
/* Nonzero if the session is server side. */
uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are
@@ -773,6 +799,19 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
int nghttp2_session_on_origin_received(nghttp2_session *session,
nghttp2_frame *frame);
+/*
+ * Called when PRIORITY_UPDATE is received, assuming |frame| is
+ * properly initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ * The callback function failed.
+ */
+int nghttp2_session_on_priority_update_received(nghttp2_session *session,
+ nghttp2_frame *frame);
+
/*
* Called when DATA is received, assuming |frame| is properly
* initialized.
diff --git a/deps/nghttp2/lib/nghttp2_stream.c b/deps/nghttp2/lib/nghttp2_stream.c
index f4c80a2..f1951f8 100644
--- a/deps/nghttp2/lib/nghttp2_stream.c
+++ b/deps/nghttp2/lib/nghttp2_stream.c
@@ -100,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->descendant_next_seq = 0;
stream->seq = 0;
stream->last_writelen = 0;
+
+ stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
}
void nghttp2_stream_free(nghttp2_stream *stream) {
@@ -463,14 +465,12 @@ static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
return 0;
}
-static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
+static void stream_update_dep_on_detach_item(nghttp2_stream *stream) {
if (nghttp2_pq_empty(&stream->obq)) {
stream_obq_remove(stream);
}
validate_tree(stream);
-
- return 0;
}
int nghttp2_stream_attach_item(nghttp2_stream *stream,
@@ -484,6 +484,10 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
stream->item = item;
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
rv = stream_update_dep_on_attach_item(stream);
if (rv != 0) {
/* This may relave stream->queued == 1, but stream->item == NULL.
@@ -497,16 +501,20 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
return 0;
}
-int nghttp2_stream_detach_item(nghttp2_stream *stream) {
+void nghttp2_stream_detach_item(nghttp2_stream *stream) {
DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
stream->item = NULL;
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
- return stream_update_dep_on_detach_item(stream);
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return;
+ }
+
+ stream_update_dep_on_detach_item(stream);
}
-int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
+void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
assert(stream->item);
DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
@@ -514,7 +522,11 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
stream->flags |= flags;
- return stream_update_dep_on_detach_item(stream);
+ 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) {
@@ -529,6 +541,10 @@ int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
return 0;
}
+ if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
+ return 0;
+ }
+
return stream_update_dep_on_attach_item(stream);
}
diff --git a/deps/nghttp2/lib/nghttp2_stream.h b/deps/nghttp2/lib/nghttp2_stream.h
index 2846c6a..71b9fb1 100644
--- a/deps/nghttp2/lib/nghttp2_stream.h
+++ b/deps/nghttp2/lib/nghttp2_stream.h
@@ -90,8 +90,15 @@ typedef enum {
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
- NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
-
+ NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
+ /* Indicates that this stream is not subject to RFC7540
+ priorities scheme. */
+ NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
+ /* Ignore client RFC 9218 priority signal. */
+ NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
+ /* Indicates that RFC 9113 leading and trailing white spaces
+ validation against a field value is not performed. */
+ NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40,
} nghttp2_stream_flag;
/* HTTP related flags to enforce HTTP semantics */
@@ -132,6 +139,11 @@ typedef enum {
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
+ /* set if priority header field is received */
+ NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16,
+ /* set if an error is encountered while parsing priority header
+ field */
+ NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17,
} nghttp2_http_flag;
struct nghttp2_stream {
@@ -204,7 +216,7 @@ struct nghttp2_stream {
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
- uint16_t http_flags;
+ uint32_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
@@ -218,6 +230,12 @@ struct nghttp2_stream {
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
is not queued. */
uint8_t window_update_queued;
+ /* extpri is a stream priority produced by nghttp2_extpri_to_uint8
+ used by RFC 9218 extensible priorities. */
+ uint8_t extpri;
+ /* http_extpri is a stream priority received in HTTP request header
+ fields and produced by nghttp2_extpri_to_uint8. */
+ uint8_t http_extpri;
};
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
@@ -240,14 +258,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
* more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates
* the reason of this action.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory
*/
-int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
+void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
/*
* Put back deferred data in this stream to active state. The |flags|
@@ -361,14 +373,8 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
/*
* Detaches |stream->item|. This function does not free
* |stream->item|. The caller must free it.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory
*/
-int nghttp2_stream_detach_item(nghttp2_stream *stream);
+void nghttp2_stream_detach_item(nghttp2_stream *stream);
/*
* Makes the |stream| depend on the |dep_stream|. This dependency is
diff --git a/deps/nghttp2/lib/nghttp2_submit.c b/deps/nghttp2/lib/nghttp2_submit.c
index 92fb03e..f5554eb 100644
--- a/deps/nghttp2/lib/nghttp2_submit.c
+++ b/deps/nghttp2/lib/nghttp2_submit.c
@@ -196,7 +196,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
flags &= NGHTTP2_FLAG_END_STREAM;
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, stream_id, pri_spec);
if (rv != 0) {
return rv;
@@ -229,6 +230,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
mem = &session->mem;
+ if (session->remote_settings.no_rfc7540_priorities == 1) {
+ return 0;
+ }
+
if (stream_id == 0 || pri_spec == NULL) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
@@ -662,6 +667,78 @@ fail_item_malloc:
return rv;
}
+int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *field_value,
+ size_t field_value_len) {
+ nghttp2_mem *mem;
+ uint8_t *buf, *p;
+ nghttp2_outbound_item *item;
+ nghttp2_frame *frame;
+ nghttp2_ext_priority_update *priority_update;
+ int rv;
+ (void)flags;
+
+ mem = &session->mem;
+
+ if (session->server) {
+ return NGHTTP2_ERR_INVALID_STATE;
+ }
+
+ if (session->remote_settings.no_rfc7540_priorities == 0) {
+ return 0;
+ }
+
+ if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ if (field_value_len) {
+ buf = nghttp2_mem_malloc(mem, field_value_len + 1);
+ if (buf == NULL) {
+ return NGHTTP2_ERR_NOMEM;
+ }
+
+ p = nghttp2_cpymem(buf, field_value, field_value_len);
+ *p = '\0';
+ } else {
+ buf = NULL;
+ }
+
+ item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
+ if (item == NULL) {
+ rv = NGHTTP2_ERR_NOMEM;
+ goto fail_item_malloc;
+ }
+
+ nghttp2_outbound_item_init(item);
+
+ item->aux_data.ext.builtin = 1;
+
+ priority_update = &item->ext_frame_payload.priority_update;
+
+ frame = &item->frame;
+ frame->ext.payload = priority_update;
+
+ nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
+ field_value_len);
+
+ rv = nghttp2_session_add_item(session, item);
+ if (rv != 0) {
+ nghttp2_frame_priority_update_free(&frame->ext, mem);
+ nghttp2_mem_free(mem, item);
+
+ return rv;
+ }
+
+ return 0;
+
+fail_item_malloc:
+ free(buf);
+
+ return rv;
+}
+
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
const nghttp2_data_provider *data_prd) {
uint8_t flags = NGHTTP2_FLAG_NONE;
@@ -688,7 +765,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
return NGHTTP2_ERR_PROTO;
}
- if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
+ if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
+ session->remote_settings.no_rfc7540_priorities != 1) {
rv = detect_self_dependency(session, -1, pri_spec);
if (rv != 0) {
return rv;
diff --git a/deps/nghttp2/lib/nghttp2_time.c b/deps/nghttp2/lib/nghttp2_time.c
new file mode 100644
index 0000000..2a5f1a6
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_time.c
@@ -0,0 +1,62 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_time.h"
+
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif /* HAVE_TIME_H */
+
+#ifdef HAVE_SYSINFOAPI_H
+# include <sysinfoapi.h>
+#endif /* HAVE_SYSINFOAPI_H */
+
+#ifndef HAVE_GETTICKCOUNT64
+static uint64_t time_now_sec(void) {
+ time_t t = time(NULL);
+
+ if (t == -1) {
+ return 0;
+ }
+
+ return (uint64_t)t;
+}
+#endif /* HAVE_GETTICKCOUNT64 */
+
+#ifdef HAVE_CLOCK_GETTIME
+uint64_t nghttp2_time_now_sec(void) {
+ struct timespec tp;
+ int rv = clock_gettime(CLOCK_MONOTONIC, &tp);
+
+ if (rv == -1) {
+ return time_now_sec();
+ }
+
+ return (uint64_t)tp.tv_sec;
+}
+#elif defined(HAVE_GETTICKCOUNT64)
+uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; }
+#else /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
+uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); }
+#endif /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
diff --git a/deps/nghttp2/lib/nghttp2_time.h b/deps/nghttp2/lib/nghttp2_time.h
new file mode 100644
index 0000000..03c0bbe
--- /dev/null
+++ b/deps/nghttp2/lib/nghttp2_time.h
@@ -0,0 +1,38 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2023 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_TIME_H
+#define NGHTTP2_TIME_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/* nghttp2_time_now_sec returns seconds from implementation-specific
+ timepoint. If it is unable to get seconds, it returns 0. */
+uint64_t nghttp2_time_now_sec(void);
+
+#endif /* NGHTTP2_TIME_H */
diff --git a/deps/nghttp2/lib/sfparse.c b/deps/nghttp2/lib/sfparse.c
new file mode 100644
index 0000000..efa2850
--- /dev/null
+++ b/deps/nghttp2/lib/sfparse.c
@@ -0,0 +1,1146 @@
+/*
+ * sfparse
+ *
+ * Copyright (c) 2023 sfparse contributors
+ * Copyright (c) 2019 nghttp3 contributors
+ * Copyright (c) 2015 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "sfparse.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#define SF_STATE_DICT 0x08u
+#define SF_STATE_LIST 0x10u
+#define SF_STATE_ITEM 0x18u
+
+#define SF_STATE_INNER_LIST 0x04u
+
+#define SF_STATE_BEFORE 0x00u
+#define SF_STATE_BEFORE_PARAMS 0x01u
+#define SF_STATE_PARAMS 0x02u
+#define SF_STATE_AFTER 0x03u
+
+#define SF_STATE_OP_MASK 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 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 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 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 SF_STATE_INITIAL 0x00u
+
+#define DIGIT_CASES \
+ case '0': \
+ case '1': \
+ case '2': \
+ case '3': \
+ case '4': \
+ case '5': \
+ case '6': \
+ case '7': \
+ case '8': \
+ case '9'
+
+#define LCALPHA_CASES \
+ case 'a': \
+ case 'b': \
+ case 'c': \
+ case 'd': \
+ case 'e': \
+ case 'f': \
+ case 'g': \
+ case 'h': \
+ case 'i': \
+ case 'j': \
+ case 'k': \
+ case 'l': \
+ case 'm': \
+ case 'n': \
+ case 'o': \
+ case 'p': \
+ case 'q': \
+ case 'r': \
+ case 's': \
+ case 't': \
+ case 'u': \
+ case 'v': \
+ case 'w': \
+ case 'x': \
+ case 'y': \
+ case 'z'
+
+#define UCALPHA_CASES \
+ case 'A': \
+ case 'B': \
+ case 'C': \
+ case 'D': \
+ case 'E': \
+ case 'F': \
+ case 'G': \
+ case 'H': \
+ case 'I': \
+ case 'J': \
+ case 'K': \
+ case 'L': \
+ case 'M': \
+ case 'N': \
+ case 'O': \
+ case 'P': \
+ case 'Q': \
+ case 'R': \
+ case 'S': \
+ case 'T': \
+ case 'U': \
+ case 'V': \
+ case 'W': \
+ case 'X': \
+ case 'Y': \
+ case 'Z'
+
+#define ALPHA_CASES \
+ UCALPHA_CASES: \
+ LCALPHA_CASES
+
+#define X20_21_CASES \
+ case ' ': \
+ case '!'
+
+#define X23_5B_CASES \
+ case '#': \
+ case '$': \
+ case '%': \
+ case '&': \
+ case '\'': \
+ case '(': \
+ case ')': \
+ case '*': \
+ case '+': \
+ case ',': \
+ case '-': \
+ case '.': \
+ case '/': \
+ DIGIT_CASES: \
+ case ':': \
+ case ';': \
+ case '<': \
+ case '=': \
+ case '>': \
+ case '?': \
+ case '@': \
+ UCALPHA_CASES: \
+ case '['
+
+#define X5D_7E_CASES \
+ case ']': \
+ case '^': \
+ case '_': \
+ case '`': \
+ LCALPHA_CASES: \
+ case '{': \
+ case '|': \
+ case '}': \
+ case '~'
+
+static int is_ws(uint8_t c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; }
+
+static void parser_discard_ows(sf_parser *sfp) {
+ for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos)
+ ;
+}
+
+static void parser_discard_sp(sf_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;
+ sfp->state |= op;
+}
+
+static void parser_unset_inner_list_state(sf_parser *sfp) {
+ sfp->state &= ~SF_STATE_INNER_LIST;
+}
+
+static int parser_key(sf_parser *sfp, sf_vec *dest) {
+ const uint8_t *base;
+
+ switch (*sfp->pos) {
+ case '*':
+ LCALPHA_CASES:
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ base = sfp->pos++;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ case '_':
+ case '-':
+ case '.':
+ case '*':
+ DIGIT_CASES:
+ LCALPHA_CASES:
+ continue;
+ }
+
+ break;
+ }
+
+ if (dest) {
+ dest->base = (uint8_t *)base;
+ dest->len = (size_t)(sfp->pos - dest->base);
+ }
+
+ return 0;
+}
+
+static int parser_number(sf_parser *sfp, sf_value *dest) {
+ int sign = 1;
+ int64_t value = 0;
+ size_t len = 0;
+ size_t fpos = 0;
+
+ if (*sfp->pos == '-') {
+ ++sfp->pos;
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ sign = -1;
+ }
+
+ assert(!parser_eof(sfp));
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ DIGIT_CASES:
+ if (++len > 15) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ value *= 10;
+ value += *sfp->pos - '0';
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (len == 0) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != '.') {
+ if (dest) {
+ dest->type = SF_TYPE_INTEGER;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->integer = value * sign;
+ }
+
+ return 0;
+ }
+
+ /* decimal */
+
+ if (len > 12) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ fpos = len;
+
+ ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ DIGIT_CASES:
+ if (++len > 15) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ value *= 10;
+ value += *sfp->pos - '0';
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (fpos == len || len - fpos > 3) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (dest) {
+ dest->type = SF_TYPE_DECIMAL;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->decimal.numer = value * sign;
+
+ switch (len - fpos) {
+ case 1:
+ dest->decimal.denom = 10;
+
+ break;
+ case 2:
+ dest->decimal.denom = 100;
+
+ break;
+ case 3:
+ dest->decimal.denom = 1000;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int parser_date(sf_parser *sfp, sf_value *dest) {
+ int rv;
+ sf_value val;
+
+ /* The first byte has already been validated by the caller. */
+ assert('@' == *sfp->pos);
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ rv = parser_number(sfp, &val);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (val.type != SF_TYPE_INTEGER) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (dest) {
+ *dest = val;
+ dest->type = SF_TYPE_DATE;
+ }
+
+ return 0;
+}
+
+static int parser_string(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+ uint32_t flags = SF_VALUE_FLAG_NONE;
+
+ /* The first byte has already been validated by the caller. */
+ assert('"' == *sfp->pos);
+
+ base = ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ X20_21_CASES:
+ X23_5B_CASES:
+ X5D_7E_CASES:
+ break;
+ case '\\':
+ ++sfp->pos;
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case '"':
+ case '\\':
+ flags = SF_VALUE_FLAG_ESCAPED_STRING;
+
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ 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;
+ }
+
+ ++sfp->pos;
+
+ return 0;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+ }
+
+ return SF_ERR_PARSE_ERROR;
+}
+
+static int parser_token(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+
+ /* The first byte has already been validated by the caller. */
+ base = sfp->pos++;
+
+ 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:
+ continue;
+ }
+
+ break;
+ }
+
+ if (dest) {
+ dest->type = SF_TYPE_TOKEN;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->vec.base = (uint8_t *)base;
+ dest->vec.len = (size_t)(sfp->pos - base);
+ }
+
+ return 0;
+}
+
+static int parser_byteseq(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+
+ /* The first byte has already been validated by the caller. */
+ assert(':' == *sfp->pos);
+
+ base = ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ case '+':
+ case '/':
+ DIGIT_CASES:
+ ALPHA_CASES:
+ continue;
+ case '=':
+ switch ((sfp->pos - base) & 0x3) {
+ case 0:
+ case 1:
+ return SF_ERR_PARSE_ERROR;
+ 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;
+ }
+
+ 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;
+ }
+
+ break;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp) || *sfp->pos != ':') {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ goto fin;
+ case ':':
+ if ((sfp->pos - base) & 0x3) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ goto fin;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+ }
+
+ return SF_ERR_PARSE_ERROR;
+
+fin:
+ if (dest) {
+ dest->type = SF_TYPE_BYTESEQ;
+ dest->flags = SF_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;
+}
+
+static int parser_boolean(sf_parser *sfp, sf_value *dest) {
+ int b;
+
+ /* The first byte has already been validated by the caller. */
+ assert('?' == *sfp->pos);
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case '0':
+ b = 0;
+
+ break;
+ case '1':
+ b = 1;
+
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ ++sfp->pos;
+
+ if (dest) {
+ dest->type = SF_TYPE_BOOLEAN;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->boolean = b;
+ }
+
+ return 0;
+}
+
+static int parser_bare_item(sf_parser *sfp, sf_value *dest) {
+ switch (*sfp->pos) {
+ case '"':
+ return parser_string(sfp, dest);
+ case '-':
+ DIGIT_CASES:
+ return parser_number(sfp, dest);
+ case '@':
+ return parser_date(sfp, dest);
+ case ':':
+ return parser_byteseq(sfp, dest);
+ case '?':
+ return parser_boolean(sfp, dest);
+ case '*':
+ ALPHA_CASES:
+ return parser_token(sfp, dest);
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+}
+
+static int parser_skip_inner_list(sf_parser *sfp);
+
+int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) {
+ int rv;
+
+ switch (sfp->state & SF_STATE_OP_MASK) {
+ case SF_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);
+
+ break;
+ case SF_STATE_PARAMS:
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != ';') {
+ parser_set_op_state(sfp, SF_STATE_AFTER);
+
+ return SF_ERR_EOF;
+ }
+
+ ++sfp->pos;
+
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ rv = parser_key(sfp, dest_key);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != '=') {
+ if (dest_value) {
+ dest_value->type = SF_TYPE_BOOLEAN;
+ dest_value->flags = SF_VALUE_FLAG_NONE;
+ dest_value->boolean = 1;
+ }
+
+ return 0;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return parser_bare_item(sfp, dest_value);
+}
+
+static int parser_skip_params(sf_parser *sfp) {
+ int rv;
+
+ for (;;) {
+ rv = sf_parser_param(sfp, NULL, NULL);
+ switch (rv) {
+ case 0:
+ break;
+ case SF_ERR_EOF:
+ return 0;
+ case SF_ERR_PARSE_ERROR:
+ return rv;
+ default:
+ assert(0);
+ abort();
+ }
+ }
+}
+
+int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state & SF_STATE_OP_MASK) {
+ case SF_STATE_BEFORE:
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case SF_STATE_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* Technically, we are entering SF_STATE_AFTER, but we will set
+ another state without reading the state. */
+ /* parser_set_op_state(sfp, SF_STATE_AFTER); */
+
+ /* fall through */
+ case SF_STATE_AFTER:
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case ' ':
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case ')':
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == ')') {
+ ++sfp->pos;
+
+ parser_unset_inner_list_state(sfp);
+ parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS);
+
+ return SF_ERR_EOF;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS);
+
+ return 0;
+}
+
+static int parser_skip_inner_list(sf_parser *sfp) {
+ int rv;
+
+ for (;;) {
+ rv = sf_parser_inner_list(sfp, NULL);
+ switch (rv) {
+ case 0:
+ break;
+ case SF_ERR_EOF:
+ return 0;
+ case SF_ERR_PARSE_ERROR:
+ return rv;
+ default:
+ assert(0);
+ abort();
+ }
+ }
+}
+
+static int parser_next_key_or_item(sf_parser *sfp) {
+ parser_discard_ows(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ if (*sfp->pos != ',') {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ ++sfp->pos;
+
+ parser_discard_ows(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return 0;
+}
+
+static int parser_dict_value(sf_parser *sfp, sf_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->boolean = 1;
+ }
+
+ sfp->state = SF_STATE_DICT_BEFORE_PARAMS;
+
+ return 0;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_DICT_BEFORE_PARAMS;
+
+ return 0;
+}
+
+int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_DICT_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_DICT_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_DICT_AFTER:
+ rv = parser_next_key_or_item(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ rv = parser_key(sfp, dest_key);
+ if (rv != 0) {
+ return rv;
+ }
+
+ return parser_dict_value(sfp, dest_value);
+}
+
+int sf_parser_list(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_LIST_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_LIST_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_LIST_AFTER:
+ rv = parser_next_key_or_item(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_LIST_BEFORE_PARAMS;
+
+ return 0;
+}
+
+int sf_parser_item(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case SF_STATE_ITEM_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_ITEM_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_ITEM_AFTER:
+ parser_discard_sp(sfp);
+
+ if (!parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return SF_ERR_EOF;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_ITEM_BEFORE_PARAMS;
+
+ return 0;
+}
+
+void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) {
+ if (datalen == 0) {
+ sfp->pos = sfp->end = NULL;
+ } else {
+ sfp->pos = data;
+ sfp->end = data + datalen;
+ }
+
+ sfp->state = SF_STATE_INITIAL;
+}
+
+void sf_unescape(sf_vec *dest, const sf_vec *src) {
+ const uint8_t *p, *q;
+ uint8_t *o;
+ size_t len, slen;
+
+ if (src->len == 0) {
+ *dest = *src;
+
+ return;
+ }
+
+ o = dest->base;
+ p = src->base;
+ len = src->len;
+
+ for (;;) {
+ q = memchr(p, '\\', len);
+ if (q == NULL) {
+ if (len == src->len) {
+ *dest = *src;
+
+ return;
+ }
+
+ memcpy(o, p, len);
+ o += len;
+
+ break;
+ }
+
+ slen = (size_t)(q - p);
+ memcpy(o, p, slen);
+ o += slen;
+
+ p = q + 1;
+ *o++ = *p++;
+ len -= slen + 2;
+ }
+
+ dest->len = (size_t)(o - dest->base);
+}
+
+void sf_base64decode(sf_vec *dest, const sf_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, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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, -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, -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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1};
+ uint8_t *o;
+ const uint8_t *p, *end;
+ uint32_t n;
+ size_t i;
+ int idx;
+
+ assert((src->len & 0x3) == 0);
+
+ if (src->len == 0) {
+ *dest = *src;
+
+ return;
+ }
+
+ o = dest->base;
+ p = src->base;
+ end = src->base + src->len;
+
+ for (; p != end;) {
+ n = 0;
+
+ for (i = 1; i <= 4; ++i, ++p) {
+ idx = index_tbl[*p];
+
+ if (idx == -1) {
+ assert(i > 2);
+
+ if (i == 3) {
+ assert(*p == '=' && *(p + 1) == '=' && p + 2 == end);
+
+ *o++ = (uint8_t)(n >> 16);
+
+ goto fin;
+ }
+
+ assert(*p == '=' && p + 1 == end);
+
+ *o++ = (uint8_t)(n >> 16);
+ *o++ = (n >> 8) & 0xffu;
+
+ goto fin;
+ }
+
+ n += (uint32_t)(idx << (24 - i * 6));
+ }
+
+ *o++ = (uint8_t)(n >> 16);
+ *o++ = (n >> 8) & 0xffu;
+ *o++ = n & 0xffu;
+ }
+
+fin:
+ dest->len = (size_t)(o - dest->base);
+}
diff --git a/deps/nghttp2/lib/sfparse.h b/deps/nghttp2/lib/sfparse.h
new file mode 100644
index 0000000..1474db1
--- /dev/null
+++ b/deps/nghttp2/lib/sfparse.h
@@ -0,0 +1,409 @@
+/*
+ * sfparse
+ *
+ * Copyright (c) 2023 sfparse contributors
+ * Copyright (c) 2019 nghttp3 contributors
+ * Copyright (c) 2015 nghttp2 contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef SFPARSE_H
+#define SFPARSE_H
+
+/* Define WIN32 when build target is Win32 API (borrowed from
+ libcurl) */
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+# define WIN32
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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 <stdint.h>
+#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+# include <inttypes.h>
+#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+#include <sys/types.h>
+#include <stddef.h>
+
+/**
+ * @enum
+ *
+ * :type:`sf_type` defines value type.
+ */
+typedef enum sf_type {
+ /**
+ * :enum:`SF_TYPE_BOOLEAN` indicates boolean type.
+ */
+ SF_TYPE_BOOLEAN,
+ /**
+ * :enum:`SF_TYPE_INTEGER` indicates integer type.
+ */
+ SF_TYPE_INTEGER,
+ /**
+ * :enum:`SF_TYPE_DECIMAL` indicates decimal type.
+ */
+ SF_TYPE_DECIMAL,
+ /**
+ * :enum:`SF_TYPE_STRING` indicates string type.
+ */
+ SF_TYPE_STRING,
+ /**
+ * :enum:`SF_TYPE_TOKEN` indicates token type.
+ */
+ SF_TYPE_TOKEN,
+ /**
+ * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type.
+ */
+ SF_TYPE_BYTESEQ,
+ /**
+ * :enum:`SF_TYPE_INNER_LIST` indicates inner list type.
+ */
+ SF_TYPE_INNER_LIST,
+ /**
+ * :enum:`SF_TYPE_DATE` indicates date type.
+ */
+ SF_TYPE_DATE
+} sf_type;
+
+/**
+ * @macro
+ *
+ * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has
+ * occurred, and it is not possible to continue the processing.
+ */
+#define SF_ERR_PARSE_ERROR -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.
+ */
+#define SF_ERR_EOF -2
+
+/**
+ * @struct
+ *
+ * :type:`sf_vec` stores sequence of bytes.
+ */
+typedef struct sf_vec {
+ /**
+ * :member:`base` points to the beginning of the sequence of bytes.
+ */
+ uint8_t *base;
+ /**
+ * :member:`len` is the number of bytes contained in this sequence.
+ */
+ size_t len;
+} sf_vec;
+
+/**
+ * @macro
+ *
+ * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set.
+ */
+#define SF_VALUE_FLAG_NONE 0x0u
+
+/**
+ * @macro
+ *
+ * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string
+ * contains escaped character(s).
+ */
+#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u
+
+/**
+ * @struct
+ *
+ * :type:`sf_decimal` contains decimal value.
+ */
+typedef struct sf_decimal {
+ /**
+ * :member:`numer` contains numerator of the decimal value.
+ */
+ int64_t numer;
+ /**
+ * :member:`denom` contains denominator of the decimal value.
+ */
+ int64_t denom;
+} sf_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`.
+ */
+typedef struct sf_value {
+ /**
+ * :member:`type` is the type of the value contained in this
+ * particular object.
+ */
+ sf_type type;
+ /**
+ * :member:`flags` is bitwise OR of one or more of
+ * :macro:`SF_VALUE_FLAG_* <SF_VALUE_FLAG_NONE>`.
+ */
+ uint32_t flags;
+ /**
+ * @anonunion_start
+ *
+ * @sf_value_value
+ */
+ union {
+ /**
+ * :member:`boolean` contains boolean value if :member:`type` ==
+ * :enum:`sf_type.SF_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`.
+ */
+ int64_t integer;
+ /**
+ * :member:`decimal` contains decimal value if :member:`type` ==
+ * :enum:`sf_type.SF_TYPE_DECIMAL`.
+ */
+ sf_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`.
+ *
+ * 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:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64
+ * encoded string. To decode this byte string, use
+ * `sf_base64decode`.
+ *
+ * If :member:`vec.len <sf_vec.len>` == 0, :member:`vec.base
+ * <sf_vec.base>` is guaranteed to be NULL.
+ */
+ sf_vec vec;
+ /**
+ * @anonunion_end
+ */
+ };
+} sf_value;
+
+/**
+ * @struct
+ *
+ * :type:`sf_parser` is the Structured Field Values parser. Use
+ * `sf_parser_init` to initialize it.
+ */
+typedef struct sf_parser {
+ /* all fields are private */
+ const uint8_t *pos;
+ const uint8_t *end;
+ uint32_t state;
+} sf_parser;
+
+/**
+ * @function
+ *
+ * `sf_parser_init` initializes |sfp| with the given buffer pointed by
+ * |data| of length |datalen|.
+ */
+void sf_parser_init(sf_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|
+ * 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
+ * while parsing field value.
+ */
+int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_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.
+ *
+ * Caller can optionally read parameters attached to the pair by
+ * calling `sf_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.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :macro:`SF_ERR_EOF`
+ * All values in the dictionary have read.
+ * :macro:`SF_ERR_PARSE_ERROR`
+ * It encountered fatal error while parsing field value.
+ */
+int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value);
+
+/**
+ * @function
+ *
+ * `sf_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`.
+ *
+ * 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.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :macro:`SF_ERR_EOF`
+ * All values in the list have read.
+ * :macro:`SF_ERR_PARSE_ERROR`
+ * It encountered fatal error while parsing field value.
+ */
+int sf_parser_list(sf_parser *sfp, sf_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.
+ *
+ * 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`.
+ *
+ * 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.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :macro:`SF_ERR_EOF`
+ * There is nothing left to read.
+ * :macro:`SF_ERR_PARSE_ERROR`
+ * It encountered fatal error while parsing field value.
+ */
+int sf_parser_item(sf_parser *sfp, sf_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.
+ *
+ * Caller can optionally read parameters attached to the item by
+ * calling `sf_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
+ * parameters attached to this inner list by calling
+ * `sf_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`
+ * All values in the inner list have read.
+ * :macro:`SF_ERR_PARSE_ERROR`
+ * It encountered fatal error while parsing field value.
+ */
+int sf_parser_inner_list(sf_parser *sfp, sf_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.
+ *
+ * :member:`dest->base <sf_vec.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
+ * <sf_vec.len>` == 0.
+ *
+ * This function sets the length of unescaped string to
+ * :member:`dest->len <sf_vec.len>`.
+ */
+void sf_unescape(sf_vec *dest, const sf_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.
+ *
+ * :member:`dest->base <sf_vec.base>` must point to the buffer that
+ * has sufficient space to store the decoded byte string.
+ *
+ * If :member:`src->len <sf_vec.len>` == 0, |*src| is assigned to
+ * |*dest|.
+ *
+ * This function sets the length of decoded byte string to
+ * :member:`dest->len <sf_vec.len>`.
+ */
+void sf_base64decode(sf_vec *dest, const sf_vec *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SFPARSE_H */
diff --git a/deps/nghttp2/nghttp2.gyp b/deps/nghttp2/nghttp2.gyp
index 0dcd034..7b02f39 100644
--- a/deps/nghttp2/nghttp2.gyp
+++ b/deps/nghttp2/nghttp2.gyp
@@ -12,7 +12,6 @@
'defines': [
'BUILDING_NGHTTP2',
'NGHTTP2_STATICLIB',
- 'HAVE_CONFIG_H',
],
'conditions': [
['OS=="win"', {
@@ -38,6 +37,7 @@
'lib/nghttp2_buf.c',
'lib/nghttp2_callbacks.c',
'lib/nghttp2_debug.c',
+ 'lib/nghttp2_extpri.c',
'lib/nghttp2_frame.c',
'lib/nghttp2_hd.c',
'lib/nghttp2_hd_huffman.c',
@@ -52,11 +52,14 @@
'lib/nghttp2_pq.c',
'lib/nghttp2_priority_spec.c',
'lib/nghttp2_queue.c',
+ 'lib/nghttp2_ratelim.c',
'lib/nghttp2_rcbuf.c',
'lib/nghttp2_session.c',
'lib/nghttp2_stream.c',
'lib/nghttp2_submit.c',
- 'lib/nghttp2_version.c'
+ 'lib/nghttp2_time.c',
+ 'lib/nghttp2_version.c',
+ 'lib/sfparse.c'
]
}
]
--
2.41.0