File CVE-2019-15605.patch of Package nodejs8.15384

ported commits,

commit e2c8f89b7572a7aea62927923e425bbd7725dca2
Author: Sam Roberts <vieuxtech@gmail.com>
Date:   Thu Jan 16 11:55:52 2020 -0800

    test: using TE to smuggle reqs is not possible
    
    See: https://hackerone.com/reports/735748
    
    PR-URL: https://github.com/nodejs-private/node-private/pull/192
    Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>

commit 49f4220ce5b92bec68c040f46823e55c27d50517
Author: Sam Roberts <vieuxtech@gmail.com>
Date:   Tue Feb 4 10:36:57 2020 -0800

    deps: upgrade http-parser to v2.9.3
    
    PR-URL: https://github.com/nodejs-private/http-parser-private/pull/4
    Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Sam Roberts <vieuxtech@gmail.com>

commit d616722f65fcfbce57e597f41466e864eba22c4f
Author: Sam Roberts <vieuxtech@gmail.com>
Date:   Tue Jan 7 14:24:54 2020 -0800

    test: check that --insecure-http-parser works
    
    Test that using --insecure-http-parser will disable validation of
    invalid characters in HTTP headers.
    
    See:
    - https://github.com/nodejs/node/pull/30567
    
    Backport-PR-URL: https://github.com/nodejs/node/pull/30471
    PR-URL: https://github.com/nodejs/node/pull/31253
    Reviewed-By: Richard Lau <riclau@uk.ibm.com>
    Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>

commit a9849c0ff6b4459880f8f6da10e6fedb3c4df620
Author: Sam Roberts <vieuxtech@gmail.com>
Date:   Wed Nov 20 11:48:58 2019 -0800

    http: opt-in insecure HTTP header parsing
    
    Allow insecure HTTP header parsing. Make clear it is insecure.
    
    See:
    - https://github.com/nodejs/node/pull/30553
    - https://github.com/nodejs/node/issues/27711#issuecomment-556265881
    - https://github.com/nodejs/node/issues/30515
    
    Backport-PR-URL: https://github.com/nodejs/node/pull/30471
    PR-URL: https://github.com/nodejs/node/pull/30567
    Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
    Reviewed-By: Anna Henningsen <anna@addaleax.net>
    Reviewed-By: Denys Otrishko <shishugi@gmail.com>
    Reviewed-By: James M Snell <jasnell@gmail.com>

commit a28e5cc1ed7e298118bd3ea8b5b96712467c3703
Author: Sam Roberts <vieuxtech@gmail.com>
Date:   Wed Nov 13 10:05:38 2019 -0800

    deps: upgrade http-parser to v2.9.1
    
    PR-URL: https://github.com/nodejs/node/pull/30471
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
    Reviewed-By: Richard Lau <riclau@uk.ibm.com>
    Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>

Index: node-v8.17.0/deps/http_parser/Makefile
===================================================================
--- node-v8.17.0.orig/deps/http_parser/Makefile
+++ node-v8.17.0/deps/http_parser/Makefile
@@ -23,8 +23,8 @@ HELPER ?=
 BINEXT ?=
 SOLIBNAME = libhttp_parser
 SOMAJOR = 2
-SOMINOR = 8
-SOREV   = 0
+SOMINOR = 9
+SOREV   = 3
 ifeq (darwin,$(PLATFORM))
 SOEXT ?= dylib
 SONAME ?= $(SOLIBNAME).$(SOMAJOR).$(SOMINOR).$(SOEXT)
@@ -133,14 +133,14 @@ tags: http_parser.c http_parser.h test.c
 install: library
 	$(INSTALL) -D  http_parser.h $(DESTDIR)$(INCLUDEDIR)/http_parser.h
 	$(INSTALL) -D $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME)
-	ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
-	ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
+	ln -sf $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
+	ln -sf $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
 
 install-strip: library
 	$(INSTALL) -D  http_parser.h $(DESTDIR)$(INCLUDEDIR)/http_parser.h
 	$(INSTALL) -D -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME)
-	ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
-	ln -s $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
+	ln -sf $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
+	ln -sf $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SOLIBNAME).$(SOEXT)
 
 uninstall:
 	rm $(DESTDIR)$(INCLUDEDIR)/http_parser.h
Index: node-v8.17.0/deps/http_parser/README.md
===================================================================
--- node-v8.17.0.orig/deps/http_parser/README.md
+++ node-v8.17.0/deps/http_parser/README.md
@@ -148,7 +148,7 @@ callback in a threadsafe manner. This al
 multi-threaded contexts.
 
 Example:
-```
+```c
  typedef struct {
   socket_t sock;
   void* buffer;
@@ -184,7 +184,7 @@ void http_parser_thread(socket_t sock) {
  parser supplied to callback functions */
  parser->data = my_data;
 
- http_parser_settings settings; / * set up callbacks */
+ http_parser_settings settings; /* set up callbacks */
  settings.on_url = my_url_callback;
 
  /* execute parser */
Index: node-v8.17.0/deps/http_parser/bench.c
===================================================================
--- node-v8.17.0.orig/deps/http_parser/bench.c
+++ node-v8.17.0/deps/http_parser/bench.c
@@ -20,10 +20,14 @@
  */
 #include "http_parser.h"
 #include <assert.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/time.h>
 
+/* 8 gb */
+static const int64_t kBytes = 8LL << 30;
+
 static const char data[] =
     "POST /joyent/http-parser HTTP/1.1\r\n"
     "Host: github.com\r\n"
@@ -38,7 +42,7 @@ static const char data[] =
     "Referer: https://github.com/joyent/http-parser\r\n"
     "Connection: keep-alive\r\n"
     "Transfer-Encoding: chunked\r\n"
-    "Cache-Control: max-age=0\r\n\r\nb\r\nhello world\r\n0\r\n\r\n";
+    "Cache-Control: max-age=0\r\n\r\nb\r\nhello world\r\n0\r\n";
 static const size_t data_len = sizeof(data) - 1;
 
 static int on_info(http_parser* p) {
@@ -67,13 +71,13 @@ int bench(int iter_count, int silent) {
   int err;
   struct timeval start;
   struct timeval end;
-  float rps;
 
   if (!silent) {
     err = gettimeofday(&start, NULL);
     assert(err == 0);
   }
 
+  fprintf(stderr, "req_len=%d\n", (int) data_len);
   for (i = 0; i < iter_count; i++) {
     size_t parsed;
     http_parser_init(&parser, HTTP_REQUEST);
@@ -83,17 +87,27 @@ int bench(int iter_count, int silent) {
   }
 
   if (!silent) {
+    double elapsed;
+    double bw;
+    double total;
+
     err = gettimeofday(&end, NULL);
     assert(err == 0);
 
     fprintf(stdout, "Benchmark result:\n");
 
-    rps = (float) (end.tv_sec - start.tv_sec) +
-          (end.tv_usec - start.tv_usec) * 1e-6f;
-    fprintf(stdout, "Took %f seconds to run\n", rps);
+    elapsed = (double) (end.tv_sec - start.tv_sec) +
+              (end.tv_usec - start.tv_usec) * 1e-6f;
+
+    total = (double) iter_count * data_len;
+    bw = (double) total / elapsed;
+
+    fprintf(stdout, "%.2f mb | %.2f mb/s | %.2f req/sec | %.2f s\n",
+        (double) total / (1024 * 1024),
+        bw / (1024 * 1024),
+        (double) iter_count / elapsed,
+        elapsed);
 
-    rps = (float) iter_count / rps;
-    fprintf(stdout, "%f req/sec\n", rps);
     fflush(stdout);
   }
 
@@ -101,11 +115,14 @@ int bench(int iter_count, int silent) {
 }
 
 int main(int argc, char** argv) {
+  int64_t iterations;
+
+  iterations = kBytes / (int64_t) data_len;
   if (argc == 2 && strcmp(argv[1], "infinite") == 0) {
     for (;;)
-      bench(5000000, 1);
+      bench(iterations, 1);
     return 0;
   } else {
-    return bench(5000000, 0);
+    return bench(iterations, 0);
   }
 }
Index: node-v8.17.0/deps/http_parser/http_parser.c
===================================================================
--- node-v8.17.0.orig/deps/http_parser/http_parser.c
+++ node-v8.17.0/deps/http_parser/http_parser.c
@@ -51,6 +51,7 @@ static uint32_t max_header_size = HTTP_M
 
 #define SET_ERRNO(e)                                                 \
 do {                                                                 \
+  parser->nread = nread;                                             \
   parser->http_errno = (e);                                          \
 } while(0)
 
@@ -58,6 +59,7 @@ do {
 #define UPDATE_STATE(V) p_state = (enum state) (V);
 #define RETURN(V)                                                    \
 do {                                                                 \
+  parser->nread = nread;                                             \
   parser->state = CURRENT_STATE();                                   \
   return (V);                                                        \
 } while (0);
@@ -151,8 +153,8 @@ do {
  */
 #define COUNT_HEADER_SIZE(V)                                         \
 do {                                                                 \
-  parser->nread += (V);                                              \
-  if (UNLIKELY(parser->nread > max_header_size)) {                   \
+  nread += (uint32_t)(V);                                            \
+  if (UNLIKELY(nread > max_header_size)) {                           \
     SET_ERRNO(HPE_HEADER_OVERFLOW);                                  \
     goto error;                                                      \
   }                                                                  \
@@ -194,7 +196,7 @@ static const char tokens[256] = {
 /*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */
         0,       0,       0,       0,       0,       0,       0,       0,
 /*  32 sp    33  !    34  "    35  #    36  $    37  %    38  &    39  '  */
-        0,      '!',      0,      '#',     '$',     '%',     '&',    '\'',
+       ' ',     '!',      0,      '#',     '$',     '%',     '&',    '\'',
 /*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */
         0,       0,      '*',     '+',      0,      '-',     '.',      0,
 /*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */
@@ -314,6 +316,8 @@ enum state
   , s_req_http_HT
   , s_req_http_HTT
   , s_req_http_HTTP
+  , s_req_http_I
+  , s_req_http_IC
   , s_req_http_major
   , s_req_http_dot
   , s_req_http_minor
@@ -377,7 +381,10 @@ enum header_states
   , h_transfer_encoding
   , h_upgrade
 
+  , h_matching_transfer_encoding_token_start
   , h_matching_transfer_encoding_chunked
+  , h_matching_transfer_encoding_token
+
   , h_matching_connection_token_start
   , h_matching_connection_keep_alive
   , h_matching_connection_close
@@ -421,14 +428,14 @@ enum http_host_state
   (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
   (c) == '$' || (c) == ',')
 
-#define STRICT_TOKEN(c)     (tokens[(unsigned char)c])
+#define STRICT_TOKEN(c)     ((c == ' ') ? 0 : tokens[(unsigned char)c])
 
 #if HTTP_PARSER_STRICT
-#define TOKEN(c)            (tokens[(unsigned char)c])
+#define TOKEN(c)            STRICT_TOKEN(c)
 #define IS_URL_CHAR(c)      (BIT_AT(normal_url_char, (unsigned char)c))
 #define IS_HOST_CHAR(c)     (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
 #else
-#define TOKEN(c)            ((c == ' ') ? ' ' : tokens[(unsigned char)c])
+#define TOKEN(c)            tokens[(unsigned char)c]
 #define IS_URL_CHAR(c)                                                         \
   (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
 #define IS_HOST_CHAR(c)                                                        \
@@ -542,7 +549,7 @@ parse_url_char(enum state s, const char
         return s_dead;
       }
 
-    /* FALLTHROUGH */
+    /* fall through */
     case s_req_server_start:
     case s_req_server:
       if (ch == '/') {
@@ -646,6 +653,7 @@ size_t http_parser_execute (http_parser
   const char *status_mark = 0;
   enum state p_state = (enum state) parser->state;
   const unsigned int lenient = parser->lenient_http_headers;
+  uint32_t nread = parser->nread;
 
   /* We're in an error state. Don't bother doing anything. */
   if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
@@ -757,21 +765,16 @@ reexecute:
 
       case s_start_res:
       {
+        if (ch == CR || ch == LF)
+          break;
         parser->flags = 0;
         parser->content_length = ULLONG_MAX;
 
-        switch (ch) {
-          case 'H':
-            UPDATE_STATE(s_res_H);
-            break;
-
-          case CR:
-          case LF:
-            break;
-
-          default:
-            SET_ERRNO(HPE_INVALID_CONSTANT);
-            goto error;
+        if (ch == 'H') {
+          UPDATE_STATE(s_res_H);
+        } else {
+          SET_ERRNO(HPE_INVALID_CONSTANT);
+          goto error;
         }
 
         CALLBACK_NOTIFY(message_begin);
@@ -1088,11 +1091,17 @@ reexecute:
 
       case s_req_http_start:
         switch (ch) {
+          case ' ':
+            break;
           case 'H':
             UPDATE_STATE(s_req_http_H);
             break;
-          case ' ':
-            break;
+          case 'I':
+            if (parser->method == HTTP_SOURCE) {
+              UPDATE_STATE(s_req_http_I);
+              break;
+            }
+            /* fall through */
           default:
             SET_ERRNO(HPE_INVALID_CONSTANT);
             goto error;
@@ -1114,6 +1123,16 @@ reexecute:
         UPDATE_STATE(s_req_http_HTTP);
         break;
 
+      case s_req_http_I:
+        STRICT_CHECK(ch != 'C');
+        UPDATE_STATE(s_req_http_IC);
+        break;
+
+      case s_req_http_IC:
+        STRICT_CHECK(ch != 'E');
+        UPDATE_STATE(s_req_http_HTTP);  /* Treat "ICE" as "HTTP". */
+        break;
+
       case s_req_http_HTTP:
         STRICT_CHECK(ch != '/');
         UPDATE_STATE(s_req_http_major);
@@ -1240,8 +1259,14 @@ reexecute:
             break;
 
           switch (parser->header_state) {
-            case h_general:
+            case h_general: {
+              size_t left = data + len - p;
+              const char* pe = p + MIN(left, max_header_size);
+              while (p+1 < pe && TOKEN(p[1])) {
+                p++;
+              }
               break;
+            }
 
             case h_C:
               parser->index++;
@@ -1313,6 +1338,7 @@ reexecute:
                 parser->header_state = h_general;
               } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
                 parser->header_state = h_transfer_encoding;
+                parser->flags |= F_TRANSFER_ENCODING;
               }
               break;
 
@@ -1341,13 +1367,14 @@ reexecute:
           }
         }
 
-        COUNT_HEADER_SIZE(p - start);
-
         if (p == data + len) {
           --p;
+          COUNT_HEADER_SIZE(p - start);
           break;
         }
 
+        COUNT_HEADER_SIZE(p - start);
+
         if (ch == ':') {
           UPDATE_STATE(s_header_value_discard_ws);
           CALLBACK_DATA(header_field);
@@ -1371,7 +1398,7 @@ reexecute:
           break;
         }
 
-        /* FALLTHROUGH */
+        /* fall through */
 
       case s_header_value_start:
       {
@@ -1393,10 +1420,14 @@ reexecute:
             if ('c' == c) {
               parser->header_state = h_matching_transfer_encoding_chunked;
             } else {
-              parser->header_state = h_general;
+              parser->header_state = h_matching_transfer_encoding_token;
             }
             break;
 
+          /* Multi-value `Transfer-Encoding` header */
+          case h_matching_transfer_encoding_token_start:
+            break;
+
           case h_content_length:
             if (UNLIKELY(!IS_NUM(ch))) {
               SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
@@ -1413,6 +1444,11 @@ reexecute:
             parser->header_state = h_content_length_num;
             break;
 
+          /* when obsolete line folding is encountered for content length
+           * continue to the s_header_value state */
+          case h_content_length_ws:
+            break;
+
           case h_connection:
             /* looking for 'Connection: keep-alive' */
             if (c == 'k') {
@@ -1468,29 +1504,25 @@ reexecute:
 
           switch (h_state) {
             case h_general:
-            {
-              const char* p_cr;
-              const char* p_lf;
-              size_t limit = data + len - p;
-
-              limit = MIN(limit, max_header_size);
-
-              p_cr = (const char*) memchr(p, CR, limit);
-              p_lf = (const char*) memchr(p, LF, limit);
-              if (p_cr != NULL) {
-                if (p_lf != NULL && p_cr >= p_lf)
-                  p = p_lf;
-                else
-                  p = p_cr;
-              } else if (UNLIKELY(p_lf != NULL)) {
-                p = p_lf;
-              } else {
-                p = data + len;
+              {
+                size_t left = data + len - p;
+                const char* pe = p + MIN(left, max_header_size);
+
+                for (; p != pe; p++) {
+                  ch = *p;
+                  if (ch == CR || ch == LF) {
+                    --p;
+                    break;
+                  }
+                  if (!lenient && !IS_HEADER_CHAR(ch)) {
+                    SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
+                    goto error;
+                  }
+                }
+                if (p == data + len)
+                  --p;
+                break;
               }
-              --p;
-
-              break;
-            }
 
             case h_connection:
             case h_transfer_encoding:
@@ -1500,7 +1532,7 @@ reexecute:
             case h_content_length:
               if (ch == ' ') break;
               h_state = h_content_length_num;
-              /* FALLTHROUGH */
+              /* fall through */
 
             case h_content_length_num:
             {
@@ -1539,16 +1571,41 @@ reexecute:
               goto error;
 
             /* Transfer-Encoding: chunked */
+            case h_matching_transfer_encoding_token_start:
+              /* looking for 'Transfer-Encoding: chunked' */
+              if ('c' == c) {
+                h_state = h_matching_transfer_encoding_chunked;
+              } else if (STRICT_TOKEN(c)) {
+                /* TODO(indutny): similar code below does this, but why?
+                 * At the very least it seems to be inconsistent given that
+                 * h_matching_transfer_encoding_token does not check for
+                 * `STRICT_TOKEN`
+                 */
+                h_state = h_matching_transfer_encoding_token;
+              } else if (c == ' ' || c == '\t') {
+                /* Skip lws */
+              } else {
+                h_state = h_general;
+              }
+              break;
+
             case h_matching_transfer_encoding_chunked:
               parser->index++;
               if (parser->index > sizeof(CHUNKED)-1
                   || c != CHUNKED[parser->index]) {
-                h_state = h_general;
+                h_state = h_matching_transfer_encoding_token;
               } else if (parser->index == sizeof(CHUNKED)-2) {
                 h_state = h_transfer_encoding_chunked;
               }
               break;
 
+            case h_matching_transfer_encoding_token:
+              if (ch == ',') {
+                h_state = h_matching_transfer_encoding_token_start;
+                parser->index = 0;
+              }
+              break;
+
             case h_matching_connection_token_start:
               /* looking for 'Connection: keep-alive' */
               if (c == 'k') {
@@ -1607,7 +1664,7 @@ reexecute:
               break;
 
             case h_transfer_encoding_chunked:
-              if (ch != ' ') h_state = h_general;
+              if (ch != ' ') h_state = h_matching_transfer_encoding_token;
               break;
 
             case h_connection_keep_alive:
@@ -1636,10 +1693,10 @@ reexecute:
         }
         parser->header_state = h_state;
 
-        COUNT_HEADER_SIZE(p - start);
-
         if (p == data + len)
           --p;
+
+        COUNT_HEADER_SIZE(p - start);
         break;
       }
 
@@ -1657,6 +1714,10 @@ reexecute:
       case s_header_value_lws:
       {
         if (ch == ' ' || ch == '\t') {
+          if (parser->header_state == h_content_length_num) {
+              /* treat obsolete line folding as space */
+              parser->header_state = h_content_length_ws;
+          }
           UPDATE_STATE(s_header_value_start);
           REEXECUTE();
         }
@@ -1709,6 +1770,11 @@ reexecute:
             case h_transfer_encoding_chunked:
               parser->flags |= F_CHUNKED;
               break;
+            case h_content_length:
+              /* do not allow empty content length */
+              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
+              goto error;
+              break;
             default:
               break;
           }
@@ -1732,12 +1798,17 @@ reexecute:
           REEXECUTE();
         }
 
-        /* Cannot use chunked encoding and a content-length header together
-           per the HTTP specification. */
-        if ((parser->flags & F_CHUNKED) &&
+        /* Cannot us transfer-encoding and a content-length header together
+           per the HTTP specification. (RFC 7230 Section 3.3.3) */
+        if ((parser->flags & F_TRANSFER_ENCODING) &&
             (parser->flags & F_CONTENTLENGTH)) {
-          SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
-          goto error;
+          /* Allow it for lenient parsing as long as `Transfer-Encoding` is
+           * not `chunked`
+           */
+          if (!lenient || (parser->flags & F_CHUNKED)) {
+            SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
+            goto error;
+          }
         }
 
         UPDATE_STATE(s_headers_done);
@@ -1772,7 +1843,7 @@ reexecute:
             case 2:
               parser->upgrade = 1;
 
-            /* FALLTHROUGH */
+              /* fall through */
             case 1:
               parser->flags |= F_SKIPBODY;
               break;
@@ -1796,6 +1867,7 @@ reexecute:
         STRICT_CHECK(ch != LF);
 
         parser->nread = 0;
+        nread = 0;
 
         hasBody = parser->flags & F_CHUNKED ||
           (parser->content_length > 0 && parser->content_length != ULLONG_MAX);
@@ -1811,8 +1883,31 @@ reexecute:
           UPDATE_STATE(NEW_MESSAGE());
           CALLBACK_NOTIFY(message_complete);
         } else if (parser->flags & F_CHUNKED) {
-          /* chunked encoding - ignore Content-Length header */
+          /* chunked encoding - ignore Content-Length header,
+           * prepare for a chunk */
           UPDATE_STATE(s_chunk_size_start);
+        } else if (parser->flags & F_TRANSFER_ENCODING) {
+          if (parser->type == HTTP_REQUEST && !lenient) {
+            /* RFC 7230 3.3.3 */
+
+            /* If a Transfer-Encoding header field
+             * is present in a request and the chunked transfer coding is not
+             * the final encoding, the message body length cannot be determined
+             * reliably; the server MUST respond with the 400 (Bad Request)
+             * status code and then close the connection.
+             */
+            SET_ERRNO(HPE_INVALID_TRANSFER_ENCODING);
+            RETURN(p - data); /* Error */
+          } else {
+            /* RFC 7230 3.3.3 */
+
+            /* If a Transfer-Encoding header field is present in a response and
+             * the chunked transfer coding is not the final encoding, the
+             * message body length is determined by reading the connection until
+             * it is closed by the server.
+             */
+            UPDATE_STATE(s_body_identity_eof);
+          }
         } else {
           if (parser->content_length == 0) {
             /* Content-Length header given but zero: Content-Length: 0\r\n */
@@ -1890,7 +1985,7 @@ reexecute:
 
       case s_chunk_size_start:
       {
-        assert(parser->nread == 1);
+        assert(nread == 1);
         assert(parser->flags & F_CHUNKED);
 
         unhex_val = unhex[(unsigned char)ch];
@@ -1958,6 +2053,7 @@ reexecute:
         STRICT_CHECK(ch != LF);
 
         parser->nread = 0;
+        nread = 0;
 
         if (parser->content_length == 0) {
           parser->flags |= F_TRAILING;
@@ -2004,6 +2100,7 @@ reexecute:
         assert(parser->flags & F_CHUNKED);
         STRICT_CHECK(ch != LF);
         parser->nread = 0;
+        nread = 0;
         UPDATE_STATE(s_chunk_size_start);
         CALLBACK_NOTIFY(chunk_complete);
         break;
@@ -2015,7 +2112,7 @@ reexecute:
     }
   }
 
-  /* Run callbacks for any marks that we have leftover after we ran our of
+  /* Run callbacks for any marks that we have leftover after we ran out of
    * bytes. There should be at most one of these set, so it's OK to invoke
    * them in series (unset marks will not result in callbacks).
    *
@@ -2064,6 +2161,12 @@ http_message_needs_eof (const http_parse
     return 0;
   }
 
+  /* RFC 7230 3.3.3, see `s_headers_almost_done` */
+  if ((parser->flags & F_TRANSFER_ENCODING) &&
+      (parser->flags & F_CHUNKED) == 0) {
+    return 1;
+  }
+
   if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
     return 0;
   }
@@ -2097,6 +2200,16 @@ http_method_str (enum http_method m)
   return ELEM_AT(method_strings, m, "<unknown>");
 }
 
+const char *
+http_status_str (enum http_status s)
+{
+  switch (s) {
+#define XX(num, name, string) case HTTP_STATUS_##name: return #string;
+    HTTP_STATUS_MAP(XX)
+#undef XX
+    default: return "<unknown>";
+  }
+}
 
 void
 http_parser_init (http_parser *parser, enum http_parser_type t)
@@ -2157,7 +2270,7 @@ http_parse_host_char(enum http_host_stat
         return s_http_host;
       }
 
-    /* FALLTHROUGH */
+    /* fall through */
     case s_http_host_v6_end:
       if (ch == ':') {
         return s_http_host_port_start;
@@ -2170,7 +2283,7 @@ http_parse_host_char(enum http_host_stat
         return s_http_host_v6_end;
       }
 
-    /* FALLTHROUGH */
+    /* fall through */
     case s_http_host_v6_start:
       if (IS_HEX(ch) || ch == ':' || ch == '.') {
         return s_http_host_v6;
@@ -2186,7 +2299,7 @@ http_parse_host_char(enum http_host_stat
         return s_http_host_v6_end;
       }
 
-    /* FALLTHROUGH */
+    /* fall through */
     case s_http_host_v6_zone_start:
       /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
       if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
@@ -2211,12 +2324,13 @@ http_parse_host_char(enum http_host_stat
 
 static int
 http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
-  assert(u->field_set & (1 << UF_HOST));
   enum http_host_state s;
 
   const char *p;
   size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
 
+  assert(u->field_set & (1 << UF_HOST));
+
   u->field_data[UF_HOST].len = 0;
 
   s = found_at ? s_http_userinfo_start : s_http_host_start;
@@ -2231,14 +2345,14 @@ http_parse_host(const char * buf, struct
     switch(new_s) {
       case s_http_host:
         if (s != s_http_host) {
-          u->field_data[UF_HOST].off = p - buf;
+          u->field_data[UF_HOST].off = (uint16_t)(p - buf);
         }
         u->field_data[UF_HOST].len++;
         break;
 
       case s_http_host_v6:
         if (s != s_http_host_v6) {
-          u->field_data[UF_HOST].off = p - buf;
+          u->field_data[UF_HOST].off = (uint16_t)(p - buf);
         }
         u->field_data[UF_HOST].len++;
         break;
@@ -2250,7 +2364,7 @@ http_parse_host(const char * buf, struct
 
       case s_http_host_port:
         if (s != s_http_host_port) {
-          u->field_data[UF_PORT].off = p - buf;
+          u->field_data[UF_PORT].off = (uint16_t)(p - buf);
           u->field_data[UF_PORT].len = 0;
           u->field_set |= (1 << UF_PORT);
         }
@@ -2259,7 +2373,7 @@ http_parse_host(const char * buf, struct
 
       case s_http_userinfo:
         if (s != s_http_userinfo) {
-          u->field_data[UF_USERINFO].off = p - buf ;
+          u->field_data[UF_USERINFO].off = (uint16_t)(p - buf);
           u->field_data[UF_USERINFO].len = 0;
           u->field_set |= (1 << UF_USERINFO);
         }
@@ -2304,6 +2418,10 @@ http_parser_parse_url(const char *buf, s
   enum http_parser_url_fields uf, old_uf;
   int found_at = 0;
 
+  if (buflen == 0) {
+    return 1;
+  }
+
   u->port = u->field_set = 0;
   s = is_connect ? s_req_server_start : s_req_spaces_before_url;
   old_uf = UF_MAX;
@@ -2331,7 +2449,7 @@ http_parser_parse_url(const char *buf, s
       case s_req_server_with_at:
         found_at = 1;
 
-      /* FALLTHROUGH */
+      /* fall through */
       case s_req_server:
         uf = UF_HOST;
         break;
@@ -2359,7 +2477,7 @@ http_parser_parse_url(const char *buf, s
       continue;
     }
 
-    u->field_data[uf].off = p - buf;
+    u->field_data[uf].off = (uint16_t)(p - buf);
     u->field_data[uf].len = 1;
 
     u->field_set |= (1 << uf);
@@ -2422,6 +2540,7 @@ http_parser_pause(http_parser *parser, i
    */
   if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
       HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
+    uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */
     SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
   } else {
     assert(0 && "Attempting to pause parser in error state");
Index: node-v8.17.0/deps/http_parser/http_parser.gyp
===================================================================
--- node-v8.17.0.orig/deps/http_parser/http_parser.gyp
+++ node-v8.17.0/deps/http_parser/http_parser.gyp
@@ -56,7 +56,7 @@
         'defines': [ 'HTTP_PARSER_STRICT=0' ],
         'include_dirs': [ '.' ],
       },
-      'defines': [ 'HTTP_MAX_HEADER_SIZE=8192', 'HTTP_PARSER_STRICT=0' ],
+      'defines': [ 'HTTP_PARSER_STRICT=0' ],
       'sources': [ './http_parser.c', ],
       'conditions': [
         ['OS=="win"', {
@@ -79,7 +79,7 @@
         'defines': [ 'HTTP_PARSER_STRICT=1' ],
         'include_dirs': [ '.' ],
       },
-      'defines': [ 'HTTP_MAX_HEADER_SIZE=8192', 'HTTP_PARSER_STRICT=1' ],
+      'defines': [ 'HTTP_PARSER_STRICT=1' ],
       'sources': [ './http_parser.c', ],
       'conditions': [
         ['OS=="win"', {
Index: node-v8.17.0/deps/http_parser/http_parser.h
===================================================================
--- node-v8.17.0.orig/deps/http_parser/http_parser.h
+++ node-v8.17.0/deps/http_parser/http_parser.h
@@ -26,8 +26,8 @@ extern "C" {
 
 /* Also update SONAME in the Makefile whenever you change these. */
 #define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 8
-#define HTTP_PARSER_VERSION_PATCH 0
+#define HTTP_PARSER_VERSION_MINOR 9
+#define HTTP_PARSER_VERSION_PATCH 3
 
 #include <stddef.h>
 #if defined(_WIN32) && !defined(__MINGW32__) && \
@@ -225,6 +225,7 @@ enum flags
   , F_UPGRADE               = 1 << 5
   , F_SKIPBODY              = 1 << 6
   , F_CONTENTLENGTH         = 1 << 7
+  , F_TRANSFER_ENCODING     = 1 << 8
   };
 
 
@@ -271,6 +272,8 @@ enum flags
      "unexpected content-length header")                             \
   XX(INVALID_CHUNK_SIZE,                                             \
      "invalid character in chunk size header")                       \
+  XX(INVALID_TRANSFER_ENCODING,                                      \
+     "request has invalid transfer-encoding")                        \
   XX(INVALID_CONSTANT, "invalid constant string")                    \
   XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
   XX(STRICT, "strict mode assertion failed")                         \
@@ -293,11 +296,11 @@ enum http_errno {
 struct http_parser {
   /** PRIVATE **/
   unsigned int type : 2;         /* enum http_parser_type */
-  unsigned int flags : 8;        /* F_* values from 'flags' enum; semi-public */
   unsigned int state : 7;        /* enum state from http_parser.c */
   unsigned int header_state : 7; /* enum header_state from http_parser.c */
   unsigned int index : 7;        /* index into current matcher */
   unsigned int lenient_http_headers : 1;
+  unsigned int flags : 16;       /* F_* values from 'flags' enum; semi-public */
 
   uint32_t nread;          /* # bytes read in various scenarios */
   uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
@@ -407,6 +410,9 @@ int http_should_keep_alive(const http_pa
 /* Returns a string version of the HTTP method. */
 const char *http_method_str(enum http_method m);
 
+/* Returns a string version of the HTTP status code. */
+const char *http_status_str(enum http_status s);
+
 /* Return a string name of the given error */
 const char *http_errno_name(enum http_errno err);
 
Index: node-v8.17.0/deps/http_parser/test.c
===================================================================
--- node-v8.17.0.orig/deps/http_parser/test.c
+++ node-v8.17.0/deps/http_parser/test.c
@@ -27,9 +27,7 @@
 #include <stdarg.h>
 
 #if defined(__APPLE__)
-# undef strlcat
 # undef strlncpy
-# undef strlcpy
 #endif  /* defined(__APPLE__) */
 
 #undef TRUE
@@ -43,7 +41,9 @@
 
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
-static http_parser *parser;
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
+
+static http_parser parser;
 
 struct message {
   const char *name; // for debugging purposes
@@ -153,10 +153,10 @@ const struct message requests[] =
   ,.body= ""
   }
 
-#define DUMBFUCK 2
-, {.name= "dumbfuck"
+#define DUMBLUCK 2
+, {.name= "dumbluck"
   ,.type= HTTP_REQUEST
-  ,.raw= "GET /dumbfuck HTTP/1.1\r\n"
+  ,.raw= "GET /dumbluck HTTP/1.1\r\n"
          "aaaaaaaaaaaaa:++++++++++\r\n"
          "\r\n"
   ,.should_keep_alive= TRUE
@@ -166,8 +166,8 @@ const struct message requests[] =
   ,.method= HTTP_GET
   ,.query_string= ""
   ,.fragment= ""
-  ,.request_path= "/dumbfuck"
-  ,.request_url= "/dumbfuck"
+  ,.request_path= "/dumbluck"
+  ,.request_url= "/dumbluck"
   ,.num_headers= 1
   ,.headers=
     { { "aaaaaaaaaaaaa",  "++++++++++" }
@@ -262,7 +262,6 @@ const struct message requests[] =
   ,.type= HTTP_REQUEST
   ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n"
          "Accept: */*\r\n"
-         "Transfer-Encoding: identity\r\n"
          "Content-Length: 5\r\n"
          "\r\n"
          "World"
@@ -275,10 +274,9 @@ const struct message requests[] =
   ,.fragment= "hey"
   ,.request_path= "/post_identity_body_world"
   ,.request_url= "/post_identity_body_world?q=search#hey"
-  ,.num_headers= 3
+  ,.num_headers= 2
   ,.headers=
     { { "Accept", "*/*" }
-    , { "Transfer-Encoding", "identity" }
     , { "Content-Length", "5" }
     }
   ,.body= "World"
@@ -371,13 +369,13 @@ const struct message requests[] =
   ,.chunk_lengths= { 5, 6 }
   }
 
-#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11
-, {.name= "with bullshit after the length"
+#define CHUNKED_W_NONSENSE_AFTER_LENGTH 11
+, {.name= "with nonsense after the length"
   ,.type= HTTP_REQUEST
-  ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n"
+  ,.raw= "POST /chunked_w_nonsense_after_length HTTP/1.1\r\n"
          "Transfer-Encoding: chunked\r\n"
          "\r\n"
-         "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n"
+         "5; ilovew3;whattheluck=aretheseparametersfor\r\nhello\r\n"
          "6; blahblah; blah\r\n world\r\n"
          "0\r\n"
          "\r\n"
@@ -388,8 +386,8 @@ const struct message requests[] =
   ,.method= HTTP_POST
   ,.query_string= ""
   ,.fragment= ""
-  ,.request_path= "/chunked_w_bullshit_after_length"
-  ,.request_url= "/chunked_w_bullshit_after_length"
+  ,.request_path= "/chunked_w_nonsense_after_length"
+  ,.request_url= "/chunked_w_nonsense_after_length"
   ,.num_headers= 1
   ,.headers=
     { { "Transfer-Encoding", "chunked" }
@@ -1174,7 +1172,80 @@ const struct message requests[] =
   ,.body= ""
   }
 
-, {.name= NULL } /* sentinel */
+#define SOURCE_ICE_REQUEST 42
+, {.name = "source request"
+  ,.type= HTTP_REQUEST
+  ,.raw= "SOURCE /music/sweet/music ICE/1.0\r\n"
+         "Host: example.com\r\n"
+         "\r\n"
+  ,.should_keep_alive= FALSE
+  ,.message_complete_on_eof= FALSE
+  ,.http_major= 1
+  ,.http_minor= 0
+  ,.method= HTTP_SOURCE
+  ,.request_path= "/music/sweet/music"
+  ,.request_url= "/music/sweet/music"
+  ,.query_string= ""
+  ,.fragment= ""
+  ,.num_headers= 1
+  ,.headers= { { "Host", "example.com" } }
+  ,.body= ""
+  }
+
+#define POST_MULTI_TE_LAST_CHUNKED 43
+, {.name= "post - multi coding transfer-encoding chunked body"
+  ,.type= HTTP_REQUEST
+  ,.raw= "POST / HTTP/1.1\r\n"
+         "Transfer-Encoding: deflate, chunked\r\n"
+         "\r\n"
+         "1e\r\nall your base are belong to us\r\n"
+         "0\r\n"
+         "\r\n"
+  ,.should_keep_alive= TRUE
+  ,.message_complete_on_eof= FALSE
+  ,.http_major= 1
+  ,.http_minor= 1
+  ,.method= HTTP_POST
+  ,.query_string= ""
+  ,.fragment= ""
+  ,.request_path= "/"
+  ,.request_url= "/"
+  ,.num_headers= 1
+  ,.headers=
+    { { "Transfer-Encoding" , "deflate, chunked" }
+    }
+  ,.body= "all your base are belong to us"
+  ,.num_chunks_complete= 2
+  ,.chunk_lengths= { 0x1e }
+  }
+
+#define POST_MULTI_LINE_TE_LAST_CHUNKED 43
+, {.name= "post - multi coding transfer-encoding chunked body"
+  ,.type= HTTP_REQUEST
+  ,.raw= "POST / HTTP/1.1\r\n"
+         "Transfer-Encoding: deflate,\r\n"
+         " chunked\r\n"
+         "\r\n"
+         "1e\r\nall your base are belong to us\r\n"
+         "0\r\n"
+         "\r\n"
+  ,.should_keep_alive= TRUE
+  ,.message_complete_on_eof= FALSE
+  ,.http_major= 1
+  ,.http_minor= 1
+  ,.method= HTTP_POST
+  ,.query_string= ""
+  ,.fragment= ""
+  ,.request_path= "/"
+  ,.request_url= "/"
+  ,.num_headers= 1
+  ,.headers=
+    { { "Transfer-Encoding" , "deflate, chunked" }
+    }
+  ,.body= "all your base are belong to us"
+  ,.num_chunks_complete= 2
+  ,.chunk_lengths= { 0x1e }
+  }
 };
 
 /* * R E S P O N S E S * */
@@ -1952,8 +2023,28 @@ const struct message responses[] =
   ,.num_chunks_complete= 3
   ,.chunk_lengths= { 2, 2 }
   }
-
-, {.name= NULL } /* sentinel */
+#define HTTP_200_MULTI_TE_NOT_LAST_CHUNKED 28
+, {.name= "HTTP 200 response with `chunked` being *not last* Transfer-Encoding"
+  ,.type= HTTP_RESPONSE
+  ,.raw= "HTTP/1.1 200 OK\r\n"
+         "Transfer-Encoding: chunked, identity\r\n"
+         "\r\n"
+         "2\r\n"
+         "OK\r\n"
+         "0\r\n"
+         "\r\n"
+  ,.should_keep_alive= FALSE
+  ,.message_complete_on_eof= TRUE
+  ,.http_major= 1
+  ,.http_minor= 1
+  ,.status_code= 200
+  ,.response_status= "OK"
+  ,.num_headers= 1
+  ,.headers= { { "Transfer-Encoding", "chunked, identity" }
+             }
+  ,.body= "2\r\nOK\r\n0\r\n\r\n"
+  ,.num_chunks_complete= 0
+  }
 };
 
 /* strnlen() is a POSIX.2008 addition. Can't rely on it being available so
@@ -1994,12 +2085,6 @@ strlncat(char *dst, size_t len, const ch
 }
 
 size_t
-strlcat(char *dst, const char *src, size_t len)
-{
-  return strlncat(dst, len, src, (size_t) -1);
-}
-
-size_t
 strlncpy(char *dst, size_t len, const char *src, size_t n)
 {
   size_t slen;
@@ -2017,16 +2102,10 @@ strlncpy(char *dst, size_t len, const ch
   return slen;
 }
 
-size_t
-strlcpy(char *dst, const char *src, size_t len)
-{
-  return strlncpy(dst, len, src, (size_t) -1);
-}
-
 int
 request_url_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
   strlncat(messages[num_messages].request_url,
            sizeof(messages[num_messages].request_url),
            buf,
@@ -2037,7 +2116,7 @@ request_url_cb (http_parser *p, const ch
 int
 header_field_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
   struct message *m = &messages[num_messages];
 
   if (m->last_header_element != FIELD)
@@ -2056,7 +2135,7 @@ header_field_cb (http_parser *p, const c
 int
 header_value_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
   struct message *m = &messages[num_messages];
 
   strlncat(m->headers[m->num_headers-1][1],
@@ -2085,7 +2164,7 @@ check_body_is_final (const http_parser *
 int
 body_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
   strlncat(messages[num_messages].body,
            sizeof(messages[num_messages].body),
            buf,
@@ -2099,7 +2178,7 @@ body_cb (http_parser *p, const char *buf
 int
 count_body_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
   assert(buf);
   messages[num_messages].body_size += len;
   check_body_is_final(p);
@@ -2109,7 +2188,8 @@ count_body_cb (http_parser *p, const cha
 int
 message_begin_cb (http_parser *p)
 {
-  assert(p == parser);
+  assert(p == &parser);
+  assert(!messages[num_messages].message_begin_cb_called);
   messages[num_messages].message_begin_cb_called = TRUE;
   return 0;
 }
@@ -2117,21 +2197,22 @@ message_begin_cb (http_parser *p)
 int
 headers_complete_cb (http_parser *p)
 {
-  assert(p == parser);
-  messages[num_messages].method = parser->method;
-  messages[num_messages].status_code = parser->status_code;
-  messages[num_messages].http_major = parser->http_major;
-  messages[num_messages].http_minor = parser->http_minor;
+  assert(p == &parser);
+  messages[num_messages].method = parser.method;
+  messages[num_messages].status_code = parser.status_code;
+  messages[num_messages].http_major = parser.http_major;
+  messages[num_messages].http_minor = parser.http_minor;
   messages[num_messages].headers_complete_cb_called = TRUE;
-  messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
+  messages[num_messages].should_keep_alive = http_should_keep_alive(&parser);
   return 0;
 }
 
 int
 message_complete_cb (http_parser *p)
 {
-  assert(p == parser);
-  if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser))
+  assert(p == &parser);
+  if (messages[num_messages].should_keep_alive !=
+      http_should_keep_alive(&parser))
   {
     fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same "
                     "value in both on_message_complete and on_headers_complete "
@@ -2162,7 +2243,7 @@ message_complete_cb (http_parser *p)
 int
 response_status_cb (http_parser *p, const char *buf, size_t len)
 {
-  assert(p == parser);
+  assert(p == &parser);
 
   messages[num_messages].status_cb_called = TRUE;
 
@@ -2176,7 +2257,7 @@ response_status_cb (http_parser *p, cons
 int
 chunk_header_cb (http_parser *p)
 {
-  assert(p == parser);
+  assert(p == &parser);
   int chunk_idx = messages[num_messages].num_chunks;
   messages[num_messages].num_chunks++;
   if (chunk_idx < MAX_CHUNKS) {
@@ -2189,7 +2270,7 @@ chunk_header_cb (http_parser *p)
 int
 chunk_complete_cb (http_parser *p)
 {
-  assert(p == parser);
+  assert(p == &parser);
 
   /* Here we want to verify that each chunk_header_cb is matched by a
    * chunk_complete_cb, so not only should the total number of calls to
@@ -2394,7 +2475,7 @@ connect_headers_complete_cb (http_parser
 int
 connect_message_complete_cb (http_parser *p)
 {
-  messages[num_messages].should_keep_alive = http_should_keep_alive(parser);
+  messages[num_messages].should_keep_alive = http_should_keep_alive(&parser);
   return message_complete_cb(p);
 }
 
@@ -2467,30 +2548,15 @@ void
 parser_init (enum http_parser_type type)
 {
   num_messages = 0;
-
-  assert(parser == NULL);
-
-  parser = malloc(sizeof(http_parser));
-
-  http_parser_init(parser, type);
-
+  http_parser_init(&parser, type);
   memset(&messages, 0, sizeof messages);
-
-}
-
-void
-parser_free ()
-{
-  assert(parser);
-  free(parser);
-  parser = NULL;
 }
 
 size_t parse (const char *buf, size_t len)
 {
   size_t nparsed;
   currently_parsing_eof = (len == 0);
-  nparsed = http_parser_execute(parser, &settings, buf, len);
+  nparsed = http_parser_execute(&parser, &settings, buf, len);
   return nparsed;
 }
 
@@ -2498,7 +2564,7 @@ size_t parse_count_body (const char *buf
 {
   size_t nparsed;
   currently_parsing_eof = (len == 0);
-  nparsed = http_parser_execute(parser, &settings_count_body, buf, len);
+  nparsed = http_parser_execute(&parser, &settings_count_body, buf, len);
   return nparsed;
 }
 
@@ -2509,7 +2575,7 @@ size_t parse_pause (const char *buf, siz
 
   currently_parsing_eof = (len == 0);
   current_pause_parser = &s;
-  nparsed = http_parser_execute(parser, current_pause_parser, buf, len);
+  nparsed = http_parser_execute(&parser, current_pause_parser, buf, len);
   return nparsed;
 }
 
@@ -2517,7 +2583,7 @@ size_t parse_connect (const char *buf, s
 {
   size_t nparsed;
   currently_parsing_eof = (len == 0);
-  nparsed = http_parser_execute(parser, &settings_connect, buf, len);
+  nparsed = http_parser_execute(&parser, &settings_connect, buf, len);
   return nparsed;
 }
 
@@ -2737,7 +2803,7 @@ static void
 print_error (const char *raw, size_t error_location)
 {
   fprintf(stderr, "\n*** %s ***\n\n",
-          http_errno_description(HTTP_PARSER_ERRNO(parser)));
+          http_errno_description(HTTP_PARSER_ERRNO(&parser)));
 
   int this_line = 0, char_len = 0;
   size_t i, j, len = strlen(raw), error_location_line = 0;
@@ -3280,6 +3346,24 @@ const struct url_test url_tests[] =
   ,.rv=1 /* s_dead */
   }
 
+, {.name="empty url"
+  ,.url=""
+  ,.is_connect=0
+  ,.rv=1
+  }
+
+, {.name="NULL url"
+  ,.url=NULL
+  ,.is_connect=0
+  ,.rv=1
+  }
+
+, {.name="full of spaces url"
+  ,.url="  "
+  ,.is_connect=0
+  ,.rv=1
+  }
+
 #if HTTP_PARSER_STRICT
 
 , {.name="tab in URL"
@@ -3364,7 +3448,7 @@ test_parse_url (void)
     memset(&u, 0, sizeof(u));
 
     rv = http_parser_parse_url(test->url,
-                               strlen(test->url),
+                               test->url ? strlen(test->url) : 0,
                                test->is_connect,
                                &u);
 
@@ -3405,6 +3489,14 @@ test_method_str (void)
 }
 
 void
+test_status_str (void)
+{
+  assert(0 == strcmp("OK", http_status_str(HTTP_STATUS_OK)));
+  assert(0 == strcmp("Not Found", http_status_str(HTTP_STATUS_NOT_FOUND)));
+  assert(0 == strcmp("<unknown>", http_status_str(1337)));
+}
+
+void
 test_message (const struct message *message)
 {
   size_t raw_len = strlen(message->raw);
@@ -3418,9 +3510,18 @@ test_message (const struct message *mess
     size_t msg2len = raw_len - msg1len;
 
     if (msg1len) {
+      assert(num_messages == 0);
+      messages[0].headers_complete_cb_called = FALSE;
+
       read = parse(msg1, msg1len);
 
-      if (message->upgrade && parser->upgrade && num_messages > 0) {
+      if (!messages[0].headers_complete_cb_called && parser.nread != read) {
+        assert(parser.nread == read);
+        print_error(msg1, read);
+        abort();
+      }
+
+      if (message->upgrade && parser.upgrade && num_messages > 0) {
         messages[num_messages - 1].upgrade = msg1 + read;
         goto test;
       }
@@ -3434,7 +3535,7 @@ test_message (const struct message *mess
 
     read = parse(msg2, msg2len);
 
-    if (message->upgrade && parser->upgrade) {
+    if (message->upgrade && parser.upgrade) {
       messages[num_messages - 1].upgrade = msg2 + read;
       goto test;
     }
@@ -3459,8 +3560,6 @@ test_message (const struct message *mess
     }
 
     if(!message_eq(0, 0, message)) abort();
-
-    parser_free();
   }
 }
 
@@ -3496,8 +3595,6 @@ test_message_count_body (const struct me
   }
 
   if(!message_eq(0, 0, message)) abort();
-
-  parser_free();
 }
 
 void
@@ -3510,11 +3607,9 @@ test_simple_type (const char *buf,
   enum http_errno err;
 
   parse(buf, strlen(buf));
-  err = HTTP_PARSER_ERRNO(parser);
+  err = HTTP_PARSER_ERRNO(&parser);
   parse(NULL, 0);
 
-  parser_free();
-
   /* In strict mode, allow us to pass with an unexpected HPE_STRICT as
    * long as the caller isn't expecting success.
    */
@@ -3643,7 +3738,7 @@ test_chunked_content_length_error (int r
   parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
   assert(parsed == strlen(buf));
 
-  buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
+  buf = "Transfer-Encoding: anything\r\nContent-Length: 1\r\n\r\n";
   size_t buflen = strlen(buf);
 
   parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
@@ -3854,7 +3949,7 @@ test_multiple3 (const struct message *r1
 
   read = parse(total, strlen(total));
 
-  if (parser->upgrade) {
+  if (parser.upgrade) {
     upgrade_message_fix(total, read, 3, r1, r2, r3);
     goto test;
   }
@@ -3881,8 +3976,6 @@ test:
   if (!message_eq(0, 0, r1)) abort();
   if (message_count > 1 && !message_eq(1, 0, r2)) abort();
   if (message_count > 2 && !message_eq(2, 0, r3)) abort();
-
-  parser_free();
 }
 
 /* SCAN through every possible breaking to make sure the
@@ -3936,9 +4029,17 @@ test_scan (const struct message *r1, con
         strlncpy(buf3, sizeof(buf1), total+j, buf3_len);
         buf3[buf3_len] = 0;
 
+        assert(num_messages == 0);
+        messages[0].headers_complete_cb_called = FALSE;
+
         read = parse(buf1, buf1_len);
 
-        if (parser->upgrade) goto test;
+        if (!messages[0].headers_complete_cb_called && parser.nread != read) {
+          print_error(buf1, read);
+          goto error;
+        }
+
+        if (parser.upgrade) goto test;
 
         if (read != buf1_len) {
           print_error(buf1, read);
@@ -3947,7 +4048,7 @@ test_scan (const struct message *r1, con
 
         read += parse(buf2, buf2_len);
 
-        if (parser->upgrade) goto test;
+        if (parser.upgrade) goto test;
 
         if (read != buf1_len + buf2_len) {
           print_error(buf2, read);
@@ -3956,7 +4057,7 @@ test_scan (const struct message *r1, con
 
         read += parse(buf3, buf3_len);
 
-        if (parser->upgrade) goto test;
+        if (parser.upgrade) goto test;
 
         if (read != buf1_len + buf2_len + buf3_len) {
           print_error(buf3, read);
@@ -3966,7 +4067,7 @@ test_scan (const struct message *r1, con
         parse(NULL, 0);
 
 test:
-        if (parser->upgrade) {
+        if (parser.upgrade) {
           upgrade_message_fix(total, read, 3, r1, r2, r3);
         }
 
@@ -3990,8 +4091,6 @@ test:
           fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n");
           goto error;
         }
-
-        parser_free();
       }
     }
   }
@@ -4055,7 +4154,7 @@ test_message_pause (const struct message
     // completion callback.
     if (messages[0].message_complete_cb_called &&
         msg->upgrade &&
-        parser->upgrade) {
+        parser.upgrade) {
       messages[0].upgrade = buf + nread;
       goto test;
     }
@@ -4063,17 +4162,16 @@ test_message_pause (const struct message
     if (nread < buflen) {
 
       // Not much do to if we failed a strict-mode check
-      if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) {
-        parser_free();
+      if (HTTP_PARSER_ERRNO(&parser) == HPE_STRICT) {
         return;
       }
 
-      assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED);
+      assert (HTTP_PARSER_ERRNO(&parser) == HPE_PAUSED);
     }
 
     buf += nread;
     buflen -= nread;
-    http_parser_pause(parser, 0);
+    http_parser_pause(&parser, 0);
   } while (buflen > 0);
 
   nread = parse_pause(NULL, 0);
@@ -4086,8 +4184,6 @@ test:
   }
 
   if(!message_eq(0, 0, msg)) abort();
-
-  parser_free();
 }
 
 /* Verify that body and next message won't be parsed in responses to CONNECT */
@@ -4107,17 +4203,12 @@ test_message_connect (const struct messa
   }
 
   if(!message_eq(0, 1, msg)) abort();
-
-  parser_free();
 }
 
 int
 main (void)
 {
-  parser = NULL;
-  int i, j, k;
-  int request_count;
-  int response_count;
+  unsigned i, j, k;
   unsigned long version;
   unsigned major;
   unsigned minor;
@@ -4131,13 +4222,11 @@ main (void)
 
   printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser));
 
-  for (request_count = 0; requests[request_count].name; request_count++);
-  for (response_count = 0; responses[response_count].name; response_count++);
-
   //// API
   test_preserve_data();
   test_parse_url();
   test_method_str();
+  test_status_str();
 
   //// NREAD
   test_header_nread_value();
@@ -4170,6 +4259,13 @@ main (void)
 
   test_simple_type(
       "POST / HTTP/1.1\r\n"
+      "Content-Length:\r\n"  // empty
+      "\r\n",
+      HPE_INVALID_CONTENT_LENGTH,
+      HTTP_REQUEST);
+
+  test_simple_type(
+      "POST / HTTP/1.1\r\n"
       "Content-Length:  42 \r\n"  // Note the surrounding whitespace.
       "\r\n",
       HPE_OK,
@@ -4189,6 +4285,20 @@ main (void)
       HPE_INVALID_CONTENT_LENGTH,
       HTTP_REQUEST);
 
+  test_simple_type(
+      "POST / HTTP/1.1\r\n"
+      "Content-Length:  42\r\n"
+      " Hello world!\r\n",
+      HPE_INVALID_CONTENT_LENGTH,
+      HTTP_REQUEST);
+
+  test_simple_type(
+      "POST / HTTP/1.1\r\n"
+      "Content-Length:  42\r\n"
+      " \r\n",
+      HPE_OK,
+      HTTP_REQUEST);
+
   //// RESPONSES
 
   test_simple_type("HTP/1.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
@@ -4196,24 +4306,25 @@ main (void)
   test_simple_type("HTTP/11.1 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
   test_simple_type("HTTP/1.01 200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
   test_simple_type("HTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
+  test_simple_type("\rHTTP/1.1\t200 OK\r\n\r\n", HPE_INVALID_VERSION, HTTP_RESPONSE);
 
-  for (i = 0; i < response_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(responses); i++) {
     test_message(&responses[i]);
   }
 
-  for (i = 0; i < response_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(responses); i++) {
     test_message_pause(&responses[i]);
   }
 
-  for (i = 0; i < response_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(responses); i++) {
     test_message_connect(&responses[i]);
   }
 
-  for (i = 0; i < response_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(responses); i++) {
     if (!responses[i].should_keep_alive) continue;
-    for (j = 0; j < response_count; j++) {
+    for (j = 0; j < ARRAY_SIZE(responses); j++) {
       if (!responses[j].should_keep_alive) continue;
-      for (k = 0; k < response_count; k++) {
+      for (k = 0; k < ARRAY_SIZE(responses); k++) {
         test_multiple3(&responses[i], &responses[j], &responses[k]);
       }
     }
@@ -4273,11 +4384,16 @@ main (void)
 
   /// REQUESTS
 
+  test_simple("GET / IHTTP/1.0\r\n\r\n", HPE_INVALID_CONSTANT);
+  test_simple("GET / ICE/1.0\r\n\r\n", HPE_INVALID_CONSTANT);
   test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION);
   test_simple("GET / HTTP/01.1\r\n\r\n", HPE_INVALID_VERSION);
   test_simple("GET / HTTP/11.1\r\n\r\n", HPE_INVALID_VERSION);
   test_simple("GET / HTTP/1.01\r\n\r\n", HPE_INVALID_VERSION);
 
+  test_simple("GET / HTTP/1.0\r\nHello: w\1rld\r\n\r\n", HPE_INVALID_HEADER_TOKEN);
+  test_simple("GET / HTTP/1.0\r\nHello: woooo\2rld\r\n\r\n", HPE_INVALID_HEADER_TOKEN);
+
   // Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js
   test_simple("GET / HTTP/1.1\r\n"
               "Test: Düsseldorf\r\n",
@@ -4291,6 +4407,12 @@ main (void)
               "fooba",
               HPE_OK);
 
+  // Unknown Transfer-Encoding in request
+  test_simple("GET / HTTP/1.1\r\n"
+              "Transfer-Encoding: unknown\r\n"
+              "\r\n",
+              HPE_INVALID_TRANSFER_ENCODING);
+
   static const char *all_methods[] = {
     "DELETE",
     "GET",
@@ -4360,9 +4482,9 @@ main (void)
               "\r\n",
               HPE_INVALID_HEADER_TOKEN);
 
-  const char *dumbfuck2 =
+  const char *dumbluck2 =
     "GET / HTTP/1.1\r\n"
-    "X-SSL-Bullshit:   -----BEGIN CERTIFICATE-----\r\n"
+    "X-SSL-Nonsense:   -----BEGIN CERTIFICATE-----\r\n"
     "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n"
     "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n"
     "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n"
@@ -4395,7 +4517,7 @@ main (void)
     "\tRA==\r\n"
     "\t-----END CERTIFICATE-----\r\n"
     "\r\n";
-  test_simple(dumbfuck2, HPE_OK);
+  test_simple(dumbluck2, HPE_OK);
 
   const char *corrupted_connection =
     "GET / HTTP/1.1\r\n"
@@ -4429,19 +4551,19 @@ main (void)
 
 
   /* check to make sure our predefined requests are okay */
-  for (i = 0; requests[i].name; i++) {
+  for (i = 0; i < ARRAY_SIZE(requests); i++) {
     test_message(&requests[i]);
   }
 
-  for (i = 0; i < request_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(requests); i++) {
     test_message_pause(&requests[i]);
   }
 
-  for (i = 0; i < request_count; i++) {
+  for (i = 0; i < ARRAY_SIZE(requests); i++) {
     if (!requests[i].should_keep_alive) continue;
-    for (j = 0; j < request_count; j++) {
+    for (j = 0; j < ARRAY_SIZE(requests); j++) {
       if (!requests[j].should_keep_alive) continue;
-      for (k = 0; k < request_count; k++) {
+      for (k = 0; k < ARRAY_SIZE(requests); k++) {
         test_multiple3(&requests[i], &requests[j], &requests[k]);
       }
     }
@@ -4462,7 +4584,7 @@ main (void)
   printf("request scan 3/4      ");
   test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END]
            , &requests[CHUNKED_W_TRAILING_HEADERS]
-           , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH]
+           , &requests[CHUNKED_W_NONSENSE_AFTER_LENGTH]
            );
 
   printf("request scan 4/4      ");
Index: node-v8.17.0/test/parallel/test-http-invalid-te.js
===================================================================
--- /dev/null
+++ node-v8.17.0/test/parallel/test-http-invalid-te.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const common = require('../common');
+
+// Test https://hackerone.com/reports/735748 is fixed.
+
+const assert = require('assert');
+const http = require('http');
+const net = require('net');
+
+const REQUEST_BB = `POST / HTTP/1.1
+Content-Type: text/plain; charset=utf-8
+Host: hacker.exploit.com
+Connection: keep-alive
+Content-Length: 10
+Transfer-Encoding: chunked, eee
+
+HELLOWORLDPOST / HTTP/1.1
+Content-Type: text/plain; charset=utf-8
+Host: hacker.exploit.com
+Connection: keep-alive
+Content-Length: 28
+
+I AM A SMUGGLED REQUEST!!!
+`;
+
+const server = http.createServer(common.mustNotCall());
+
+server.on('clientError', common.mustCall((err) => {
+  assert.strictEqual(err.code, 'HPE_UNEXPECTED_CONTENT_LENGTH');
+  server.close();
+}));
+
+server.listen(0, common.mustCall(() => {
+  const client = net.connect(
+    server.address().port,
+    common.mustCall(() => {
+      client.end(REQUEST_BB.replace(/\n/g, '\r\n'));
+    }));
+}));
Index: node-v8.17.0/test/parallel/test-http-insecure-parser.js
===================================================================
--- /dev/null
+++ node-v8.17.0/test/parallel/test-http-insecure-parser.js
@@ -0,0 +1,35 @@
+// Flags: --insecure-http-parser
+
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+const net = require('net');
+
+const server = http.createServer(function(req, res) {
+  assert.strictEqual(req.headers['content-type'], 'text/te\bt');
+  req.pipe(res);
+});
+
+server.listen(0, common.mustCall(function() {
+  const bufs = [];
+  const client = net.connect(
+    this.address().port,
+    function() {
+      client.write(
+        'GET / HTTP/1.1\r\n' +
+        'Content-Type: text/te\x08t\r\n' +
+        'Connection: close\r\n\r\n');
+    }
+  );
+  client.on('data', function(chunk) {
+    bufs.push(chunk);
+  });
+  client.on('end', common.mustCall(function() {
+    const head = Buffer.concat(bufs)
+      .toString('latin1')
+      .split('\r\n')[0];
+    assert.strictEqual(head, 'HTTP/1.1 200 OK');
+    server.close();
+  }));
+}));
Index: node-v8.17.0/doc/api/cli.md
===================================================================
--- node-v8.17.0.orig/doc/api/cli.md
+++ node-v8.17.0/doc/api/cli.md
@@ -412,6 +412,17 @@ added: v8.15.0
 
 Specify the maximum size, in bytes, of HTTP headers. Defaults to 8KB.
 
+### `--insecure-http-parser`
+<!-- YAML
+added: REPLACEME
+-->
+
+Use an insecure HTTP parser that accepts invalid HTTP headers. This may allow
+interoperability with non-conformant HTTP implementations. It may also allow
+request smuggling and other HTTP attacks that rely on invalid headers being
+accepted. Avoid using this option.
+
+
 ## Environment Variables
 
 ### `NODE_DEBUG=module[,…]`
Index: node-v8.17.0/doc/node.1
===================================================================
--- node-v8.17.0.orig/doc/node.1
+++ node-v8.17.0/doc/node.1
@@ -115,6 +115,13 @@ Set the host:port to be used when the in
 Specify the maximum size of HTTP headers in bytes. Defaults to 8KB.
 
 .TP
+.BR \-\-insecure\-http\-parser
+Use an insecure HTTP parser that accepts invalid HTTP headers. This may allow
+interoperability with non-conformant HTTP implementations. It may also allow
+request smuggling and other HTTP attacks that rely on invalid headers being
+accepted. Avoid using this option.
+
+.TP
 .BR \-\-no\-deprecation
 Silence deprecation warnings.
 
Index: node-v8.17.0/lib/_http_client.js
===================================================================
--- node-v8.17.0.orig/lib/_http_client.js
+++ node-v8.17.0/lib/_http_client.js
@@ -31,6 +31,7 @@ const {
   debug,
   freeParser,
   httpSocketSetup,
+  isLenient,
   parsers
 } = require('_http_common');
 const { OutgoingMessage } = require('_http_outgoing');
@@ -622,7 +623,7 @@ function tickOnSocket(req, socket) {
   var parser = parsers.alloc();
   req.socket = socket;
   req.connection = socket;
-  parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol]);
+  parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol], isLenient());
   if (process.domain) {
     process.domain.add(parser);
   }
Index: node-v8.17.0/lib/_http_common.js
===================================================================
--- node-v8.17.0.orig/lib/_http_common.js
+++ node-v8.17.0/lib/_http_common.js
@@ -164,7 +164,7 @@ function parserOnMessageComplete() {
 
 
 var parsers = new FreeList('parsers', 1000, function() {
-  var parser = new HTTPParser(HTTPParser.REQUEST);
+  var parser = new HTTPParser(HTTPParser.REQUEST, isLenient());
 
   parser._headers = [];
   parser._url = '';
@@ -353,6 +353,16 @@ function checkInvalidHeaderChar(val) {
   return false;
 }
 
+let warnedLenient = false;
+
+function isLenient() {
+  if (process.insecureHttpParser && !warnedLenient) {
+    warnedLenient = true;
+    process.emitWarning('Using insecure HTTP parsing');
+  }
+  return !!process.insecureHttpParser;
+}
+
 module.exports = {
   _checkInvalidHeaderChar: checkInvalidHeaderChar,
   _checkIsHttpToken: checkIsHttpToken,
@@ -364,5 +374,6 @@ module.exports = {
   httpSocketSetup,
   methods,
   parsers,
-  kIncomingMessage
+  kIncomingMessage,
+  isLenient
 };
Index: node-v8.17.0/lib/_http_server.js
===================================================================
--- node-v8.17.0.orig/lib/_http_server.js
+++ node-v8.17.0/lib/_http_server.js
@@ -34,6 +34,7 @@ const {
   chunkExpression,
   httpSocketSetup,
   kIncomingMessage,
+  isLenient,
   _checkInvalidHeaderChar: checkInvalidHeaderChar
 } = require('_http_common');
 const { OutgoingMessage } = require('_http_outgoing');
@@ -333,7 +334,7 @@ function connectionListenerInternal(serv
   socket.on('timeout', socketOnTimeout);
 
   var parser = parsers.alloc();
-  parser.reinitialize(HTTPParser.REQUEST, parser[is_reused_symbol]);
+  parser.reinitialize(HTTPParser.REQUEST, parser[is_reused_symbol], isLenient());
   parser.socket = socket;
 
   // We are starting to wait for our headers.
Index: node-v8.17.0/src/node.cc
===================================================================
--- node-v8.17.0.orig/src/node.cc
+++ node-v8.17.0/src/node.cc
@@ -206,6 +206,8 @@ uint64_t max_http_header_size = 8 * 1024
 // used by C++ modules as well
 bool no_deprecation = false;
 
+bool insecure_http_parser = false;
+
 #if HAVE_OPENSSL
 // use OpenSSL's cert store instead of bundled certs
 bool ssl_openssl_cert_store =
@@ -2865,6 +2867,11 @@ void SetupProcessObject(Environment* env
     READONLY_PROPERTY(process, "noDeprecation", True(env->isolate()));
   }
 
+  // --insecure-http-parser
+  if (insecure_http_parser) {
+    READONLY_PROPERTY(process, "insecureHttpParser", True(env->isolate()));
+  }
+
   // --no-warnings
   if (no_process_warnings) {
     READONLY_PROPERTY(process, "noProcessWarnings", True(env->isolate()));
@@ -3403,6 +3410,8 @@ static void ParseArgs(int* argc,
       force_repl = true;
     } else if (strcmp(arg, "--no-deprecation") == 0) {
       no_deprecation = true;
+    } else if (strcmp(arg, "--insecure-http-parser") == 0) {
+      insecure_http_parser = true;
     } else if (strcmp(arg, "--napi-modules") == 0) {
       // no-op
     } else if (strcmp(arg, "--no-warnings") == 0) {
Index: node-v8.17.0/src/node_http_parser.cc
===================================================================
--- node-v8.17.0.orig/src/node_http_parser.cc
+++ node-v8.17.0/src/node_http_parser.cc
@@ -161,12 +161,12 @@ struct StringPtr {
 
 class Parser : public AsyncWrap {
  public:
-  Parser(Environment* env, Local<Object> wrap, enum http_parser_type type)
+  Parser(Environment* env, Local<Object> wrap, enum http_parser_type type, bool lenient)
       : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
         current_buffer_len_(0),
         current_buffer_data_(nullptr) {
     Wrap(object(), this);
-    Init(type);
+    Init(type, lenient);
   }
 
 
@@ -383,7 +383,7 @@ class Parser : public AsyncWrap {
     http_parser_type type =
         static_cast<http_parser_type>(args[0]->Int32Value());
     CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
-    new Parser(env, args.This(), type);
+    new Parser(env, args.This(), type, args[1]->IsTrue());
   }
 
 
@@ -476,6 +476,7 @@ class Parser : public AsyncWrap {
 
   static void Reinitialize(const FunctionCallbackInfo<Value>& args) {
     Environment* env = Environment::GetCurrent(args);
+    bool lenient = args[2]->IsTrue();
 
     CHECK(args[0]->IsInt32());
     CHECK(args[1]->IsBoolean());
@@ -494,7 +495,7 @@ class Parser : public AsyncWrap {
     if (isReused) {
       parser->AsyncReset();
     }
-    parser->Init(type);
+    parser->Init(type, lenient);
   }
 
 
@@ -738,8 +739,9 @@ class Parser : public AsyncWrap {
   }
 
 
-  void Init(enum http_parser_type type) {
+  void Init(enum http_parser_type type, bool lenient) {
     http_parser_init(&parser_, type);
+    parser_.lenient_http_headers = lenient;
     url_.Reset();
     status_message_.Reset();
     num_fields_ = 0;
Index: node-v8.17.0/src/node.h
===================================================================
--- node-v8.17.0.orig/src/node.h
+++ node-v8.17.0/src/node.h
@@ -197,6 +197,7 @@ typedef intptr_t ssize_t;
 namespace node {
 
 NODE_EXTERN extern bool no_deprecation;
+NODE_EXTERN extern bool insecure_http_parser;
 #if HAVE_OPENSSL
 NODE_EXTERN extern bool ssl_openssl_cert_store;
 # if NODE_FIPS_MODE