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,