Commit 6f61c22a625 for nodejs
commit 6f61c22a625a5fc6e27aae429552d349a4ef6229
Author: Node.js GitHub Bot <github-bot@iojs.org>
Date: Wed Nov 11 11:29:16 2026 -0500
deps: update nghttp2 to 1.71.0
PR-URL: https://github.com/nodejs/node/pull/67331
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
diff --git a/deps/nghttp2/lib/Makefile.in b/deps/nghttp2/lib/Makefile.in
index 128fb291258..aebda670702 100644
--- a/deps/nghttp2/lib/Makefile.in
+++ b/deps/nghttp2/lib/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# Makefile.in generated by automake 1.18.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+# Copyright (C) 1994-2025 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -86,6 +86,8 @@ am__make_running_with_option = \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+am__rm_f = rm -f $(am__rm_f_notfound)
+am__rm_rf = rm -rf $(am__rm_f_notfound)
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -141,10 +143,9 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
- test -z "$$files" \
- || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
- || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
- $(am__cd) "$$dir" && rm -f $$files; }; \
+ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \
}
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
@@ -436,8 +437,10 @@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
+am__rm_f_notfound = @am__rm_f_notfound@
am__tar = @am__tar@
am__untar = @am__untar@
+am__xargs_n = @am__xargs_n@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -612,15 +615,13 @@ uninstall-libLTLIBRARIES:
done
clean-libLTLIBRARIES:
- -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ -$(am__rm_f) $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
- test -z "$$locs" || { \
- echo rm -f $${locs}; \
- rm -f $${locs}; \
- }
+ echo rm -f $${locs}; \
+ $(am__rm_f) $${locs}
libnghttp2.la: $(libnghttp2_la_OBJECTS) $(libnghttp2_la_DEPENDENCIES) $(EXTRA_libnghttp2_la_DEPENDENCIES)
$(AM_V_CCLD)$(libnghttp2_la_LINK) -rpath $(libdir) $(libnghttp2_la_OBJECTS) $(libnghttp2_la_LIBADD) $(LIBS)
@@ -660,7 +661,7 @@ distclean-compile:
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
- @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+ @: >>$@
am--depfiles: $(am__depfiles_remade)
@@ -813,6 +814,7 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -903,9 +905,9 @@ mostlyclean-generic:
clean-generic:
distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
- -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+ -$(am__rm_f) $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
+ -$(am__rm_f) $(DISTCLEANFILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -916,7 +918,7 @@ clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-recursive
- -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo
-rm -f ./$(DEPDIR)/nghttp2_buf.Plo
-rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo
-rm -f ./$(DEPDIR)/nghttp2_debug.Plo
@@ -987,7 +989,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
- -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo
+ -rm -f ./$(DEPDIR)/nghttp2_alpn.Plo
-rm -f ./$(DEPDIR)/nghttp2_buf.Plo
-rm -f ./$(DEPDIR)/nghttp2_callbacks.Plo
-rm -f ./$(DEPDIR)/nghttp2_debug.Plo
@@ -1055,3 +1057,10 @@ uninstall-am: uninstall-libLTLIBRARIES uninstall-pkgconfigDATA
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+
+# Tell GNU make to disable its built-in pattern rules.
+%:: %,v
+%:: RCS/%,v
+%:: RCS/%
+%:: s.%
+%:: SCCS/s.%
diff --git a/deps/nghttp2/lib/includes/Makefile.in b/deps/nghttp2/lib/includes/Makefile.in
index 833a90fb339..1b115bde50e 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.5 from Makefile.am.
+# Makefile.in generated by automake 1.18.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+# Copyright (C) 1994-2025 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -93,6 +93,8 @@ am__make_running_with_option = \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+am__rm_f = rm -f $(am__rm_f_notfound)
+am__rm_rf = rm -rf $(am__rm_f_notfound)
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -168,10 +170,9 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
- test -z "$$files" \
- || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
- || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
- $(am__cd) "$$dir" && rm -f $$files; }; \
+ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \
}
am__installdirs = "$(DESTDIR)$(includedir)"
HEADERS = $(nobase_include_HEADERS)
@@ -341,8 +342,10 @@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
+am__rm_f_notfound = @am__rm_f_notfound@
am__tar = @am__tar@
am__untar = @am__untar@
+am__xargs_n = @am__xargs_n@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -508,6 +511,7 @@ cscopelist-am: $(am__tagged_files)
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -572,8 +576,8 @@ mostlyclean-generic:
clean-generic:
distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -$(am__rm_f) $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -666,3 +670,10 @@ uninstall-am: uninstall-nobase_includeHEADERS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+
+# Tell GNU make to disable its built-in pattern rules.
+%:: %,v
+%:: RCS/%,v
+%:: RCS/%
+%:: s.%
+%:: SCCS/s.%
diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
index 2a494894d2d..eac691280ba 100644
--- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
+++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h
@@ -465,10 +465,10 @@ typedef enum {
/**
* Possible flooding by peer was detected in this HTTP/2 session.
* Flooding is measured by how many PING and SETTINGS frames with
- * ACK flag set are queued for transmission. These frames are
- * response for the peer initiated frames, and peer can cause memory
- * exhaustion on server side to send these frames forever and does
- * not read network.
+ * ACK flag set are queued for transmission, and the size of the
+ * outbound queue. These frames are response for the peer initiated
+ * frames, and peer can cause memory exhaustion on server side to
+ * send these frames forever and does not read network.
*/
NGHTTP2_ERR_FLOODED = -904,
/**
@@ -3258,6 +3258,21 @@ NGHTTP2_EXTERN void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option,
uint64_t burst,
uint64_t rate);
+/**
+ * @function
+ *
+ * This function sets the maximum number of frames allowed in the
+ * outbound queue. The limit is checked after
+ * `nghttp2_session_mem_recv2()` and `nghttp2_session_recv()`. The
+ * current queue size (excluding deferred DATA frames) can be obtained
+ * by `nghttp2_session_get_outbound_queue_size()`. If it exceeds
+ * |val|, `nghttp2_session_mem_recv2()` and `nghttp2_session_recv()`
+ * return :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`. The default
+ * value is 5000.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_max_outbound_queue_size(nghttp2_option *option, size_t val);
+
/**
* @function
*
@@ -4581,6 +4596,8 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is server session.
+ * :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
+ * The required memory for |nva| of length |nvlen| is too large.
*
* .. warning::
*
@@ -4724,7 +4741,8 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
- * The |stream_id| is 0.
+ * The |stream_id| is 0; The required memory for |nva| of length
+ * |nvlen| is too large.
* :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
@@ -4794,7 +4812,8 @@ nghttp2_submit_response2(nghttp2_session *session, int32_t stream_id,
* :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
- * The |stream_id| is 0.
+ * The |stream_id| is 0; The required memory for |nva| of length
+ * |nvlen| is too large.
*/
NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
int32_t stream_id,
@@ -4860,7 +4879,8 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* No stream ID is available because maximum stream ID was
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
- * The |stream_id| is 0.
+ * The |stream_id| is 0; The required memory for |nva| of length
+ * |nvlen| is too large.
* :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|
@@ -5087,8 +5107,8 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* copies all the elements in the |iv|.
*
* While updating individual stream's local window size, if the window
- * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
- * RST_STREAM is issued against such a stream.
+ * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, GOAWAY
+ * frame is submitted and the connection will be terminated.
*
* SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is
* automatically submitted by the library and application could not
@@ -5162,7 +5182,8 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; The |stream_id| does not designate stream
- * that peer initiated.
+ * that peer initiated; The required memory for |nva| of length
+ * |nvlen| is too large.
* :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h
index 6c1a73206f3..c665394e051 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.70.0"
+#define NGHTTP2_VERSION "1.71.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 0x014600
+#define NGHTTP2_VERSION_NUM 0x014700
#endif /* NGHTTP2VER_H */
diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c
index 657607aed54..25fd025ab06 100644
--- a/deps/nghttp2/lib/nghttp2_frame.c
+++ b/deps/nghttp2/lib/nghttp2_frame.c
@@ -1048,8 +1048,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) {
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem) {
size_t i;
- uint8_t *data = NULL;
- size_t buflen = 0;
+ uint8_t *data;
+ size_t buflen;
nghttp2_nv *p;
if (nvlen == 0) {
@@ -1058,18 +1058,32 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
return 0;
}
+ if (sizeof(nghttp2_nv) > SIZE_MAX / nvlen) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ buflen = sizeof(nghttp2_nv) * nvlen;
+
for (i = 0; i < nvlen; ++i) {
/* + 1 for null-termination */
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) {
+ if (nva[i].namelen == SIZE_MAX ||
+ buflen > SIZE_MAX - nva[i].namelen - 1) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
buflen += nva[i].namelen + 1;
}
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) {
+ if (nva[i].valuelen == SIZE_MAX ||
+ buflen > SIZE_MAX - nva[i].valuelen - 1) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
buflen += nva[i].valuelen + 1;
}
}
- buflen += sizeof(nghttp2_nv) * nvlen;
-
*nva_ptr = nghttp2_mem_malloc(mem, buflen);
if (*nva_ptr == NULL) {
diff --git a/deps/nghttp2/lib/nghttp2_frame.h b/deps/nghttp2/lib/nghttp2_frame.h
index c0917c0df4c..32631de843f 100644
--- a/deps/nghttp2/lib/nghttp2_frame.h
+++ b/deps/nghttp2/lib/nghttp2_frame.h
@@ -597,6 +597,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ * The required memory for |nva| of length |nvlen| is too large.
*/
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem);
diff --git a/deps/nghttp2/lib/nghttp2_helper.c b/deps/nghttp2/lib/nghttp2_helper.c
index 70a80bc6faa..d4b04ff8d70 100644
--- a/deps/nghttp2/lib/nghttp2_helper.c
+++ b/deps/nghttp2/lib/nghttp2_helper.c
@@ -247,7 +247,8 @@ int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
int nghttp2_should_send_window_update(int32_t local_window_size,
int32_t recv_window_size) {
- return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
+ return recv_window_size > 0 && local_window_size > 0 &&
+ recv_window_size >= local_window_size / 2;
}
const char *nghttp2_strerror(int error_code) {
diff --git a/deps/nghttp2/lib/nghttp2_map.c b/deps/nghttp2/lib/nghttp2_map.c
index b1b1c93c03a..47a6e0a59e2 100644
--- a/deps/nghttp2/lib/nghttp2_map.c
+++ b/deps/nghttp2/lib/nghttp2_map.c
@@ -74,20 +74,19 @@ int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr),
return 0;
}
-/* Hasher from
- https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
- to maximize the output's sensitivity to all input bits. */
-#define NGHTTP2_MAP_HASHER 0xF1357AEA2E62A9C5ULL
-/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
- the high bits with the good distribution. */
-#define NGHTTP2_MAP_FIBO 0x9E3779B97F4A7C15ULL
-
-static size_t map_index(const nghttp2_map *map, nghttp2_map_key_type key32) {
- uint64_t key = (uint64_t)key32;
-
- key += map->seed;
- key *= NGHTTP2_MAP_HASHER;
- return (size_t)((key * NGHTTP2_MAP_FIBO) >> (64 - map->hashbits));
+/* 64-bit finalizer (fmix64) from MurmurHash3 to maximize the output's
+ sensitivity to all input bits. */
+#define NGHTTP2_MAP_HASHER1 0xFF51AFD7ED558CCDULL
+#define NGHTTP2_MAP_HASHER2 0xC4CEB9FE1A85EC53ULL
+
+static size_t map_index(const nghttp2_map *map, nghttp2_map_key_type key) {
+ key ^= map->seed;
+ key ^= key >> 33;
+ key *= NGHTTP2_MAP_HASHER1;
+ key ^= key >> 33;
+ key *= NGHTTP2_MAP_HASHER2;
+ key ^= key >> 33;
+ return (size_t)(key >> (64 - map->hashbits));
}
#ifndef WIN32
@@ -109,17 +108,17 @@ void nghttp2_map_print_distance(const nghttp2_map *map) {
}
idx = map_index(map, map->keys[i]);
- fprintf(stderr, "@%zu key=%d base=%zu distance=%u\n", i, map->keys[i], idx,
- map->psl[i] - 1);
+ fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%zu\n", i,
+ map->keys[i], idx, map->psl[i] - 1);
}
}
#endif /* !defined(WIN32) */
static void map_set_entry(nghttp2_map *map, size_t idx,
- nghttp2_map_key_type key, void *data, size_t psl) {
+ nghttp2_map_key_type key, size_t psl, void *data) {
map->keys[idx] = key;
+ map->psl[idx] = psl;
map->data[idx] = data;
- map->psl[idx] = (uint8_t)psl;
}
#define NGHTTP2_SWAP(TYPE, A, B) \
@@ -131,15 +130,15 @@ static void map_set_entry(nghttp2_map *map, size_t idx,
} while (0)
/*
- * map_insert inserts |key| and |data| to |map|, and returns the index
- * where the pair is stored if it succeeds. Otherwise, it returns one
- * of the following negative error codes:
+ * map_insert inserts |key| and |data| to |map|.
+ *
+ * It returns 0 if it succeeds, or one of the following negative error
+ * codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The another data associated to |key| is already present.
*/
-static nghttp2_ssize map_insert(nghttp2_map *map, nghttp2_map_key_type key,
- void *data) {
+static int map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
size_t idx = map_index(map, key);
size_t mask = ((size_t)1 << map->hashbits) - 1;
size_t psl = 1;
@@ -149,16 +148,16 @@ static nghttp2_ssize map_insert(nghttp2_map *map, nghttp2_map_key_type key,
kpsl = map->psl[idx];
if (kpsl == 0) {
- map_set_entry(map, idx, key, data, psl);
+ map_set_entry(map, idx, key, psl, data);
++map->size;
- return (nghttp2_ssize)idx;
+ return 0;
}
if (psl > kpsl) {
NGHTTP2_SWAP(nghttp2_map_key_type, &key, &map->keys[idx]);
+ NGHTTP2_SWAP(size_t, &psl, &map->psl[idx]);
NGHTTP2_SWAP(void *, &data, &map->data[idx]);
- NGHTTP2_SWAP(uint8_t, &psl, &map->psl[idx]);
} else if (map->keys[idx] == key) {
/* This check ensures that no duplicate keys are inserted. But
it is just a waste after first swap or if this function is
@@ -180,14 +179,14 @@ static nghttp2_ssize map_insert(nghttp2_map *map, nghttp2_map_key_type key,
static int map_resize(nghttp2_map *map, size_t new_hashbits) {
size_t i;
size_t tablelen;
- nghttp2_ssize idx;
nghttp2_map new_map = {
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
void *buf;
- (void)idx;
+ int rv;
+ (void)rv;
if (new_hashbits > NGHTTP2_MAP_MAX_HASHBITS) {
return NGHTTP2_ERR_NOMEM;
@@ -196,16 +195,16 @@ static int map_resize(nghttp2_map *map, size_t new_hashbits) {
tablelen = (size_t)1 << new_hashbits;
buf = nghttp2_mem_calloc(map->mem, tablelen,
- sizeof(nghttp2_map_key_type) + sizeof(void *) +
- sizeof(uint8_t));
- if (buf == NULL) {
+ sizeof(nghttp2_map_key_type) + sizeof(size_t) +
+ sizeof(void *));
+ if (!buf) {
return NGHTTP2_ERR_NOMEM;
}
new_map.keys = buf;
- new_map.data =
- (void *)((uint8_t *)new_map.keys + tablelen * sizeof(nghttp2_map_key_type));
- new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
+ new_map.psl = (size_t *)(void *)((uint8_t *)new_map.keys +
+ tablelen * sizeof(nghttp2_map_key_type));
+ new_map.data = (void *)((uint8_t *)new_map.psl + tablelen * sizeof(size_t));
if (map->size) {
tablelen = (size_t)1 << map->hashbits;
@@ -215,31 +214,26 @@ static int map_resize(nghttp2_map *map, size_t new_hashbits) {
continue;
}
- idx = map_insert(&new_map, map->keys[i], map->data[i]);
+ rv = map_insert(&new_map, map->keys[i], map->data[i]);
/* map_insert must not fail because all keys are unique during
resize. */
- assert(idx >= 0);
+ assert(0 == rv);
}
}
nghttp2_mem_free(map->mem, map->keys);
map->keys = new_map.keys;
- map->data = new_map.data;
map->psl = new_map.psl;
+ map->data = new_map.data;
map->hashbits = new_hashbits;
return 0;
}
-/* NGHTTP2_MAX_PSL_RESIZE_THRESH is the maximum psl threshold. If
- reached, resize the table. */
-#define NGHTTP2_MAX_PSL_RESIZE_THRESH 128
-
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
int rv;
size_t tablelen;
- nghttp2_ssize idx;
assert(data);
@@ -256,27 +250,9 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
if (rv != 0) {
return rv;
}
-
- idx = map_insert(map, key, data);
- if (idx < 0) {
- return (int)idx;
- }
-
- return 0;
- }
-
- idx = map_insert(map, key, data);
- if (idx < 0) {
- return (int)idx;
- }
-
- /* Resize if psl reaches really large value which is almost
- improbable, but just in case. */
- if (map->psl[idx] - 1 < NGHTTP2_MAX_PSL_RESIZE_THRESH) {
- return 0;
}
- return map_resize(map, map->hashbits + 1);
+ return map_insert(map, key, data);
}
void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) {
@@ -334,7 +310,7 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
break;
}
- map_set_entry(map, dest, map->keys[idx], map->data[idx], kpsl - 1);
+ map_set_entry(map, dest, map->keys[idx], kpsl - 1, map->data[idx]);
dest = idx;
diff --git a/deps/nghttp2/lib/nghttp2_map.h b/deps/nghttp2/lib/nghttp2_map.h
index c47b279345d..864ecdbce81 100644
--- a/deps/nghttp2/lib/nghttp2_map.h
+++ b/deps/nghttp2/lib/nghttp2_map.h
@@ -36,15 +36,15 @@
/* Implementation of unordered map */
-typedef int32_t nghttp2_map_key_type;
+typedef uint64_t nghttp2_map_key_type;
typedef struct nghttp2_map {
nghttp2_map_key_type *keys;
- void **data;
/* psl is the Probe Sequence Length. 0 has special meaning that the
element is not stored at i-th position if psl[i] == 0. Because
of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
- uint8_t *psl;
+ size_t *psl;
+ void **data;
nghttp2_mem *mem;
uint64_t seed;
size_t size;
diff --git a/deps/nghttp2/lib/nghttp2_option.c b/deps/nghttp2/lib/nghttp2_option.c
index 7e44a241ba1..a1aa2738eb7 100644
--- a/deps/nghttp2/lib/nghttp2_option.c
+++ b/deps/nghttp2/lib/nghttp2_option.c
@@ -162,3 +162,9 @@ void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option,
option->glitch_burst = burst;
option->glitch_rate = rate;
}
+
+void nghttp2_option_set_max_outbound_queue_size(nghttp2_option *option,
+ size_t val) {
+ option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE;
+ option->max_outbound_queue_size = val;
+}
diff --git a/deps/nghttp2/lib/nghttp2_option.h b/deps/nghttp2/lib/nghttp2_option.h
index db739b609ed..d53dd98f0be 100644
--- a/deps/nghttp2/lib/nghttp2_option.h
+++ b/deps/nghttp2/lib/nghttp2_option.h
@@ -73,6 +73,7 @@
#define NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT 0x8000U
#define NGHTTP2_OPT_MAX_CONTINUATIONS 0x010000U
#define NGHTTP2_OPT_GLITCH_RATE_LIMIT 0x020000U
+#define NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE 0x040000U
/**
* Struct to store option values for nghttp2_session.
@@ -108,6 +109,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_MAX_CONTINUATIONS
*/
size_t max_continuations;
+ /**
+ * NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE
+ */
+ size_t max_outbound_queue_size;
/**
* Bitwise OR of NGHTTP2_OPT_* values to determine which fields are
* specified.
diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c
index f4c2afc8009..bd4415f4933 100644
--- a/deps/nghttp2/lib/nghttp2_session.c
+++ b/deps/nghttp2/lib/nghttp2_session.c
@@ -285,7 +285,8 @@ nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
int32_t stream_id) {
nghttp2_stream *stream;
- stream = (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id);
+ stream = (nghttp2_stream *)nghttp2_map_find(&session->streams,
+ (nghttp2_map_key_type)stream_id);
if (stream == NULL || (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) ||
stream->state == NGHTTP2_STREAM_IDLE) {
@@ -297,7 +298,8 @@ nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
int32_t stream_id) {
- return (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id);
+ return (nghttp2_stream *)nghttp2_map_find(&session->streams,
+ (nghttp2_map_key_type)stream_id);
}
static void session_inbound_frame_reset(nghttp2_session *session) {
@@ -498,6 +500,8 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
(*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
(*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS;
+ (*session_ptr)->max_outbound_queue_size =
+ NGHTTP2_DEFAULT_MAX_OUTBOUND_QUEUE_SIZE;
if (option) {
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -578,6 +582,10 @@ static int session_new(nghttp2_session **session_ptr,
nghttp2_ratelim_init(&(*session_ptr)->glitch_ratelim,
option->glitch_burst, option->glitch_rate);
}
+
+ if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE) {
+ (*session_ptr)->max_outbound_queue_size = option->max_outbound_queue_size;
+ }
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -1245,7 +1253,8 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
stream_user_data);
stream->seq = session->stream_seq++;
- rv = nghttp2_map_insert(&session->streams, stream_id, stream);
+ rv = nghttp2_map_insert(&session->streams, (nghttp2_map_key_type)stream_id,
+ stream);
if (rv != 0) {
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
@@ -1366,7 +1375,8 @@ void nghttp2_session_destroy_stream(nghttp2_session *session,
session_ob_data_remove(session, stream);
}
- nghttp2_map_remove(&session->streams, stream->stream_id);
+ nghttp2_map_remove(&session->streams,
+ (nghttp2_map_key_type)stream->stream_id);
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
}
@@ -2510,13 +2520,6 @@ static int session_after_frame_sent1(nghttp2_session *session) {
aux_data = &item->aux_data.data;
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
- /* We update flow control window after a frame was completely
- sent. This is possible because we choose payload length not to
- exceed the window */
- session->remote_window_size -= (int32_t)frame->hd.length;
- if (stream) {
- stream->remote_window_size -= (int32_t)frame->hd.length;
- }
if (stream && aux_data->eof) {
session_detach_stream_item(session, stream);
@@ -2823,6 +2826,20 @@ static int session_call_send_data(nghttp2_session *session,
}
}
+static void session_update_remote_window(nghttp2_session *session,
+ int32_t stream_id, size_t datalen) {
+ nghttp2_stream *stream;
+
+ session->remote_window_size -= (int32_t)datalen;
+
+ stream = nghttp2_session_get_stream(session, stream_id);
+ if (!stream) {
+ return;
+ }
+
+ stream->remote_window_size -= (int32_t)datalen;
+}
+
static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
const uint8_t **data_ptr,
int fast_cb) {
@@ -3081,6 +3098,9 @@ static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
return 0;
}
+ session_update_remote_window(session, frame->hd.stream_id,
+ frame->hd.length);
+
pause = (rv == NGHTTP2_ERR_PAUSE);
rv = session_after_frame_sent1(session);
@@ -3130,6 +3150,7 @@ nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session,
const uint8_t **data_ptr) {
int rv;
nghttp2_ssize len;
+ const nghttp2_frame *frame;
*data_ptr = NULL;
@@ -3139,6 +3160,14 @@ nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session,
}
if (session->aob.item) {
+ frame = &session->aob.item->frame;
+
+ if (frame->hd.type == NGHTTP2_DATA &&
+ (size_t)len == NGHTTP2_FRAME_HDLEN + frame->hd.length) {
+ session_update_remote_window(session, frame->hd.stream_id,
+ frame->hd.length);
+ }
+
/* We have to call session_after_frame_sent1 here to handle stream
closure upon transmission of frames. Otherwise, END_STREAM may
be reached to client before we call nghttp2_session_mem_send
@@ -3158,6 +3187,7 @@ int nghttp2_session_send(nghttp2_session *session) {
nghttp2_ssize datalen;
nghttp2_ssize sentlen;
nghttp2_bufs *framebufs;
+ const nghttp2_frame *frame;
framebufs = &session->aob.framebufs;
@@ -3182,6 +3212,17 @@ int nghttp2_session_send(nghttp2_session *session) {
}
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
+
+ if (sentlen > 0 && session->aob.item) {
+ frame = &session->aob.item->frame;
+
+ if (frame->hd.type == NGHTTP2_DATA &&
+ (size_t)datalen == NGHTTP2_FRAME_HDLEN + frame->hd.length) {
+ session_update_remote_window(session, frame->hd.stream_id,
+ frame->hd.length);
+ }
+ }
+
/* Rewind the offset to the amount of unsent bytes */
framebufs->cur->buf.pos -= datalen - sentlen;
}
@@ -4022,6 +4063,22 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed");
}
+
+ if ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) &&
+ (session->server || stream->status_code / 100 == 2)) {
+ rv = session_update_glitch_ratelim(session);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (session->iframe.state == NGHTTP2_IB_IGN_ALL) {
+ return 0;
+ }
+
+ return session_inflate_handle_invalid_stream(session, frame,
+ NGHTTP2_ERR_PROTO);
+ }
+
if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
if (stream->state == NGHTTP2_STREAM_OPENED) {
rv = session_call_on_begin_headers(session, frame);
@@ -4199,6 +4256,11 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) {
return NGHTTP2_ERR_FLOW_CONTROL;
}
+ if ((int64_t)stream->local_window_size - (int64_t)stream->recv_window_size >
+ NGHTTP2_MAX_WINDOW_SIZE) {
+ return NGHTTP2_ERR_FLOW_CONTROL;
+ }
+
if (stream->window_update_queued) {
return 0;
}
@@ -4633,6 +4695,13 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "PUSH_PROMISE: stream closed");
}
+ if ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) &&
+ stream->status_code / 100 == 2) {
+ return session_inflate_handle_invalid_connection(
+ session, frame, NGHTTP2_ERR_PROTO,
+ "PUSH_PROMISE: not allowed in CONNECT stream");
+ }
+
promised_stream = nghttp2_session_open_stream(
session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_STREAM_RESERVED, NULL);
@@ -4899,6 +4968,12 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session,
"PRIORITY_UPDATE: max concurrent streams exceeded");
}
+ if (session->num_idle_streams + session->num_incoming_streams >=
+ session->pending_local_max_concurrent_stream) {
+ /* Ignore priority hints for excessive streams. */
+ return session_call_on_frame_received(session, frame);
+ }
+
stream =
nghttp2_session_open_stream(session, priority_update->stream_id,
NGHTTP2_FLAG_NONE, NGHTTP2_STREAM_IDLE, NULL);
@@ -5147,7 +5222,8 @@ static int session_update_consumed_size(nghttp2_session *session,
int32_t recv_size;
int rv;
- if ((size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
+ if (delta_size > NGHTTP2_MAX_WINDOW_SIZE ||
+ (size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
return nghttp2_session_terminate_session(session,
NGHTTP2_FLOW_CONTROL_ERROR);
}
@@ -5416,6 +5492,42 @@ inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
return (nghttp2_ssize)(readlen);
}
+static int session_update_recv_window_on_data_hd(nghttp2_session *session) {
+ const nghttp2_inbound_frame *iframe = &session->iframe;
+ int32_t stream_id = iframe->frame.hd.stream_id;
+ size_t datalen = iframe->frame.hd.length;
+ nghttp2_stream *stream;
+ int rv;
+
+ if (datalen == 0) {
+ return 0;
+ }
+
+ rv = nghttp2_session_update_recv_connection_window_size(session, datalen);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return 0;
+ }
+
+ stream = nghttp2_session_get_stream(session, stream_id);
+ if (!stream) {
+ return 0;
+ }
+
+ rv = nghttp2_session_update_recv_stream_window_size(
+ session, stream, datalen,
+ !(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) &&
+ stream->state != NGHTTP2_STREAM_CLOSING);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ return 0;
+}
+
static const uint8_t static_in[] = {0};
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
@@ -5423,8 +5535,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return (ssize_t)nghttp2_session_mem_recv2(session, in, inlen);
}
-nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
- const uint8_t *in, size_t inlen) {
+static nghttp2_ssize session_mem_recv(nghttp2_session *session,
+ const uint8_t *in, size_t inlen) {
const uint8_t *first, *last;
nghttp2_inbound_frame *iframe = &session->iframe;
size_t readlen;
@@ -5563,10 +5675,28 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
DEBUGF("recv: DATA not allowed stream_id=%d\n",
iframe->frame.hd.stream_id);
+ rv = session_update_recv_window_on_data_hd(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return (nghttp2_ssize)inlen;
+ }
+
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
+ rv = session_update_recv_window_on_data_hd(session);
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ if (iframe->state == NGHTTP2_IB_IGN_ALL) {
+ return (nghttp2_ssize)inlen;
+ }
+
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if (rv < 0) {
rv = nghttp2_session_terminate_session_with_reason(
@@ -6671,6 +6801,19 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS;
}
+ if (cont_hd.length > session->local_settings.max_frame_size) {
+ DEBUGF("recv: length is too large %zu > %u\n", cont_hd.length,
+ session->local_settings.max_frame_size);
+ rv = nghttp2_session_terminate_session_with_reason(
+ session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size");
+
+ if (nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+
+ return (nghttp2_ssize)inlen;
+ }
+
/* CONTINUATION won't bear NGHTTP2_PADDED flag */
iframe->frame.hd.flags =
@@ -6711,16 +6854,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)(in - first);
}
- /* Pad Length field is subject to flow control */
- rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
-
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (nghttp2_ssize)inlen;
- }
-
/* Pad Length field is consumed immediately */
rv =
nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen);
@@ -6733,21 +6866,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)inlen;
}
- stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
- if (stream) {
- rv = nghttp2_session_update_recv_stream_window_size(
- session, stream, readlen,
- iframe->payloadleft ||
- (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
-
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (nghttp2_ssize)inlen;
- }
- }
-
busy = 1;
padlen = inbound_frame_compute_pad(iframe);
@@ -6800,28 +6918,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
if (readlen > 0) {
nghttp2_ssize data_readlen;
- rv =
- nghttp2_session_update_recv_connection_window_size(session, readlen);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
-
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (nghttp2_ssize)inlen;
- }
-
- rv = nghttp2_session_update_recv_stream_window_size(
- session, stream, readlen,
- iframe->payloadleft ||
- (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
-
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (nghttp2_ssize)inlen;
- }
-
data_readlen =
inbound_frame_effective_readlen(iframe, iframe->payloadleft, readlen);
@@ -6933,18 +7029,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
iframe->payloadleft);
if (readlen > 0) {
- /* Update connection-level flow control window for ignored
- DATA frame too */
- rv =
- nghttp2_session_update_recv_connection_window_size(session, readlen);
- if (nghttp2_is_fatal(rv)) {
- return rv;
- }
-
- if (iframe->state == NGHTTP2_IB_IGN_ALL) {
- return (nghttp2_ssize)inlen;
- }
-
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* Ignored DATA is considered as "consumed" immediately. */
rv = session_update_connection_consumed_size(session, readlen);
@@ -7094,6 +7178,23 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)(in - first);
}
+nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
+ const uint8_t *in, size_t inlen) {
+ nghttp2_ssize nread;
+
+ nread = session_mem_recv(session, in, inlen);
+ if (nread < 0 && nghttp2_is_fatal((int)nread)) {
+ return nread;
+ }
+
+ if (nghttp2_session_get_outbound_queue_size(session) >
+ session->max_outbound_queue_size) {
+ return NGHTTP2_ERR_FLOODED;
+ }
+
+ return nread;
+}
+
int nghttp2_session_recv(nghttp2_session *session) {
uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH];
while (1) {
@@ -7696,13 +7797,13 @@ nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session,
int32_t stream_id) {
nghttp2_stream *stream;
- int32_t size;
+ int64_t size;
stream = nghttp2_session_get_stream(session, stream_id);
if (stream == NULL) {
return -1;
}
- size = stream->local_window_size - stream->recv_window_size;
+ size = (int64_t)stream->local_window_size - (int64_t)stream->recv_window_size;
/* size could be negative if local endpoint reduced
SETTINGS_INITIAL_WINDOW_SIZE */
@@ -7710,7 +7811,13 @@ int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session,
return 0;
}
- return size;
+ /* In this case, GOAWAY with NGHTTP2_FLOW_CONTROL_ERROR has already
+ been queued or sent */
+ if (size > NGHTTP2_MAX_WINDOW_SIZE) {
+ return NGHTTP2_MAX_WINDOW_SIZE;
+ }
+
+ return (int32_t)size;
}
int32_t
diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h
index 1b04464cda8..c385ddf20d5 100644
--- a/deps/nghttp2/lib/nghttp2_session.h
+++ b/deps/nghttp2/lib/nghttp2_session.h
@@ -110,6 +110,9 @@ typedef struct {
HEADER frame. */
#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8
+/* The default maximum size of the outbound queue. */
+#define NGHTTP2_DEFAULT_MAX_OUTBOUND_QUEUE_SIZE 5000
+
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
@@ -280,6 +283,8 @@ struct nghttp2_session {
/* The number of CONTINUATION frames following an incoming HEADER
frame. This variable is reset when END_HEADERS flag is seen. */
size_t num_continuations;
+ /* The maximum size of the outbound queue. */
+ size_t max_outbound_queue_size;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The last stream ID this session initiated. For client session,