You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5803 lines
186 KiB
5803 lines
186 KiB
11 months ago
|
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
|
||
|
|