From ab6092ed6d6978536e5bc81068bb08e4abaee2dd Mon Sep 17 00:00:00 2001 From: thunder-coding Date: Fri, 24 Sep 2021 09:04:23 +0000 Subject: [PATCH] deps: update nghttp2 to v1.57.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a combination of 9 commits. - deps: update `nghttp2` to v1.45.1 PR-URL: https://github.com/nodejs/node/pull/40206 Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Jiawen Geng - deps: update nghttp2 to 1.47.0 Added script to update nghttp2 in future. One can use ```sh $ ./tools/update-nghttp2.sh 1.47.0 ``` It will automatically copy and update the nghttps in deps. Fixes: https://github.com/nodejs/node/issues/42089 PR-URL: https://github.com/nodejs/node/pull/42127 Reviewed-By: Matteo Collina Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: Mestery Reviewed-By: Darshan Sen - deps: update nghttp2 to 1.51.0 PR-URL: https://github.com/nodejs/node/pull/45537 Reviewed-By: Rafael Gonzaga Reviewed-By: Matteo Collina - deps: update nghttp2 to 1.52.0 Refs: https://github.com/nghttp2/nghttp2/releases/tag/v1.52.0 PR-URL: https://github.com/nodejs/node/pull/46636 Reviewed-By: Colin Ihrig Reviewed-By: Mohammed Keyvanzadeh Reviewed-By: Rafael Gonzaga - deps: update nghttp2 to 1.53.0 PR-URL: https://github.com/nodejs/node/pull/47997 Backport-PR-URL: https://github.com/nodejs/node/pull/50151 Reviewed-By: Rafael Gonzaga Reviewed-By: Luigi Pinca Reviewed-By: Marco Ippolito - deps: update nghttp2 to 1.55.0 PR-URL: https://github.com/nodejs/node/pull/48746 Backport-PR-URL: https://github.com/nodejs/node/pull/50151 Reviewed-By: Luigi Pinca Reviewed-By: Michaël Zasso Reviewed-By: Rafael Gonzaga Reviewed-By: Marco Ippolito Reviewed-By: Yagiz Nizipli Reviewed-By: Trivikram Kamat - deps: update nghttp2 to 1.55.1 PR-URL: https://github.com/nodejs/node/pull/48790 Backport-PR-URL: https://github.com/nodejs/node/pull/50151 Reviewed-By: Luigi Pinca Reviewed-By: Yongsheng Zhang Reviewed-By: Stephen Belanger Reviewed-By: Rafael Gonzaga Reviewed-By: Yagiz Nizipli - deps: update nghttp2 to 1.56.0 PR-URL: https://github.com/nodejs/node/pull/49582 Backport-PR-URL: https://github.com/nodejs/node/pull/50151 Reviewed-By: Luigi Pinca - deps: update nghttp2 to 1.57.0 PR-URL: https://github.com/nodejs/node/pull/50121 Backport-PR-URL: https://github.com/nodejs/node/pull/50151 Reviewed-By: Matteo Collina Reviewed-By: Michael Dawson Reviewed-By: Rich Trott Reviewed-By: Marco Ippolito Reviewed-By: Tobias Nießen Signed-off-by: Jan Staněk --- deps/nghttp2/lib/CMakeLists.txt | 5 +- deps/nghttp2/lib/Makefile.am | 13 +- deps/nghttp2/lib/Makefile.in | 93 +- deps/nghttp2/lib/Makefile.msvc | 38 +- deps/nghttp2/lib/includes/Makefile.in | 44 +- deps/nghttp2/lib/includes/nghttp2/nghttp2.h | 1144 ++++++++++------ .../nghttp2/lib/includes/nghttp2/nghttp2ver.h | 4 +- deps/nghttp2/lib/nghttp2_buf.h | 2 +- deps/nghttp2/lib/nghttp2_extpri.c | 35 + deps/nghttp2/lib/nghttp2_extpri.h | 65 + deps/nghttp2/lib/nghttp2_frame.c | 124 +- deps/nghttp2/lib/nghttp2_frame.h | 99 +- deps/nghttp2/lib/nghttp2_hd.c | 14 +- deps/nghttp2/lib/nghttp2_hd.h | 1 + deps/nghttp2/lib/nghttp2_helper.c | 174 ++- deps/nghttp2/lib/nghttp2_http.c | 153 ++- deps/nghttp2/lib/nghttp2_http.h | 3 + deps/nghttp2/lib/nghttp2_ksl.c | 707 ---------- deps/nghttp2/lib/nghttp2_ksl.h | 315 ----- deps/nghttp2/lib/nghttp2_map.c | 361 +++--- deps/nghttp2/lib/nghttp2_map.h | 68 +- deps/nghttp2/lib/nghttp2_net.h | 14 +- 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_outbound_item.h | 2 +- deps/nghttp2/lib/nghttp2_pq.c | 3 +- deps/nghttp2/lib/nghttp2_pq.h | 10 +- deps/nghttp2/lib/nghttp2_ratelim.c | 75 ++ deps/nghttp2/lib/nghttp2_ratelim.h | 57 + deps/nghttp2/lib/nghttp2_session.c | 889 ++++++++++--- deps/nghttp2/lib/nghttp2_session.h | 55 +- deps/nghttp2/lib/nghttp2_stream.c | 33 +- deps/nghttp2/lib/nghttp2_stream.h | 42 +- deps/nghttp2/lib/nghttp2_submit.c | 84 +- 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 | 54 +- test/parallel/test-http2-methods.js | 2 +- test/parallel/test-http2-multiplex.js | 2 +- tools/update-nghttp2.sh | 59 + 43 files changed, 4434 insertions(+), 2107 deletions(-) create mode 100644 deps/nghttp2/lib/nghttp2_extpri.c create mode 100644 deps/nghttp2/lib/nghttp2_extpri.h delete mode 100644 deps/nghttp2/lib/nghttp2_ksl.c delete mode 100644 deps/nghttp2/lib/nghttp2_ksl.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 create mode 100755 tools/update-nghttp2.sh diff --git a/deps/nghttp2/lib/CMakeLists.txt b/deps/nghttp2/lib/CMakeLists.txt index a02a534b1a..7adba3a3ff 100644 --- a/deps/nghttp2/lib/CMakeLists.txt +++ b/deps/nghttp2/lib/CMakeLists.txt @@ -23,8 +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 - nghttp2_ksl.c + sfparse.c ) set(NGHTTP2_RES "") diff --git a/deps/nghttp2/lib/Makefile.am b/deps/nghttp2/lib/Makefile.am index 63fa0fa832..c3ace4029a 100644 --- a/deps/nghttp2/lib/Makefile.am +++ b/deps/nghttp2/lib/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ @DEFS@ +AM_LDFLAGS = @LIBTOOL_LDFLAGS@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libnghttp2.pc @@ -49,8 +50,11 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ nghttp2_mem.c \ nghttp2_http.c \ nghttp2_rcbuf.c \ + nghttp2_extpri.c \ + nghttp2_ratelim.c \ + nghttp2_time.c \ nghttp2_debug.c \ - nghttp2_ksl.c + sfparse.c HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_frame.h \ @@ -66,9 +70,12 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_mem.h \ nghttp2_http.h \ nghttp2_rcbuf.h \ + nghttp2_extpri.h \ + nghttp2_ratelim.h \ + nghttp2_time.h \ nghttp2_debug.h \ - nghttp2_ksl.h + sfparse.h libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) -libnghttp2_la_LDFLAGS = -no-undefined \ +libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) diff --git a/deps/nghttp2/lib/Makefile.in b/deps/nghttp2/lib/Makefile.in index 14ec74591b..0b95613bc2 100644 --- a/deps/nghttp2/lib/Makefile.in +++ b/deps/nghttp2/lib/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -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_ksl.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,19 +185,21 @@ 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_ksl.Plo ./$(DEPDIR)/nghttp2_map.Plo \ - ./$(DEPDIR)/nghttp2_mem.Plo ./$(DEPDIR)/nghttp2_npn.Plo \ - ./$(DEPDIR)/nghttp2_option.Plo \ + ./$(DEPDIR)/nghttp2_map.Plo ./$(DEPDIR)/nghttp2_mem.Plo \ + ./$(DEPDIR)/nghttp2_npn.Plo ./$(DEPDIR)/nghttp2_option.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) @@ -262,8 +260,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libnghttp2.pc.in \ $(top_srcdir)/depcomp @@ -302,16 +298,14 @@ 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@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CUNIT_CFLAGS = @CUNIT_CFLAGS@ CUNIT_LIBS = @CUNIT_LIBS@ CXX = @CXX@ @@ -320,7 +314,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -CYTHON = @CYTHON@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ @@ -330,9 +323,13 @@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ +EXTRABPFCFLAGS = @EXTRABPFCFLAGS@ EXTRACFLAG = @EXTRACFLAG@ +EXTRA_DEFS = @EXTRA_DEFS@ FGREP = @FGREP@ +FILECMD = @FILECMD@ GREP = @GREP@ HAVE_CXX14 = @HAVE_CXX14@ INSTALL = @INSTALL@ @@ -342,9 +339,12 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JANSSON_CFLAGS = @JANSSON_CFLAGS@ JANSSON_LIBS = @JANSSON_LIBS@ +JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@ JEMALLOC_LIBS = @JEMALLOC_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ +LIBBPF_CFLAGS = @LIBBPF_CFLAGS@ +LIBBPF_LIBS = @LIBBPF_LIBS@ LIBCARES_CFLAGS = @LIBCARES_CFLAGS@ LIBCARES_LIBS = @LIBCARES_LIBS@ LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@ @@ -353,9 +353,18 @@ LIBEV_CFLAGS = @LIBEV_CFLAGS@ LIBEV_LIBS = @LIBEV_LIBS@ LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@ LIBMRUBY_LIBS = @LIBMRUBY_LIBS@ +LIBNGHTTP3_CFLAGS = @LIBNGHTTP3_CFLAGS@ +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_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ +LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ +LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIBTOOL_LDFLAGS = @LIBTOOL_LDFLAGS@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ LIBXML2_LIBS = @LIBXML2_LIBS@ LIPO = @LIPO@ @@ -389,14 +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_LDFLAGS = @PYTHON_LDFLAGS@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ @@ -487,6 +491,7 @@ AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG) AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \ @DEFS@ +AM_LDFLAGS = @LIBTOOL_LDFLAGS@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libnghttp2.pc DISTCLEANFILES = $(pkgconfig_DATA) @@ -506,8 +511,11 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ nghttp2_mem.c \ nghttp2_http.c \ nghttp2_rcbuf.c \ + nghttp2_extpri.c \ + nghttp2_ratelim.c \ + nghttp2_time.c \ nghttp2_debug.c \ - nghttp2_ksl.c + sfparse.c HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_frame.h \ @@ -523,11 +531,14 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_mem.h \ nghttp2_http.h \ nghttp2_rcbuf.h \ + nghttp2_extpri.h \ + nghttp2_ratelim.h \ + nghttp2_time.h \ nghttp2_debug.h \ - nghttp2_ksl.h + sfparse.h libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) -libnghttp2_la_LDFLAGS = -no-undefined \ +libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) all: all-recursive @@ -613,13 +624,13 @@ 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 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_hd_huffman_data.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_helper.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_http.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_ksl.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_map.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_mem.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_npn.Plo@am__quote@ # am--include-marker @@ -628,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) @@ -789,7 +803,6 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am @@ -896,13 +909,13 @@ 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 -rm -f ./$(DEPDIR)/nghttp2_hd_huffman_data.Plo -rm -f ./$(DEPDIR)/nghttp2_helper.Plo -rm -f ./$(DEPDIR)/nghttp2_http.Plo - -rm -f ./$(DEPDIR)/nghttp2_ksl.Plo -rm -f ./$(DEPDIR)/nghttp2_map.Plo -rm -f ./$(DEPDIR)/nghttp2_mem.Plo -rm -f ./$(DEPDIR)/nghttp2_npn.Plo @@ -911,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 @@ -964,13 +980,13 @@ 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 -rm -f ./$(DEPDIR)/nghttp2_hd_huffman_data.Plo -rm -f ./$(DEPDIR)/nghttp2_helper.Plo -rm -f ./$(DEPDIR)/nghttp2_http.Plo - -rm -f ./$(DEPDIR)/nghttp2_ksl.Plo -rm -f ./$(DEPDIR)/nghttp2_map.Plo -rm -f ./$(DEPDIR)/nghttp2_mem.Plo -rm -f ./$(DEPDIR)/nghttp2_npn.Plo @@ -979,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/Makefile.msvc b/deps/nghttp2/lib/Makefile.msvc index f649c0bda4..611b39d0b1 100644 --- a/deps/nghttp2/lib/Makefile.msvc +++ b/deps/nghttp2/lib/Makefile.msvc @@ -6,15 +6,8 @@ # The MIT License apply. # -# -# Choose your weapons: -# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension. -# THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) -USE_CYTHON := 0 -#USE_CYTHON := 1 - _VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g') _VERSION := $(subst ., ,$(_VERSION)) VER_MAJOR := $(word 1,$(_VERSION)) @@ -102,7 +95,7 @@ NGHTTP2_OBJ_D := $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj))) clean_nghttp2_pyd_0 clean_nghttp2_pyd_1 -all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) build_nghttp2_pyd_$(USE_CYTHON) +all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) @echo 'Welcome to NgHTTP2 (release + debug).' @echo 'Do a "make -f Makefile.MSVC install" at own risk!' @@ -121,7 +114,7 @@ $(OBJ_DIR): install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \ $(TARGETS) \ - copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON) + copy_headers_and_libs # # This MUST be done before using the 'install_nghttp2_pyd_1' rule. @@ -160,31 +153,6 @@ $(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res WIN_OBJDIR:=$(shell cygpath -w $(abspath $(OBJ_DIR))) WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR)) -../python/setup.py: ../python/setup.py.in $(THIS_MAKEFILE) - cd ../python ; \ - echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \ - sed -e 's/@top_srcdir@/../' \ - -e 's%@top_builddir@%$(WIN_OBJDIR)%' \ - -e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ; - -build_nghttp2_pyd_0: ; - -build_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx) - cd ../python ; \ - python setup.py build_ext -i -f bdist_wininst - -install_nghttp2_pyd_0: ; - -install_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx) - cd ../python ; \ - pip install . - -clean_nghttp2_pyd_0: ; - -clean_nghttp2_pyd_1: - cd ../python ; \ - rm -fR build dist - $(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE) $(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $< @echo @@ -262,7 +230,7 @@ clean: rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h @echo -vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON) +vclean realclean: clean - rm -rf $(OBJ_DIR) - rm -f .depend.MSVC diff --git a/deps/nghttp2/lib/includes/Makefile.in b/deps/nghttp2/lib/includes/Makefile.in index e1948dfeaa..3de90d7bef 100644 --- a/deps/nghttp2/lib/includes/Makefile.in +++ b/deps/nghttp2/lib/includes/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.2 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -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 @@ -197,8 +192,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ @@ -210,16 +203,14 @@ 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@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CUNIT_CFLAGS = @CUNIT_CFLAGS@ CUNIT_LIBS = @CUNIT_LIBS@ CXX = @CXX@ @@ -228,7 +219,6 @@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ -CYTHON = @CYTHON@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ @@ -238,9 +228,13 @@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ +EXTRABPFCFLAGS = @EXTRABPFCFLAGS@ EXTRACFLAG = @EXTRACFLAG@ +EXTRA_DEFS = @EXTRA_DEFS@ FGREP = @FGREP@ +FILECMD = @FILECMD@ GREP = @GREP@ HAVE_CXX14 = @HAVE_CXX14@ INSTALL = @INSTALL@ @@ -250,9 +244,12 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JANSSON_CFLAGS = @JANSSON_CFLAGS@ JANSSON_LIBS = @JANSSON_LIBS@ +JEMALLOC_CFLAGS = @JEMALLOC_CFLAGS@ JEMALLOC_LIBS = @JEMALLOC_LIBS@ LD = @LD@ LDFLAGS = @LDFLAGS@ +LIBBPF_CFLAGS = @LIBBPF_CFLAGS@ +LIBBPF_LIBS = @LIBBPF_LIBS@ LIBCARES_CFLAGS = @LIBCARES_CFLAGS@ LIBCARES_LIBS = @LIBCARES_LIBS@ LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@ @@ -261,9 +258,18 @@ LIBEV_CFLAGS = @LIBEV_CFLAGS@ LIBEV_LIBS = @LIBEV_LIBS@ LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@ LIBMRUBY_LIBS = @LIBMRUBY_LIBS@ +LIBNGHTTP3_CFLAGS = @LIBNGHTTP3_CFLAGS@ +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_QUICTLS_CFLAGS = @LIBNGTCP2_CRYPTO_QUICTLS_CFLAGS@ +LIBNGTCP2_CRYPTO_QUICTLS_LIBS = @LIBNGTCP2_CRYPTO_QUICTLS_LIBS@ +LIBNGTCP2_LIBS = @LIBNGTCP2_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ +LIBTOOL_LDFLAGS = @LIBTOOL_LDFLAGS@ LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ LIBXML2_LIBS = @LIBXML2_LIBS@ LIPO = @LIPO@ @@ -297,14 +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_LDFLAGS = @PYTHON_LDFLAGS@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ -PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SED = @SED@ @@ -497,7 +498,6 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index d9fae5bf0c..fa22081c51 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -411,12 +411,12 @@ typedef enum { */ NGHTTP2_ERR_TOO_MANY_SETTINGS = -537, /** - * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is - * under unexpected condition and processing was terminated (e.g., - * out of memory). If application receives this error code, it must - * stop using that :type:`nghttp2_session` object and only allowed - * operation for that object is deallocate it using - * `nghttp2_session_del()`. + * The errors < :enum:`nghttp2_error.NGHTTP2_ERR_FATAL` mean that + * the library is under unexpected condition and processing was + * terminated (e.g., out of memory). If application receives this + * error code, it must stop using that :type:`nghttp2_session` + * object and only allowed operation for that object is deallocate + * it using `nghttp2_session_del()`. */ NGHTTP2_ERR_FATAL = -900, /** @@ -545,9 +545,9 @@ typedef struct { * :type:`nghttp2_on_frame_send_callback`, and * :type:`nghttp2_on_frame_not_send_callback`), it may not be * NULL-terminated if header field is passed from application with - * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`). When application - * is constructing this struct, |name| is not required to be - * NULL-terminated. + * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`). + * When application is constructing this struct, |name| is not + * required to be NULL-terminated. */ uint8_t *name; /** @@ -558,9 +558,9 @@ typedef struct { * :type:`nghttp2_on_frame_send_callback`, and * :type:`nghttp2_on_frame_not_send_callback`), it may not be * NULL-terminated if header field is passed from application with - * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`). When - * application is constructing this struct, |value| is not required - * to be NULL-terminated. + * the flag :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE`). + * When application is constructing this struct, |value| is not + * required to be NULL-terminated. */ uint8_t *value; /** @@ -634,7 +634,11 @@ typedef enum { * The ORIGIN frame, which is defined by `RFC 8336 * `_. */ - 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 `_) */ - 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 */ @@ -717,8 +725,8 @@ typedef enum { * * Default maximum number of incoming concurrent streams. Use * `nghttp2_submit_settings()` with - * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the - * maximum number of incoming concurrent streams. + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` + * to change the maximum number of incoming concurrent streams. * * .. note:: * @@ -872,38 +880,41 @@ typedef enum { * The implementation of this function must read at most |length| * bytes of data from |source| (or possibly other places) and store * them in |buf| and return number of data stored in |buf|. If EOF is - * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|. + * reached, set :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag + * in |*data_flags|. * * Sometime it is desirable to avoid copying data into |buf| and let * application to send data directly. To achieve this, set - * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly - * other flags, just like when we do copy), and return the number of - * bytes to send without copying data into |buf|. The library, seeing - * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` to + * |*data_flags| (and possibly other flags, just like when we do + * copy), and return the number of bytes to send without copying data + * into |buf|. The library, seeing + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY`, will invoke * :type:`nghttp2_send_data_callback`. The application must send * complete DATA frame in that callback. * * If this callback is set by `nghttp2_submit_request()`, * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and * `nghttp2_submit_data()` with flag parameter - * :enum:`NGHTTP2_FLAG_END_STREAM` set, and - * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA - * frame will have END_STREAM flag set. Usually, this is expected - * behaviour and all are fine. One exception is send trailer fields. - * You cannot send trailer fields after sending frame with END_STREAM - * set. To avoid this problem, one can set - * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with - * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set - * END_STREAM in DATA frame. Then application can use - * `nghttp2_submit_trailer()` to send trailer fields. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` set, and + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` flag is set to + * |*data_flags|, DATA frame will have END_STREAM flag set. Usually, + * this is expected behaviour and all are fine. One exception is send + * trailer fields. You cannot send trailer fields after sending frame + * with END_STREAM set. To avoid this problem, one can set + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM` along + * with :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF` to signal the + * library not to set END_STREAM in DATA frame. Then application can + * use `nghttp2_submit_trailer()` to send trailer fields. * `nghttp2_submit_trailer()` can be called inside this callback. * * If the application wants to postpone DATA frames (e.g., * asynchronous I/O, or reading data blocks for long time), it is - * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading - * any data in this invocation. The library removes DATA frame from - * the outgoing queue temporarily. To move back deferred DATA frame - * to outgoing queue, call `nghttp2_session_resume_data()`. + * achieved by returning :enum:`nghttp2_error.NGHTTP2_ERR_DEFERRED` + * without reading any data in this invocation. The library removes + * DATA frame from the outgoing queue temporarily. To move back + * deferred DATA frame to outgoing queue, call + * `nghttp2_session_resume_data()`. * * By default, |length| is limited to 16KiB at maximum. If peer * allows larger frames, application can enlarge transmission buffer @@ -912,16 +923,17 @@ typedef enum { * * If the application just wants to return from * `nghttp2_session_send()` or `nghttp2_session_mem_send()` without - * sending anything, return :enum:`NGHTTP2_ERR_PAUSE`. + * sending anything, return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. * * In case of error, there are 2 choices. Returning - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream - * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a - * different error code is desirable, use - * `nghttp2_submit_rst_stream()` with a desired error code and then - * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Returning - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session - * failure. + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will + * close the stream by issuing RST_STREAM with + * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. If a different + * error code is desirable, use `nghttp2_submit_rst_stream()` with a + * desired error code and then return + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * Returning :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will + * signal the entire session failure. */ typedef ssize_t (*nghttp2_data_source_read_callback)( nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length, @@ -1301,8 +1313,9 @@ typedef union { * |length| bytes of data stored in |data|. The |flags| is currently * not used and always 0. It must return the number of bytes sent if * it succeeds. If it cannot send any single byte without blocking, - * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`. For other errors, - * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The + * it must return :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. For + * other errors, it must return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The * |user_data| pointer is the third argument passed in to the call to * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. * @@ -1330,9 +1343,10 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, /** * @functypedef * - * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is - * used in :type:`nghttp2_data_source_read_callback` to send complete - * DATA frame. + * Callback function invoked when + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in + * :type:`nghttp2_data_source_read_callback` to send complete DATA + * frame. * * The |frame| is a DATA frame to send. The |framehd| is the * serialized frame header (9 bytes). The |length| is the length of @@ -1350,21 +1364,22 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, * If all data were written successfully, return 0. * * If it cannot send any data at all, just return - * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback - * with the same parameters later (It is recommended to send complete - * DATA frame at once in this function to deal with error; if partial - * frame data has already sent, it is impossible to send another data - * in that state, and all we can do is tear down connection). When - * data is fully processed, but application wants to make - * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return - * immediately without processing next frames, return - * :enum:`NGHTTP2_ERR_PAUSE`. If application decided to reset this - * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then + * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`; the library will call + * this callback with the same parameters later (It is recommended to + * send complete DATA frame at once in this function to deal with + * error; if partial frame data has already sent, it is impossible to + * send another data in that state, and all we can do is tear down + * connection). When data is fully processed, but application wants + * to make `nghttp2_session_mem_send()` or `nghttp2_session_send()` + * return immediately without processing next frames, return + * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE`. If application decided to + * reset this stream, return + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then * the library will send RST_STREAM with INTERNAL_ERROR as error code. * The application can also return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in - * connection closure. Returning any other value is treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which will + * result in connection closure. Returning any other value is treated + * as :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. */ typedef int (*nghttp2_send_data_callback)(nghttp2_session *session, nghttp2_frame *frame, @@ -1381,11 +1396,13 @@ typedef int (*nghttp2_send_data_callback)(nghttp2_session *session, * currently not used and always 0. It must return the number of * bytes written in |buf| if it succeeds. If it cannot read any * single byte without blocking, it must return - * :enum:`NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF before it reads any - * single byte, it must return :enum:`NGHTTP2_ERR_EOF`. For other - * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. - * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`. The - * |user_data| pointer is the third argument passed in to the call to + * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. If it gets EOF + * before it reads any single byte, it must return + * :enum:`nghttp2_error.NGHTTP2_ERR_EOF`. For other errors, it must + * return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. + * Returning 0 is treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. The |user_data| + * pointer is the third argument passed in to the call to * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`. * * This callback is required if the application uses @@ -1413,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. @@ -1429,7 +1440,8 @@ typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf, * The implementation of this function must return 0 if it succeeds. * If nonzero value is returned, it is treated as fatal error and * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_frame_recv_callback()`. @@ -1457,7 +1469,8 @@ typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session, * The implementation of this function must return 0 if it succeeds. * If nonzero is returned, it is treated as fatal error and * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`. @@ -1480,9 +1493,9 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)( * `nghttp2_session_server_new()`. * * If the application uses `nghttp2_session_mem_recv()`, it can return - * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` - * return without processing further input bytes. The memory by - * pointed by the |data| is retained until + * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make + * `nghttp2_session_mem_recv()` return without processing further + * input bytes. The memory by pointed by the |data| is retained until * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. * The application must retain the input bytes which was used to * produce the |data| parameter, because it may refer to the memory @@ -1491,7 +1504,8 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)( * The implementation of this function must return 0 if it succeeds. * If nonzero is returned, it is treated as fatal error, and * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`. @@ -1511,19 +1525,20 @@ typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session, * `nghttp2_session_server_new()`. * * The implementation of this function must return 0 if it succeeds. - * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the - * transmission of the given frame. + * It can also return :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` to + * cancel the transmission of the given frame. * * If there is a fatal error while executing this callback, the - * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, - * which makes `nghttp2_session_send()` and - * `nghttp2_session_mem_send()` functions immediately return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * implementation should return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, which makes + * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * If the other value is returned, it is treated as if - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. But the - * implementation should not rely on this since the library may define - * new return value to extend its capability. + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. + * But the implementation should not rely on this since the library + * may define new return value to extend its capability. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_before_frame_send_callback()`. @@ -1542,7 +1557,8 @@ typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session, * The implementation of this function must return 0 if it succeeds. * If nonzero is returned, it is treated as fatal error and * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_frame_send_callback()`. @@ -1564,7 +1580,8 @@ typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session, * The implementation of this function must return 0 if it succeeds. * If nonzero is returned, it is treated as fatal error and * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * `nghttp2_session_get_stream_user_data()` can be used to get * associated data. @@ -1595,7 +1612,8 @@ typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session, * If nonzero is returned, it is treated as fatal error and * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`, * `nghttp2_session_send()`, and `nghttp2_session_mem_send()` - * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * functions immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_stream_close_callback()`. @@ -1613,10 +1631,11 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session, * will be emitted by :type:`nghttp2_on_header_callback`. * * The ``frame->hd.flags`` may not have - * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one - * or more CONTINUATION frames are involved. But the application does - * not need to care about that because the header name/value pairs are - * emitted transparently regardless of CONTINUATION frames. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_HEADERS` flag set, which + * indicates that one or more CONTINUATION frames are involved. But + * the application does not need to care about that because the header + * name/value pairs are emitted transparently regardless of + * CONTINUATION frames. * * The server applications probably create an object to store * information about new stream if ``frame->hd.type == @@ -1639,26 +1658,31 @@ typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session, * trailer fields also has ``frame->headers.cat == * NGHTTP2_HCAT_HEADERS`` which does not contain any status code. * - * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close - * the stream (promised stream if frame is PUSH_PROMISE) by issuing - * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, + * Returning + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will + * close the stream (promised stream if frame is PUSH_PROMISE) by + * issuing RST_STREAM with + * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case, * :type:`nghttp2_on_header_callback` and * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a * different error code is desirable, use * `nghttp2_submit_rst_stream()` with a desired error code and then - * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use - * ``frame->push_promise.promised_stream_id`` as stream_id parameter - * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. + * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * Again, use ``frame->push_promise.promised_stream_id`` as stream_id + * parameter in `nghttp2_submit_rst_stream()` if frame is + * PUSH_PROMISE. * * The implementation of this function must return 0 if it succeeds. - * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to + * It can return + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to * reset the stream (promised stream if frame is PUSH_PROMISE). For * critical errors, it must return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the other value is - * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` - * is returned. If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other + * value is returned, it is treated as if + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned. If + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned, * `nghttp2_session_mem_recv()` function will immediately return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_begin_headers_callback()`. @@ -1675,16 +1699,17 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session, * The |value| of length |valuelen| is header value. The |flags| is * bitwise OR of one or more of :type:`nghttp2_nv_flag`. * - * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver - * must not index this name/value pair when forwarding it to the next - * hop. More specifically, "Literal Header Field never Indexed" - * representation must be used in HPACK encoding. + * If :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_INDEX` is set in + * |flags|, the receiver must not index this name/value pair when + * forwarding it to the next hop. More specifically, "Literal Header + * Field never Indexed" representation must be used in HPACK encoding. * * When this callback is invoked, ``frame->hd.type`` is either - * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`. After all - * header name/value pairs are processed with this callback, and no - * error has been detected, :type:`nghttp2_on_frame_recv_callback` - * will be invoked. If there is an error in decompression, + * :enum:`nghttp2_frame_type.NGHTTP2_HEADERS` or + * :enum:`nghttp2_frame_type.NGHTTP2_PUSH_PROMISE`. After all header + * name/value pairs are processed with this callback, and no error has + * been detected, :type:`nghttp2_on_frame_recv_callback` will be + * invoked. If there is an error in decompression, * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be * invoked. * @@ -1702,34 +1727,39 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session, * explained in :ref:`http-messaging` section. * * If the application uses `nghttp2_session_mem_recv()`, it can return - * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()` - * return without processing further input bytes. The memory pointed - * by |frame|, |name| and |value| parameters are retained until - * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called. - * The application must retain the input bytes which was used to - * produce these parameters, because it may refer to the memory region - * included in the input bytes. - * - * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close - * the stream (promised stream if frame is PUSH_PROMISE) by issuing - * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, + * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make + * `nghttp2_session_mem_recv()` return without processing further + * input bytes. The memory pointed by |frame|, |name| and |value| + * parameters are retained until `nghttp2_session_mem_recv()` or + * `nghttp2_session_recv()` is called. The application must retain + * the input bytes which was used to produce these parameters, because + * it may refer to the memory region included in the input bytes. + * + * Returning + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will + * close the stream (promised stream if frame is PUSH_PROMISE) by + * issuing RST_STREAM with + * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. In this case, * :type:`nghttp2_on_header_callback` and * :type:`nghttp2_on_frame_recv_callback` will not be invoked. If a * different error code is desirable, use * `nghttp2_submit_rst_stream()` with a desired error code and then - * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. Again, use - * ``frame->push_promise.promised_stream_id`` as stream_id parameter - * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE. + * return :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * Again, use ``frame->push_promise.promised_stream_id`` as stream_id + * parameter in `nghttp2_submit_rst_stream()` if frame is + * PUSH_PROMISE. * * The implementation of this function must return 0 if it succeeds. - * It may return :enum:`NGHTTP2_ERR_PAUSE` or - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical - * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If - * the other nonzero value is returned, it is treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, + * It may return :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` or + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For + * other critical failures, it must return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other + * nonzero value is returned, it is treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` is returned, * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_header_callback()`. @@ -1796,11 +1826,12 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, * * With this callback, application inspects the incoming invalid * field, and it also can reset stream from this callback by returning - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the - * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error - * code, call `nghttp2_submit_rst_stream()` with the error code of - * choice in addition to returning - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By + * default, the error code is + * :enum:`nghttp2_error_code.NGHTTP2_PROTOCOL_ERROR`. To change the + * error code, call `nghttp2_submit_rst_stream()` with the error code + * of choice in addition to returning + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. * * If 0 is returned, the header field is ignored, and the stream is * not reset. @@ -1831,11 +1862,12 @@ typedef int (*nghttp2_on_invalid_header_callback)( * * With this callback, application inspects the incoming invalid * field, and it also can reset stream from this callback by returning - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the - * error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error - * code, call `nghttp2_submit_rst_stream()` with the error code of - * choice in addition to returning - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By + * default, the error code is + * :enum:`nghttp2_error_code.NGHTTP2_INTERNAL_ERROR`. To change the + * error code, call `nghttp2_submit_rst_stream()` with the error code + * of choice in addition to returning + * :enum:`nghttp2_error.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. */ typedef int (*nghttp2_on_invalid_header_callback2)( nghttp2_session *session, const nghttp2_frame *frame, nghttp2_rcbuf *name, @@ -1849,11 +1881,12 @@ typedef int (*nghttp2_on_invalid_header_callback2)( * |frame|. The application must choose the total length of payload * including padded bytes in range [frame->hd.length, max_payloadlen], * inclusive. Choosing number not in this range will be treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Returning * ``frame->hd.length`` means no padding is added. Returning - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will make * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_select_padding_callback()`. @@ -1873,16 +1906,17 @@ typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session, * |remote_max_frame_size|)]. If a value greater than this range is * returned than the max allow value will be used. Returning a value * smaller than this range is treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. The |frame_type| is provided - * for future extensibility and identifies the type of frame (see - * :type:`nghttp2_frame_type`) for which to get the length for. - * Currently supported frame types are: :enum:`NGHTTP2_DATA`. + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. The + * |frame_type| is provided for future extensibility and identifies + * the type of frame (see :type:`nghttp2_frame_type`) for which to get + * the length for. Currently supported frame types are: + * :enum:`nghttp2_frame_type.NGHTTP2_DATA`. * * This callback can be used to control the length in bytes for which * :type:`nghttp2_data_source_read_callback` is allowed to send to the * remote endpoint. This callback is optional. Returning - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session - * failure. + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` will signal the + * entire session failure. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_data_source_read_length_callback()`. @@ -1909,7 +1943,8 @@ typedef ssize_t (*nghttp2_data_source_read_length_callback)( * The implementation of this function must return 0 if it succeeds. * If nonzero value is returned, it is treated as fatal error and * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. * * To set this callback to :type:`nghttp2_session_callbacks`, use * `nghttp2_session_callbacks_set_on_begin_frame_callback()`. @@ -1928,14 +1963,15 @@ typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session, * The implementation of this function must return 0 if it succeeds. * * To abort processing this extension frame, return - * :enum:`NGHTTP2_ERR_CANCEL`. + * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`. * * If fatal error occurred, application should return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the - * other values are returned, currently they are treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other + * values are returned, currently they are treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. */ typedef int (*nghttp2_on_extension_chunk_recv_callback)( nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data, @@ -1965,14 +2001,15 @@ typedef int (*nghttp2_on_extension_chunk_recv_callback)( * |*payload|, and do its own mechanism to process extension frames. * * To abort processing this extension frame, return - * :enum:`NGHTTP2_ERR_CANCEL`. + * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`. * * If fatal error occurred, application should return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the - * other values are returned, currently they are treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other + * values are returned, currently they are treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. */ typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session, void **payload, @@ -1994,17 +2031,18 @@ typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session, * bytes written into |buf| when it succeeds. * * To abort processing this extension frame, return - * :enum:`NGHTTP2_ERR_CANCEL`, and + * :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL`, and * :type:`nghttp2_on_frame_not_send_callback` will be invoked. * * If fatal error occurred, application should return - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions - * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the - * other values are returned, currently they are treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If the return value is - * strictly larger than |len|, it is treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + * immediately return + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the other + * values are returned, currently they are treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. If the return + * value is strictly larger than |len|, it is treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. */ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, uint8_t *buf, size_t len, @@ -2029,12 +2067,12 @@ typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session, * * Normally, application should return 0 from this callback. If fatal * error occurred while doing something in this callback, application - * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * library will return immediately with return value - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value - * is returned from this callback, they are treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not - * rely on this details. + * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. + * In this case, library will return immediately with return value + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if + * nonzero value is returned from this callback, they are treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application + * should not rely on this details. */ typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, size_t len, void *user_data); @@ -2055,12 +2093,12 @@ typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg, * * Normally, application should return 0 from this callback. If fatal * error occurred while doing something in this callback, application - * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. In this case, - * library will return immediately with return value - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if nonzero value - * is returned from this callback, they are treated as - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not - * rely on this details. + * should return :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. + * In this case, library will return immediately with return value + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`. Currently, if + * nonzero value is returned from this callback, they are treated as + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE`, but application + * should not rely on this details. */ typedef int (*nghttp2_error_callback2)(nghttp2_session *session, int lib_error_code, const char *msg, @@ -2090,7 +2128,7 @@ typedef struct nghttp2_session_callbacks nghttp2_session_callbacks; * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -2287,7 +2325,7 @@ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback( * @function * * Sets callback function invoked when - * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_COPY` is used in * :type:`nghttp2_data_source_read_callback` to avoid data copy. */ NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback( @@ -2470,7 +2508,7 @@ typedef struct nghttp2_option nghttp2_option; * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr); @@ -2531,7 +2569,8 @@ nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option, * If this option is not used or used with zero value, if MAGIC does * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()` * and `nghttp2_session_mem_recv()` will return error - * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error. + * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal + * error. */ NGHTTP2_EXTERN void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); @@ -2616,8 +2655,8 @@ nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option, * received. If this option is set to nonzero, the library won't send * PING frame with ACK flag set in the response for incoming PING * frame. The application can send PING frame with ACK flag set using - * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags - * parameter. + * `nghttp2_submit_ping()` with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` + * as flags parameter. */ NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val); @@ -2631,7 +2670,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, * `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If * application attempts to send header fields larger than this limit, * the transmission of the frame fails with error code - * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`. + * :enum:`nghttp2_error.NGHTTP2_ERR_FRAME_SIZE_ERROR`. */ NGHTTP2_EXTERN void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option, @@ -2656,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); @@ -2682,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 * @@ -2700,7 +2791,7 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -2726,7 +2817,7 @@ nghttp2_session_client_new(nghttp2_session **session_ptr, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -2752,7 +2843,7 @@ nghttp2_session_server_new(nghttp2_session **session_ptr, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -2778,7 +2869,7 @@ nghttp2_session_client_new2(nghttp2_session **session_ptr, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -2804,7 +2895,7 @@ nghttp2_session_server_new2(nghttp2_session **session_ptr, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_session_client_new3( @@ -2829,7 +2920,7 @@ NGHTTP2_EXTERN int nghttp2_session_client_new3( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_session_server_new3( @@ -2853,12 +2944,12 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session); * outbound queue and sends it to the remote peer. It does this as * many times as possible until the user callback * :type:`nghttp2_send_callback` returns - * :enum:`NGHTTP2_ERR_WOULDBLOCK`, the outbound queue becomes empty - * or flow control is triggered (remote window size becomes depleted - * or maximum number of concurrent streams is reached). - * This function calls several callback functions which are passed - * when initializing the |session|. Here is the simple time chart - * which tells when each callback is invoked: + * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`, the outbound queue + * becomes empty or flow control is triggered (remote window size + * becomes depleted or maximum number of concurrent streams is + * reached). This function calls several callback functions which are + * passed when initializing the |session|. Here is the simple time + * chart which tells when each callback is invoked: * * 1. Get the next frame to send from outbound queue. * @@ -2876,7 +2967,7 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session); * * 6. :type:`nghttp2_before_frame_send_callback` is invoked. * - * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from + * 7. If :enum:`nghttp2_error.NGHTTP2_ERR_CANCEL` is returned from * :type:`nghttp2_before_frame_send_callback`, the current frame * transmission is canceled, and * :type:`nghttp2_on_frame_not_send_callback` is invoked. Abort @@ -2894,9 +2985,9 @@ NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` * The callback function failed. */ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session); @@ -2928,7 +3019,7 @@ NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session); * |*data_ptr| if it succeeds, or one of the following negative error * codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. * * .. note:: @@ -2950,8 +3041,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, * * This function receives as many frames as possible until the user * callback :type:`nghttp2_recv_callback` returns - * :enum:`NGHTTP2_ERR_WOULDBLOCK`. This function calls several - * callback functions which are passed when initializing the + * :enum:`nghttp2_error.NGHTTP2_ERR_WOULDBLOCK`. This function calls + * several callback functions which are passed when initializing the * |session|. Here is the simple time chart which tells when each * callback is invoked: * @@ -2996,18 +3087,18 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_send(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_EOF` + * :enum:`nghttp2_error.NGHTTP2_ERR_EOF` * The remote peer did shutdown on the connection. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` * The callback function failed. - * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC` * Invalid client magic was detected. This error only returns * when |session| was configured as server and * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. - * :enum:`NGHTTP2_ERR_FLOODED` + * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED` * Flooding was detected in this HTTP/2 session, and it must be * closed. This is most likely caused by misbehaviour of peer. */ @@ -3017,7 +3108,7 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); * @function * * Processes data |in| as an input from the remote endpoint. The - * |inlen| indicates the number of bytes in the |in|. + * |inlen| indicates the number of bytes to receive in the |in|. * * This function behaves like `nghttp2_session_recv()` except that it * does not use :type:`nghttp2_recv_callback` to receive data; the @@ -3026,27 +3117,27 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session); * are called in the same way as they are in `nghttp2_session_recv()`. * * In the current implementation, this function always tries to - * processes all input data unless either an error occurs or - * :enum:`NGHTTP2_ERR_PAUSE` is returned from + * processes |inlen| bytes of input data unless either an error occurs or + * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from * :type:`nghttp2_on_header_callback` or * :type:`nghttp2_on_data_chunk_recv_callback`. If - * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the - * number of bytes which was used to produce the data or frame for the - * callback. + * :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is used, the return value + * includes the number of bytes which was used to produce the data or + * frame for the callback. * * This function returns the number of processed bytes, or one of the * following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` + * :enum:`nghttp2_error.NGHTTP2_ERR_CALLBACK_FAILURE` * The callback function failed. - * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC` + * :enum:`nghttp2_error.NGHTTP2_ERR_BAD_CLIENT_MAGIC` * Invalid client magic was detected. This error only returns * when |session| was configured as server and * `nghttp2_option_set_no_recv_client_magic()` is not used with * nonzero value. - * :enum:`NGHTTP2_ERR_FLOODED` + * :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED` * Flooding was detected in this HTTP/2 session, and it must be * closed. This is most likely caused by misbehaviour of peer. */ @@ -3063,9 +3154,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The stream does not exist; or no deferred data exist. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session, @@ -3126,7 +3217,7 @@ nghttp2_session_get_stream_user_data(nghttp2_session *session, * This function returns 0 if it succeeds, or one of following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The stream does not exist */ NGHTTP2_EXTERN int @@ -3343,7 +3434,7 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session, @@ -3370,9 +3461,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |last_stream_id| is invalid. */ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, @@ -3387,7 +3478,7 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, * * This function is only usable for server. If this function is * called with client side session, this function returns - * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. * * To gracefully shutdown HTTP/2 session, server should call this * function to send GOAWAY with last_stream_id (1u << 31) - 1. And @@ -3409,9 +3500,9 @@ NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * The |session| is initialized as client. */ NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session); @@ -3446,7 +3537,7 @@ NGHTTP2_EXTERN uint32_t nghttp2_session_get_local_settings( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |next_stream_id| is strictly less than the value * `nghttp2_session_get_next_stream_id()` returns; or * |next_stream_id| is invalid (e.g., even integer for client, or @@ -3481,11 +3572,11 @@ nghttp2_session_get_next_stream_id(nghttp2_session *session); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * Automatic WINDOW_UPDATE is not disabled. */ NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session, @@ -3502,9 +3593,9 @@ NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * Automatic WINDOW_UPDATE is not disabled. */ NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session, @@ -3521,11 +3612,11 @@ NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * Automatic WINDOW_UPDATE is not disabled. */ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, @@ -3552,12 +3643,17 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session, * found, we use default priority instead of given |pri_spec|. That * is make stream depend on root stream with weight 16. * + * If + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` + * of value of 1 is submitted via `nghttp2_submit_settings()`, this + * function does nothing and returns 0. + * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * Attempted to depend on itself; or no stream exist for the given * |stream_id|; or |stream_id| is 0 */ @@ -3595,12 +3691,17 @@ nghttp2_session_change_stream_priority(nghttp2_session *session, * found, we use default priority instead of given |pri_spec|. That * is make stream depend on root stream with weight 16. * + * If + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` + * of value of 1 is submitted via `nghttp2_submit_settings()`, this + * function does nothing and returns 0. + * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * Attempted to depend on itself; or stream denoted by |stream_id| * already exists; or |stream_id| cannot be used to create idle * stream (in other words, local endpoint has already opened @@ -3651,11 +3752,11 @@ nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |settings_payload| is badly formed. - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The stream ID 1 is already used or closed; or is not available. */ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, @@ -3695,11 +3796,11 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |settings_payload| is badly formed. - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The stream ID 1 is already used or closed; or is not available. */ NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session, @@ -3723,10 +3824,10 @@ NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session, * This function returns the number of bytes written in |buf|, or one * of the following negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |iv| contains duplicate settings ID or invalid value. * - * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` * The provided |buflen| size is too small to hold the output. */ NGHTTP2_EXTERN ssize_t nghttp2_pack_settings_payload( @@ -3757,8 +3858,8 @@ NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code); * on with |weight| and its exclusive flag. If |exclusive| is * nonzero, exclusive flag is set. * - * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`, - * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. + * The |weight| must be in [:macro:`NGHTTP2_MIN_WEIGHT`, + * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. */ NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec, int32_t stream_id, @@ -3793,11 +3894,17 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, * this function will copy its data members. * - * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, - * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is - * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes - * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, + * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` + * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes + * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes + * :macro:`NGHTTP2_MAX_WEIGHT`. + * + * If + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` + * of value of 1 is received by a remote endpoint, |pri_spec| is + * ignored, and treated as if ``NULL`` is specified. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The application is responsible to include @@ -3808,12 +3915,12 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in * |nva| is preserved. For header fields with - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name - * and value are not copied respectively. With - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to - * pass header field name in lowercase. The application should - * maintain the references to them until + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, + * header field name and value are not copied respectively. With + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application + * is responsible to pass header field name in lowercase. The + * application should maintain the references to them until * :type:`nghttp2_on_frame_send_callback` or * :type:`nghttp2_on_frame_not_send_callback` is called. * @@ -3835,15 +3942,15 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec); * This function returns assigned stream ID if it succeeds, or one of * the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` * No stream ID is available because maximum stream ID was * reached. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * Trying to depend on itself (new stream ID equals * ``pri_spec->stream_id``). - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The |session| is server session. * * .. warning:: @@ -3878,12 +3985,12 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in * |nva| is preserved. For header fields with - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name - * and value are not copied respectively. With - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to - * pass header field name in lowercase. The application should - * maintain the references to them until + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, + * header field name and value are not copied respectively. With + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application + * is responsible to pass header field name in lowercase. The + * application should maintain the references to them until * :type:`nghttp2_on_frame_send_callback` or * :type:`nghttp2_on_frame_not_send_callback` is called. * @@ -3909,16 +4016,16 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. - * :enum:`NGHTTP2_ERR_DATA_EXIST` + * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` * DATA or HEADERS has been already submitted and not fully * processed yet. Normally, this does not happen, but when * application wrongly calls `nghttp2_submit_response()` twice, * this may happen. - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The |session| is client session. * * .. warning:: @@ -3944,12 +4051,12 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in * |nva| is preserved. For header fields with - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name - * and value are not copied respectively. With - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to - * pass header field name in lowercase. The application should - * maintain the references to them until + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, + * header field name and value are not copied respectively. With + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application + * is responsible to pass header field name in lowercase. The + * application should maintain the references to them until * :type:`nghttp2_on_frame_send_callback` or * :type:`nghttp2_on_frame_not_send_callback` is called. * @@ -3961,16 +4068,16 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, * |nva| will be sent as response headers, which will result in error. * * This function has the same effect with `nghttp2_submit_headers()`, - * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and - * stream_user_data to NULL. + * with flags = :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` and both + * pri_spec and stream_user_data to NULL. * * To submit trailer fields after `nghttp2_submit_response()` is * called, the application has to specify * :type:`nghttp2_data_provider` to `nghttp2_submit_response()`. * Inside of :type:`nghttp2_data_source_read_callback`, when setting - * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set - * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`. After that, the - * application can send trailer fields using + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_EOF`, also set + * :enum:`nghttp2_data_flag.NGHTTP2_DATA_FLAG_NO_END_STREAM`. After + * that, the application can send trailer fields using * `nghttp2_submit_trailer()`. `nghttp2_submit_trailer()` can be used * inside :type:`nghttp2_data_source_read_callback`. * @@ -3978,9 +4085,9 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, * Otherwise, this function returns 0 if it succeeds, or one of the * following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. */ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, @@ -3993,10 +4100,10 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * Submits HEADERS frame. The |flags| is bitwise OR of the * following values: * - * * :enum:`NGHTTP2_FLAG_END_STREAM` + * * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` * - * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has - * END_STREAM flag set. + * If |flags| includes :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, + * this frame has END_STREAM flag set. * * The library handles the CONTINUATION frame internally and it * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE @@ -4013,11 +4120,16 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * use `nghttp2_priority_spec_init()`. If |pri_spec| is not ``NULL``, * this function will copy its data members. * - * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, - * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is - * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes - * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, + * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` + * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes + * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`. + * + * If + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` + * of value of 1 is received by a remote endpoint, |pri_spec| is + * ignored, and treated as if ``NULL`` is specified. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with * |nvlen| elements. The application is responsible to include @@ -4028,12 +4140,12 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in * |nva| is preserved. For header fields with - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name - * and value are not copied respectively. With - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to - * pass header field name in lowercase. The application should - * maintain the references to them until + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, + * header field name and value are not copied respectively. With + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application + * is responsible to pass header field name in lowercase. The + * application should maintain the references to them until * :type:`nghttp2_on_frame_send_callback` or * :type:`nghttp2_on_frame_not_send_callback` is called. * @@ -4051,19 +4163,19 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session, * |stream_id| is -1. Otherwise, this function returns 0 if it * succeeds, or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` * No stream ID is available because maximum stream ID was * reached. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0; or trying to depend on itself (stream ID * equals ``pri_spec->stream_id``). - * :enum:`NGHTTP2_ERR_DATA_EXIST` + * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` * DATA or HEADERS has been already submitted and not fully * processed yet. This happens if stream denoted by |stream_id| * is in reserved state. - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * The |stream_id| is -1, and |session| is server session. * * .. warning:: @@ -4085,8 +4197,8 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers( * * Submits one or more DATA frames to the stream |stream_id|. The * data to be sent are provided by |data_prd|. If |flags| contains - * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM - * flag set. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM`, the last DATA frame + * has END_STREAM flag set. * * This function does not take ownership of the |data_prd|. The * function copies the members of the |data_prd|. @@ -4094,27 +4206,28 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_headers( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_DATA_EXIST` + * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` * DATA or HEADERS has been already submitted and not fully * processed yet. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. - * :enum:`NGHTTP2_ERR_STREAM_CLOSED` + * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED` * The stream was already closed; or the |stream_id| is invalid. * * .. note:: * * Currently, only one DATA or HEADERS is allowed for a stream at a * time. Submitting these frames more than once before first DATA - * or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST` - * error code. The earliest callback which tells that previous - * frame is done is :type:`nghttp2_on_frame_send_callback`. In side - * that callback, new data can be submitted using - * `nghttp2_submit_data()`. Of course, all data except for last one - * must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in - * |flags|. This sounds a bit complicated, and we recommend to use + * or HEADERS is finished results in + * :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST` error code. The + * earliest callback which tells that previous frame is done is + * :type:`nghttp2_on_frame_send_callback`. In side that callback, + * new data can be submitted using `nghttp2_submit_data()`. Of + * course, all data except for last one must not have + * :enum:`nghttp2_flag.NGHTTP2_FLAG_END_STREAM` flag set in |flags|. + * This sounds a bit complicated, and we recommend to use * `nghttp2_submit_request()` and `nghttp2_submit_response()` to * avoid this cascading issue. The experience shows that for HTTP * use, these two functions are enough to implement both client and @@ -4131,25 +4244,31 @@ NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags, * to the priority specification |pri_spec|. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * The |pri_spec| is priority specification of this request. ``NULL`` * is not allowed for this function. To specify the priority, use * `nghttp2_priority_spec_init()`. This function will copy its data * members. * - * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`, - * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` is - * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes - * :enum:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than - * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`. + * The ``pri_spec->weight`` must be in [:macro:`NGHTTP2_MIN_WEIGHT`, + * :macro:`NGHTTP2_MAX_WEIGHT`], inclusive. If ``pri_spec->weight`` + * is strictly less than :macro:`NGHTTP2_MIN_WEIGHT`, it becomes + * :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than + * :macro:`NGHTTP2_MAX_WEIGHT`, it becomes + * :macro:`NGHTTP2_MAX_WEIGHT`. + * + * If + * :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES` + * of value of 1 is received by a remote endpoint, this function does + * nothing and returns 0. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0; or the |pri_spec| is NULL; or trying to * depend on itself. */ @@ -4158,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 * @@ -4167,14 +4341,14 @@ nghttp2_submit_priority(nghttp2_session *session, uint8_t flags, * The pre-defined error code is one of :enum:`nghttp2_error_code`. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0. */ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session, @@ -4189,7 +4363,7 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session, * indicates the number of :type:`nghttp2_settings_entry`. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * This function does not take ownership of the |iv|. This function * copies all the elements in the |iv|. @@ -4198,16 +4372,17 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session, * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, * RST_STREAM is issued against such a stream. * - * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted - * by the library and application could not send it at its will. + * SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is + * automatically submitted by the library and application could not + * send it at its will. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |iv| contains invalid value (e.g., initial window size * strictly greater than (1 << 31) - 1. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, @@ -4235,12 +4410,12 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in * |nva| is preserved. For header fields with - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name - * and value are not copied respectively. With - * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to - * pass header field name in lowercase. The application should - * maintain the references to them until + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME` and + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, + * header field name and value are not copied respectively. With + * :enum:`nghttp2_nv_flag.NGHTTP2_NV_FLAG_NO_COPY_NAME`, application + * is responsible to pass header field name in lowercase. The + * application should maintain the references to them until * :type:`nghttp2_on_frame_send_callback` or * :type:`nghttp2_on_frame_not_send_callback` is called. * @@ -4259,18 +4434,18 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session, * This function returns assigned promised stream ID if it succeeds, * or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_PROTO` + * :enum:`nghttp2_error.NGHTTP2_ERR_PROTO` * This function was invoked when |session| is initialized as * client. - * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` + * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE` * No stream ID is available because maximum stream ID was * reached. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is 0; The |stream_id| does not designate stream * that peer initiated. - * :enum:`NGHTTP2_ERR_STREAM_CLOSED` + * :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED` * The stream was already closed; or the |stream_id| is invalid. * * .. warning:: @@ -4299,10 +4474,10 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise( * * The |flags| is bitwise OR of 0 or more of the following value. * - * * :enum:`NGHTTP2_FLAG_ACK` + * * :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` * * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags| - * should be :enum:`NGHTTP2_FLAG_NONE`. + * should be :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * If the |opaque_data| is non ``NULL``, then it should point to the 8 * bytes array of memory to specify opaque data to send with PING @@ -4312,7 +4487,7 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_push_promise( * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, @@ -4327,7 +4502,7 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, * The pre-defined error code is one of :enum:`nghttp2_error_code`. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * The |last_stream_id| is peer's stream ID or 0. So if |session| is * initialized as client, |last_stream_id| must be even or 0. If @@ -4357,9 +4532,9 @@ NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |opaque_data_len| is too large; the |last_stream_id| is * invalid. */ @@ -4415,7 +4590,7 @@ nghttp2_session_check_server_session(nghttp2_session *session); * Submits WINDOW_UPDATE frame. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * The |stream_id| is the stream ID to send this WINDOW_UPDATE. To * send connection level WINDOW_UPDATE, specify 0 to |stream_id|. @@ -4442,9 +4617,9 @@ nghttp2_session_check_server_session(nghttp2_session *session); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_FLOW_CONTROL` + * :enum:`nghttp2_error.NGHTTP2_ERR_FLOW_CONTROL` * The local window size overflow or gets negative. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, @@ -4462,7 +4637,7 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, * to transmission queue. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * This sounds similar to `nghttp2_submit_window_update()`, but there * are 2 differences. The first difference is that this function @@ -4481,9 +4656,9 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session, * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The |stream_id| is negative. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -4514,18 +4689,19 @@ nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags, * * The standard HTTP/2 frame cannot be sent with this function, so * |type| must be strictly grater than 0x9. Otherwise, this function - * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`. + * will fail with error code + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * If :type:`nghttp2_pack_extension_callback` is not set. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * If |type| specifies standard HTTP/2 frame type. The frame * types in the rage [0x0, 0x9], both inclusive, are standard * HTTP/2 frame type, and cannot be sent using this function. - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory */ NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session, @@ -4539,8 +4715,8 @@ NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session, * extension to HTTP/2. If this frame is received, and * `nghttp2_option_set_user_recv_extension_type()` is not set, and * `nghttp2_option_set_builtin_recv_extension_type()` is set for - * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to - * this struct. + * :enum:`nghttp2_frame_type.NGHTTP2_ALTSVC`, + * ``nghttp2_extension.payload`` will point to this struct. * * It has the following members: */ @@ -4574,7 +4750,7 @@ typedef struct { * `RFC 7383 `_. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * The |origin| points to the origin this alternative service is * associated with. The |origin_len| is the length of the origin. If @@ -4584,16 +4760,16 @@ typedef struct { * * The ALTSVC frame is only usable from server side. If this function * is invoked with client side session, this function returns - * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * The function is called from client side session - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * The sum of |origin_len| and |field_value_len| is larger than * 16382; or |origin_len| is 0 while |stream_id| is 0; or * |origin_len| is not 0 while |stream_id| is not 0. @@ -4632,8 +4808,8 @@ typedef struct { * If this frame is received, and * `nghttp2_option_set_user_recv_extension_type()` is not set, and * `nghttp2_option_set_builtin_recv_extension_type()` is set for - * :enum:`NGHTTP2_ORIGIN`, ``nghttp2_extension.payload`` will point to - * this struct. + * :enum:`nghttp2_frame_type.NGHTTP2_ORIGIN`, + * ``nghttp2_extension.payload`` will point to this struct. * * It has the following members: */ @@ -4657,7 +4833,7 @@ typedef struct { * `RFC 8336 `_. * * The |flags| is currently ignored and should be - * :enum:`NGHTTP2_FLAG_NONE`. + * :enum:`nghttp2_flag.NGHTTP2_FLAG_NONE`. * * The |ov| points to the array of origins. The |nov| specifies the * number of origins included in |ov|. This function creates copies @@ -4665,13 +4841,13 @@ typedef struct { * * The ORIGIN frame is only usable by a server. If this function is * invoked with client side session, this function returns - * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * The function is called from client side session. - * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT` * There are too many origins, or an origin is too large to fit * into a default frame payload. */ @@ -4680,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 ` 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 * @@ -4791,13 +5069,51 @@ NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len); * Returns nonzero if HTTP header field value |value| of length |len| * is valid according to * http://tools.ietf.org/html/rfc7230#section-3.2 + * + * This function is considered obsolete, and application should + * consider to use `nghttp2_check_header_value_rfc9113()` instead. */ NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len); /** * @function * - * Returns nonzero if the |value| which is supposed to the value of + * Returns nonzero if HTTP header field value |value| of length |len| + * is valid according to + * http://tools.ietf.org/html/rfc7230#section-3.2, plus + * https://datatracker.ietf.org/doc/html/rfc9113#section-8.2.1 + */ +NGHTTP2_EXTERN int nghttp2_check_header_value_rfc9113(const uint8_t *value, + size_t len); + +/** + * @function + * + * Returns nonzero if the |value| which is supposed to be the value of + * the :method header field is valid according to + * https://datatracker.ietf.org/doc/html/rfc7231#section-4 and + * https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 + */ +NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len); + +/** + * @function + * + * Returns nonzero if the |value| which is supposed to be the value of + * the :path header field is valid according to + * https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3 + * + * |value| is valid if it merely consists of the allowed characters. + * In particular, it does not check whether |value| follows the syntax + * of path. The allowed characters are all characters valid by + * `nghttp2_check_header_value` minus SPC and HT. + */ +NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len); + +/** + * @function + * + * Returns nonzero if the |value| which is supposed to be the value of the * :authority or host header field is valid according to * https://tools.ietf.org/html/rfc3986#section-3.2 * @@ -4831,7 +5147,7 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater; * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -4885,7 +5201,7 @@ NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int @@ -4899,24 +5215,24 @@ nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, * the |buf| of length |buflen|. * * If |buf| is not large enough to store the deflated header block, - * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The - * caller should use `nghttp2_hd_deflate_bound()` to know the upper - * bound of buffer size required to deflate given header name/value - * pairs. + * this function fails with + * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller + * should use `nghttp2_hd_deflate_bound()` to know the upper bound of + * buffer size required to deflate given header name/value pairs. * * Once this function fails, subsequent call of this function always - * returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. * * After this function returns, it is safe to delete the |nva|. * * This function returns the number of bytes written to |buf| if it * succeeds, or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_HEADER_COMP` + * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` * Deflation process has failed. - * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` * The provided |buflen| size is too small to hold the output. */ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, @@ -4932,23 +5248,24 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, * must be set in len field of :type:`nghttp2_vec`. If and only if * one chunk is filled up completely, next chunk will be used. If * |vec| is not large enough to store the deflated header block, this - * function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller + * function fails with + * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE`. The caller * should use `nghttp2_hd_deflate_bound()` to know the upper bound of * buffer size required to deflate given header name/value pairs. * * Once this function fails, subsequent call of this function always - * returns :enum:`NGHTTP2_ERR_HEADER_COMP`. + * returns :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP`. * * After this function returns, it is safe to delete the |nva|. * * This function returns the number of bytes written to |vec| if it * succeeds, or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_HEADER_COMP` + * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` * Deflation process has failed. - * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INSUFF_BUFSIZE` * The provided |buflen| size is too small to hold the output. */ NGHTTP2_EXTERN ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater, @@ -5028,7 +5345,7 @@ typedef struct nghttp2_hd_inflater nghttp2_hd_inflater; * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. */ NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr); @@ -5077,9 +5394,9 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater); * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_INVALID_STATE` + * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE` * The function is called while header block is being inflated. * Probably, application missed to call * `nghttp2_hd_inflate_end_headers()`. @@ -5117,7 +5434,8 @@ typedef enum { * * Inflates name/value block stored in |in| with length |inlen|. This * function performs decompression. For each successful emission of - * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + * header name/value pair, + * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in * |*inflate_flags| and name/value pair is assigned to the |nv_out| * and the function returns. The caller must not free the members of * |nv_out|. @@ -5140,11 +5458,11 @@ typedef enum { * This function returns the number of bytes processed if it succeeds, * or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_HEADER_COMP` + * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` * Inflation process has failed. - * :enum:`NGHTTP2_ERR_BUFFER_ERROR` + * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR` * The header field name or value is too large. * * Example follows:: @@ -5199,7 +5517,8 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, * * Inflates name/value block stored in |in| with length |inlen|. This * function performs decompression. For each successful emission of - * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in + * header name/value pair, + * :enum:`nghttp2_hd_inflate_flag.NGHTTP2_HD_INFLATE_EMIT` is set in * |*inflate_flags| and name/value pair is assigned to the |nv_out| * and the function returns. The caller must not free the members of * |nv_out|. @@ -5215,8 +5534,9 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, * for the next header block input. * * In other words, if |in_final| is nonzero, and this function returns - * |inlen|, you can assert that :enum:`NGHTTP2_HD_INFLATE_FINAL` is - * set in |*inflate_flags|. + * |inlen|, you can assert that + * :enum:`nghttp2_hd_inflate_final.NGHTTP2_HD_INFLATE_FINAL` is set in + * |*inflate_flags|. * * The caller can feed complete compressed header block. It also can * feed it in several chunks. The caller must set |in_final| to @@ -5226,11 +5546,11 @@ NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, * This function returns the number of bytes processed if it succeeds, * or one of the following negative error codes: * - * :enum:`NGHTTP2_ERR_NOMEM` + * :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM` * Out of memory. - * :enum:`NGHTTP2_ERR_HEADER_COMP` + * :enum:`nghttp2_error.NGHTTP2_ERR_HEADER_COMP` * Inflation process has failed. - * :enum:`NGHTTP2_ERR_BUFFER_ERROR` + * :enum:`nghttp2_error.NGHTTP2_ERR_BUFFER_ERROR` * The header field name or value is too large. * * Example follows:: @@ -5401,7 +5721,7 @@ typedef enum { * * Returns state of |stream|. The root stream retrieved by * `nghttp2_session_get_root_stream()` will have stream state - * :enum:`NGHTTP2_STREAM_STATE_IDLE`. + * :enum:`nghttp2_stream_proto_state.NGHTTP2_STREAM_STATE_IDLE`. */ NGHTTP2_EXTERN nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream); diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index ff6bf3d3b2..f56954e7fd 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.42.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 0x012a00 +#define NGHTTP2_VERSION_NUM 0x013900 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_buf.h b/deps/nghttp2/lib/nghttp2_buf.h index 06cce67a11..45f62f16e2 100644 --- a/deps/nghttp2/lib/nghttp2_buf.h +++ b/deps/nghttp2/lib/nghttp2_buf.h @@ -99,7 +99,7 @@ void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem); * |new_cap|. If extensions took place, buffer pointers in |buf| will * change. * - * This function returns 0 if it succeeds, or one of the followings + * This function returns 0 if it succeeds, or one of the following * negative error codes: * * NGHTTP2_ERR_NOMEM diff --git a/deps/nghttp2/lib/nghttp2_extpri.c b/deps/nghttp2/lib/nghttp2_extpri.c new file mode 100644 index 0000000000..3fd9b78163 --- /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 0000000000..23c6ddc0c0 --- /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 +#endif /* HAVE_CONFIG_H */ + +#include + +/* + * 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 382a26c818..77cb463df5 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, @@ -654,8 +670,6 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, var_gift_payloadlen = 0; } - payloadlen -= var_gift_payloadlen; - if (!var_gift_payloadlen) { var_gift_payload = NULL; } else { @@ -674,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); @@ -690,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, @@ -700,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; @@ -729,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, @@ -878,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; @@ -1073,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; @@ -1107,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; } /* @@ -1147,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 615bbf31f5..d58668806c 100644 --- a/deps/nghttp2/lib/nghttp2_frame.h +++ b/deps/nghttp2/lib/nghttp2_frame.h @@ -46,7 +46,7 @@ #define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14) #define NGHTTP2_MAX_PAYLOADLEN 16384 -/* The one frame buffer length for tranmission. We may use several of +/* The one frame buffer length for transmission. We may use several of them to support CONTINUATION. To account for Pad Length field, we allocate extra 1 byte, which saves extra large memcopying. */ #define NGHTTP2_FRAMEBUF_CHUNKLEN \ @@ -57,7 +57,7 @@ /* Maximum headers block size to send, calculated using nghttp2_hd_deflate_bound(). This is the default value, and can be - overridden by nghttp2_option_set_max_send_header_block_size(). */ + overridden by nghttp2_option_set_max_send_header_block_length(). */ #define NGHTTP2_MAX_HEADERSLEN 65536 /* The number of bytes for each SETTINGS entry */ @@ -73,6 +73,7 @@ typedef union { nghttp2_ext_altsvc altsvc; nghttp2_ext_origin origin; + nghttp2_ext_priority_update priority_update; } nghttp2_ext_frame_payload; void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd); @@ -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 5e86931525..8a2bda64c1 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: @@ -1263,6 +1268,8 @@ int nghttp2_hd_inflate_change_table_size( return NGHTTP2_ERR_INVALID_STATE; } + inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size; + /* It seems that encoder is not required to send dynamic table size update if the table size is not changed after applying SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this @@ -1275,13 +1282,12 @@ int nghttp2_hd_inflate_change_table_size( /* Remember minimum value, and validate that encoder sends the value less than or equal to this. */ inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size; - } - inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size; + inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size; - inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size; + hd_context_shrink_table_size(&inflater->ctx, NULL); + } - hd_context_shrink_table_size(&inflater->ctx, NULL); return 0; } diff --git a/deps/nghttp2/lib/nghttp2_hd.h b/deps/nghttp2/lib/nghttp2_hd.h index 267402881f..6de0052aae 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 0bd5414723..93dd4754b7 100644 --- a/deps/nghttp2/lib/nghttp2_helper.c +++ b/deps/nghttp2/lib/nghttp2_helper.c @@ -507,7 +507,179 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) { return 1; } -/* Generated by genauthroitychartbl.py */ +int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) { + if (len == 0) { + return 1; + } + + if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || + *(value + len - 1) == '\t') { + return 0; + } + + return nghttp2_check_header_value(value, len); +} + +/* Generated by genmethodchartbl.py */ +static char VALID_METHOD_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, + 0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, + 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, + 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */, + 0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, + 1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */, + 0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */, + 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */, + 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, + 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, + 0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, + 0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */, + 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */, + 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, + 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, + 0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, + 0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */, + 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */, + 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, + 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, + 0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, + 0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */, + 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */, + 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, + 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, + 0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, + 0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */, + 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */, + 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, + 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, + 0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, + 0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */, + 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */, + 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, + 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, + 0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, + 0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */, + 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */ +}; + +int nghttp2_check_method(const uint8_t *value, size_t len) { + const uint8_t *last; + if (len == 0) { + return 0; + } + for (last = value + len; value != last; ++value) { + if (!VALID_METHOD_CHARS[*value]) { + return 0; + } + } + return 1; +} + +/* Generated by genpathchartbl.py */ +static char VALID_PATH_CHARS[] = { + 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, + 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, + 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, + 0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */, + 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, + 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, + 0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */, + 0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */, + 0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */, + 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, + 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, + 1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */, + 1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */, + 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, + 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, + 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, + 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, + 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, + 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, + 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, + 1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */, + 1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */, + 1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */, + 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, + 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, + 1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */, + 1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */, + 1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */, + 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, + 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, + 1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */, + 1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */, + 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */, + 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */, + 1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, + 1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, + 1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */, + 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */, + 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */, + 1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, + 1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, + 1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */, + 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */, + 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */, + 1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, + 1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, + 1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */, + 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */, + 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */, + 1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, + 1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, + 1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */, + 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */, + 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */, + 1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, + 1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, + 1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */, + 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */, + 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */, + 1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, + 1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, + 1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */, + 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */ +}; + +int nghttp2_check_path(const uint8_t *value, size_t len) { + const uint8_t *last; + for (last = value + len; value != last; ++value) { + if (!VALID_PATH_CHARS[*value]) { + return 0; + } + } + return 1; +} + +/* Generated by genauthoritychartbl.py */ static char VALID_AUTHORITY_CHARS[] = { 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c index 62f57b6aec..ecdeb21ddb 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) { @@ -360,13 +378,46 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, return NGHTTP2_ERR_IGN_HTTP_HEADER; } - if (nv->token == NGHTTP2_TOKEN__AUTHORITY || - nv->token == NGHTTP2_TOKEN_HOST) { - rv = nghttp2_check_authority(nv->value->base, nv->value->len); - } else if (nv->token == NGHTTP2_TOKEN__SCHEME) { + switch (nv->token) { + case NGHTTP2_TOKEN__METHOD: + rv = nghttp2_check_method(nv->value->base, nv->value->len); + break; + case NGHTTP2_TOKEN__PATH: + rv = nghttp2_check_path(nv->value->base, nv->value->len); + break; + case NGHTTP2_TOKEN__AUTHORITY: + case NGHTTP2_TOKEN_HOST: + if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { + rv = nghttp2_check_authority(nv->value->base, nv->value->len); + } else if ( + stream->flags & + NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { + rv = nghttp2_check_header_value(nv->value->base, nv->value->len); + } else { + rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len); + } + break; + case NGHTTP2_TOKEN__SCHEME: rv = check_scheme(nv->value->base, nv->value->len); - } else { - rv = nghttp2_check_header_value(nv->value->base, nv->value->len); + break; + case NGHTTP2_TOKEN__PROTOCOL: + /* Check the value consists of just white spaces, which was done + in check_pseudo_header before + nghttp2_check_header_value_rfc9113 has been introduced. */ + if ((stream->flags & + NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) && + lws(nv->value->base, nv->value->len)) { + rv = 0; + break; + } + /* fall through */ + default: + if (stream->flags & + NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) { + rv = nghttp2_check_header_value(nv->value->base, nv->value->len); + } else { + rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len); + } } if (rv == 0) { @@ -434,16 +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; @@ -528,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 dd057cdb60..d9992fe690 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_ksl.c b/deps/nghttp2/lib/nghttp2_ksl.c deleted file mode 100644 index dffd1cbcff..0000000000 --- a/deps/nghttp2/lib/nghttp2_ksl.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2020 nghttp2 contributors - * Copyright (c) 2018 ngtcp2 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_ksl.h" - -#include -#include -#include -#include - -#include "nghttp2_mem.h" - -static size_t ksl_nodelen(size_t keylen) { - return (sizeof(nghttp2_ksl_node) + keylen - sizeof(uint64_t) + 0xf) & - (size_t)~0xf; -} - -static size_t ksl_blklen(size_t nodelen) { - return sizeof(nghttp2_ksl_blk) + nodelen * NGHTTP2_KSL_MAX_NBLK - - sizeof(uint64_t); -} - -/* - * ksl_node_set_key sets |key| to |node|. - */ -static void ksl_node_set_key(nghttp2_ksl *ksl, nghttp2_ksl_node *node, - const void *key) { - memcpy(node->key, key, ksl->keylen); -} - -int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen, - nghttp2_mem *mem) { - size_t nodelen = ksl_nodelen(keylen); - size_t blklen = ksl_blklen(nodelen); - nghttp2_ksl_blk *head; - - ksl->head = nghttp2_mem_malloc(mem, blklen); - if (!ksl->head) { - return NGHTTP2_ERR_NOMEM; - } - ksl->front = ksl->back = ksl->head; - ksl->compar = compar; - ksl->keylen = keylen; - ksl->nodelen = nodelen; - ksl->n = 0; - ksl->mem = mem; - - head = ksl->head; - head->next = head->prev = NULL; - head->n = 0; - head->leaf = 1; - - return 0; -} - -/* - * ksl_free_blk frees |blk| recursively. - */ -static void ksl_free_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) { - size_t i; - - if (!blk->leaf) { - for (i = 0; i < blk->n; ++i) { - ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk); - } - } - - nghttp2_mem_free(ksl->mem, blk); -} - -void nghttp2_ksl_free(nghttp2_ksl *ksl) { - if (!ksl) { - return; - } - - ksl_free_blk(ksl, ksl->head); -} - -/* - * ksl_split_blk splits |blk| into 2 nghttp2_ksl_blk objects. The new - * nghttp2_ksl_blk is always the "right" block. - * - * It returns the pointer to the nghttp2_ksl_blk created which is the - * located at the right of |blk|, or NULL which indicates out of - * memory error. - */ -static nghttp2_ksl_blk *ksl_split_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) { - nghttp2_ksl_blk *rblk; - - rblk = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen)); - if (rblk == NULL) { - return NULL; - } - - rblk->next = blk->next; - blk->next = rblk; - if (rblk->next) { - rblk->next->prev = rblk; - } else if (ksl->back == blk) { - ksl->back = rblk; - } - rblk->prev = blk; - rblk->leaf = blk->leaf; - - rblk->n = blk->n / 2; - - memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n), - ksl->nodelen * rblk->n); - - blk->n -= rblk->n; - - assert(blk->n >= NGHTTP2_KSL_MIN_NBLK); - assert(rblk->n >= NGHTTP2_KSL_MIN_NBLK); - - return rblk; -} - -/* - * ksl_split_node splits a node included in |blk| at the position |i| - * into 2 adjacent nodes. The new node is always inserted at the - * position |i+1|. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int ksl_split_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) { - nghttp2_ksl_node *node; - nghttp2_ksl_blk *lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk, *rblk; - - rblk = ksl_split_blk(ksl, lblk); - if (rblk == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - memmove(blk->nodes + (i + 2) * ksl->nodelen, - blk->nodes + (i + 1) * ksl->nodelen, - ksl->nodelen * (blk->n - (i + 1))); - - node = nghttp2_ksl_nth_node(ksl, blk, i + 1); - node->blk = rblk; - ++blk->n; - ksl_node_set_key(ksl, node, - nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key); - - node = nghttp2_ksl_nth_node(ksl, blk, i); - ksl_node_set_key(ksl, node, - nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); - - return 0; -} - -/* - * ksl_split_head splits a head (root) block. It increases the height - * of skip list by 1. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -static int ksl_split_head(nghttp2_ksl *ksl) { - nghttp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL; - nghttp2_ksl_node *node; - - rblk = ksl_split_blk(ksl, ksl->head); - if (rblk == NULL) { - return NGHTTP2_ERR_NOMEM; - } - - lblk = ksl->head; - - nhead = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen)); - if (nhead == NULL) { - nghttp2_mem_free(ksl->mem, rblk); - return NGHTTP2_ERR_NOMEM; - } - nhead->next = nhead->prev = NULL; - nhead->n = 2; - nhead->leaf = 0; - - node = nghttp2_ksl_nth_node(ksl, nhead, 0); - ksl_node_set_key(ksl, node, - nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); - node->blk = lblk; - - node = nghttp2_ksl_nth_node(ksl, nhead, 1); - ksl_node_set_key(ksl, node, - nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key); - node->blk = rblk; - - ksl->head = nhead; - - return 0; -} - -/* - * insert_node inserts a node whose key is |key| with the associated - * |data| at the index of |i|. This function assumes that the number - * of nodes contained by |blk| is strictly less than - * NGHTTP2_KSL_MAX_NBLK. - */ -static void ksl_insert_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i, - const nghttp2_ksl_key *key, void *data) { - nghttp2_ksl_node *node; - - assert(blk->n < NGHTTP2_KSL_MAX_NBLK); - - memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen, - ksl->nodelen * (blk->n - i)); - - node = nghttp2_ksl_nth_node(ksl, blk, i); - ksl_node_set_key(ksl, node, key); - node->data = data; - - ++blk->n; -} - -static size_t ksl_bsearch(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, - const nghttp2_ksl_key *key, - nghttp2_ksl_compar compar) { - ssize_t left = -1, right = (ssize_t)blk->n, mid; - nghttp2_ksl_node *node; - - while (right - left > 1) { - mid = (left + right) / 2; - node = nghttp2_ksl_nth_node(ksl, blk, (size_t)mid); - if (compar((nghttp2_ksl_key *)node->key, key)) { - left = mid; - } else { - right = mid; - } - } - - return (size_t)right; -} - -int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it, - const nghttp2_ksl_key *key, void *data) { - nghttp2_ksl_blk *blk = ksl->head; - nghttp2_ksl_node *node; - size_t i; - int rv; - - if (blk->n == NGHTTP2_KSL_MAX_NBLK) { - rv = ksl_split_head(ksl); - if (rv != 0) { - return rv; - } - blk = ksl->head; - } - - for (;;) { - i = ksl_bsearch(ksl, blk, key, ksl->compar); - - if (blk->leaf) { - if (i < blk->n && - !ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) { - if (it) { - *it = nghttp2_ksl_end(ksl); - } - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - ksl_insert_node(ksl, blk, i, key, data); - ++ksl->n; - if (it) { - nghttp2_ksl_it_init(it, ksl, blk, i); - } - return 0; - } - - if (i == blk->n) { - /* This insertion extends the largest key in this subtree. */ - for (; !blk->leaf;) { - node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1); - if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) { - rv = ksl_split_node(ksl, blk, blk->n - 1); - if (rv != 0) { - return rv; - } - node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1); - } - ksl_node_set_key(ksl, node, key); - blk = node->blk; - } - ksl_insert_node(ksl, blk, blk->n, key, data); - ++ksl->n; - if (it) { - nghttp2_ksl_it_init(it, ksl, blk, blk->n - 1); - } - return 0; - } - - node = nghttp2_ksl_nth_node(ksl, blk, i); - - if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) { - rv = ksl_split_node(ksl, blk, i); - if (rv != 0) { - return rv; - } - if (ksl->compar((nghttp2_ksl_key *)node->key, key)) { - node = nghttp2_ksl_nth_node(ksl, blk, i + 1); - if (ksl->compar((nghttp2_ksl_key *)node->key, key)) { - ksl_node_set_key(ksl, node, key); - } - } - } - - blk = node->blk; - } -} - -/* - * ksl_remove_node removes the node included in |blk| at the index of - * |i|. - */ -static void ksl_remove_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) { - memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen, - ksl->nodelen * (blk->n - (i + 1))); - - --blk->n; -} - -/* - * ksl_merge_node merges 2 nodes which are the nodes at the index of - * |i| and |i + 1|. - * - * If |blk| is the direct descendant of head (root) block and the head - * block contains just 2 nodes, the merged block becomes head block, - * which decreases the height of |ksl| by 1. - * - * This function returns the pointer to the merged block. - */ -static nghttp2_ksl_blk *ksl_merge_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, - size_t i) { - nghttp2_ksl_blk *lblk, *rblk; - - assert(i + 1 < blk->n); - - lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk; - rblk = nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk; - - assert(lblk->n + rblk->n < NGHTTP2_KSL_MAX_NBLK); - - memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes, - ksl->nodelen * rblk->n); - - lblk->n += rblk->n; - lblk->next = rblk->next; - if (lblk->next) { - lblk->next->prev = lblk; - } else if (ksl->back == rblk) { - ksl->back = lblk; - } - - nghttp2_mem_free(ksl->mem, rblk); - - if (ksl->head == blk && blk->n == 2) { - nghttp2_mem_free(ksl->mem, ksl->head); - ksl->head = lblk; - } else { - ksl_remove_node(ksl, blk, i + 1); - ksl_node_set_key(ksl, nghttp2_ksl_nth_node(ksl, blk, i), - nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key); - } - - return lblk; -} - -/* - * ksl_shift_left moves the first node in blk->nodes[i]->blk->nodes to - * blk->nodes[i - 1]->blk->nodes. - */ -static void ksl_shift_left(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) { - nghttp2_ksl_node *lnode, *rnode, *dest, *src; - - assert(i > 0); - - lnode = nghttp2_ksl_nth_node(ksl, blk, i - 1); - rnode = nghttp2_ksl_nth_node(ksl, blk, i); - - assert(lnode->blk->n < NGHTTP2_KSL_MAX_NBLK); - assert(rnode->blk->n > NGHTTP2_KSL_MIN_NBLK); - - dest = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n); - src = nghttp2_ksl_nth_node(ksl, rnode->blk, 0); - - memcpy(dest, src, ksl->nodelen); - ksl_node_set_key(ksl, lnode, dest->key); - ++lnode->blk->n; - - --rnode->blk->n; - memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen, - ksl->nodelen * rnode->blk->n); -} - -/* - * ksl_shift_right moves the last node in blk->nodes[i]->blk->nodes to - * blk->nodes[i + 1]->blk->nodes. - */ -static void ksl_shift_right(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) { - nghttp2_ksl_node *lnode, *rnode, *dest, *src; - - assert(i < blk->n - 1); - - lnode = nghttp2_ksl_nth_node(ksl, blk, i); - rnode = nghttp2_ksl_nth_node(ksl, blk, i + 1); - - assert(lnode->blk->n > NGHTTP2_KSL_MIN_NBLK); - assert(rnode->blk->n < NGHTTP2_KSL_MAX_NBLK); - - memmove(rnode->blk->nodes + ksl->nodelen, rnode->blk->nodes, - ksl->nodelen * rnode->blk->n); - ++rnode->blk->n; - - dest = nghttp2_ksl_nth_node(ksl, rnode->blk, 0); - src = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1); - - memcpy(dest, src, ksl->nodelen); - - --lnode->blk->n; - ksl_node_set_key( - ksl, lnode, - nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key); -} - -/* - * key_equal returns nonzero if |lhs| and |rhs| are equal using the - * function |compar|. - */ -static int key_equal(nghttp2_ksl_compar compar, const nghttp2_ksl_key *lhs, - const nghttp2_ksl_key *rhs) { - return !compar(lhs, rhs) && !compar(rhs, lhs); -} - -int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it, - const nghttp2_ksl_key *key) { - nghttp2_ksl_blk *blk = ksl->head; - nghttp2_ksl_node *node; - size_t i; - - if (!blk->leaf && blk->n == 2 && - nghttp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP2_KSL_MIN_NBLK && - nghttp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP2_KSL_MIN_NBLK) { - blk = ksl_merge_node(ksl, ksl->head, 0); - } - - for (;;) { - i = ksl_bsearch(ksl, blk, key, ksl->compar); - - if (i == blk->n) { - if (it) { - *it = nghttp2_ksl_end(ksl); - } - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - if (blk->leaf) { - if (ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) { - if (it) { - *it = nghttp2_ksl_end(ksl); - } - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - ksl_remove_node(ksl, blk, i); - --ksl->n; - if (it) { - if (blk->n == i && blk->next) { - nghttp2_ksl_it_init(it, ksl, blk->next, 0); - } else { - nghttp2_ksl_it_init(it, ksl, blk, i); - } - } - return 0; - } - - node = nghttp2_ksl_nth_node(ksl, blk, i); - - if (node->blk->n == NGHTTP2_KSL_MIN_NBLK) { - if (i > 0 && nghttp2_ksl_nth_node(ksl, blk, i - 1)->blk->n > - NGHTTP2_KSL_MIN_NBLK) { - ksl_shift_right(ksl, blk, i - 1); - blk = node->blk; - } else if (i + 1 < blk->n && - nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk->n > - NGHTTP2_KSL_MIN_NBLK) { - ksl_shift_left(ksl, blk, i + 1); - blk = node->blk; - } else if (i > 0) { - blk = ksl_merge_node(ksl, blk, i - 1); - } else { - assert(i + 1 < blk->n); - blk = ksl_merge_node(ksl, blk, i); - } - } else { - blk = node->blk; - } - } -} - -nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl, - const nghttp2_ksl_key *key) { - nghttp2_ksl_blk *blk = ksl->head; - nghttp2_ksl_it it; - size_t i; - - for (;;) { - i = ksl_bsearch(ksl, blk, key, ksl->compar); - - if (blk->leaf) { - if (i == blk->n && blk->next) { - blk = blk->next; - i = 0; - } - nghttp2_ksl_it_init(&it, ksl, blk, i); - return it; - } - - if (i == blk->n) { - /* This happens if descendant has smaller key. Fast forward to - find last node in this subtree. */ - for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk) - ; - if (blk->next) { - blk = blk->next; - i = 0; - } else { - i = blk->n; - } - nghttp2_ksl_it_init(&it, ksl, blk, i); - return it; - } - blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk; - } -} - -nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl, - const nghttp2_ksl_key *key, - nghttp2_ksl_compar compar) { - nghttp2_ksl_blk *blk = ksl->head; - nghttp2_ksl_it it; - size_t i; - - for (;;) { - i = ksl_bsearch(ksl, blk, key, compar); - - if (blk->leaf) { - if (i == blk->n && blk->next) { - blk = blk->next; - i = 0; - } - nghttp2_ksl_it_init(&it, ksl, blk, i); - return it; - } - - if (i == blk->n) { - /* This happens if descendant has smaller key. Fast forward to - find last node in this subtree. */ - for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk) - ; - if (blk->next) { - blk = blk->next; - i = 0; - } else { - i = blk->n; - } - nghttp2_ksl_it_init(&it, ksl, blk, i); - return it; - } - blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk; - } -} - -void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key, - const nghttp2_ksl_key *new_key) { - nghttp2_ksl_blk *blk = ksl->head; - nghttp2_ksl_node *node; - size_t i; - - for (;;) { - i = ksl_bsearch(ksl, blk, old_key, ksl->compar); - - assert(i < blk->n); - node = nghttp2_ksl_nth_node(ksl, blk, i); - - if (blk->leaf) { - assert(key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key)); - ksl_node_set_key(ksl, node, new_key); - return; - } - - if (key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key) || - ksl->compar((nghttp2_ksl_key *)node->key, new_key)) { - ksl_node_set_key(ksl, node, new_key); - } - - blk = node->blk; - } -} - -static void ksl_print(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t level) { - size_t i; - nghttp2_ksl_node *node; - - fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n); - - if (blk->leaf) { - for (i = 0; i < blk->n; ++i) { - node = nghttp2_ksl_nth_node(ksl, blk, i); - fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key); - } - fprintf(stderr, "\n"); - return; - } - - for (i = 0; i < blk->n; ++i) { - ksl_print(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk, level + 1); - } -} - -size_t nghttp2_ksl_len(nghttp2_ksl *ksl) { return ksl->n; } - -void nghttp2_ksl_clear(nghttp2_ksl *ksl) { - size_t i; - nghttp2_ksl_blk *head; - - if (!ksl->head->leaf) { - for (i = 0; i < ksl->head->n; ++i) { - ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, ksl->head, i)->blk); - } - } - - ksl->front = ksl->back = ksl->head; - ksl->n = 0; - - head = ksl->head; - - head->next = head->prev = NULL; - head->n = 0; - head->leaf = 1; -} - -void nghttp2_ksl_print(nghttp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); } - -nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl) { - nghttp2_ksl_it it; - nghttp2_ksl_it_init(&it, ksl, ksl->front, 0); - return it; -} - -nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl) { - nghttp2_ksl_it it; - nghttp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n); - return it; -} - -void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl, - nghttp2_ksl_blk *blk, size_t i) { - it->ksl = ksl; - it->blk = blk; - it->i = i; -} - -void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it) { - assert(it->i < it->blk->n); - return nghttp2_ksl_nth_node(it->ksl, it->blk, it->i)->data; -} - -void nghttp2_ksl_it_prev(nghttp2_ksl_it *it) { - assert(!nghttp2_ksl_it_begin(it)); - - if (it->i == 0) { - it->blk = it->blk->prev; - it->i = it->blk->n - 1; - } else { - --it->i; - } -} - -int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it) { - return it->i == 0 && it->blk->prev == NULL; -} diff --git a/deps/nghttp2/lib/nghttp2_ksl.h b/deps/nghttp2/lib/nghttp2_ksl.h deleted file mode 100644 index 39d900ffbf..0000000000 --- a/deps/nghttp2/lib/nghttp2_ksl.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2020 nghttp2 contributors - * Copyright (c) 2018 ngtcp2 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_KSL_H -#define NGHTTP2_KSL_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#include - -#include - -/* - * Skip List using single key instead of range. - */ - -#define NGHTTP2_KSL_DEGR 16 -/* NGHTTP2_KSL_MAX_NBLK is the maximum number of nodes which a single - block can contain. */ -#define NGHTTP2_KSL_MAX_NBLK (2 * NGHTTP2_KSL_DEGR - 1) -/* NGHTTP2_KSL_MIN_NBLK is the minimum number of nodes which a single - block other than root must contains. */ -#define NGHTTP2_KSL_MIN_NBLK (NGHTTP2_KSL_DEGR - 1) - -/* - * nghttp2_ksl_key represents key in nghttp2_ksl. - */ -typedef void nghttp2_ksl_key; - -struct nghttp2_ksl_node; -typedef struct nghttp2_ksl_node nghttp2_ksl_node; - -struct nghttp2_ksl_blk; -typedef struct nghttp2_ksl_blk nghttp2_ksl_blk; - -/* - * nghttp2_ksl_node is a node which contains either nghttp2_ksl_blk or - * opaque data. If a node is an internal node, it contains - * nghttp2_ksl_blk. Otherwise, it has data. The key is stored at the - * location starting at key. - */ -struct nghttp2_ksl_node { - union { - nghttp2_ksl_blk *blk; - void *data; - }; - union { - uint64_t align; - /* key is a buffer to include key associated to this node. - Because the length of key is unknown until nghttp2_ksl_init is - called, the actual buffer will be allocated after this - field. */ - uint8_t key[1]; - }; -}; - -/* - * nghttp2_ksl_blk contains nghttp2_ksl_node objects. - */ -struct nghttp2_ksl_blk { - /* next points to the next block if leaf field is nonzero. */ - nghttp2_ksl_blk *next; - /* prev points to the previous block if leaf field is nonzero. */ - nghttp2_ksl_blk *prev; - /* n is the number of nodes this object contains in nodes. */ - size_t n; - /* leaf is nonzero if this block contains leaf nodes. */ - int leaf; - union { - uint64_t align; - /* nodes is a buffer to contain NGHTTP2_KSL_MAX_NBLK - nghttp2_ksl_node objects. Because nghttp2_ksl_node object is - allocated along with the additional variable length key - storage, the size of buffer is unknown until nghttp2_ksl_init is - called. */ - uint8_t nodes[1]; - }; -}; - -/* - * nghttp2_ksl_compar is a function type which returns nonzero if key - * |lhs| should be placed before |rhs|. It returns 0 otherwise. - */ -typedef int (*nghttp2_ksl_compar)(const nghttp2_ksl_key *lhs, - const nghttp2_ksl_key *rhs); - -struct nghttp2_ksl; -typedef struct nghttp2_ksl nghttp2_ksl; - -struct nghttp2_ksl_it; -typedef struct nghttp2_ksl_it nghttp2_ksl_it; - -/* - * nghttp2_ksl_it is a forward iterator to iterate nodes. - */ -struct nghttp2_ksl_it { - const nghttp2_ksl *ksl; - nghttp2_ksl_blk *blk; - size_t i; -}; - -/* - * nghttp2_ksl is a deterministic paged skip list. - */ -struct nghttp2_ksl { - /* head points to the root block. */ - nghttp2_ksl_blk *head; - /* front points to the first leaf block. */ - nghttp2_ksl_blk *front; - /* back points to the last leaf block. */ - nghttp2_ksl_blk *back; - nghttp2_ksl_compar compar; - size_t n; - /* keylen is the size of key */ - size_t keylen; - /* nodelen is the actual size of nghttp2_ksl_node including key - storage. */ - size_t nodelen; - nghttp2_mem *mem; -}; - -/* - * nghttp2_ksl_init initializes |ksl|. |compar| specifies compare - * function. |keylen| is the length of key. - * - * It returns 0 if it succeeds, or one of the following negative error - * codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - */ -int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen, - nghttp2_mem *mem); - -/* - * nghttp2_ksl_free frees resources allocated for |ksl|. If |ksl| is - * NULL, this function does nothing. It does not free the memory - * region pointed by |ksl| itself. - */ -void nghttp2_ksl_free(nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_insert inserts |key| with its associated |data|. On - * successful insertion, the iterator points to the inserted node is - * stored in |*it|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_INVALID_ARGUMENT - * |key| already exists. - */ -int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it, - const nghttp2_ksl_key *key, void *data); - -/* - * nghttp2_ksl_remove removes the |key| from |ksl|. - * - * This function assigns the iterator to |*it|, which points to the - * node which is located at the right next of the removed node if |it| - * is not NULL. If |key| is not found, no deletion takes place and - * the return value of nghttp2_ksl_end(ksl) is assigned to |*it|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_INVALID_ARGUMENT - * |key| does not exist. - */ -int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it, - const nghttp2_ksl_key *key); - -/* - * nghttp2_ksl_lower_bound returns the iterator which points to the - * first node which has the key which is equal to |key| or the last - * node which satisfies !compar(&node->key, key). If there is no such - * node, it returns the iterator which satisfies nghttp2_ksl_it_end(it) - * != 0. - */ -nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl, - const nghttp2_ksl_key *key); - -/* - * nghttp2_ksl_lower_bound_compar works like nghttp2_ksl_lower_bound, - * but it takes custom function |compar| to do lower bound search. - */ -nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl, - const nghttp2_ksl_key *key, - nghttp2_ksl_compar compar); - -/* - * nghttp2_ksl_update_key replaces the key of nodes which has |old_key| - * with |new_key|. |new_key| must be strictly greater than the - * previous node and strictly smaller than the next node. - */ -void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key, - const nghttp2_ksl_key *new_key); - -/* - * nghttp2_ksl_begin returns the iterator which points to the first - * node. If there is no node in |ksl|, it returns the iterator which - * satisfies nghttp2_ksl_it_end(it) != 0. - */ -nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_end returns the iterator which points to the node - * following the last node. The returned object satisfies - * nghttp2_ksl_it_end(). If there is no node in |ksl|, it returns the - * iterator which satisfies nghttp2_ksl_it_begin(it) != 0. - */ -nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_len returns the number of elements stored in |ksl|. - */ -size_t nghttp2_ksl_len(nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_clear removes all elements stored in |ksl|. - */ -void nghttp2_ksl_clear(nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_nth_node returns the |n|th node under |blk|. - */ -#define nghttp2_ksl_nth_node(KSL, BLK, N) \ - ((nghttp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) - -/* - * nghttp2_ksl_print prints its internal state in stderr. It assumes - * that the key is of type int64_t. This function should be used for - * the debugging purpose only. - */ -void nghttp2_ksl_print(nghttp2_ksl *ksl); - -/* - * nghttp2_ksl_it_init initializes |it|. - */ -void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl, - nghttp2_ksl_blk *blk, size_t i); - -/* - * nghttp2_ksl_it_get returns the data associated to the node which - * |it| points to. It is undefined to call this function when - * nghttp2_ksl_it_end(it) returns nonzero. - */ -void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it); - -/* - * nghttp2_ksl_it_next advances the iterator by one. It is undefined - * if this function is called when nghttp2_ksl_it_end(it) returns - * nonzero. - */ -#define nghttp2_ksl_it_next(IT) \ - (++(IT)->i == (IT)->blk->n && (IT)->blk->next \ - ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \ - : 0) - -/* - * nghttp2_ksl_it_prev moves backward the iterator by one. It is - * undefined if this function is called when nghttp2_ksl_it_begin(it) - * returns nonzero. - */ -void nghttp2_ksl_it_prev(nghttp2_ksl_it *it); - -/* - * nghttp2_ksl_it_end returns nonzero if |it| points to the beyond the - * last node. - */ -#define nghttp2_ksl_it_end(IT) \ - ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL) - -/* - * nghttp2_ksl_it_begin returns nonzero if |it| points to the first - * node. |it| might satisfy both nghttp2_ksl_it_begin(&it) and - * nghttp2_ksl_it_end(&it) if the skip list has no node. - */ -int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it); - -/* - * nghttp2_ksl_key returns the key of the node which |it| points to. - * It is undefined to call this function when nghttp2_ksl_it_end(it) - * returns nonzero. - */ -#define nghttp2_ksl_it_key(IT) \ - ((nghttp2_ksl_key *)nghttp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key) - -#endif /* NGHTTP2_KSL_H */ diff --git a/deps/nghttp2/lib/nghttp2_map.c b/deps/nghttp2/lib/nghttp2_map.c index d12a1f4757..5f63fc2bb8 100644 --- a/deps/nghttp2/lib/nghttp2_map.c +++ b/deps/nghttp2/lib/nghttp2_map.c @@ -27,172 +27,166 @@ #include #include +#include #include "nghttp2_helper.h" -#define INITIAL_TABLE_LENGTH 256 +#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 = INITIAL_TABLE_LENGTH; - 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) { - size_t i; - nghttp2_map_bucket *bkt; - if (!map) { return; } - for (i = 0; i < map->tablelen; ++i) { - bkt = &map->table[i]; - if (bkt->ksl) { - nghttp2_ksl_free(bkt->ksl); - nghttp2_mem_free(map->mem, bkt->ksl); - } - } - nghttp2_mem_free(map->mem, map->table); } -void nghttp2_map_each_free(nghttp2_map *map, - int (*func)(nghttp2_map_entry *entry, void *ptr), +void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr), void *ptr) { uint32_t i; nghttp2_map_bucket *bkt; - nghttp2_ksl_it it; for (i = 0; i < map->tablelen; ++i) { bkt = &map->table[i]; - if (bkt->ptr) { - func(bkt->ptr, ptr); - bkt->ptr = NULL; - assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0); + if (bkt->data == NULL) { continue; } - if (bkt->ksl) { - for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it); - nghttp2_ksl_it_next(&it)) { - func(nghttp2_ksl_it_get(&it), ptr); - } - - nghttp2_ksl_free(bkt->ksl); - nghttp2_mem_free(map->mem, bkt->ksl); - bkt->ksl = NULL; - } + func(bkt->data, ptr); } } -int nghttp2_map_each(nghttp2_map *map, - int (*func)(nghttp2_map_entry *entry, void *ptr), +int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr), void *ptr) { int rv; uint32_t i; nghttp2_map_bucket *bkt; - nghttp2_ksl_it it; + + if (map->size == 0) { + return 0; + } for (i = 0; i < map->tablelen; ++i) { bkt = &map->table[i]; - if (bkt->ptr) { - rv = func(bkt->ptr, ptr); - if (rv != 0) { - return rv; - } - assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0); + if (bkt->data == NULL) { continue; } - if (bkt->ksl) { - for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it); - nghttp2_ksl_it_next(&it)) { - rv = func(nghttp2_ksl_it_get(&it), ptr); - if (rv != 0) { - return rv; - } - } + rv = func(bkt->data, ptr); + if (rv != 0) { + return rv; } } + return 0; } -void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) { - entry->key = key; - entry->next = NULL; +static uint32_t hash(nghttp2_map_key_type key) { + return (uint32_t)key * 2654435769u; } -/* FNV1a hash */ -static uint32_t hash(key_type key, uint32_t mod) { - uint8_t *p, *end; - uint32_t h = 0x811C9DC5u; +static size_t h2idx(uint32_t hash, uint32_t bits) { + return hash >> (32 - bits); +} - p = (uint8_t *)&key; - end = p + sizeof(key_type); +static size_t distance(uint32_t tablelen, uint32_t tablelenbits, + nghttp2_map_bucket *bkt, size_t idx) { + return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1); +} - for (; p != end;) { - h ^= *p++; - h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); - } +static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash, + nghttp2_map_key_type *pkey, void **pdata) { + uint32_t h = bkt->hash; + nghttp2_map_key_type key = bkt->key; + void *data = bkt->data; - return h & (mod - 1); + bkt->hash = *phash; + bkt->key = *pkey; + bkt->data = *pdata; + + *phash = h; + *pkey = key; + *pdata = data; } -static int less(const nghttp2_ksl_key *lhs, const nghttp2_ksl_key *rhs) { - return *(key_type *)lhs < *(key_type *)rhs; +static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash, + nghttp2_map_key_type key, void *data) { + bkt->hash = hash; + bkt->key = key; + bkt->data = data; } -static int map_insert(nghttp2_map *map, nghttp2_map_bucket *table, - uint32_t tablelen, nghttp2_map_entry *entry) { - uint32_t h = hash(entry->key, tablelen); - nghttp2_map_bucket *bkt = &table[h]; - nghttp2_mem *mem = map->mem; - int rv; +void nghttp2_map_print_distance(nghttp2_map *map) { + uint32_t i; + size_t idx; + nghttp2_map_bucket *bkt; - if (bkt->ptr == NULL && - (bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0)) { - bkt->ptr = entry; - return 0; - } + for (i = 0; i < map->tablelen; ++i) { + bkt = &map->table[i]; - if (!bkt->ksl) { - bkt->ksl = nghttp2_mem_malloc(mem, sizeof(*bkt->ksl)); - if (bkt->ksl == NULL) { - return NGHTTP2_ERR_NOMEM; + if (bkt->data == NULL) { + fprintf(stderr, "@%u \n", i); + continue; } - nghttp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem); + + idx = h2idx(bkt->hash, map->tablelenbits); + fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i, + bkt->hash, bkt->key, idx, + distance(map->tablelen, map->tablelenbits, bkt, idx)); } +} - if (bkt->ptr) { - rv = nghttp2_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr); - if (rv != 0) { - return rv; +static int insert(nghttp2_map_bucket *table, uint32_t tablelen, + uint32_t tablelenbits, uint32_t hash, + nghttp2_map_key_type key, void *data) { + size_t idx = h2idx(hash, tablelenbits); + size_t d = 0, dd; + nghttp2_map_bucket *bkt; + + for (;;) { + bkt = &table[idx]; + + if (bkt->data == NULL) { + map_bucket_set_data(bkt, hash, key, data); + return 0; } - bkt->ptr = NULL; - } + dd = distance(tablelen, tablelenbits, bkt, idx); + if (d > dd) { + map_bucket_swap(bkt, &hash, &key, &data); + d = dd; + } else if (bkt->key == key) { + /* TODO This check is just a waste after first swap or if this + function is called from map_resize. That said, there is no + difference with or without this conditional in performance + wise. */ + return NGHTTP2_ERR_INVALID_ARGUMENT; + } - return nghttp2_ksl_insert(bkt->ksl, NULL, &entry->key, entry); + ++d; + idx = (idx + 1) & (tablelen - 1); + } } -/* new_tablelen must be power of 2 */ -static int map_resize(nghttp2_map *map, uint32_t new_tablelen) { +/* new_tablelen must be power of 2 and new_tablelen == (1 << + new_tablelenbits) must hold. */ +static int map_resize(nghttp2_map *map, uint32_t new_tablelen, + uint32_t new_tablelenbits) { uint32_t i; nghttp2_map_bucket *new_table; nghttp2_map_bucket *bkt; - nghttp2_ksl_it it; int rv; + (void)rv; new_table = nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket)); @@ -202,64 +196,46 @@ static int map_resize(nghttp2_map *map, uint32_t new_tablelen) { for (i = 0; i < map->tablelen; ++i) { bkt = &map->table[i]; - - if (bkt->ptr) { - rv = map_insert(map, new_table, new_tablelen, bkt->ptr); - if (rv != 0) { - goto fail; - } - assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0); + if (bkt->data == NULL) { continue; } + rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key, + bkt->data); - if (bkt->ksl) { - for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it); - nghttp2_ksl_it_next(&it)) { - rv = map_insert(map, new_table, new_tablelen, nghttp2_ksl_it_get(&it)); - if (rv != 0) { - goto fail; - } - } - } - } - - for (i = 0; i < map->tablelen; ++i) { - bkt = &map->table[i]; - if (bkt->ksl) { - nghttp2_ksl_free(bkt->ksl); - nghttp2_mem_free(map->mem, bkt->ksl); - } + assert(0 == rv); } nghttp2_mem_free(map->mem, map->table); map->tablelen = new_tablelen; + map->tablelenbits = new_tablelenbits; map->table = new_table; return 0; - -fail: - for (i = 0; i < new_tablelen; ++i) { - bkt = &new_table[i]; - if (bkt->ksl) { - nghttp2_ksl_free(bkt->ksl); - nghttp2_mem_free(map->mem, bkt->ksl); - } - } - - return rv; } -int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) { +int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { int rv; + assert(data); + /* Load factor is 0.75 */ if ((map->size + 1) * 4 > map->tablelen * 3) { - rv = map_resize(map, map->tablelen * 2); - 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; + } } } - rv = map_insert(map, map->table, map->tablelen, new_entry); + + rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key, + data); if (rv != 0) { return rv; } @@ -267,68 +243,93 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) { return 0; } -nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) { - nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)]; - nghttp2_ksl_it it; +void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) { + uint32_t h; + size_t idx; + nghttp2_map_bucket *bkt; + size_t d = 0; - if (bkt->ptr) { - if (bkt->ptr->key == key) { - return bkt->ptr; - } + if (map->size == 0) { return NULL; } - if (bkt->ksl) { - it = nghttp2_ksl_lower_bound(bkt->ksl, &key); - if (nghttp2_ksl_it_end(&it) || - *(key_type *)nghttp2_ksl_it_key(&it) != key) { + h = hash(key); + idx = h2idx(h, map->tablelenbits); + + for (;;) { + bkt = &map->table[idx]; + + if (bkt->data == NULL || + d > distance(map->tablelen, map->tablelenbits, bkt, idx)) { return NULL; } - return nghttp2_ksl_it_get(&it); - } - return NULL; + if (bkt->key == key) { + return bkt->data; + } + + ++d; + idx = (idx + 1) & (map->tablelen - 1); + } } -int nghttp2_map_remove(nghttp2_map *map, key_type key) { - nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)]; - int rv; +int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { + uint32_t h; + size_t idx, didx; + nghttp2_map_bucket *bkt; + size_t d = 0; - if (bkt->ptr) { - if (bkt->ptr->key == key) { - bkt->ptr = NULL; - --map->size; - return 0; - } + if (map->size == 0) { return NGHTTP2_ERR_INVALID_ARGUMENT; } - if (bkt->ksl) { - rv = nghttp2_ksl_remove(bkt->ksl, NULL, &key); - if (rv != 0) { - return rv; + h = hash(key); + idx = h2idx(h, map->tablelenbits); + + for (;;) { + bkt = &map->table[idx]; + + if (bkt->data == NULL || + d > distance(map->tablelen, map->tablelenbits, bkt, idx)) { + return NGHTTP2_ERR_INVALID_ARGUMENT; } - --map->size; - return 0; - } - return NGHTTP2_ERR_INVALID_ARGUMENT; -} + if (bkt->key == key) { + map_bucket_set_data(bkt, 0, 0, NULL); -void nghttp2_map_clear(nghttp2_map *map) { - uint32_t i; - nghttp2_map_bucket *bkt; + didx = idx; + idx = (idx + 1) & (map->tablelen - 1); - for (i = 0; i < map->tablelen; ++i) { - bkt = &map->table[i]; - bkt->ptr = NULL; - if (bkt->ksl) { - nghttp2_ksl_free(bkt->ksl); - nghttp2_mem_free(map->mem, bkt->ksl); - bkt->ksl = NULL; + for (;;) { + bkt = &map->table[idx]; + if (bkt->data == NULL || + distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) { + break; + } + + map->table[didx] = *bkt; + map_bucket_set_data(bkt, 0, 0, NULL); + didx = idx; + + idx = (idx + 1) & (map->tablelen - 1); + } + + --map->size; + + return 0; } + + ++d; + idx = (idx + 1) & (map->tablelen - 1); + } +} + +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 2cf59f698e..d90245aab7 100644 --- a/deps/nghttp2/lib/nghttp2_map.h +++ b/deps/nghttp2/lib/nghttp2_map.h @@ -33,43 +33,29 @@ #include #include "nghttp2_mem.h" -#include "nghttp2_ksl.h" /* Implementation of unordered map */ -typedef int32_t key_type; - -typedef struct nghttp2_map_entry { - struct nghttp2_map_entry *next; - key_type key; -#if SIZEOF_INT_P == 4 - /* we requires 8 bytes aligment */ - int64_t pad; -#endif -} nghttp2_map_entry; +typedef int32_t nghttp2_map_key_type; typedef struct nghttp2_map_bucket { - nghttp2_map_entry *ptr; - nghttp2_ksl *ksl; + uint32_t hash; + nghttp2_map_key_type key; + void *data; } nghttp2_map_bucket; -typedef struct { +typedef struct nghttp2_map { nghttp2_map_bucket *table; nghttp2_mem *mem; size_t size; uint32_t tablelen; + uint32_t tablelenbits; } 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 @@ -81,21 +67,14 @@ void nghttp2_map_free(nghttp2_map *map); /* * Deallocates each entries using |func| function and any resources * allocated for |map|. The |func| function is responsible for freeing - * given the |entry| object. The |ptr| will be passed to the |func| as + * given the |data| object. The |ptr| will be passed to the |func| as * send argument. The return value of the |func| will be ignored. */ -void nghttp2_map_each_free(nghttp2_map *map, - int (*func)(nghttp2_map_entry *entry, void *ptr), +void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr), void *ptr); /* - * Initializes the |entry| with the |key|. All entries to be inserted - * to the map must be initialized with this function. - */ -void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key); - -/* - * Inserts the new |entry| with the key |entry->key| to the map |map|. + * Inserts the new |data| with the |key| to the map |map|. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -105,25 +84,25 @@ void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key); * NGHTTP2_ERR_NOMEM * Out of memory */ -int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry); +int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data); /* - * Returns the entry associated by the key |key|. If there is no such - * entry, this function returns NULL. + * Returns the data associated by the key |key|. If there is no such + * data, this function returns NULL. */ -nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key); +void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key); /* - * Removes the entry associated by the key |key| from the |map|. The - * removed entry is not freed by this function. + * Removes the data associated by the key |key| from the |map|. The + * removed data is not freed by this function. * * This function returns 0 if it succeeds, or one of the following * negative error codes: * * NGHTTP2_ERR_INVALID_ARGUMENT - * The entry associated by |key| does not exist. + * The data associated by |key| does not exist. */ -int nghttp2_map_remove(nghttp2_map *map, key_type key); +int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key); /* * Removes all entries from |map|. @@ -136,21 +115,22 @@ void nghttp2_map_clear(nghttp2_map *map); size_t nghttp2_map_size(nghttp2_map *map); /* - * Applies the function |func| to each entry in the |map| with the + * Applies the function |func| to each data in the |map| with the * optional user supplied pointer |ptr|. * * If the |func| returns 0, this function calls the |func| with the - * next entry. If the |func| returns nonzero, it will not call the + * next data. If the |func| returns nonzero, it will not call the * |func| for further entries and return the return value of the * |func| immediately. Thus, this function returns 0 if all the * invocations of the |func| return 0, or nonzero value which the last * invocation of |func| returns. * - * Don't use this function to free each entry. Use + * Don't use this function to free each data. Use * nghttp2_map_each_free() instead. */ -int nghttp2_map_each(nghttp2_map *map, - int (*func)(nghttp2_map_entry *entry, void *ptr), +int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr), void *ptr); +void nghttp2_map_print_distance(nghttp2_map *map); + #endif /* NGHTTP2_MAP_H */ diff --git a/deps/nghttp2/lib/nghttp2_net.h b/deps/nghttp2/lib/nghttp2_net.h index 95ffee74a1..521f98143e 100644 --- a/deps/nghttp2/lib/nghttp2_net.h +++ b/deps/nghttp2/lib/nghttp2_net.h @@ -42,7 +42,7 @@ #if defined(WIN32) /* Windows requires ws2_32 library for ntonl family functions. We define inline functions for those function so that we don't have - dependeny on that lib. */ + dependency on that lib. */ # ifdef _MSC_VER # define STIN static __inline @@ -53,7 +53,7 @@ STIN uint32_t htonl(uint32_t hostlong) { uint32_t res; unsigned char *p = (unsigned char *)&res; - *p++ = hostlong >> 24; + *p++ = (unsigned char)(hostlong >> 24); *p++ = (hostlong >> 16) & 0xffu; *p++ = (hostlong >> 8) & 0xffu; *p = hostlong & 0xffu; @@ -63,7 +63,7 @@ STIN uint32_t htonl(uint32_t hostlong) { STIN uint16_t htons(uint16_t hostshort) { uint16_t res; unsigned char *p = (unsigned char *)&res; - *p++ = hostshort >> 8; + *p++ = (unsigned char)(hostshort >> 8); *p = hostshort & 0xffu; return res; } @@ -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 34348e6606..43d4e95229 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 939729fdcd..2259e1849d 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 f651c8029a..2a3041db19 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_outbound_item.h b/deps/nghttp2/lib/nghttp2_outbound_item.h index b5f503a312..bd4611b551 100644 --- a/deps/nghttp2/lib/nghttp2_outbound_item.h +++ b/deps/nghttp2/lib/nghttp2_outbound_item.h @@ -111,7 +111,7 @@ struct nghttp2_outbound_item { to this structure to avoid frequent memory allocation. */ nghttp2_ext_frame_payload ext_frame_payload; nghttp2_aux_data aux_data; - /* The priority used in priority comparion. Smaller is served + /* The priority used in priority comparison. Smaller is served earlier. For PING, SETTINGS and non-DATA frames (excluding response HEADERS frame) have dedicated cycle value defined above. For DATA frame, cycle is computed by taking into account of diff --git a/deps/nghttp2/lib/nghttp2_pq.c b/deps/nghttp2/lib/nghttp2_pq.c index bebccc7606..64353acc96 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 2d7b702ac1..c8d90ef2cc 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 @@ -114,7 +108,7 @@ typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg); void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg); /* - * Applys |fun| to each item in |pq|. The |arg| is passed as arg + * Applies |fun| to each item in |pq|. The |arg| is passed as arg * parameter to callback function. This function must not change the * ordering key. If the return value from callback is nonzero, this * function returns 1 immediately without iterating remaining items. diff --git a/deps/nghttp2/lib/nghttp2_ratelim.c b/deps/nghttp2/lib/nghttp2_ratelim.c new file mode 100644 index 0000000000..7011655b00 --- /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 0000000000..866ed3f00a --- /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 +#endif /* HAVE_CONFIG_H */ + +#include + +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 2e7e907f25..ec5024d0f2 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); @@ -666,7 +723,7 @@ int nghttp2_session_server_new3(nghttp2_session **session_ptr, return 0; } -static int free_streams(nghttp2_map_entry *entry, void *ptr) { +static int free_streams(void *entry, void *ptr) { nghttp2_session *session; nghttp2_stream *stream; nghttp2_outbound_item *item; @@ -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,7 +1389,11 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session, (int32_t)session->local_settings.initial_window_size, stream_user_data, mem); - rv = nghttp2_map_insert(&session->streams, &stream->map_entry); + if (session_no_rfc7540_pri_no_fallback(session)) { + stream->seq = session->stream_seq++; + } + + rv = nghttp2_map_insert(&session->streams, stream_id, stream); if (rv != 0) { nghttp2_stream_free(stream); nghttp2_mem_free(mem, stream); @@ -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; @@ -2424,7 +2737,7 @@ static int session_call_on_frame_send(nghttp2_session *session, return 0; } -static int find_stream_on_goaway_func(nghttp2_map_entry *entry, void *ptr) { +static int find_stream_on_goaway_func(void *entry, void *ptr) { nghttp2_close_stream_on_goaway_arg *arg; nghttp2_stream *stream; @@ -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) { @@ -4194,8 +4519,7 @@ static int session_process_rst_stream_frame(nghttp2_session *session) { return nghttp2_session_on_rst_stream_received(session, frame); } -static int update_remote_initial_window_size_func(nghttp2_map_entry *entry, - void *ptr) { +static int update_remote_initial_window_size_func(void *entry, void *ptr) { int rv; nghttp2_update_window_size_arg *arg; nghttp2_stream *stream; @@ -4215,8 +4539,8 @@ static int update_remote_initial_window_size_func(nghttp2_map_entry *entry, if (stream->remote_window_size > 0 && nghttp2_stream_check_deferred_by_flow_control(stream)) { - rv = nghttp2_stream_resume_deferred_item( - stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); + rv = session_resume_deferred_stream_item( + arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); if (nghttp2_is_fatal(rv)) { return rv; @@ -4248,8 +4572,7 @@ session_update_remote_initial_window_size(nghttp2_session *session, update_remote_initial_window_size_func, &arg); } -static int update_local_initial_window_size_func(nghttp2_map_entry *entry, - void *ptr) { +static int update_local_initial_window_size_func(void *entry, void *ptr) { int rv; nghttp2_update_window_size_arg *arg; nghttp2_stream *stream; @@ -4261,9 +4584,16 @@ static int update_local_initial_window_size_func(nghttp2_map_entry *entry, return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, NGHTTP2_FLOW_CONTROL_ERROR); } - if (!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && - stream->window_update_queued == 0 && - nghttp2_should_send_window_update(stream->local_window_size, + + if (stream->window_update_queued) { + return 0; + } + + if (arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) { + return session_update_stream_consumed_size(arg->session, stream, 0); + } + + if (nghttp2_should_send_window_update(stream->local_window_size, stream->recv_window_size)) { rv = nghttp2_session_add_window_update(arg->session, NGHTTP2_FLAG_NONE, @@ -4384,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; } } @@ -4542,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); @@ -4686,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); } @@ -4828,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; @@ -4900,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; @@ -4934,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; @@ -5271,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); @@ -5343,7 +5783,7 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) { /* * This function returns the effective payload length in the data of - * length |readlen| when the remaning payload is |payloadleft|. The + * length |readlen| when the remaining payload is |payloadleft|. The * |payloadleft| does not include |readlen|. If padding was started * strictly before this data chunk, this function returns -1. */ @@ -5431,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 || @@ -5468,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); @@ -5884,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; @@ -5925,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) { @@ -5990,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); @@ -6152,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: @@ -6214,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) { @@ -6405,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); @@ -6432,8 +6930,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, /* CONTINUATION won't bear NGHTTP2_PADDED flag */ - iframe->frame.hd.flags = (uint8_t)( - iframe->frame.hd.flags | (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS)); + iframe->frame.hd.flags = + (uint8_t)(iframe->frame.hd.flags | + (cont_hd.flags & NGHTTP2_FLAG_END_HEADERS)); iframe->frame.hd.length += cont_hd.length; busy = 1; @@ -6462,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 */ @@ -6612,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)) { @@ -6792,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) { @@ -6864,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)); @@ -6963,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; } @@ -7017,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; @@ -7034,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; @@ -7108,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; } @@ -7230,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)) { @@ -7310,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)) { @@ -7418,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); @@ -7441,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); @@ -7724,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; } @@ -7756,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; @@ -7797,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 07bfbb6c90..b119329a04 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 @@ -408,7 +434,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id, uint32_t error_code); /* - * Adds PING frame. This is a convenient functin built on top of + * Adds PING frame. This is a convenient function built on top of * nghttp2_session_add_frame() to add PING easily. * * If the |opaque_data| is not NULL, it must point to 8 bytes memory @@ -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 dc3a6b11cc..f1951f879d 100644 --- a/deps/nghttp2/lib/nghttp2_stream.c +++ b/deps/nghttp2/lib/nghttp2_stream.c @@ -33,7 +33,7 @@ #include "nghttp2_frame.h" /* Maximum distance between any two stream's cycle in the same - prirority queue. Imagine stream A's cycle is A, and stream B's + priority queue. Imagine stream A's cycle is A, and stream B's cycle is B, and A < B. The cycle is unsigned 32 bit integer, it may get overflow. Because of how we calculate the next cycle value, if B - A is less than or equals to @@ -62,7 +62,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, int32_t weight, int32_t remote_initial_window_size, int32_t local_initial_window_size, void *stream_user_data, nghttp2_mem *mem) { - nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id); nghttp2_pq_init(&stream->obq, stream_less, mem); stream->stream_id = stream_id; @@ -101,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->descendant_next_seq = 0; stream->seq = 0; stream->last_writelen = 0; + + stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY; } void nghttp2_stream_free(nghttp2_stream *stream) { @@ -464,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, @@ -485,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. @@ -498,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, @@ -515,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) { @@ -530,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 a1b807d295..71b9fb1140 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,11 +139,14 @@ typedef enum { /* set if final response is expected */ NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14, NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15, + /* set if priority header field is received */ + NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16, + /* set if an error is encountered while parsing priority header + field */ + NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17, } nghttp2_http_flag; struct nghttp2_stream { - /* Intrusive Map */ - nghttp2_map_entry map_entry; /* Entry for dep_prev->obq */ nghttp2_pq_entry pq_entry; /* Priority Queue storing direct descendant (nghttp2_stream). Only @@ -206,7 +216,7 @@ struct nghttp2_stream { /* status code from remote server */ int16_t status_code; /* Bitwise OR of zero or more nghttp2_http_flag values */ - uint16_t http_flags; + uint32_t http_flags; /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ uint8_t flags; /* Bitwise OR of zero or more nghttp2_shut_flag values */ @@ -220,6 +230,12 @@ struct nghttp2_stream { this stream. The nonzero does not necessarily mean WINDOW_UPDATE is not queued. */ uint8_t window_update_queued; + /* extpri is a stream priority produced by nghttp2_extpri_to_uint8 + used by RFC 9218 extensible priorities. */ + uint8_t extpri; + /* http_extpri is a stream priority received in HTTP request header + fields and produced by nghttp2_extpri_to_uint8. */ + uint8_t http_extpri; }; void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, @@ -242,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| @@ -363,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 744a49cf60..f5554eb564 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; } @@ -492,8 +497,6 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session, return nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1); } - - return 0; } int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, @@ -664,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; @@ -690,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 0000000000..2a5f1a6ff5 --- /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 +#endif /* HAVE_TIME_H */ + +#ifdef HAVE_SYSINFOAPI_H +# include +#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 0000000000..03c0bbe944 --- /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 +#endif /* HAVE_CONFIG_H */ + +#include + +/* 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 0000000000..efa2850c9d --- /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 +#include +#include + +#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 0000000000..1474db1429 --- /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 +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +# include +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#include + +/** + * @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_* `. + */ + 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 ` == 0, :member:`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 ` must point to the buffer that + * has sufficient space to store the unescaped string. + * + * If there is no escape character in |src|, |*src| is assigned to + * |*dest|. This includes the case that :member:`src->len + * ` == 0. + * + * This function sets the length of unescaped string to + * :member:`dest->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 ` must point to the buffer that + * has sufficient space to store the decoded byte string. + * + * If :member:`src->len ` == 0, |*src| is assigned to + * |*dest|. + * + * This function sets the length of decoded byte string to + * :member:`dest->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 21fd6ba5ec..87909c5f29 100644 --- a/deps/nghttp2/nghttp2.gyp +++ b/deps/nghttp2/nghttp2.gyp @@ -1,4 +1,34 @@ { + 'variables': { + 'nghttp2_sources': [ + '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', + 'lib/nghttp2_hd_huffman_data.c', + 'lib/nghttp2_helper.c', + 'lib/nghttp2_http.c', + 'lib/nghttp2_map.c', + 'lib/nghttp2_mem.c', + 'lib/nghttp2_npn.c', + 'lib/nghttp2_option.c', + 'lib/nghttp2_outbound_item.c', + '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_time.c', + 'lib/nghttp2_version.c', + 'lib/sfparse.c', + ] + }, 'target_defaults': { 'defines': [ '_U_=' @@ -35,29 +65,7 @@ 'include_dirs': [ 'lib/includes' ] }, 'sources': [ - 'lib/nghttp2_buf.c', - 'lib/nghttp2_callbacks.c', - 'lib/nghttp2_debug.c', - 'lib/nghttp2_frame.c', - 'lib/nghttp2_hd.c', - 'lib/nghttp2_hd_huffman.c', - 'lib/nghttp2_hd_huffman_data.c', - 'lib/nghttp2_helper.c', - 'lib/nghttp2_http.c', - 'lib/nghttp2_ksl.c', - 'lib/nghttp2_map.c', - 'lib/nghttp2_mem.c', - 'lib/nghttp2_npn.c', - 'lib/nghttp2_option.c', - 'lib/nghttp2_outbound_item.c', - 'lib/nghttp2_pq.c', - 'lib/nghttp2_priority_spec.c', - 'lib/nghttp2_queue.c', - 'lib/nghttp2_rcbuf.c', - 'lib/nghttp2_session.c', - 'lib/nghttp2_stream.c', - 'lib/nghttp2_submit.c', - 'lib/nghttp2_version.c' + '<@(nghttp2_sources)', ] } ] diff --git a/test/parallel/test-http2-methods.js b/test/parallel/test-http2-methods.js index 143b50b66b..936a264e99 100644 --- a/test/parallel/test-http2-methods.js +++ b/test/parallel/test-http2-methods.js @@ -8,7 +8,7 @@ const h2 = require('http2'); const server = h2.createServer(); -const methods = [undefined, 'GET', 'POST', 'PATCH', 'FOO', 'A B C']; +const methods = ['GET', 'POST', 'PATCH', 'FOO', 'A_B_C']; let expected = methods.length; // We use the lower-level API here diff --git a/test/parallel/test-http2-multiplex.js b/test/parallel/test-http2-multiplex.js index 1778bced5f..4c157d0ede 100644 --- a/test/parallel/test-http2-multiplex.js +++ b/test/parallel/test-http2-multiplex.js @@ -29,7 +29,7 @@ server.listen(0, common.mustCall(() => { }); function doRequest() { - const req = client.request({ ':method': 'POST ' }); + const req = client.request({ ':method': 'POST' }); let data = ''; req.setEncoding('utf8'); diff --git a/tools/update-nghttp2.sh b/tools/update-nghttp2.sh new file mode 100755 index 0000000000..d7e176d3e1 --- /dev/null +++ b/tools/update-nghttp2.sh @@ -0,0 +1,59 @@ +#!/bin/sh +set -e +# Shell script to update nghttp2 in the source treee to specific version + +BASE_DIR="$( pwd )"/ +DEPS_DIR="$BASE_DIR"deps/ +NGHTTP2_VERSION=$1 + +if [ "$#" -le 0 ]; then + echo "Error: please provide an nghttp2 version to update to" + exit 1 +fi + +echo "Making temporary workspace" + +WORKSPACE=$(mktemp -d 2> /dev/null || mktemp -d -t 'tmp') + +cleanup () { + EXIT_CODE=$? + [ -d "$WORKSPACE" ] && rm -rf "$WORKSPACE" + exit $EXIT_CODE +} + +trap cleanup INT TERM EXIT + +NGHTTP2_REF="v$NGHTTP2_VERSION" +NGHTTP2_TARBALL="nghttp2-$NGHTTP2_VERSION.tar.gz" + +cd "$WORKSPACE" + +echo "Fetching nghttp2 source archive" +curl -sL -o "$NGHTTP2_TARBALL" "https://github.com/nghttp2/nghttp2/releases/download/$NGHTTP2_REF/$NGHTTP2_TARBALL" +gzip -dc "$NGHTTP2_TARBALL" | tar xf - +rm "$NGHTTP2_TARBALL" +mv "nghttp2-$NGHTTP2_VERSION" nghttp2 + +echo "Removing everything, except lib/ and COPYING" +cd nghttp2 +for dir in *; do + if [ "$dir" = "lib" ] || [ "$dir" = "COPYING" ]; then + continue + fi + rm -rf "$dir" +done + +echo "Copying existing gyp files" +cp "$DEPS_DIR/nghttp2/nghttp2.gyp" "$WORKSPACE/nghttp2" + +echo "Replacing existing nghttp2" +rm -rf "$DEPS_DIR/nghttp2" +mv "$WORKSPACE/nghttp2" "$DEPS_DIR/" + +echo "All done!" +echo "" +echo "Please git add nghttp2, commit the new version:" +echo "" +echo "$ git add -A deps/nghttp2" +echo "$ git commit -m \"deps: update nghttp2 to $NGHTTP2_VERSION\"" +echo "" -- 2.41.0