Imported Upstream version 1.41.0
authorSeonah Moon <seonah1.moon@samsung.com>
Wed, 10 Jun 2020 05:00:43 +0000 (14:00 +0900)
committerSeonah Moon <seonah1.moon@samsung.com>
Wed, 10 Jun 2020 05:00:58 +0000 (14:00 +0900)
Change-Id: I8982758c4e5db3aaf3aa4b4c3de419df99ba7118

53 files changed:
AUTHORS
CMakeLists.txt
ChangeLog
configure
configure.ac
doc/CMakeLists.txt
doc/Makefile.am
doc/Makefile.in
doc/bash_completion/h2load
doc/enums.rst
doc/h2load.1
doc/h2load.1.rst
doc/macros.rst
doc/nghttp.1
doc/nghttp2_option_set_max_settings.rst [new file with mode: 0644]
doc/nghttpd.1
doc/nghttpx.1
doc/nghttpx.1.rst
doc/sources/contribute.rst
doc/sources/nghttpx-howto.rst
doc/sources/tutorial-client.rst
integration-tests/nghttpx_http2_test.go
integration-tests/server_tester.go
lib/CMakeLists.txt
lib/includes/nghttp2/nghttp2.h
lib/includes/nghttp2/nghttp2ver.h
lib/nghttp2_helper.c
lib/nghttp2_option.c
lib/nghttp2_option.h
lib/nghttp2_session.c
lib/nghttp2_session.h
lib/nghttp2_submit.c
ltmain.sh
m4/libtool.m4
python/Makefile.in
src/h2load.cc
src/h2load.h
src/shrpx-unittest.cc
src/shrpx.cc
src/shrpx_client_handler.cc
src/shrpx_client_handler.h
src/shrpx_tls.cc
src/util.cc
src/util.h
src/util_test.cc
src/util_test.h
tests/main.c
tests/nghttp2_session_test.c
tests/nghttp2_session_test.h
third-party/llhttp/include/llhttp.h
third-party/llhttp/src/api.c
third-party/llhttp/src/http.c
third-party/llhttp/src/llhttp.c

diff --git a/AUTHORS b/AUTHORS
index 4da9664..4536741 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -45,9 +45,13 @@ Etienne Cimon
 Fabian Möller
 Fabian Wiesel
 Gabi Davar
+Gaël PORTAY
+Geoff Hill
 Gitai
 Google Inc.
+Jacky Tian
 Jacob Champion
+James M Snell
 Jan Kundrát
 Jan-E
 Janusz Dziemidowicz
@@ -64,6 +68,7 @@ Kenny Peng
 Kit Chan
 Kyle Schomp
 LazyHamster
+Leo Neat
 Lucas Pardue
 MATSUMOTO Ryosuke
 Marc Bachmann
index 741d449..69c2c7b 100644 (file)
 
 cmake_minimum_required(VERSION 3.0)
 # XXX using 1.8.90 instead of 1.9.0-DEV
-project(nghttp2 VERSION 1.40.0)
+project(nghttp2 VERSION 1.41.0)
 
 # See versioning rule:
 #  http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
-set(LT_CURRENT  33)
+set(LT_CURRENT  34)
 set(LT_REVISION 0)
-set(LT_AGE      19)
+set(LT_AGE      20)
 
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
 include(Version)
index c17e088..3e04f08 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
-commit cc05c5fe8cfc8287ddc4930fa9684af878d9e631 (HEAD, tag: v1.40.0, origin/master, origin/HEAD, master)
+commit 8f7b008b158e12de0e58247afd170f127dbb6456 (HEAD, tag: v1.41.0, origin/master, origin/HEAD, master)
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-11-15
+AuthorDate: 2020-06-02
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-11-15
+CommitDate: 2020-06-02
+
+    Update bash_completion
+
+commit 83086ba91a20a444a3b151bd5e0f55037795a31a
+Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
+AuthorDate: 2020-06-02
+Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
+CommitDate: 2020-06-02
 
     Update manual pages
 
-commit 66d7b194d4e27c8a316cbc5e8dca1722394401a9
+commit c3b46625633cd9a4519f6fbcd9048127b84a5514
+Merge: 3eecc2ca f8da73bd
+Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+AuthorDate: 2020-06-02
+Commit:     GitHub <noreply@github.com>
+CommitDate: 2020-06-02
+
+    Merge pull request from GHSA-q5wr-xfw9-q7xr
+    
+    Implement max settings option
+
+commit 3eecc2ca45530024abb687bf808ec768eaa5e98a
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-11-15
+AuthorDate: 2020-06-02
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-11-15
+CommitDate: 2020-06-02
 
-    Update AUTHORS
+    Bump version number to v1.41.0, LT revision to 34:0:20
 
-commit 41060943bdeff0ed575e3f0c011a0df17b9d8027
+commit 881c060d8c92c5246d9a6b5829e63838869bbaa9
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-11-15
+AuthorDate: 2020-06-02
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-11-15
+CommitDate: 2020-06-02
+
+    Update AUTHORS
+
+commit f8da73bd042f810f34d19f9eae02b46d870af394
+Author:     James M Snell <jasnell@gmail.com>
+AuthorDate: 2020-04-19
+Commit:     James M Snell <jasnell@gmail.com>
+CommitDate: 2020-05-05
 
-    Bump up version number to 1.40.0, LT revision to 33:0:19
+    Earlier check for settings flood
 
-commit 5ae9bb8925c1cb1e945b41d140367f27b3dd5c98
+commit 336a98feb0d56b9ac54e12736b18785c27f75090
+Author:     James M Snell <jasnell@gmail.com>
+AuthorDate: 2020-04-17
+Commit:     James M Snell <jasnell@gmail.com>
+CommitDate: 2020-05-05
+
+    Implement max settings option
+
+commit ef41583614e95efd12b6cce821e34837c1b28ed0
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-11-09
+AuthorDate: 2020-04-22
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-11-09
+CommitDate: 2020-04-22
 
-    Fail fast if huffman decoding context is in failure state
+    Revert "Add missing connection error handling"
+    
+    This reverts commit b7d16101413276884d7f51c64f989f5f61abecb8.
 
-commit bb519154fe62f7ff7e5eb7269e05043dec6d3682
-Merge: db9a8f6e 77f5487a
+commit 979e6c5325826d06922f25047ffafb7ed92fa749
+Merge: b7d16101 c663349f
 Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-11-02
+AuthorDate: 2020-04-21
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-11-02
+CommitDate: 2020-04-21
 
-    Merge pull request #1413 from nghttp2/check-authority
+    Merge pull request #1459 from nghttp2/proxyprotov2
     
-    Add nghttp2_check_authority as public API
+    nghttpx: Add PROXY protocol version 2
 
-commit 77f5487a588f3c02a9671b7dd684186a5c34c1ea
+commit b7d16101413276884d7f51c64f989f5f61abecb8
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-11-02
+AuthorDate: 2020-04-21
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-11-02
+CommitDate: 2020-04-21
 
-    Add nghttp2_check_authority as public API
+    Add missing connection error handling
 
-commit db9a8f6efe6cc692e09c81fed200d159071566d1
-Merge: 6f28a69b 6ce4835e
+commit cd53bd81bfbf571a0f7836b5979e19702a76890f
+Merge: 3b17a659 e5625b8c
 Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-10-29
+AuthorDate: 2020-04-18
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-10-29
+CommitDate: 2020-04-18
 
-    Merge pull request #1409 from nghttp2/fix-wrong-stream-close-error-code
+    Merge pull request #1460 from gportay/patch-1
     
-    Fix the bug that stream is closed with wrong error code
+    Fix doc
 
-commit 6f28a69b7d5bd93b67e2ca7af04bf9fa0b3c5c89
-Merge: d08c4395 29042f1c
-Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-10-29
+commit e5625b8cf083b076c0fcb9d4b80749f30c75b4f7
+Author:     Gaël PORTAY <gael.portay@gmail.com>
+AuthorDate: 2020-04-18
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-10-29
+CommitDate: 2020-04-18
 
-    Merge pull request #1411 from richard78917/fix_warning
-    
-    priority_spec::valid(): remove const qualifier from return value
+    Fix doc
 
-commit 6ce4835eeafe5bcea91c9672fcd3f9ef68ebd472
+commit c663349f24b851865f4f1f5ca21de542a2e5c07f
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-10-29
+AuthorDate: 2020-04-18
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-10-29
+CommitDate: 2020-04-18
 
-    Fix the bug that stream is closed with wrong error code
-    
-    This commit fixes the bug that stream is closed with wrong error code
-    (0).  This happens when STREAM or DATA frame with END_STREAM flag set
-    is received and it violates HTTP messaging rule (i.e., content-length
-    does not match) and the other side of stream has been closed.  In this
-    case, nghttp2_on_stream_close_callback should be called with nonzero
-    error code, but previously it is called with 0 (NO_ERROR).
-
-commit 29042f1c95ef5d17fde7e8d972d2af24e47adf1b
-Author:     Richard Wolfert <richard.wolfert@mavenir.com>
-AuthorDate: 2019-10-29
-Commit:     Richard Wolfert <richard.wolfert@mavenir.com>
-CommitDate: 2019-10-29
-
-    priority_spec::valid(): remove const qualifier from return value
-    
-    gcc generates warning:
-    * type qualifiers ignored on function return type [-Wignored-qualifiers]
-
-commit d08c43951f5bf599dace882ed0e67ded2ff8519e
-Merge: 6f967c6e 5d6964cf
-Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-10-12
-Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-10-12
-
-    Merge pull request #1405 from nghttp2/huffman
-    
-    Faster Huffman encoding/decoding
+    integration: Add PROXY protocol v2 tests
 
-commit 5d6964cf81aaf41b4af5fdfbf4b06737bcb8f9a0
+commit 854e9fe395e928d31650a0f398897cc209064c90
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-10-08
+AuthorDate: 2020-04-18
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-10-12
+CommitDate: 2020-04-18
 
-    Faster huffman decoding
+    nghttpx: Always call init_forwarded_for
+    
+    Always call init_forwarded_for to get the default when source address
+    in PROXY protocol is ignored.  This ensures that forwarded header
+    field has the same value as x-forwarded-for.
 
-commit 0d855bfc1ba6e4201e21d7d130dbaad0907c8a3e
+commit c60ea227cc61294da0ea0355108c2f90d77f974a
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-10-08
+AuthorDate: 2020-04-18
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-10-12
+CommitDate: 2020-04-18
 
-    Faster huffman encoding
+    Update doc
 
-commit 6f967c6ef3ea5799b59a5cea6b6f4bec10d25b04
+commit 49cd8e6e733a74d52d442a3d2667fd130d6437c8
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-21
+AuthorDate: 2020-04-17
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-21
+CommitDate: 2020-04-18
 
-    Fix errors reported by coverity scan
+    nghttpx: Add PROXY-protocol v2 support
 
-commit b8a43db84c5ce9a91cede2f4faf4706c1b3f4010
-Merge: 70b62c1a 28b1f0b9
+commit 3b17a659f69fb2ef5d2239142437da2902e61911
+Merge: 600fcdf5 dc7a7df6
 Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-09-21
+AuthorDate: 2020-03-31
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-09-21
+CommitDate: 2020-03-31
 
-    Merge pull request #1394 from wrowe/fix-static-libname
+    Merge pull request #1453 from Leo-Neat/master
     
-    Avoid filename collision of static and dynamic lib
+    Add CIFuzz
 
-commit 70b62c1a32eb56edc67eae0609949e0830ec14ad
-Merge: 1dd966f1 72b71a6b
+commit 600fcdf52d60f67ecd936d61eaf0c7ecb8624075
+Merge: b3f85e2d 4922bb41
 Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-09-21
+AuthorDate: 2020-03-31
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-09-21
+CommitDate: 2020-03-31
 
-    Merge pull request #1393 from wrowe/fix-static-msvcrt
+    Merge pull request #1455 from xjtian/long_serials
     
-    Add new flag ENABLE_STATIC_CRT for Windows
+    Fix get_x509_serial for long serial numbers
 
-commit 28b1f0b90f82cccb3f1977ed3b580d2c98421f94
-Author:     William A Rowe Jr <wrowe@pivotal.io>
-AuthorDate: 2019-09-16
-Commit:     William A Rowe Jr <wrowe@pivotal.io>
-CommitDate: 2019-09-16
+commit 4922bb41d604a15483e12f1b33bac2bf6628d866
+Author:     Jacky Tian <xjtian@fb.com>
+AuthorDate: 2020-03-31
+Commit:     Jacky Tian <xjtian@fb.com>
+CommitDate: 2020-03-31
 
-    Avoid filename collision of static and dynamic lib
-    
-    Renames the output of the ENABLE_STATIC_LIB library/archive output
-    to nghttp2_static.lib/.a to avoid filenames colliding with the output
-    name for ENABLE_SHARED_LIB library/archive, when both are enabled.
-    
-    Signed-off-by: William A Rowe Jr <wrowe@pivotal.io>
-    Signed-off-by: Yechiel Kalmenson <ykalmenson@pivotal.io>
+    static_cast size parameter in StringRef constructor to size_t
 
-commit 1dd966f1897421fe10d1ad91cfe466526636fcad
-Merge: f8933fe5 fe8946dd
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-17
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-17
+commit aad8697575d90b1763c31ad06986be0550917aac
+Author:     Jacky Tian <xjtian@fb.com>
+AuthorDate: 2020-03-30
+Commit:     Jacky Tian <xjtian@fb.com>
+CommitDate: 2020-03-31
 
-    Merge branch 'fix-nghttpx-mruby'
+    Fix get_x509_serial for long serial numbers
 
-commit fe8946ddc7c081eb0b2f376fc99279121a3f2a8b
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-16
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-16
+commit dc7a7df61c7cd1cc05c9c09f827e564495c2bebe
+Author:     Leo Neat <lneat@google.com>
+AuthorDate: 2020-03-18
+Commit:     Leo Neat <lneat@google.com>
+CommitDate: 2020-03-18
 
-    nghttpx: Fix bug that mruby is incorrectly shared between backends
-    
-    Previously, mruby context is wrongly shared by multiple patterns if
-    the underlying SharedDownstreamAddr is shared by multiple
-    DownstreamAddrGroups.  This commit fixes it.
+    Adding CIFuzz
 
-commit 72b71a6ba3f843bdea27f5c1cf926a5e1b152e48
-Author:     William A Rowe Jr <wrowe@pivotal.io>
-AuthorDate: 2019-09-14
-Commit:     William A Rowe Jr <wrowe@pivotal.io>
-CommitDate: 2019-09-14
+commit b3f85e2daa629732ac3ebb092cd5543c26045e03
+Merge: ffb49c6c 2ec58551
+Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+AuthorDate: 2020-02-20
+Commit:     GitHub <noreply@github.com>
+CommitDate: 2020-02-20
 
-    Add new flag ENABLE_STATIC_CRT for Windows
-    
-    This change adds the CMake option;
-    
-      ENABLE_STATIC_CRT  Build libnghttp2 against the MS LIBCMT[d]
+    Merge pull request #1444 from nghttp2/fix-recv-window-flow-control-issue
     
-    This avoids linking to msvcrt.lib for binaries to compile (/MT[d])
-    and link against the static C Runtime libcrt.lib, and
-    avoiding the msvcrt[d].dll dependency.
-    
-    Signed-off-by: William A Rowe Jr <wrowe@pivotal.io>
-    Signed-off-by: Yechiel Kalmenson <ykalmenson@pivotal.io>
+    Fix receiving stream data stall
 
-commit f8933fe50468413eb149df7e331e7335400f1649
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-07
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-07
+commit ffb49c6c589617d6c9a4172464b9100b377e56f9
+Merge: 459df42b 866eadb5
+Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+AuthorDate: 2020-02-20
+Commit:     GitHub <noreply@github.com>
+CommitDate: 2020-02-20
 
-    nghttpx: Reconnect h1 backend if it lost connection before sending headers
+    Merge pull request #1435 from geoffhill/master
     
-    This is the second attempt.  The first attempt was
-    8a59ce6d37471ec7a437d4700cabd98c55115b1e and it failed.
+    Enable session_create_idle_stream test, fix errors
 
-commit 89c33d690fd4667dd07c5791638eb6a4653a7f73
+commit 2ec585518e83bec7de8deb0d429cd744d99fc72b
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-07
+AuthorDate: 2020-02-19
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-07
-
-    Update neverbleed
+CommitDate: 2020-02-20
 
-commit 7079dc5e753c1881aa6f162bbb4a9bb6d44e79ed
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-06
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-06
-
-    Update neverbleed to fix memory leak
-
-commit 5080db84e267d9b036c08ac7b2de8b7696c4d6b2
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-06
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-06
-
-    Revert "nghttpx: Reconnect h1 backend if it lost connection before sending headers"
+    Fix receiving stream data stall
     
-    This reverts commit 8a59ce6d37471ec7a437d4700cabd98c55115b1e.
-
-commit 053c7ac5889c280e1108b2bdd40c48d40920172a
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-03
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-03
-
-    nghttpx: Returns 408 if backend timed out before sending headers
-
-commit 8a59ce6d37471ec7a437d4700cabd98c55115b1e
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-09-03
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-09-03
-
-    nghttpx: Reconnect h1 backend if it lost connection before sending headers
+    Previously, if automatic window update is enabled (which is default),
+    after window size is set to 0 by
+    nghttp2_session_set_local_window_size, once the receiving window is
+    exhausted, even after window size is increased by
+    nghttp2_session_set_local_window_size, no more data cannot be
+    received.  This is because nghttp2_session_set_local_window_size does
+    not submit WINDOW_UPDATE.  It is only triggered when new data arrives
+    but since window is filled up, no more data cannot be received, thus
+    dead lock happens.
+    
+    This commit fixes this issue.  nghttp2_session_set_local_window_size
+    submits WINDOW_UPDATE if necessary.
+    
+    https://github.com/curl/curl/issues/4939
 
-commit f2fde180cdcca1f0a1c12d097c92510a887f6500
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-08-19
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-19
+commit 459df42b8b074dffd40ac1f95fc65ad099050a7a
+Merge: 5e13274b a4c1fed5
+Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
+AuthorDate: 2020-02-11
+Commit:     GitHub <noreply@github.com>
+CommitDate: 2020-02-11
 
-    Remove redundant null check before delete
+    Merge pull request #1442 from nghttp2/upgrade-llhttp
     
-    Reported in https://github.com/nghttp2/nghttp2/issues/1384
+    Bump llhttp to 2.0.4
 
-commit 95efb3e19d174354ca50c65d5d7227d92bcd60e1
+commit a4c1fed5139b2df7ce611a519a7b1d69aee3bae0
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-25
+AuthorDate: 2020-02-11
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-14
+CommitDate: 2020-02-11
 
-    Don't read too greedily
+    Bump llhttp to 2.0.4
 
-commit 0a6ce87c22c69438ecbffe52a2859c3a32f1620f
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-25
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-14
+commit 866eadb5de0f859d30272f5359a79c195271cd6c
+Author:     Geoff Hill <geoffhill@fb.com>
+AuthorDate: 2020-01-23
+Commit:     Geoff Hill <geoffhill@fb.com>
+CommitDate: 2020-01-23
 
-    Add nghttp2_option_set_max_outbound_ack
+    Enable session_create_idle_stream test, fix errors
+    
+    Add the currently-unused `test_nghttp2_session_create_idle_stream()`
+    function to the test suite definition.
+    
+    Modify the test in two places to make it pass:
+    
+      * Use stream ID=10 as the priority stream ID to test automatic creation
+        of streams for priority specs. The code below checks against stream
+        ID=10 so I assume this was a typo in the test.
+    
+      * Set the `last_sent_stream_id` instead of the `next_stream_id` to test
+        that idle streams cannot be created with smaller numbers than the
+        most-recently-seen stream ID. Looking at the validation path in
+        `session_detect_idle_stream()`, I think this was another test typo.
 
-commit 2aa79fa91d2714ad704277c1c027c7f18cdd94f0
+commit 5e13274b7c533b00f2a14582de5f6b34c08b0018
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-08-14
+AuthorDate: 2019-12-21
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-14
+CommitDate: 2019-12-21
 
-    Bump up LT revision to 32:0:18
+    Fix typo
 
-commit 3980678d24ff1bd84b95ec88d1acc07326af3e62
-Merge: 448bbbc3 319d5ab1
+commit e0d7f7de5e58b2e9abd92ee3384f78e91d018503
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-08-06
+AuthorDate: 2019-12-21
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-06
+CommitDate: 2019-12-21
 
-    Merge branch 'nghttpx-fix-request-stall'
+    h2load: Allow port in --connect-to
 
-commit 319d5ab1c6d916b6b8a0d85b2ae3f01b3ad04f2c
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-08-06
+commit df575f968fa3d82fb40c2637e7d3e245def43766
+Author:     lucas <lucas@cloudflare.com>
+AuthorDate: 2019-12-12
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-06
+CommitDate: 2019-12-21
 
-    nghttpx: Fix request stall
-    
-    Fix request stall if backend connection is reused and buffer is full.
+    h2load: add --connect-to option
 
-commit 448bbbc38c0f260447d0aae579d678885aa0f16c
+commit 1fff737955d3e080d4e4be9ecb615c83fd3fd767
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-08-06
+AuthorDate: 2019-12-18
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-08-06
+CommitDate: 2019-12-18
 
-    integration-tests: gofmt
+    clang-format-9
 
-commit e575a2aad99fe57126ad817c57356ea0ce51d213
-Merge: 7a590893 4f7aedc9
+commit b40c6c862fafe87fa32b28bf040456b064482893
+Merge: 2d5f7659 9bc2c75e
 Author:     Tatsuhiro Tsujikawa <404610+tatsuhiro-t@users.noreply.github.com>
-AuthorDate: 2019-08-01
+AuthorDate: 2019-12-08
 Commit:     GitHub <noreply@github.com>
-CommitDate: 2019-08-01
+CommitDate: 2019-12-08
 
-    Merge pull request #1377 from Aldrog/cmake_systemd
+    Merge pull request #1418 from vszakats/patch-1
     
-    Support building nghttpx with systemd using cmake
-
-commit 4f7aedc9d274183f4db17634d320a6d60ef2edb5
-Author:     Andrew Penkrat <Andrey.Penkrat@lanit-tercom.com>
-AuthorDate: 2019-07-29
-Commit:     Andrew Penkrat <Andrey.Penkrat@lanit-tercom.com>
-CommitDate: 2019-07-29
-
-    cmake: Support building nghttpx with systemd
-
-commit 7a5908933e55297ce2d8a0217391663ddf0c3f31
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-22
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-06-22
-
-    Fix clang-8 warning
-
-commit ee4431344511886efc66395a38b9bf5dddd7151b
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-11
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-06-11
-
-    Fix FPE with default backend
+    lib/CMakeLists.txt: Make hard-coded static lib suffix optional
 
-commit abef9b90ef2ba35ec25adbca7cb8d0b9a6c2d044
-Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-11
-Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-06-11
+commit 9bc2c75e388fbb5e6e694ef4471bd63521c966ae
+Author:     Viktor Szakats <vszakats@users.noreply.github.com>
+AuthorDate: 2019-11-15
+Commit:     Viktor Szakats <commit@vsz.me>
+CommitDate: 2019-11-15
 
-    Fix log-level is not set with cmd-line or configuration file
+    lib/CMakeLists.txt: Make hard-coded static lib suffix optional
+    
+    It can be set via the `STATIC_LIB_SUFFIX` variable.
+    
+    This fixes every existing dependent project that relied on the name
+    having no suffix and thus capable of using either a static or shared
+    flavour depending on which one is present on this or how the linker
+    is configured.
+    
+    Ref: https://github.com/nghttp2/nghttp2/pull/1394
 
-commit 12a999f0b8bc67706fdd5ff9b134ab67d495c76a
+commit 2d5f76594a8c4e11d6e2a70588c01433f214150b
 Author:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-AuthorDate: 2019-06-11
+AuthorDate: 2019-11-15
 Commit:     Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>
-CommitDate: 2019-06-11
+CommitDate: 2019-11-15
 
-    Bump up version number to 1.40.0-DEV
+    Bump up version number to 1.41.0-DEV
index 696af86..6d789f7 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for nghttp2 1.40.0.
+# Generated by GNU Autoconf 2.69 for nghttp2 1.41.0.
 #
 # Report bugs to <t-tujikawa@users.sourceforge.net>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='nghttp2'
 PACKAGE_TARNAME='nghttp2'
-PACKAGE_VERSION='1.40.0'
-PACKAGE_STRING='nghttp2 1.40.0'
+PACKAGE_VERSION='1.41.0'
+PACKAGE_STRING='nghttp2 1.41.0'
 PACKAGE_BUGREPORT='t-tujikawa@users.sourceforge.net'
 PACKAGE_URL=''
 
@@ -1464,7 +1464,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures nghttp2 1.40.0 to adapt to many kinds of systems.
+\`configure' configures nghttp2 1.41.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1536,7 +1536,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of nghttp2 1.40.0:";;
+     short | recursive ) echo "Configuration of nghttp2 1.41.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1732,7 +1732,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-nghttp2 configure 1.40.0
+nghttp2 configure 1.41.0
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2692,7 +2692,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by nghttp2 $as_me 1.40.0, which was
+It was created by nghttp2 $as_me 1.41.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -5925,7 +5925,7 @@ esac
 fi
 
 : ${AR=ar}
-: ${AR_FLAGS=cru}
+: ${AR_FLAGS=cr}
 
 
 
@@ -7688,8 +7688,8 @@ int forced_loaded() { return 2;}
 _LT_EOF
       echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
       $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
-      echo "$AR cru libconftest.a conftest.o" >&5
-      $AR cru libconftest.a conftest.o 2>&5
+      echo "$AR cr libconftest.a conftest.o" >&5
+      $AR cr libconftest.a conftest.o 2>&5
       echo "$RANLIB libconftest.a" >&5
       $RANLIB libconftest.a 2>&5
       cat > conftest.c << _LT_EOF
@@ -12663,7 +12663,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='nghttp2'
- VERSION='1.40.0'
+ VERSION='1.41.0'
 
 
 cat >>confdefs.h <<_ACEOF
 AM_BACKSLASH='\'
 
 
-LT_CURRENT=33
+LT_CURRENT=34
 
 LT_REVISION=0
 
-LT_AGE=19
+LT_AGE=20
 
 
 major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/^0-9//g"`
@@ -24922,7 +24922,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by nghttp2 $as_me 1.40.0, which was
+This file was extended by nghttp2 $as_me 1.41.0, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24988,7 +24988,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-nghttp2 config.status 1.40.0
+nghttp2 config.status 1.41.0
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 08a7bee..961b78d 100644 (file)
@@ -25,7 +25,7 @@ dnl Do not change user variables!
 dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
 
 AC_PREREQ(2.61)
-AC_INIT([nghttp2], [1.40.0], [t-tujikawa@users.sourceforge.net])
+AC_INIT([nghttp2], [1.41.0], [t-tujikawa@users.sourceforge.net])
 AC_CONFIG_AUX_DIR([.])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
@@ -44,9 +44,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
 dnl See versioning rule:
 dnl  http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
-AC_SUBST(LT_CURRENT, 33)
+AC_SUBST(LT_CURRENT, 34)
 AC_SUBST(LT_REVISION, 0)
-AC_SUBST(LT_AGE, 19)
+AC_SUBST(LT_AGE, 20)
 
 major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
 minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
index 34c0279..f3aec84 100644 (file)
@@ -42,6 +42,7 @@ set(APIDOCS
   nghttp2_option_set_no_recv_client_magic.rst
   nghttp2_option_set_peer_max_concurrent_streams.rst
   nghttp2_option_set_user_recv_extension_type.rst
+  nghttp2_option_set_max_settings.rst
   nghttp2_pack_settings_payload.rst
   nghttp2_priority_spec_check_default.rst
   nghttp2_priority_spec_default_init.rst
index 4d73cef..f073bfa 100644 (file)
@@ -69,6 +69,7 @@ APIDOCS= \
        nghttp2_option_set_peer_max_concurrent_streams.rst \
        nghttp2_option_set_user_recv_extension_type.rst \
        nghttp2_option_set_max_outbound_ack.rst \
+       nghttp2_option_set_max_settings.rst \
        nghttp2_pack_settings_payload.rst \
        nghttp2_priority_spec_check_default.rst \
        nghttp2_priority_spec_default_init.rst \
index 0c30bf2..db35c52 100644 (file)
@@ -426,6 +426,7 @@ APIDOCS = \
        nghttp2_option_set_peer_max_concurrent_streams.rst \
        nghttp2_option_set_user_recv_extension_type.rst \
        nghttp2_option_set_max_outbound_ack.rst \
+       nghttp2_option_set_max_settings.rst \
        nghttp2_pack_settings_payload.rst \
        nghttp2_priority_spec_check_default.rst \
        nghttp2_priority_spec_default_init.rst \
index 3022d45..a737a49 100644 (file)
@@ -8,7 +8,7 @@ _h2load()
     _get_comp_words_by_ref cur prev
     case $cur in
         -*)
-            COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --header-table-size --requests --log-file --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
+            COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --connect-to --header-table-size --requests --log-file --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
             ;;
         *)
             _filedir
index 866b2b9..cfdb5d4 100644 (file)
@@ -170,6 +170,11 @@ Enums
         (``-536``) 
         When a local endpoint expects to receive SETTINGS frame, it
         receives an other type of frame.
+    .. macro:: NGHTTP2_ERR_TOO_MANY_SETTINGS
+
+        (``-537``) 
+        When a local endpoint receives too many settings entries
+        in a single SETTINGS frame.
     .. macro:: NGHTTP2_ERR_FATAL
 
         (``-900``) 
index d47e8b8..1070ebb 100644 (file)
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "H2LOAD" "1" "Nov 15, 2019" "1.40.0" "nghttp2"
+.TH "H2LOAD" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
 .SH NAME
 h2load \- HTTP/2 benchmarking tool
 .
@@ -284,6 +284,12 @@ to buffering.  Status code is \-1 for failed streams.
 .UNINDENT
 .INDENT 0.0
 .TP
+.B \-\-connect\-to=<HOST>[:<PORT>]
+Host and port to connect  instead of using the authority
+in <URI>.
+.UNINDENT
+.INDENT 0.0
+.TP
 .B \-v, \-\-verbose
 Output debug information.
 .UNINDENT
index 3edc9d9..265ae83 100644 (file)
@@ -239,6 +239,11 @@ OPTIONS
     appear slightly  out of order with  multiple threads due
     to buffering.  Status code is -1 for failed streams.
 
+.. option:: --connect-to=<HOST>[:<PORT>]
+
+    Host and port to connect  instead of using the authority
+    in <URI>.
+
 .. option:: -v, --verbose
 
     Output debug information.
index 1c2b15e..583e745 100644 (file)
@@ -81,6 +81,10 @@ Macros
 
     
     The length of :macro:`NGHTTP2_CLIENT_MAGIC`.
+.. macro:: NGHTTP2_DEFAULT_MAX_SETTINGS
+
+    
+    The default max number of settings per SETTINGS frame
 .. macro:: NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS
 
     
index d34cf1e..8b8237d 100644 (file)
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "NGHTTP" "1" "Nov 15, 2019" "1.40.0" "nghttp2"
+.TH "NGHTTP" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
 .SH NAME
 nghttp \- HTTP/2 client
 .
diff --git a/doc/nghttp2_option_set_max_settings.rst b/doc/nghttp2_option_set_max_settings.rst
new file mode 100644 (file)
index 0000000..ba325e7
--- /dev/null
@@ -0,0 +1,16 @@
+
+nghttp2_option_set_max_settings
+===============================
+
+Synopsis
+--------
+
+*#include <nghttp2/nghttp2.h>*
+
+.. function:: void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val)
+
+    
+    This function sets the maximum number of SETTINGS entries per
+    SETTINGS frame that will be accepted. If more than those entries
+    are received, the peer is considered to be misbehaving and session
+    will be closed. The default value is 32.
index 315d50b..fb46e54 100644 (file)
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "NGHTTPD" "1" "Nov 15, 2019" "1.40.0" "nghttp2"
+.TH "NGHTTPD" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
 .SH NAME
 nghttpd \- HTTP/2 server
 .
index 9f18c70..c101661 100644 (file)
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH "NGHTTPX" "1" "Nov 15, 2019" "1.40.0" "nghttp2"
+.TH "NGHTTPX" "1" "Jun 02, 2020" "1.41.0" "nghttp2"
 .SH NAME
 nghttpx \- HTTP/2 proxy
 .
@@ -316,7 +316,7 @@ specify  "healthmon"  parameter.   This is  disabled  by
 default.  Any  requests which come through  this address
 are replied with 200 HTTP status, without no body.
 .sp
-To  accept   PROXY  protocol   version  1   on  frontend
+To accept  PROXY protocol  version 1  and 2  on frontend
 connection,  specify  "proxyproto" parameter.   This  is
 disabled by default.
 .sp
index 67ebff0..5259eb9 100644 (file)
@@ -300,7 +300,7 @@ Connections
     default.  Any  requests which come through  this address
     are replied with 200 HTTP status, without no body.
 
-    To  accept   PROXY  protocol   version  1   on  frontend
+    To accept  PROXY protocol  version 1  and 2  on frontend
     connection,  specify  "proxyproto" parameter.   This  is
     disabled by default.
 
index bea72b1..b2aa9d0 100644 (file)
@@ -26,14 +26,14 @@ Coding style
 We use clang-format to format source code consistently.  The
 clang-format configuration file .clang-format is located at the root
 directory.  Since clang-format produces slightly different results
-between versions, we currently use clang-format-8.
+between versions, we currently use clang-format-9.
 
 To detect any violation to the coding style, we recommend to setup git
 pre-commit hook to check coding style of the changes you introduced.
 The pre-commit file is located at the root directory.  Copy it under
 .git/hooks and make sure that it is executable.  The pre-commit script
 uses clang-format-diff.py to detect any style errors.  If it is not in
-your PATH or it exists under different name (e.g., clang-format-diff-8
+your PATH or it exists under different name (e.g., clang-format-diff-9
 in debian), either add it to PATH variable or add git option
 ``clangformatdiff.binary`` to point to the script.
 
index 11d3eb0..bbb7c20 100644 (file)
@@ -401,6 +401,9 @@ like so:
 
    frontend=*,443;proxyproto
 
+nghttpx supports both PROXY protocol v1 and v2.  AF_UNIX in PROXY
+protocol version 2 is ignored.
+
 Session affinity
 ----------------
 
index 46fc34b..7c086a8 100644 (file)
@@ -422,7 +422,7 @@ the ``on_header_callback()`` is called for each name/value pair::
       return 0;
     }
 
-In this tutorial, we just print the name/value pairs on stdout.
+In this tutorial, we just print the name/value pairs on stderr.
 
 After the HEADERS frame has been fully received (and thus all response
 header name/value pairs have been received), the
index 0698dd2..84646fa 100644 (file)
@@ -9,6 +9,7 @@ import (
        "golang.org/x/net/http2/hpack"
        "io"
        "io/ioutil"
+       "net"
        "net/http"
        "regexp"
        "strings"
@@ -1506,6 +1507,235 @@ func TestH2H1ProxyProtocolV1InvalidID(t *testing.T) {
        }
 }
 
+// TestH2H1ProxyProtocolV2TCP4 tests PROXY protocol version 2
+// containing AF_INET family is accepted and X-Forwarded-For contains
+// advertised src address.
+func TestH2H1ProxyProtocolV2TCP4(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
+               if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
+                       t.Errorf("X-Forwarded-For: %v; want %v", got, want)
+               }
+               if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
+                       t.Errorf("Forwarded: %v; want %v", got, want)
+               }
+       })
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command: proxyProtocolV2CommandProxy,
+               sourceAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.2").To4(),
+                       Port: 12345,
+               },
+               destinationAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.100").To4(),
+                       Port: 8080,
+               },
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       res, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2TCP4",
+       })
+
+       if err != nil {
+               t.Fatalf("Error st.http2() = %v", err)
+       }
+
+       if got, want := res.status, 200; got != want {
+               t.Errorf("res.status: %v; want %v", got, want)
+       }
+}
+
+// TestH2H1ProxyProtocolV2TCP6 tests PROXY protocol version 2
+// containing AF_INET6 family is accepted and X-Forwarded-For contains
+// advertised src address.
+func TestH2H1ProxyProtocolV2TCP6(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
+               if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
+                       t.Errorf("X-Forwarded-For: %v; want %v", got, want)
+               }
+               if got, want := r.Header.Get("Forwarded"), `for="[2001:db8:85a3::8a2e:370:7334]"`; got != want {
+                       t.Errorf("Forwarded: %v; want %v", got, want)
+               }
+       })
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command: proxyProtocolV2CommandProxy,
+               sourceAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+                       Port: 12345,
+               },
+               destinationAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("::1"),
+                       Port: 8080,
+               },
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       res, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2TCP6",
+       })
+
+       if err != nil {
+               t.Fatalf("Error st.http2() = %v", err)
+       }
+
+       if got, want := res.status, 200; got != want {
+               t.Errorf("res.status: %v; want %v", got, want)
+       }
+}
+
+// TestH2H1ProxyProtocolV2Local tests PROXY protocol version 2
+// containing cmd == Local is ignored.
+func TestH2H1ProxyProtocolV2Local(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
+               if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
+                       t.Errorf("X-Forwarded-For: %v; want %v", got, want)
+               }
+               if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
+                       t.Errorf("Forwarded: %v; want %v", got, want)
+               }
+       })
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command: proxyProtocolV2CommandLocal,
+               sourceAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.2").To4(),
+                       Port: 12345,
+               },
+               destinationAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.100").To4(),
+                       Port: 8080,
+               },
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       res, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2Local",
+       })
+
+       if err != nil {
+               t.Fatalf("Error st.http2() = %v", err)
+       }
+
+       if got, want := res.status, 200; got != want {
+               t.Errorf("res.status: %v; want %v", got, want)
+       }
+}
+
+// TestH2H1ProxyProtocolV2UnknownCmd tests PROXY protocol version 2
+// containing unknown cmd should be rejected.
+func TestH2H1ProxyProtocolV2UnknownCmd(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command: 0xf,
+               sourceAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.2").To4(),
+                       Port: 12345,
+               },
+               destinationAddress: &net.TCPAddr{
+                       IP:   net.ParseIP("192.168.0.100").To4(),
+                       Port: 8080,
+               },
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       _, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2UnknownCmd",
+       })
+
+       if err == nil {
+               t.Fatalf("connection was not terminated")
+       }
+}
+
+// TestH2H1ProxyProtocolV2Unix tests PROXY protocol version 2
+// containing AF_UNIX family is ignored.
+func TestH2H1ProxyProtocolV2Unix(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
+               if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
+                       t.Errorf("X-Forwarded-For: %v; want %v", got, want)
+               }
+               if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
+                       t.Errorf("Forwarded: %v; want %v", got, want)
+               }
+       })
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command: proxyProtocolV2CommandProxy,
+               sourceAddress: &net.UnixAddr{
+                       Name: "/foo",
+                       Net:  "unix",
+               },
+               destinationAddress: &net.UnixAddr{
+                       Name: "/bar",
+                       Net:  "unix",
+               },
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       res, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2Unix",
+       })
+
+       if err != nil {
+               t.Fatalf("Error st.http2() = %v", err)
+       }
+
+       if got, want := res.status, 200; got != want {
+               t.Errorf("res.status: %v; want %v", got, want)
+       }
+}
+
+// TestH2H1ProxyProtocolV2Unspec tests PROXY protocol version 2
+// containing AF_UNSPEC family is ignored.
+func TestH2H1ProxyProtocolV2Unspec(t *testing.T) {
+       st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
+               if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
+                       t.Errorf("X-Forwarded-For: %v; want %v", got, want)
+               }
+               if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
+                       t.Errorf("Forwarded: %v; want %v", got, want)
+               }
+       })
+       defer st.Close()
+
+       var b bytes.Buffer
+       writeProxyProtocolV2(&b, proxyProtocolV2{
+               command:        proxyProtocolV2CommandProxy,
+               additionalData: []byte("foobar"),
+       })
+       st.conn.Write(b.Bytes())
+
+       res, err := st.http2(requestParam{
+               name: "TestH2H1ProxyProtocolV2Unspec",
+       })
+
+       if err != nil {
+               t.Fatalf("Error st.http2() = %v", err)
+       }
+
+       if got, want := res.status, 200; got != want {
+               t.Errorf("res.status: %v; want %v", got, want)
+       }
+}
+
 // TestH2H1ExternalDNS tests that DNS resolution using external DNS
 // with HTTP/1 backend works.
 func TestH2H1ExternalDNS(t *testing.T) {
index 89e7f29..113e27d 100644 (file)
@@ -4,6 +4,7 @@ import (
        "bufio"
        "bytes"
        "crypto/tls"
+       "encoding/binary"
        "errors"
        "fmt"
        "github.com/tatsuhiro-t/go-nghttp2"
@@ -671,3 +672,93 @@ type APIResponse struct {
        Code   int                    `json:"code,omitempty"`
        Data   map[string]interface{} `json:"data,omitempty"`
 }
+
+type proxyProtocolV2 struct {
+       command            proxyProtocolV2Command
+       sourceAddress      net.Addr
+       destinationAddress net.Addr
+       additionalData     []byte
+}
+
+type proxyProtocolV2Command int
+
+const (
+       proxyProtocolV2CommandLocal proxyProtocolV2Command = 0x0
+       proxyProtocolV2CommandProxy proxyProtocolV2Command = 0x1
+)
+
+type proxyProtocolV2Family int
+
+const (
+       proxyProtocolV2FamilyUnspec proxyProtocolV2Family = 0x0
+       proxyProtocolV2FamilyInet   proxyProtocolV2Family = 0x1
+       proxyProtocolV2FamilyInet6  proxyProtocolV2Family = 0x2
+       proxyProtocolV2FamilyUnix   proxyProtocolV2Family = 0x3
+)
+
+type proxyProtocolV2Protocol int
+
+const (
+       proxyProtocolV2ProtocolUnspec proxyProtocolV2Protocol = 0x0
+       proxyProtocolV2ProtocolStream proxyProtocolV2Protocol = 0x1
+       proxyProtocolV2ProtocolDgram  proxyProtocolV2Protocol = 0x2
+)
+
+func writeProxyProtocolV2(w io.Writer, hdr proxyProtocolV2) {
+       w.Write([]byte{0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A})
+       w.Write([]byte{byte(0x20 | hdr.command)})
+
+       switch srcAddr := hdr.sourceAddress.(type) {
+       case *net.TCPAddr:
+               dstAddr := hdr.destinationAddress.(*net.TCPAddr)
+               if len(srcAddr.IP) != len(dstAddr.IP) {
+                       panic("len(srcAddr.IP) != len(dstAddr.IP)")
+               }
+               var fam byte
+               if len(srcAddr.IP) == 4 {
+                       fam = byte(proxyProtocolV2FamilyInet << 4)
+               } else {
+                       fam = byte(proxyProtocolV2FamilyInet6 << 4)
+               }
+               fam |= byte(proxyProtocolV2ProtocolStream)
+               w.Write([]byte{fam})
+               length := uint16(len(srcAddr.IP)*2 + 4 + len(hdr.additionalData))
+               binary.Write(w, binary.BigEndian, length)
+               w.Write(srcAddr.IP)
+               w.Write(dstAddr.IP)
+               binary.Write(w, binary.BigEndian, uint16(srcAddr.Port))
+               binary.Write(w, binary.BigEndian, uint16(dstAddr.Port))
+       case *net.UnixAddr:
+               dstAddr := hdr.destinationAddress.(*net.UnixAddr)
+               if len(srcAddr.Name) > 108 {
+                       panic("too long Unix source address")
+               }
+               if len(dstAddr.Name) > 108 {
+                       panic("too long Unix destination address")
+               }
+               fam := byte(proxyProtocolV2FamilyUnix << 4)
+               switch srcAddr.Net {
+               case "unix":
+                       fam |= byte(proxyProtocolV2ProtocolStream)
+               case "unixdgram":
+                       fam |= byte(proxyProtocolV2ProtocolDgram)
+               default:
+                       fam |= byte(proxyProtocolV2ProtocolUnspec)
+               }
+               w.Write([]byte{fam})
+               length := uint16(216 + len(hdr.additionalData))
+               binary.Write(w, binary.BigEndian, length)
+               zeros := make([]byte, 108)
+               w.Write([]byte(srcAddr.Name))
+               w.Write(zeros[:108-len(srcAddr.Name)])
+               w.Write([]byte(dstAddr.Name))
+               w.Write(zeros[:108-len(dstAddr.Name)])
+       default:
+               fam := byte(proxyProtocolV2FamilyUnspec<<4) | byte(proxyProtocolV2ProtocolUnspec)
+               w.Write([]byte{fam})
+               length := uint16(len(hdr.additionalData))
+               binary.Write(w, binary.BigEndian, length)
+       }
+
+       w.Write(hdr.additionalData)
+}
index 4e3f5da..4dc2fcd 100644 (file)
@@ -62,7 +62,7 @@ if(HAVE_CUNIT OR ENABLE_STATIC_LIB)
   set_target_properties(nghttp2_static PROPERTIES
     COMPILE_FLAGS "${WARNCFLAGS}"
     VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
-    ARCHIVE_OUTPUT_NAME nghttp2_static
+    ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX}
   )
   target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB")
   if(ENABLE_STATIC_LIB)
index e3aeb9f..9be6eea 100644 (file)
@@ -229,6 +229,13 @@ typedef struct {
 #define NGHTTP2_CLIENT_MAGIC_LEN 24
 
 /**
+ * @macro
+ *
+ * The default max number of settings per SETTINGS frame
+ */
+#define NGHTTP2_DEFAULT_MAX_SETTINGS 32
+
+/**
  * @enum
  *
  * Error codes used in this library.  The code range is [-999, -500],
@@ -399,6 +406,11 @@ typedef enum {
    */
   NGHTTP2_ERR_SETTINGS_EXPECTED = -536,
   /**
+   * When a local endpoint receives too many settings entries
+   * in a single SETTINGS frame.
+   */
+  NGHTTP2_ERR_TOO_MANY_SETTINGS = -537,
+  /**
    * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
    * under unexpected condition and processing was terminated (e.g.,
    * out of memory).  If application receives this error code, it must
@@ -2662,6 +2674,17 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_outbound_ack(nghttp2_option *option,
 /**
  * @function
  *
+ * This function sets the maximum number of SETTINGS entries per
+ * SETTINGS frame that will be accepted. If more than those entries
+ * are received, the peer is considered to be misbehaving and session
+ * will be closed. The default value is 32.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_max_settings(nghttp2_option *option,
+                                                    size_t val);
+
+/**
+ * @function
+ *
  * Initializes |*session_ptr| for client use.  The all members of
  * |callbacks| are copied to |*session_ptr|.  Therefore |*session_ptr|
  * does not store |callbacks|.  The |user_data| is an arbitrary user
index 45d21e2..795a44c 100644 (file)
@@ -29,7 +29,7 @@
  * @macro
  * Version number of the nghttp2 library release
  */
-#define NGHTTP2_VERSION "1.40.0"
+#define NGHTTP2_VERSION "1.41.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 0x012800
+#define NGHTTP2_VERSION_NUM 0x012900
 
 #endif /* NGHTTP2VER_H */
index 91136a6..0bd5414 100644 (file)
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
   case NGHTTP2_ERR_FLOODED:
     return "Flooding was detected in this HTTP/2 session, and it must be "
            "closed";
+  case NGHTTP2_ERR_TOO_MANY_SETTINGS:
+    return "SETTINGS frame contained more than the maximum allowed entries";
   default:
     return "Unknown error code";
   }
index e53f22d..34348e6 100644 (file)
@@ -121,3 +121,8 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
   option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
   option->max_outbound_ack = val;
 }
+
+void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
+  option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
+  option->max_settings = val;
+}
index 1f740aa..939729f 100644 (file)
@@ -67,6 +67,7 @@ typedef enum {
   NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
   NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
   NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
+  NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
 } nghttp2_option_flag;
 
 /**
@@ -86,6 +87,10 @@ struct nghttp2_option {
    */
   size_t max_outbound_ack;
   /**
+   * NGHTTP2_OPT_MAX_SETTINGS
+   */
+  size_t max_settings;
+  /**
    * Bitwise OR of nghttp2_option_flag to determine that which fields
    * are specified.
    */
index 9df3d6f..39f81f4 100644 (file)
@@ -458,6 +458,7 @@ static int session_new(nghttp2_session **session_ptr,
 
   (*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
   (*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
+  (*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
 
   if (option) {
     if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -521,6 +522,11 @@ static int session_new(nghttp2_session **session_ptr,
     if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_ACK) {
       (*session_ptr)->max_outbound_ack = option->max_outbound_ack;
     }
+
+    if ((option->opt_set_mask & NGHTTP2_OPT_MAX_SETTINGS) &&
+        option->max_settings) {
+      (*session_ptr)->max_settings = option->max_settings;
+    }
   }
 
   rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -2494,14 +2500,6 @@ static int session_update_stream_consumed_size(nghttp2_session *session,
 static int session_update_connection_consumed_size(nghttp2_session *session,
                                                    size_t delta_size);
 
-static int session_update_recv_connection_window_size(nghttp2_session *session,
-                                                      size_t delta_size);
-
-static int session_update_recv_stream_window_size(nghttp2_session *session,
-                                                  nghttp2_stream *stream,
-                                                  size_t delta_size,
-                                                  int send_window_update);
-
 /*
  * Called after a frame is sent.  This function runs
  * on_frame_send_callback and handles stream closure upon END_STREAM
@@ -2735,7 +2733,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
       if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
         rv = session_update_connection_consumed_size(session, 0);
       } else {
-        rv = session_update_recv_connection_window_size(session, 0);
+        rv = nghttp2_session_update_recv_connection_window_size(session, 0);
       }
 
       if (nghttp2_is_fatal(rv)) {
@@ -2761,7 +2759,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
     if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
       rv = session_update_stream_consumed_size(session, stream, 0);
     } else {
-      rv = session_update_recv_stream_window_size(session, stream, 0, 1);
+      rv =
+          nghttp2_session_update_recv_stream_window_size(session, stream, 0, 1);
     }
 
     if (nghttp2_is_fatal(rv)) {
@@ -5019,22 +5018,10 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, size_t delta,
   return 0;
 }
 
-/*
- * Accumulates received bytes |delta_size| for stream-level flow
- * control and decides whether to send WINDOW_UPDATE to that stream.
- * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
- * be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- *     Out of memory.
- */
-static int session_update_recv_stream_window_size(nghttp2_session *session,
-                                                  nghttp2_stream *stream,
-                                                  size_t delta_size,
-                                                  int send_window_update) {
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+                                                   nghttp2_stream *stream,
+                                                   size_t delta_size,
+                                                   int send_window_update) {
   int rv;
   rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
                                stream->local_window_size);
@@ -5063,20 +5050,8 @@ static int session_update_recv_stream_window_size(nghttp2_session *session,
   return 0;
 }
 
-/*
- * Accumulates received bytes |delta_size| for connection-level flow
- * control and decides whether to send WINDOW_UPDATE to the
- * connection.  If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
- * WINDOW_UPDATE will not be sent.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- *     Out of memory.
- */
-static int session_update_recv_connection_window_size(nghttp2_session *session,
-                                                      size_t delta_size) {
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+                                                       size_t delta_size) {
   int rv;
   rv = adjust_recv_window_size(&session->recv_window_size, delta_size,
                                session->local_window_size);
@@ -5678,6 +5653,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
           break;
         }
 
+        /* Check the settings flood counter early to be safe */
+        if (session->obq_flood_counter_ >= session->max_outbound_ack &&
+            !(iframe->frame.hd.flags & NGHTTP2_FLAG_ACK)) {
+          return NGHTTP2_ERR_FLOODED;
+        }
+
         iframe->state = NGHTTP2_IB_READ_SETTINGS;
 
         if (iframe->payloadleft) {
@@ -5688,6 +5669,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
           iframe->max_niv =
               iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
 
+          if (iframe->max_niv - 1 > session->max_settings) {
+            rv = nghttp2_session_terminate_session_with_reason(
+                session, NGHTTP2_ENHANCE_YOUR_CALM,
+                "SETTINGS: too many setting entries");
+            if (nghttp2_is_fatal(rv)) {
+              return rv;
+            }
+            return (ssize_t)inlen;
+          }
+
           iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
                                                    iframe->max_niv);
 
@@ -6454,7 +6445,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
       }
 
       /* Pad Length field is subject to flow control */
-      rv = session_update_recv_connection_window_size(session, readlen);
+      rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
       if (nghttp2_is_fatal(rv)) {
         return rv;
       }
@@ -6477,7 +6468,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
 
       stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
       if (stream) {
-        rv = session_update_recv_stream_window_size(
+        rv = nghttp2_session_update_recv_stream_window_size(
             session, stream, readlen,
             iframe->payloadleft ||
                 (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6524,7 +6515,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
       if (readlen > 0) {
         ssize_t data_readlen;
 
-        rv = session_update_recv_connection_window_size(session, readlen);
+        rv = nghttp2_session_update_recv_connection_window_size(session,
+                                                                readlen);
         if (nghttp2_is_fatal(rv)) {
           return rv;
         }
@@ -6533,7 +6525,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
           return (ssize_t)inlen;
         }
 
-        rv = session_update_recv_stream_window_size(
+        rv = nghttp2_session_update_recv_stream_window_size(
             session, stream, readlen,
             iframe->payloadleft ||
                 (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
@@ -6634,7 +6626,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
       if (readlen > 0) {
         /* Update connection-level flow control window for ignored
            DATA frame too */
-        rv = session_update_recv_connection_window_size(session, readlen);
+        rv = nghttp2_session_update_recv_connection_window_size(session,
+                                                                readlen);
         if (nghttp2_is_fatal(rv)) {
           return rv;
         }
@@ -7454,6 +7447,11 @@ static int nghttp2_session_upgrade_internal(nghttp2_session *session,
   if (settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
     return NGHTTP2_ERR_INVALID_ARGUMENT;
   }
+  /* SETTINGS frame contains too many settings */
+  if (settings_payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH
+        > session->max_settings) {
+    return NGHTTP2_ERR_TOO_MANY_SETTINGS;
+  }
   rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload,
                                               settings_payloadlen, mem);
   if (rv != 0) {
index 90ead9c..07bfbb6 100644 (file)
@@ -267,6 +267,8 @@ struct nghttp2_session {
   /* The maximum length of header block to send.  Calculated by the
      same way as nghttp2_hd_deflate_bound() does. */
   size_t max_send_header_block_length;
+  /* The maximum number of settings accepted per SETTINGS frame. */
+  size_t max_settings;
   /* 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,
@@ -898,4 +900,36 @@ int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
                                                   uint32_t error_code,
                                                   const char *reason);
 
+/*
+ * Accumulates received bytes |delta_size| for connection-level flow
+ * control and decides whether to send WINDOW_UPDATE to the
+ * connection.  If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
+ * WINDOW_UPDATE will not be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
+                                                       size_t delta_size);
+
+/*
+ * Accumulates received bytes |delta_size| for stream-level flow
+ * control and decides whether to send WINDOW_UPDATE to that stream.
+ * If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
+ * be sent.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
+                                                   nghttp2_stream *stream,
+                                                   size_t delta_size,
+                                                   int send_window_update);
+
 #endif /* NGHTTP2_SESSION_H */
index f604eff..744a49c 100644 (file)
@@ -450,6 +450,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
     if (rv != 0) {
       return rv;
     }
+
+    if (window_size_increment > 0) {
+      return nghttp2_session_add_window_update(session, 0, stream_id,
+                                               window_size_increment);
+    }
+
+    return nghttp2_session_update_recv_connection_window_size(session, 0);
   } else {
     stream = nghttp2_session_get_stream(session, stream_id);
 
@@ -476,11 +483,14 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
     if (rv != 0) {
       return rv;
     }
-  }
 
-  if (window_size_increment > 0) {
-    return nghttp2_session_add_window_update(session, 0, stream_id,
-                                             window_size_increment);
+    if (window_size_increment > 0) {
+      return nghttp2_session_add_window_update(session, 0, stream_id,
+                                               window_size_increment);
+    }
+
+    return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
+                                                          1);
   }
 
   return 0;
index d11f1e0..0cb7f90 100644 (file)
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -31,7 +31,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.6 Debian-2.4.6-11"
+VERSION="2.4.6 Debian-2.4.6-14"
 package_revision=2.4.6
 
 
@@ -387,7 +387,7 @@ EXIT_SKIP=77          # $? = 77 is used to indicate a skipped test to automake.
 # putting '$debug_cmd' at the start of all your functions, you can get
 # bash to show function call trace with:
 #
-#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+#    debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
 debug_cmd=${debug_cmd-":"}
 exit_cmd=:
 
@@ -2141,7 +2141,7 @@ include the following information:
        compiler:       $LTCC
        compiler flags: $LTCFLAGS
        linker:         $LD (gnu? $with_gnu_ld)
-       version:        $progname $scriptversion Debian-2.4.6-11
+       version:        $progname $scriptversion Debian-2.4.6-14
        automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
        autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
 
@@ -7368,10 +7368,12 @@ func_mode_link ()
       # -stdlib=*            select c++ std lib with clang
       # -fsanitize=*         Clang/GCC memory and address sanitizer
       # -fuse-ld=*           Linker select flags for GCC
+      # -static-*            direct GCC to link specific libraries statically
+      # -fcilkplus           Cilk Plus language extension features for C/C++
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
-      -specs=*|-fsanitize=*|-fuse-ld=*)
+      -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus)
         func_quote_for_eval "$arg"
        arg=$func_quote_for_eval_result
         func_append compile_command " $arg"
index 9d6dd9f..a6d21ae 100644 (file)
@@ -1041,8 +1041,8 @@ int forced_loaded() { return 2;}
 _LT_EOF
       echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
       $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
-      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
-      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
       echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
       $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
       cat > conftest.c << _LT_EOF
@@ -1492,7 +1492,7 @@ need_locks=$enable_libtool_lock
 m4_defun([_LT_PROG_AR],
 [AC_CHECK_TOOLS(AR, [ar], false)
 : ${AR=ar}
-: ${AR_FLAGS=cru}
+: ${AR_FLAGS=cr}
 _LT_DECL([], [AR], [1], [The archiver])
 _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
 
index 5d1d63f..709bc6f 100644 (file)
@@ -449,9 +449,9 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
+@ENABLE_PYTHON_BINDINGS_FALSE@install-exec-local:
 @ENABLE_PYTHON_BINDINGS_FALSE@uninstall-local:
 @ENABLE_PYTHON_BINDINGS_FALSE@clean-local:
-@ENABLE_PYTHON_BINDINGS_FALSE@install-exec-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libtool clean-local mostlyclean-am
index 334b1e2..2f08cac 100644 (file)
@@ -94,6 +94,7 @@ Config::Config()
       log_fd(-1),
       port(0),
       default_port(0),
+      connect_to_port(0),
       verbose(false),
       timing_script(false),
       base_uri_unix(false),
@@ -1563,8 +1564,13 @@ void resolve_host() {
   hints.ai_protocol = 0;
   hints.ai_flags = AI_ADDRCONFIG;
 
-  rv = getaddrinfo(config.host.c_str(), util::utos(config.port).c_str(), &hints,
-                   &res);
+  const auto &resolve_host =
+      config.connect_to_host.empty() ? config.host : config.connect_to_host;
+  auto port =
+      config.connect_to_port == 0 ? config.port : config.connect_to_port;
+
+  rv =
+      getaddrinfo(resolve_host.c_str(), util::utos(port).c_str(), &hints, &res);
   if (rv != 0) {
     std::cerr << "getaddrinfo() failed: " << gai_strerror(rv) << std::endl;
     exit(EXIT_FAILURE);
@@ -1979,6 +1985,9 @@ Options:
               response  time when  using  one worker  thread, but  may
               appear slightly  out of order with  multiple threads due
               to buffering.  Status code is -1 for failed streams.
+  --connect-to=<HOST>[:<PORT>]
+              Host and port to connect  instead of using the authority
+              in <URI>.
   -v, --verbose
               Output debug information.
   --version   Display version information and exit.
@@ -2037,6 +2046,7 @@ int main(int argc, char **argv) {
         {"encoder-header-table-size", required_argument, &flag, 8},
         {"warm-up-time", required_argument, &flag, 9},
         {"log-file", required_argument, &flag, 10},
+        {"connect-to", required_argument, &flag, 11},
         {nullptr, 0, nullptr, 0}};
     int option_index = 0;
     auto c = getopt_long(argc, argv,
@@ -2264,6 +2274,19 @@ int main(int argc, char **argv) {
         // --log-file
         logfile = optarg;
         break;
+      case 11: {
+        // --connect-to
+        auto p = util::split_hostport(StringRef{optarg});
+        int64_t port = 0;
+        if (p.first.empty() ||
+            (!p.second.empty() && (port = util::parse_uint(p.second)) == -1)) {
+          std::cerr << "--connect-to: Invalid value " << optarg << std::endl;
+          exit(EXIT_FAILURE);
+        }
+        config.connect_to_host = p.first.str();
+        config.connect_to_port = port;
+        break;
+      }
       }
       break;
     default:
@@ -2494,7 +2517,7 @@ int main(int argc, char **argv) {
   shared_nva.emplace_back(":method", config.data_fd == -1 ? "GET" : "POST");
   shared_nva.emplace_back("user-agent", user_agent);
 
-  // list overridalbe headers
+  // list header fields that can be overridden.
   auto override_hdrs = make_array<std::string>(":authority", ":host", ":method",
                                                ":scheme", "user-agent");
 
index a5de461..ca68997 100644 (file)
@@ -69,6 +69,7 @@ struct Config {
   nghttp2::Headers custom_headers;
   std::string scheme;
   std::string host;
+  std::string connect_to_host;
   std::string ifile;
   std::string ciphers;
   // length of upload data
@@ -101,6 +102,7 @@ struct Config {
   int log_fd;
   uint16_t port;
   uint16_t default_port;
+  uint16_t connect_to_port;
   bool verbose;
   bool timing_script;
   std::string base_uri;
index dd4fadf..3cf3816 100644 (file)
@@ -195,6 +195,8 @@ int main(int argc, char *argv[]) {
       !CU_add_test(pSuite, "util_decode_hex", shrpx::test_util_decode_hex) ||
       !CU_add_test(pSuite, "util_extract_host",
                    shrpx::test_util_extract_host) ||
+      !CU_add_test(pSuite, "util_split_hostport",
+                   shrpx::test_util_split_hostport) ||
       !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
       !CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
       !CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
index 2dd0493..4ff5e47 100644 (file)
@@ -1914,7 +1914,7 @@ Connections:
               default.  Any  requests which come through  this address
               are replied with 200 HTTP status, without no body.
 
-              To  accept   PROXY  protocol   version  1   on  frontend
+              To accept  PROXY protocol  version 1  and 2  on frontend
               connection,  specify  "proxyproto" parameter.   This  is
               disabled by default.
 
index e118008..2b6638a 100644 (file)
@@ -447,8 +447,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
       *p = '\0';
 
       forwarded_for_ = StringRef{buf.base, p};
-    } else if (!faddr_->accept_proxy_protocol &&
-               !config->conn.upstream.accept_proxy_protocol) {
+    } else {
       init_forwarded_for(family, ipaddr_);
     }
   }
@@ -1149,6 +1148,16 @@ int ClientHandler::on_proxy_protocol_finish() {
   return 0;
 }
 
+namespace {
+// PROXY-protocol v2 header signature
+constexpr uint8_t PROXY_PROTO_V2_SIG[] =
+    "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
+
+// PROXY-protocol v2 header length
+constexpr size_t PROXY_PROTO_V2_HDLEN =
+    str_size(PROXY_PROTO_V2_SIG) + /* ver_cmd(1) + fam(1) + len(2) = */ 4;
+} // namespace
+
 // http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
 int ClientHandler::proxy_protocol_read() {
   if (LOG_ENABLED(INFO)) {
@@ -1157,6 +1166,14 @@ int ClientHandler::proxy_protocol_read() {
 
   auto first = rb_.pos();
 
+  if (rb_.rleft() >= PROXY_PROTO_V2_HDLEN &&
+      (*(first + str_size(PROXY_PROTO_V2_SIG)) & 0xf0) == 0x20) {
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol: Detected v2 header signature";
+    }
+    return proxy_protocol_v2_read();
+  }
+
   // NULL character really destroys functions which expects NULL
   // terminated string.  We won't expect it in PROXY protocol line, so
   // find it here.
@@ -1338,6 +1355,167 @@ int ClientHandler::proxy_protocol_read() {
   return on_proxy_protocol_finish();
 }
 
+int ClientHandler::proxy_protocol_v2_read() {
+  // Assume that first str_size(PROXY_PROTO_V2_SIG) octets match v2
+  // protocol signature and followed by the bytes which indicates v2.
+  assert(rb_.rleft() >= PROXY_PROTO_V2_HDLEN);
+
+  auto p = rb_.pos() + str_size(PROXY_PROTO_V2_SIG);
+
+  assert(((*p) & 0xf0) == 0x20);
+
+  enum { LOCAL, PROXY } cmd;
+
+  auto cmd_bits = (*p++) & 0xf;
+  switch (cmd_bits) {
+  case 0x0:
+    cmd = LOCAL;
+    break;
+  case 0x01:
+    cmd = PROXY;
+    break;
+  default:
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol-v2: Unknown command " << log::hex
+                       << cmd_bits;
+    }
+    return -1;
+  }
+
+  auto fam = *p++;
+  uint16_t len;
+  memcpy(&len, p, sizeof(len));
+  len = ntohs(len);
+
+  p += sizeof(len);
+
+  if (LOG_ENABLED(INFO)) {
+    CLOG(INFO, this) << "PROXY-protocol-v2: Detected family=" << log::hex << fam
+                     << ", len=" << log::dec << len;
+  }
+
+  if (rb_.last() - p < len) {
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this)
+          << "PROXY-protocol-v2: Prematurely truncated header block; require "
+          << len << " bytes, " << rb_.last() - p << " bytes left";
+    }
+    return -1;
+  }
+
+  int family;
+  std::array<char, std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)> src_addr,
+      dst_addr;
+  size_t addrlen;
+
+  switch (fam) {
+  case 0x11:
+  case 0x12:
+    if (len < 12) {
+      if (LOG_ENABLED(INFO)) {
+        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_INET addresses";
+      }
+      return -1;
+    }
+    family = AF_INET;
+    addrlen = 4;
+    break;
+  case 0x21:
+  case 0x22:
+    if (len < 36) {
+      if (LOG_ENABLED(INFO)) {
+        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_INET6 addresses";
+      }
+      return -1;
+    }
+    family = AF_INET6;
+    addrlen = 16;
+    break;
+  case 0x31:
+  case 0x32:
+    if (len < 216) {
+      if (LOG_ENABLED(INFO)) {
+        CLOG(INFO, this) << "PROXY-protocol-v2: Too short AF_UNIX addresses";
+      }
+      return -1;
+    }
+    // fall through
+  case 0x00: {
+    // UNSPEC and UNIX are just ignored.
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol-v2: Ignore combination of address "
+                          "family and protocol "
+                       << log::hex << fam;
+    }
+    rb_.drain(PROXY_PROTO_V2_HDLEN + len);
+    return on_proxy_protocol_finish();
+  }
+  default:
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol-v2: Unknown combination of address "
+                          "family and protocol "
+                       << log::hex << fam;
+    }
+    return -1;
+  }
+
+  if (cmd != PROXY) {
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol-v2: Ignore non-PROXY command";
+    }
+    rb_.drain(PROXY_PROTO_V2_HDLEN + len);
+    return on_proxy_protocol_finish();
+  }
+
+  if (inet_ntop(family, p, src_addr.data(), src_addr.size()) == nullptr) {
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this) << "PROXY-protocol-v2: Unable to parse source address";
+    }
+    return -1;
+  }
+
+  p += addrlen;
+
+  if (inet_ntop(family, p, dst_addr.data(), dst_addr.size()) == nullptr) {
+    if (LOG_ENABLED(INFO)) {
+      CLOG(INFO, this)
+          << "PROXY-protocol-v2: Unable to parse destination address";
+    }
+    return -1;
+  }
+
+  p += addrlen;
+
+  uint16_t src_port;
+
+  memcpy(&src_port, p, sizeof(src_port));
+  src_port = ntohs(src_port);
+
+  // We don't use destination port.
+  p += 4;
+
+  ipaddr_ = make_string_ref(balloc_, StringRef{src_addr.data()});
+  port_ = util::make_string_ref_uint(balloc_, src_port);
+
+  if (LOG_ENABLED(INFO)) {
+    CLOG(INFO, this) << "PROXY-protocol-v2: Finished reading proxy addresses, "
+                     << p - rb_.pos() << " bytes read, "
+                     << PROXY_PROTO_V2_HDLEN + len - (p - rb_.pos())
+                     << " bytes left";
+  }
+
+  auto config = get_config();
+  auto &fwdconf = config->http.forwarded;
+
+  if ((fwdconf.params & FORWARDED_FOR) &&
+      fwdconf.for_node_type == ForwardedNode::IP) {
+    init_forwarded_for(family, ipaddr_);
+  }
+
+  rb_.drain(PROXY_PROTO_V2_HDLEN + len);
+  return on_proxy_protocol_finish();
+}
+
 StringRef ClientHandler::get_forwarded_by() const {
   auto &fwdconf = get_config()->http.forwarded;
 
index c31b1ee..bc56d48 100644 (file)
@@ -77,6 +77,7 @@ public:
   int upstream_write();
 
   int proxy_protocol_read();
+  int proxy_protocol_v2_read();
   int on_proxy_protocol_finish();
 
   // Performs I/O operation.  Internally calls on_read()/on_write().
index 746311f..c562530 100644 (file)
@@ -2030,17 +2030,6 @@ StringRef get_x509_issuer_name(BlockAllocator &balloc, X509 *x) {
 #endif /* !WORDS_BIGENDIAN */
 
 StringRef get_x509_serial(BlockAllocator &balloc, X509 *x) {
-#if OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
-  auto sn = X509_get0_serialNumber(x);
-  uint64_t r;
-  if (ASN1_INTEGER_get_uint64(&r, sn) != 1) {
-    return StringRef{};
-  }
-
-  r = bswap64(r);
-  return util::format_hex(
-      balloc, StringRef{reinterpret_cast<uint8_t *>(&r), sizeof(r)});
-#else  // !OPENSSL_1_1_API || OPENSSL_IS_BORINGSSL
   auto sn = X509_get_serialNumber(x);
   auto bn = BN_new();
   auto bn_d = defer(BN_free, bn);
@@ -2052,8 +2041,7 @@ StringRef get_x509_serial(BlockAllocator &balloc, X509 *x) {
   auto n = BN_bn2bin(bn, b.data());
   assert(n <= 20);
 
-  return util::format_hex(balloc, StringRef{std::begin(b), std::end(b)});
-#endif // !OPENSSL_1_1_API
+  return util::format_hex(balloc, StringRef{b.data(), static_cast<size_t>(n)});
 }
 
 namespace {
index bb30fcd..187fd3a 100644 (file)
@@ -1537,6 +1537,41 @@ StringRef extract_host(const StringRef &hostport) {
   return StringRef{std::begin(hostport), p};
 }
 
+std::pair<StringRef, StringRef> split_hostport(const StringRef &hostport) {
+  if (hostport.empty()) {
+    return {};
+  }
+  if (hostport[0] == '[') {
+    // assume this is IPv6 numeric address
+    auto p = std::find(std::begin(hostport), std::end(hostport), ']');
+    if (p == std::end(hostport)) {
+      return {};
+    }
+    if (p + 1 == std::end(hostport)) {
+      return {StringRef{std::begin(hostport) + 1, p}, {}};
+    }
+    if (*(p + 1) != ':' || p + 2 == std::end(hostport)) {
+      return {};
+    }
+    return {StringRef{std::begin(hostport) + 1, p},
+            StringRef{p + 2, std::end(hostport)}};
+  }
+
+  auto p = std::find(std::begin(hostport), std::end(hostport), ':');
+  if (p == std::begin(hostport)) {
+    return {};
+  }
+  if (p == std::end(hostport)) {
+    return {StringRef{std::begin(hostport), p}, {}};
+  }
+  if (p + 1 == std::end(hostport)) {
+    return {};
+  }
+
+  return {StringRef{std::begin(hostport), p},
+          StringRef{p + 1, std::end(hostport)}};
+}
+
 std::mt19937 make_mt19937() {
   std::random_device rd;
   return std::mt19937(rd());
index 38761e0..3443fe0 100644 (file)
@@ -769,6 +769,13 @@ int sha1(uint8_t *buf, const StringRef &s);
 // NULL-terminated.
 StringRef extract_host(const StringRef &hostport);
 
+// split_hostport splits host and port in |hostport|.  Unlike
+// extract_host, square brackets enclosing host name is stripped.  If
+// port is not available, it returns empty string in the second
+// string.  The returned string might not be NULL-terminated.  On any
+// error, it returns a pair which has empty strings.
+std::pair<StringRef, StringRef> split_hostport(const StringRef &hostport);
+
 // Returns new std::mt19937 object.
 std::mt19937 make_mt19937();
 
index d375b43..6ad313d 100644 (file)
@@ -628,4 +628,28 @@ void test_util_extract_host(void) {
   CU_ASSERT(util::extract_host(StringRef{}).empty());
 }
 
+void test_util_split_hostport(void) {
+  CU_ASSERT(std::make_pair(StringRef::from_lit("foo"), StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("foo")));
+  CU_ASSERT(
+      std::make_pair(StringRef::from_lit("foo"), StringRef::from_lit("80")) ==
+      util::split_hostport(StringRef::from_lit("foo:80")));
+  CU_ASSERT(
+      std::make_pair(StringRef::from_lit("::1"), StringRef::from_lit("80")) ==
+      util::split_hostport(StringRef::from_lit("[::1]:80")));
+  CU_ASSERT(std::make_pair(StringRef::from_lit("::1"), StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("[::1]")));
+
+  CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) ==
+            util::split_hostport(StringRef{}));
+  CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("[::1]:")));
+  CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("foo:")));
+  CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("[::1:")));
+  CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) ==
+            util::split_hostport(StringRef::from_lit("[::1]80")));
+}
+
 } // namespace shrpx
index 41ba9fe..cc34f7d 100644 (file)
@@ -67,6 +67,7 @@ void test_util_format_hex(void);
 void test_util_is_hex_string(void);
 void test_util_decode_hex(void);
 void test_util_extract_host(void);
+void test_util_split_hostport(void);
 
 } // namespace shrpx
 
index 46e9b1c..67eb4a1 100644 (file)
@@ -307,6 +307,8 @@ int main() {
       !CU_add_test(pSuite, "session_flooding", test_nghttp2_session_flooding) ||
       !CU_add_test(pSuite, "session_change_stream_priority",
                    test_nghttp2_session_change_stream_priority) ||
+      !CU_add_test(pSuite, "session_create_idle_stream",
+                   test_nghttp2_session_create_idle_stream) ||
       !CU_add_test(pSuite, "session_repeated_priority_change",
                    test_nghttp2_session_repeated_priority_change) ||
       !CU_add_test(pSuite, "session_repeated_priority_submission",
@@ -315,6 +317,8 @@ int main() {
                    test_nghttp2_session_set_local_window_size) ||
       !CU_add_test(pSuite, "session_cancel_from_before_frame_send",
                    test_nghttp2_session_cancel_from_before_frame_send) ||
+      !CU_add_test(pSuite, "session_too_many_settings",
+                   test_nghttp2_session_too_many_settings) ||
       !CU_add_test(pSuite, "session_removed_closed_stream",
                    test_nghttp2_session_removed_closed_stream) ||
       !CU_add_test(pSuite, "session_pause_data",
index b366a6a..33ee3ad 100644 (file)
@@ -10141,7 +10141,7 @@ void test_nghttp2_session_create_idle_stream(void) {
 
   /* If pri_spec->stream_id does not exist, and it is idle stream, it
      is created too */
-  nghttp2_priority_spec_init(&pri_spec, 8, 109, 0);
+  nghttp2_priority_spec_init(&pri_spec, 10, 109, 0);
 
   rv = nghttp2_session_create_idle_stream(session, 8, &pri_spec);
 
@@ -10174,7 +10174,7 @@ void test_nghttp2_session_create_idle_stream(void) {
   CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
 
   /* It is an error to create non-idle stream */
-  session->next_stream_id = 20;
+  session->last_sent_stream_id = 20;
   pri_spec.stream_id = 2;
 
   rv = nghttp2_session_create_idle_stream(session, 18, &pri_spec);
@@ -10468,6 +10468,62 @@ void test_nghttp2_session_set_local_window_size(void) {
   CU_ASSERT(0 == nghttp2_session_send(session));
 
   nghttp2_session_del(session);
+
+  /* Make sure that nghttp2_session_set_local_window_size submits
+     WINDOW_UPDATE if necessary to increase stream-level window. */
+  nghttp2_session_client_new(&session, &callbacks, NULL);
+  stream = open_sent_stream(session, 1);
+  stream->recv_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
+
+  CU_ASSERT(0 == nghttp2_session_set_local_window_size(
+                     session, NGHTTP2_FLAG_NONE, 1, 0));
+  CU_ASSERT(0 == stream->recv_window_size);
+  CU_ASSERT(0 == nghttp2_session_get_stream_local_window_size(session, 1));
+  /* This should submit WINDOW_UPDATE frame because stream-level
+     receiving window is now full. */
+  CU_ASSERT(0 ==
+            nghttp2_session_set_local_window_size(session, NGHTTP2_FLAG_NONE, 1,
+                                                  NGHTTP2_INITIAL_WINDOW_SIZE));
+  CU_ASSERT(0 == stream->recv_window_size);
+  CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
+            nghttp2_session_get_stream_local_window_size(session, 1));
+
+  item = nghttp2_session_get_next_ob_item(session);
+
+  CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
+  CU_ASSERT(1 == item->frame.hd.stream_id);
+  CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
+            item->frame.window_update.window_size_increment);
+
+  nghttp2_session_del(session);
+
+  /* Make sure that nghttp2_session_set_local_window_size submits
+     WINDOW_UPDATE if necessary to increase connection-level
+     window. */
+  nghttp2_session_client_new(&session, &callbacks, NULL);
+  session->recv_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
+
+  CU_ASSERT(0 == nghttp2_session_set_local_window_size(
+                     session, NGHTTP2_FLAG_NONE, 0, 0));
+  CU_ASSERT(0 == session->recv_window_size);
+  CU_ASSERT(0 == nghttp2_session_get_local_window_size(session));
+  /* This should submit WINDOW_UPDATE frame because connection-level
+     receiving window is now full. */
+  CU_ASSERT(0 ==
+            nghttp2_session_set_local_window_size(session, NGHTTP2_FLAG_NONE, 0,
+                                                  NGHTTP2_INITIAL_WINDOW_SIZE));
+  CU_ASSERT(0 == session->recv_window_size);
+  CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
+            nghttp2_session_get_local_window_size(session));
+
+  item = nghttp2_session_get_next_ob_item(session);
+
+  CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
+  CU_ASSERT(0 == item->frame.hd.stream_id);
+  CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
+            item->frame.window_update.window_size_increment);
+
+  nghttp2_session_del(session);
 }
 
 void test_nghttp2_session_cancel_from_before_frame_send(void) {
@@ -10558,6 +10614,67 @@ void test_nghttp2_session_cancel_from_before_frame_send(void) {
   nghttp2_session_del(session);
 }
 
+void test_nghttp2_session_too_many_settings(void) {
+  nghttp2_session *session;
+  nghttp2_option *option;
+  nghttp2_session_callbacks callbacks;
+  nghttp2_frame frame;
+  nghttp2_bufs bufs;
+  nghttp2_buf *buf;
+  ssize_t rv;
+  my_user_data ud;
+  nghttp2_settings_entry iv[3];
+  nghttp2_mem *mem;
+  nghttp2_outbound_item *item;
+
+  mem = nghttp2_mem_default();
+  frame_pack_bufs_init(&bufs);
+
+  memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
+  callbacks.on_frame_recv_callback = on_frame_recv_callback;
+  callbacks.send_callback = null_send_callback;
+
+  nghttp2_option_new(&option);
+  nghttp2_option_set_max_settings(option, 1);
+
+  nghttp2_session_client_new2(&session, &callbacks, &ud, option);
+
+  CU_ASSERT(1 == session->max_settings);
+
+  nghttp2_option_del(option);
+
+  iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
+  iv[0].value = 3000;
+
+  iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+  iv[1].value = 16384;
+
+  nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 2),
+                              2);
+
+  rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
+
+  CU_ASSERT(0 == rv);
+  CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
+
+  nghttp2_frame_settings_free(&frame.settings, mem);
+
+  buf = &bufs.head->buf;
+  assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
+
+  ud.frame_recv_cb_called = 0;
+
+  rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
+  CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
+
+  item = nghttp2_session_get_next_ob_item(session);
+  CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
+
+  nghttp2_bufs_reset(&bufs);
+  nghttp2_bufs_free(&bufs);
+  nghttp2_session_del(session);
+}
+
 static void
 prepare_session_removed_closed_stream(nghttp2_session *session,
                                       nghttp2_hd_deflater *deflater) {
index e872c5d..818c808 100644 (file)
@@ -156,6 +156,7 @@ void test_nghttp2_session_repeated_priority_change(void);
 void test_nghttp2_session_repeated_priority_submission(void);
 void test_nghttp2_session_set_local_window_size(void);
 void test_nghttp2_session_cancel_from_before_frame_send(void);
+void test_nghttp2_session_too_many_settings(void);
 void test_nghttp2_session_removed_closed_stream(void);
 void test_nghttp2_session_pause_data(void);
 void test_nghttp2_session_no_closed_streams(void);
index f9e008c..3be7d12 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef INCLUDE_LLHTTP_H_
 #define INCLUDE_LLHTTP_H_
 
-#define LLHTTP_VERSION_MAJOR 1
-#define LLHTTP_VERSION_MINOR 1
-#define LLHTTP_VERSION_PATCH 3
+#define LLHTTP_VERSION_MAJOR 2
+#define LLHTTP_VERSION_MINOR 0
+#define LLHTTP_VERSION_PATCH 4
 
 #ifndef INCLUDE_LLHTTP_ITSELF_H_
 #define INCLUDE_LLHTTP_ITSELF_H_
@@ -29,7 +29,7 @@ struct llhttp__internal_s {
   uint8_t http_major;
   uint8_t http_minor;
   uint8_t header_state;
-  uint8_t flags;
+  uint16_t flags;
   uint8_t upgrade;
   uint16_t status_code;
   uint8_t finish;
@@ -66,14 +66,15 @@ enum llhttp_errno {
   HPE_INVALID_CHUNK_SIZE = 12,
   HPE_INVALID_STATUS = 13,
   HPE_INVALID_EOF_STATE = 14,
-  HPE_CB_MESSAGE_BEGIN = 15,
-  HPE_CB_HEADERS_COMPLETE = 16,
-  HPE_CB_MESSAGE_COMPLETE = 17,
-  HPE_CB_CHUNK_HEADER = 18,
-  HPE_CB_CHUNK_COMPLETE = 19,
-  HPE_PAUSED = 20,
-  HPE_PAUSED_UPGRADE = 21,
-  HPE_USER = 22
+  HPE_INVALID_TRANSFER_ENCODING = 15,
+  HPE_CB_MESSAGE_BEGIN = 16,
+  HPE_CB_HEADERS_COMPLETE = 17,
+  HPE_CB_MESSAGE_COMPLETE = 18,
+  HPE_CB_CHUNK_HEADER = 19,
+  HPE_CB_CHUNK_COMPLETE = 20,
+  HPE_PAUSED = 21,
+  HPE_PAUSED_UPGRADE = 22,
+  HPE_USER = 23
 };
 typedef enum llhttp_errno llhttp_errno_t;
 
@@ -85,7 +86,9 @@ enum llhttp_flags {
   F_UPGRADE = 0x10,
   F_CONTENT_LENGTH = 0x20,
   F_SKIPBODY = 0x40,
-  F_TRAILING = 0x80
+  F_TRAILING = 0x80,
+  F_LENIENT = 0x100,
+  F_TRANSFER_ENCODING = 0x200
 };
 typedef enum llhttp_flags llhttp_flags_t;
 
@@ -157,14 +160,15 @@ typedef enum llhttp_method llhttp_method_t;
   XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \
   XX(13, INVALID_STATUS, INVALID_STATUS) \
   XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \
-  XX(15, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
-  XX(16, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
-  XX(17, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
-  XX(18, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
-  XX(19, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
-  XX(20, PAUSED, PAUSED) \
-  XX(21, PAUSED_UPGRADE, PAUSED_UPGRADE) \
-  XX(22, USER, USER) \
+  XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \
+  XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \
+  XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \
+  XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \
+  XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \
+  XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \
+  XX(21, PAUSED, PAUSED) \
+  XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \
+  XX(23, USER, USER) \
 
 
 #define HTTP_METHOD_MAP(XX) \
@@ -297,7 +301,7 @@ llhttp_errno_t llhttp_finish(llhttp_t* parser);
 int llhttp_message_needs_eof(const llhttp_t* parser);
 
 /* Returns `1` if there might be any other messages following the last that was
- * successfuly parsed.
+ * successfully parsed.
  */
 int llhttp_should_keep_alive(const llhttp_t* parser);
 
@@ -353,6 +357,18 @@ const char* llhttp_errno_name(llhttp_errno_t err);
 /* Returns textual name of HTTP method */
 const char* llhttp_method_name(llhttp_method_t method);
 
+
+/* Enables/disables lenient header value parsing (disabled by default).
+ *
+ * Lenient parsing disables header value token checks, extending llhttp's
+ * protocol support to highly non-compliant clients/server. No
+ * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
+ * lenient parsing is "on".
+ *
+ * **(USE AT YOUR OWN RISK)**
+ */
+void llhttp_set_lenient(llhttp_t* parser, int enabled);
+
 #ifdef __cplusplus
 }  /* extern "C" */
 #endif
index 45227b3..6f72465 100644 (file)
@@ -127,6 +127,15 @@ const char* llhttp_method_name(llhttp_method_t method) {
 }
 
 
+void llhttp_set_lenient(llhttp_t* parser, int enabled) {
+  if (enabled) {
+    parser->flags |= F_LENIENT;
+  } else {
+    parser->flags &= ~F_LENIENT;
+  }
+}
+
+
 /* Callbacks */
 
 
index 67834c2..6e4906d 100644 (file)
@@ -32,6 +32,7 @@ int llhttp__before_headers_complete(llhttp_t* parser, const char* p,
  * 2 - chunk_size_start
  * 3 - body_identity
  * 4 - body_identity_eof
+ * 5 - invalid transfer-encoding for request
  */
 int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
                                    const char* endp) {
@@ -47,8 +48,29 @@ int llhttp__after_headers_complete(llhttp_t* parser, const char* p,
   if (parser->flags & F_SKIPBODY) {
     return 0;
   } else if (parser->flags & F_CHUNKED) {
-    /* chunked encoding - ignore Content-Length header */
+    /* chunked encoding - ignore Content-Length header, prepare for a chunk */
     return 2;
+  } else if (parser->flags & F_TRANSFER_ENCODING) {
+    if (parser->type == HTTP_REQUEST && (parser->flags & F_LENIENT) == 0) {
+      /* 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.
+       */
+      return 5;
+    } 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.
+       */
+      return 4;
+    }
   } else {
     if (!(parser->flags & F_CONTENT_LENGTH)) {
       if (!llhttp_message_needs_eof(parser)) {
@@ -74,9 +96,11 @@ int llhttp__after_message_complete(llhttp_t* parser, const char* p,
   int should_keep_alive;
 
   should_keep_alive = llhttp_should_keep_alive(parser);
-  parser->flags = 0;
   parser->finish = HTTP_FINISH_SAFE;
 
+  /* Keep `F_LENIENT` flag between messages, but reset every other flag */
+  parser->flags &= F_LENIENT;
+
   /* NOTE: this is ignored in loose parsing mode */
   return should_keep_alive;
 }
@@ -95,6 +119,12 @@ int llhttp_message_needs_eof(const llhttp_t* parser) {
     return 0;
   }
 
+  /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */
+  if ((parser->flags & F_TRANSFER_ENCODING) &&
+      (parser->flags & F_CHUNKED) == 0) {
+    return 1;
+  }
+
   if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {
     return 0;
   }
index dc363aa..2a44fa6 100644 (file)
@@ -2,6 +2,20 @@
 #include <stdint.h>
 #include <string.h>
 
+#ifdef __SSE4_2__
+ #ifdef _MSC_VER
+  #include <nmmintrin.h>
+ #else  /* !_MSC_VER */
+  #include <x86intrin.h>
+ #endif  /* _MSC_VER */
+#endif  /* __SSE4_2__ */
+
+#ifdef _MSC_VER
+ #define ALIGN(n) _declspec(align(n))
+#else  /* !_MSC_VER */
+ #define ALIGN(n) __attribute__((aligned(n)))
+#endif  /* _MSC_VER */
+
 #include "llhttp.h"
 
 typedef int (*llhttp__internal__span_cb)(
@@ -10,147 +24,171 @@ typedef int (*llhttp__internal__span_cb)(
 static const unsigned char llparse_blob0[] = {
   'C', 'L'
 };
-static const unsigned char llparse_blob1[] = {
-  'o', 'n'
+#ifdef __SSE4_2__
+static const unsigned char ALIGN(16) llparse_blob1[] = {
+  0x9, 0x9, 0xc, 0xc, '!', '"', '$', '>', '@', '~', 0x80,
+  0xff, 0x0, 0x0, 0x0, 0x0
 };
+#endif  /* __SSE4_2__ */
 static const unsigned char llparse_blob2[] = {
-  'e', 'c', 't', 'i', 'o', 'n'
+  'o', 'n'
 };
 static const unsigned char llparse_blob3[] = {
-  'l', 'o', 's', 'e'
+  'e', 'c', 't', 'i', 'o', 'n'
 };
 static const unsigned char llparse_blob4[] = {
-  'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e'
+  'l', 'o', 's', 'e'
 };
 static const unsigned char llparse_blob5[] = {
-  'p', 'g', 'r', 'a', 'd', 'e'
+  'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e'
 };
 static const unsigned char llparse_blob6[] = {
-  'h', 'u', 'n', 'k', 'e', 'd'
+  'p', 'g', 'r', 'a', 'd', 'e'
 };
-static const unsigned char llparse_blob7[] = {
-  'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h'
+#ifdef __SSE4_2__
+static const unsigned char ALIGN(16) llparse_blob7[] = {
+  0x9, 0x9, ' ', '~', 0x80, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0
 };
+#endif  /* __SSE4_2__ */
 static const unsigned char llparse_blob8[] = {
+  'c', 'h', 'u', 'n', 'k', 'e', 'd'
+};
+#ifdef __SSE4_2__
+static const unsigned char ALIGN(16) llparse_blob9[] = {
+  ' ', '!', '#', '\'', '*', '+', '-', '.', '0', '9', 'A',
+  'Z', '^', 'z', '|', '|'
+};
+#endif  /* __SSE4_2__ */
+#ifdef __SSE4_2__
+static const unsigned char ALIGN(16) llparse_blob10[] = {
+  '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0
+};
+#endif  /* __SSE4_2__ */
+static const unsigned char llparse_blob11[] = {
+  'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h'
+};
+static const unsigned char llparse_blob12[] = {
   'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c',
   't', 'i', 'o', 'n'
 };
-static const unsigned char llparse_blob9[] = {
+static const unsigned char llparse_blob13[] = {
   'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c',
   'o', 'd', 'i', 'n', 'g'
 };
-static const unsigned char llparse_blob10[] = {
+static const unsigned char llparse_blob14[] = {
   'p', 'g', 'r', 'a', 'd', 'e'
 };
-static const unsigned char llparse_blob11[] = {
+static const unsigned char llparse_blob15[] = {
   0xd, 0xa
 };
-static const unsigned char llparse_blob12[] = {
+static const unsigned char llparse_blob16[] = {
   'T', 'T', 'P', '/'
 };
-static const unsigned char llparse_blob13[] = {
+static const unsigned char llparse_blob17[] = {
   'C', 'E', '/'
 };
-static const unsigned char llparse_blob14[] = {
+static const unsigned char llparse_blob18[] = {
   'I', 'N', 'D'
 };
-static const unsigned char llparse_blob15[] = {
+static const unsigned char llparse_blob19[] = {
   'E', 'C', 'K', 'O', 'U', 'T'
 };
-static const unsigned char llparse_blob16[] = {
+static const unsigned char llparse_blob20[] = {
   'N', 'E', 'C', 'T'
 };
-static const unsigned char llparse_blob17[] = {
+static const unsigned char llparse_blob21[] = {
   'E', 'L', 'E', 'T', 'E'
 };
-static const unsigned char llparse_blob18[] = {
+static const unsigned char llparse_blob22[] = {
   'E', 'T'
 };
-static const unsigned char llparse_blob19[] = {
+static const unsigned char llparse_blob23[] = {
   'E', 'A', 'D'
 };
-static const unsigned char llparse_blob20[] = {
+static const unsigned char llparse_blob24[] = {
   'N', 'K'
 };
-static const unsigned char llparse_blob21[] = {
+static const unsigned char llparse_blob25[] = {
   'C', 'K'
 };
-static const unsigned char llparse_blob22[] = {
+static const unsigned char llparse_blob26[] = {
   'S', 'E', 'A', 'R', 'C', 'H'
 };
-static const unsigned char llparse_blob23[] = {
+static const unsigned char llparse_blob27[] = {
   'R', 'G', 'E'
 };
-static const unsigned char llparse_blob24[] = {
+static const unsigned char llparse_blob28[] = {
   'C', 'T', 'I', 'V', 'I', 'T', 'Y'
 };
-static const unsigned char llparse_blob25[] = {
+static const unsigned char llparse_blob29[] = {
   'L', 'E', 'N', 'D', 'A', 'R'
 };
-static const unsigned char llparse_blob26[] = {
+static const unsigned char llparse_blob30[] = {
   'V', 'E'
 };
-static const unsigned char llparse_blob27[] = {
+static const unsigned char llparse_blob31[] = {
   'O', 'T', 'I', 'F', 'Y'
 };
-static const unsigned char llparse_blob28[] = {
+static const unsigned char llparse_blob32[] = {
   'P', 'T', 'I', 'O', 'N', 'S'
 };
-static const unsigned char llparse_blob29[] = {
+static const unsigned char llparse_blob33[] = {
   'T', 'C', 'H'
 };
-static const unsigned char llparse_blob30[] = {
+static const unsigned char llparse_blob34[] = {
   'S', 'T'
 };
-static const unsigned char llparse_blob31[] = {
+static const unsigned char llparse_blob35[] = {
   'O', 'P'
 };
-static const unsigned char llparse_blob32[] = {
+static const unsigned char llparse_blob36[] = {
   'I', 'N', 'D'
 };
-static const unsigned char llparse_blob33[] = {
+static const unsigned char llparse_blob37[] = {
   'A', 'T', 'C', 'H'
 };
-static const unsigned char llparse_blob34[] = {
+static const unsigned char llparse_blob38[] = {
   'G', 'E'
 };
-static const unsigned char llparse_blob35[] = {
+static const unsigned char llparse_blob39[] = {
   'I', 'N', 'D'
 };
-static const unsigned char llparse_blob36[] = {
+static const unsigned char llparse_blob40[] = {
   'O', 'R', 'T'
 };
-static const unsigned char llparse_blob37[] = {
+static const unsigned char llparse_blob41[] = {
   'A', 'R', 'C', 'H'
 };
-static const unsigned char llparse_blob38[] = {
+static const unsigned char llparse_blob42[] = {
   'U', 'R', 'C', 'E'
 };
-static const unsigned char llparse_blob39[] = {
+static const unsigned char llparse_blob43[] = {
   'B', 'S', 'C', 'R', 'I', 'B', 'E'
 };
-static const unsigned char llparse_blob40[] = {
+static const unsigned char llparse_blob44[] = {
   'R', 'A', 'C', 'E'
 };
-static const unsigned char llparse_blob41[] = {
+static const unsigned char llparse_blob45[] = {
   'I', 'N', 'D'
 };
-static const unsigned char llparse_blob42[] = {
+static const unsigned char llparse_blob46[] = {
   'N', 'K'
 };
-static const unsigned char llparse_blob43[] = {
+static const unsigned char llparse_blob47[] = {
   'C', 'K'
 };
-static const unsigned char llparse_blob44[] = {
+static const unsigned char llparse_blob48[] = {
   'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E'
 };
-static const unsigned char llparse_blob45[] = {
+static const unsigned char llparse_blob49[] = {
   'H', 'T', 'T', 'P', '/'
 };
-static const unsigned char llparse_blob46[] = {
+static const unsigned char llparse_blob50[] = {
   'A', 'D'
 };
-static const unsigned char llparse_blob47[] = {
+static const unsigned char llparse_blob51[] = {
   'T', 'P', '/'
 };
 
@@ -259,6 +297,7 @@ enum llparse_state_e {
   s_n_llhttp__internal__n_header_value_discard_ws_almost_done,
   s_n_llhttp__internal__n_header_value_lws,
   s_n_llhttp__internal__n_header_value_almost_done,
+  s_n_llhttp__internal__n_header_value_lenient,
   s_n_llhttp__internal__n_header_value_otherwise,
   s_n_llhttp__internal__n_header_value_connection_token,
   s_n_llhttp__internal__n_header_value_connection_ws,
@@ -266,13 +305,15 @@ enum llparse_state_e {
   s_n_llhttp__internal__n_header_value_connection_2,
   s_n_llhttp__internal__n_header_value_connection_3,
   s_n_llhttp__internal__n_header_value_connection,
-  s_n_llhttp__internal__n_error_15,
+  s_n_llhttp__internal__n_error_18,
   s_n_llhttp__internal__n_header_value,
   s_n_llhttp__internal__n_header_value_discard_rws,
-  s_n_llhttp__internal__n_error_16,
+  s_n_llhttp__internal__n_error_19,
   s_n_llhttp__internal__n_header_value_content_length_ws,
   s_n_llhttp__internal__n_header_value_content_length,
-  s_n_llhttp__internal__n_header_value_te_chunked_1,
+  s_n_llhttp__internal__n_header_value_te_chunked_last,
+  s_n_llhttp__internal__n_header_value_te_token_ows,
+  s_n_llhttp__internal__n_header_value_te_token,
   s_n_llhttp__internal__n_header_value_te_chunked,
   s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1,
   s_n_llhttp__internal__n_header_value_discard_ws,
@@ -487,10 +528,32 @@ int llhttp__after_message_complete(
     llhttp__internal_t* s, const unsigned char* p,
     const unsigned char* endp);
 
+int llhttp__internal__c_update_finish_1(
+    llhttp__internal_t* state,
+    const unsigned char* p,
+    const unsigned char* endp) {
+  state->finish = 0;
+  return 0;
+}
+
 int llhttp__internal__c_test_flags_1(
     llhttp__internal_t* state,
     const unsigned char* p,
     const unsigned char* endp) {
+  return (state->flags & 544) == 544;
+}
+
+int llhttp__internal__c_test_flags_2(
+    llhttp__internal_t* state,
+    const unsigned char* p,
+    const unsigned char* endp) {
+  return (state->flags & 256) == 256;
+}
+
+int llhttp__internal__c_test_flags_3(
+    llhttp__internal_t* state,
+    const unsigned char* p,
+    const unsigned char* endp) {
   return (state->flags & 40) == 40;
 }
 
@@ -559,7 +622,7 @@ int llhttp__internal__c_or_flags(
   return 0;
 }
 
-int llhttp__internal__c_update_finish_1(
+int llhttp__internal__c_update_finish_2(
     llhttp__internal_t* state,
     const unsigned char* p,
     const unsigned char* endp) {
@@ -671,7 +734,7 @@ int llhttp__internal__c_update_header_state_6(
   return 0;
 }
 
-int llhttp__internal__c_test_flags_2(
+int llhttp__internal__c_test_flags_5(
     llhttp__internal_t* state,
     const unsigned char* p,
     const unsigned char* endp) {
@@ -712,6 +775,14 @@ int llhttp__internal__c_or_flags_15(
   return 0;
 }
 
+int llhttp__internal__c_or_flags_16(
+    llhttp__internal_t* state,
+    const unsigned char* p,
+    const unsigned char* endp) {
+  state->flags |= 512;
+  return 0;
+}
+
 int llhttp__internal__c_update_header_state_8(
     llhttp__internal_t* state,
     const unsigned char* p,
@@ -720,7 +791,7 @@ int llhttp__internal__c_update_header_state_8(
   return 0;
 }
 
-int llhttp__internal__c_or_flags_16(
+int llhttp__internal__c_or_flags_17(
     llhttp__internal_t* state,
     const unsigned char* p,
     const unsigned char* endp) {
@@ -824,14 +895,14 @@ static llparse_state_t llhttp__internal__run(
     s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: {
       switch (llhttp__after_message_complete(state, p, endp)) {
         default:
-          goto s_n_llhttp__internal__n_start;
+          goto s_n_llhttp__internal__n_invoke_update_finish_1;
       }
       /* UNREACHABLE */;
       abort();
     }
     case s_n_llhttp__internal__n_pause_1:
     s_n_llhttp__internal__n_pause_1: {
-      state->error = 0x15;
+      state->error = 0x16;
       state->reason = "Pause on CONNECT/Upgrade";
       state->error_pos = (const char*) p;
       state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;
@@ -855,7 +926,7 @@ static llparse_state_t llhttp__internal__run(
       switch (llhttp__on_message_complete(state, p, endp)) {
         case 0:
           goto s_n_llhttp__internal__n_invoke_is_equal_upgrade;
-        case 20:
+        case 21:
           goto s_n_llhttp__internal__n_pause_5;
         default:
           goto s_n_llhttp__internal__n_error_9;
@@ -1277,7 +1348,7 @@ static llparse_state_t llhttp__internal__run(
       }
       state->_span_pos0 = (void*) p;
       state->_span_cb0 = llhttp__on_body;
-      goto s_n_llhttp__internal__n_invoke_update_finish_1;
+      goto s_n_llhttp__internal__n_eof;
       /* UNREACHABLE */;
       abort();
     }
@@ -1291,7 +1362,9 @@ static llparse_state_t llhttp__internal__run(
         case 3:
           goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1;
         case 4:
-          goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;
+          goto s_n_llhttp__internal__n_invoke_update_finish_2;
+        case 5:
+          goto s_n_llhttp__internal__n_error_10;
         default:
           goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete;
       }
@@ -1363,7 +1436,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_invoke_load_header_state_2;
+          goto s_n_llhttp__internal__n_invoke_load_header_state_3;
         }
       }
       /* UNREACHABLE */;
@@ -1380,7 +1453,27 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_header_value_lws;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_12;
+          goto s_n_llhttp__internal__n_error_15;
+        }
+      }
+      /* UNREACHABLE */;
+      abort();
+    }
+    case s_n_llhttp__internal__n_header_value_lenient:
+    s_n_llhttp__internal__n_header_value_lenient: {
+      if (p == endp) {
+        return s_n_llhttp__internal__n_header_value_lenient;
+      }
+      switch (*p) {
+        case 10: {
+          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;
+        }
+        case 13: {
+          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;
+        }
+        default: {
+          p++;
+          goto s_n_llhttp__internal__n_header_value_lenient;
         }
       }
       /* UNREACHABLE */;
@@ -1399,7 +1492,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_13;
+          goto s_n_llhttp__internal__n_invoke_test_flags_4;
         }
       }
       /* UNREACHABLE */;
@@ -1462,7 +1555,7 @@ static llparse_state_t llhttp__internal__run(
         }
         case ',': {
           p++;
-          goto s_n_llhttp__internal__n_invoke_load_header_state_3;
+          goto s_n_llhttp__internal__n_invoke_load_header_state_4;
         }
         default: {
           goto s_n_llhttp__internal__n_invoke_update_header_state_4;
@@ -1478,7 +1571,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_value_connection_1;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob3, 4);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob4, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -1502,7 +1595,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_value_connection_2;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob4, 9);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 9);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -1526,7 +1619,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_value_connection_3;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 6);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -1576,8 +1669,8 @@ static llparse_state_t llhttp__internal__run(
       /* UNREACHABLE */;
       abort();
     }
-    case s_n_llhttp__internal__n_error_15:
-    s_n_llhttp__internal__n_error_15: {
+    case s_n_llhttp__internal__n_error_18:
+    s_n_llhttp__internal__n_error_18: {
       state->error = 0xb;
       state->reason = "Content-Length overflow";
       state->error_pos = (const char*) p;
@@ -1609,6 +1702,30 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_value;
       }
+      #ifdef __SSE4_2__
+      if (endp - p >= 16) {
+        __m128i ranges;
+        __m128i input;
+        int avail;
+        int match_len;
+      
+        /* Load input */
+        input = _mm_loadu_si128((__m128i const*) p);
+        ranges = _mm_loadu_si128((__m128i const*) llparse_blob7);
+      
+        /* Find first character that does not match `ranges` */
+        match_len = _mm_cmpestri(ranges, 6,
+            input, 16,
+            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
+              _SIDD_NEGATIVE_POLARITY);
+      
+        if (match_len != 0) {
+          p += match_len;
+          goto s_n_llhttp__internal__n_header_value;
+        }
+        goto s_n_llhttp__internal__n_header_value_otherwise;
+      }
+      #endif  /* __SSE4_2__ */
       switch (lookup_table[(uint8_t) *p]) {
         case 1: {
           p++;
@@ -1644,8 +1761,8 @@ static llparse_state_t llhttp__internal__run(
       /* UNREACHABLE */;
       abort();
     }
-    case s_n_llhttp__internal__n_error_16:
-    s_n_llhttp__internal__n_error_16: {
+    case s_n_llhttp__internal__n_error_19:
+    s_n_llhttp__internal__n_error_19: {
       state->error = 0xb;
       state->reason = "Invalid character in Content-Length";
       state->error_pos = (const char*) p;
@@ -1671,7 +1788,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_header_value_content_length_ws;
         }
         default: {
-          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4;
+          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5;
         }
       }
       /* UNREACHABLE */;
@@ -1740,48 +1857,81 @@ static llparse_state_t llhttp__internal__run(
       /* UNREACHABLE */;
       abort();
     }
-    case s_n_llhttp__internal__n_header_value_te_chunked_1:
-    s_n_llhttp__internal__n_header_value_te_chunked_1: {
-      llparse_match_t match_seq;
-      
+    case s_n_llhttp__internal__n_header_value_te_chunked_last:
+    s_n_llhttp__internal__n_header_value_te_chunked_last: {
       if (p == endp) {
-        return s_n_llhttp__internal__n_header_value_te_chunked_1;
+        return s_n_llhttp__internal__n_header_value_te_chunked_last;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 6);
-      p = match_seq.current;
-      switch (match_seq.status) {
-        case kMatchComplete: {
-          p++;
+      switch (*p) {
+        case 10: {
           goto s_n_llhttp__internal__n_invoke_update_header_state_8;
         }
-        case kMatchPause: {
-          return s_n_llhttp__internal__n_header_value_te_chunked_1;
+        case 13: {
+          goto s_n_llhttp__internal__n_invoke_update_header_state_8;
         }
-        case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_invoke_update_header_state_7;
+        case ' ': {
+          p++;
+          goto s_n_llhttp__internal__n_header_value_te_chunked_last;
+        }
+        default: {
+          goto s_n_llhttp__internal__n_header_value_te_chunked;
         }
       }
       /* UNREACHABLE */;
       abort();
     }
-    case s_n_llhttp__internal__n_header_value_te_chunked:
-    s_n_llhttp__internal__n_header_value_te_chunked: {
+    case s_n_llhttp__internal__n_header_value_te_token_ows:
+    s_n_llhttp__internal__n_header_value_te_token_ows: {
       if (p == endp) {
-        return s_n_llhttp__internal__n_header_value_te_chunked;
+        return s_n_llhttp__internal__n_header_value_te_token_ows;
       }
-      switch (((*p) | 0x20)) {
-        case 10: {
-          goto s_n_llhttp__internal__n_header_value_discard_rws;
-        }
-        case 13: {
-          goto s_n_llhttp__internal__n_header_value_discard_rws;
+      switch (*p) {
+        case 9: {
+          p++;
+          goto s_n_llhttp__internal__n_header_value_te_token_ows;
         }
         case ' ': {
-          goto s_n_llhttp__internal__n_header_value_discard_rws;
+          p++;
+          goto s_n_llhttp__internal__n_header_value_te_token_ows;
         }
-        case 'c': {
+        default: {
+          goto s_n_llhttp__internal__n_header_value_te_chunked;
+        }
+      }
+      /* UNREACHABLE */;
+      abort();
+    }
+    case s_n_llhttp__internal__n_header_value_te_token:
+    s_n_llhttp__internal__n_header_value_te_token: {
+      static uint8_t lookup_table[] = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
+      };
+      if (p == endp) {
+        return s_n_llhttp__internal__n_header_value_te_token;
+      }
+      switch (lookup_table[(uint8_t) *p]) {
+        case 1: {
           p++;
-          goto s_n_llhttp__internal__n_header_value_te_chunked_1;
+          goto s_n_llhttp__internal__n_header_value_te_token;
+        }
+        case 2: {
+          p++;
+          goto s_n_llhttp__internal__n_header_value_te_token_ows;
         }
         default: {
           goto s_n_llhttp__internal__n_invoke_update_header_state_7;
@@ -1790,6 +1940,30 @@ static llparse_state_t llhttp__internal__run(
       /* UNREACHABLE */;
       abort();
     }
+    case s_n_llhttp__internal__n_header_value_te_chunked:
+    s_n_llhttp__internal__n_header_value_te_chunked: {
+      llparse_match_t match_seq;
+      
+      if (p == endp) {
+        return s_n_llhttp__internal__n_header_value_te_chunked;
+      }
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob8, 7);
+      p = match_seq.current;
+      switch (match_seq.status) {
+        case kMatchComplete: {
+          p++;
+          goto s_n_llhttp__internal__n_header_value_te_chunked_last;
+        }
+        case kMatchPause: {
+          return s_n_llhttp__internal__n_header_value_te_chunked;
+        }
+        case kMatchMismatch: {
+          goto s_n_llhttp__internal__n_header_value_te_token;
+        }
+      }
+      /* UNREACHABLE */;
+      abort();
+    }
     case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1:
     s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: {
       if (p == endp) {
@@ -1797,7 +1971,7 @@ static llparse_state_t llhttp__internal__run(
       }
       state->_span_pos0 = (void*) p;
       state->_span_cb0 = llhttp__on_header_value;
-      goto s_n_llhttp__internal__n_invoke_load_header_state_1;
+      goto s_n_llhttp__internal__n_invoke_load_header_state_2;
       /* UNREACHABLE */;
       abort();
     }
@@ -1840,7 +2014,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_17;
+          goto s_n_llhttp__internal__n_error_20;
         }
       }
       /* UNREACHABLE */;
@@ -1869,6 +2043,42 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_general;
       }
+      #ifdef __SSE4_2__
+      if (endp - p >= 16) {
+        __m128i ranges;
+        __m128i input;
+        int avail;
+        int match_len;
+      
+        /* Load input */
+        input = _mm_loadu_si128((__m128i const*) p);
+        ranges = _mm_loadu_si128((__m128i const*) llparse_blob9);
+      
+        /* Find first character that does not match `ranges` */
+        match_len = _mm_cmpestri(ranges, 16,
+            input, 16,
+            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
+              _SIDD_NEGATIVE_POLARITY);
+      
+        if (match_len != 0) {
+          p += match_len;
+          goto s_n_llhttp__internal__n_header_field_general;
+        }
+        ranges = _mm_loadu_si128((__m128i const*) llparse_blob10);
+      
+        /* Find first character that does not match `ranges` */
+        match_len = _mm_cmpestri(ranges, 2,
+            input, 16,
+            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
+              _SIDD_NEGATIVE_POLARITY);
+      
+        if (match_len != 0) {
+          p += match_len;
+          goto s_n_llhttp__internal__n_header_field_general;
+        }
+        goto s_n_llhttp__internal__n_header_field_general_otherwise;
+      }
+      #endif  /* __SSE4_2__ */
       switch (lookup_table[(uint8_t) *p]) {
         case 1: {
           p++;
@@ -1908,7 +2118,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_3;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob2, 6);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob3, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -1933,7 +2143,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_4;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob7, 10);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob11, 10);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -1979,7 +2189,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_1;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob1, 2);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob2, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2003,7 +2213,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_5;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob8, 15);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob12, 15);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2028,7 +2238,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_6;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob9, 16);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob13, 16);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2053,7 +2263,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_header_field_7;
       }
-      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob10, 6);
+      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob14, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2148,7 +2358,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_url_skip_lf_to_http09;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob11, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2159,7 +2369,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_url_skip_lf_to_http09;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_18;
+          goto s_n_llhttp__internal__n_error_21;
         }
       }
       /* UNREACHABLE */;
@@ -2176,7 +2386,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_header_field_start;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_19;
+          goto s_n_llhttp__internal__n_error_22;
         }
       }
       /* UNREACHABLE */;
@@ -2197,7 +2407,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_http_end_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_19;
+          goto s_n_llhttp__internal__n_error_22;
         }
       }
       /* UNREACHABLE */;
@@ -2260,7 +2470,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_http_minor;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_20;
+          goto s_n_llhttp__internal__n_error_23;
         }
       }
       /* UNREACHABLE */;
@@ -2277,7 +2487,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_http_minor;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_21;
+          goto s_n_llhttp__internal__n_error_24;
         }
       }
       /* UNREACHABLE */;
@@ -2340,7 +2550,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_http_major;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_22;
+          goto s_n_llhttp__internal__n_error_25;
         }
       }
       /* UNREACHABLE */;
@@ -2353,7 +2563,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_req_http_start_1;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob12, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2364,7 +2574,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_req_http_start_1;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_24;
+          goto s_n_llhttp__internal__n_error_27;
         }
       }
       /* UNREACHABLE */;
@@ -2377,7 +2587,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_req_http_start_2;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2388,7 +2598,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_req_http_start_2;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_24;
+          goto s_n_llhttp__internal__n_error_27;
         }
       }
       /* UNREACHABLE */;
@@ -2413,7 +2623,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_http_start_2;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_24;
+          goto s_n_llhttp__internal__n_error_27;
         }
       }
       /* UNREACHABLE */;
@@ -2467,7 +2677,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_25;
+          goto s_n_llhttp__internal__n_error_28;
         }
       }
       /* UNREACHABLE */;
@@ -2524,7 +2734,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_span_end_stub_query_3;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_26;
+          goto s_n_llhttp__internal__n_error_29;
         }
       }
       /* UNREACHABLE */;
@@ -2554,7 +2764,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_url_query;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_27;
+          goto s_n_llhttp__internal__n_error_30;
         }
       }
       /* UNREACHABLE */;
@@ -2583,6 +2793,30 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_url_path;
       }
+      #ifdef __SSE4_2__
+      if (endp - p >= 16) {
+        __m128i ranges;
+        __m128i input;
+        int avail;
+        int match_len;
+      
+        /* Load input */
+        input = _mm_loadu_si128((__m128i const*) p);
+        ranges = _mm_loadu_si128((__m128i const*) llparse_blob1);
+      
+        /* Find first character that does not match `ranges` */
+        match_len = _mm_cmpestri(ranges, 12,
+            input, 16,
+            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |
+              _SIDD_NEGATIVE_POLARITY);
+      
+        if (match_len != 0) {
+          p += match_len;
+          goto s_n_llhttp__internal__n_url_path;
+        }
+        goto s_n_llhttp__internal__n_url_query_or_fragment;
+      }
+      #endif  /* __SSE4_2__ */
       switch (lookup_table[(uint8_t) *p]) {
         case 1: {
           p++;
@@ -2671,10 +2905,10 @@ static llparse_state_t llhttp__internal__run(
         }
         case 7: {
           p++;
-          goto s_n_llhttp__internal__n_error_28;
+          goto s_n_llhttp__internal__n_error_31;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_29;
+          goto s_n_llhttp__internal__n_error_32;
         }
       }
       /* UNREACHABLE */;
@@ -2729,7 +2963,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_url_server_with_at;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_30;
+          goto s_n_llhttp__internal__n_error_33;
         }
       }
       /* UNREACHABLE */;
@@ -2746,7 +2980,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_url_server;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_32;
+          goto s_n_llhttp__internal__n_error_35;
         }
       }
       /* UNREACHABLE */;
@@ -2760,22 +2994,22 @@ static llparse_state_t llhttp__internal__run(
       switch (*p) {
         case 10: {
           p++;
-          goto s_n_llhttp__internal__n_error_31;
+          goto s_n_llhttp__internal__n_error_34;
         }
         case 13: {
           p++;
-          goto s_n_llhttp__internal__n_error_31;
+          goto s_n_llhttp__internal__n_error_34;
         }
         case ' ': {
           p++;
-          goto s_n_llhttp__internal__n_error_31;
+          goto s_n_llhttp__internal__n_error_34;
         }
         case '/': {
           p++;
           goto s_n_llhttp__internal__n_url_schema_delim_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_32;
+          goto s_n_llhttp__internal__n_error_35;
         }
       }
       /* UNREACHABLE */;
@@ -2817,7 +3051,7 @@ static llparse_state_t llhttp__internal__run(
       switch (lookup_table[(uint8_t) *p]) {
         case 1: {
           p++;
-          goto s_n_llhttp__internal__n_error_31;
+          goto s_n_llhttp__internal__n_error_34;
         }
         case 2: {
           goto s_n_llhttp__internal__n_span_end_stub_schema;
@@ -2827,7 +3061,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_url_schema;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_33;
+          goto s_n_llhttp__internal__n_error_36;
         }
       }
       /* UNREACHABLE */;
@@ -2859,7 +3093,7 @@ static llparse_state_t llhttp__internal__run(
       switch (lookup_table[(uint8_t) *p]) {
         case 1: {
           p++;
-          goto s_n_llhttp__internal__n_error_31;
+          goto s_n_llhttp__internal__n_error_34;
         }
         case 2: {
           goto s_n_llhttp__internal__n_span_start_stub_path_2;
@@ -2868,7 +3102,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_url_schema;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_34;
+          goto s_n_llhttp__internal__n_error_37;
         }
       }
       /* UNREACHABLE */;
@@ -2924,7 +3158,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_spaces_before_url;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_35;
+          goto s_n_llhttp__internal__n_error_38;
         }
       }
       /* UNREACHABLE */;
@@ -2949,7 +3183,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_1;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -2962,7 +3196,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_2;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2974,7 +3208,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_2;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -2987,7 +3221,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_4;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 6);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -2999,7 +3233,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_4;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3012,7 +3246,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_6;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3024,7 +3258,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_6;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3042,7 +3276,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_method_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3063,7 +3297,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_7;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3084,7 +3318,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_5;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3097,7 +3331,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_8;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 5);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 5);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3109,7 +3343,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_8;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3122,7 +3356,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_9;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3134,7 +3368,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_9;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3147,7 +3381,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_10;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3159,7 +3393,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_10;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3172,7 +3406,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_12;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3184,7 +3418,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_12;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3197,7 +3431,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_13;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3209,7 +3443,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_13;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3230,7 +3464,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_13;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3243,7 +3477,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_15;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 6);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3255,7 +3489,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_15;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3268,7 +3502,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_16;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3280,7 +3514,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_16;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3293,7 +3527,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_18;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 7);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 7);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3305,7 +3539,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_18;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3318,7 +3552,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_20;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 6);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3330,7 +3564,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_20;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3348,7 +3582,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_method_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3369,7 +3603,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_21;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3390,7 +3624,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_19;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3403,7 +3637,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_22;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3415,7 +3649,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_22;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3444,7 +3678,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_22;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3457,7 +3691,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_23;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 5);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 5);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3469,7 +3703,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_23;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3482,7 +3716,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_24;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 6);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 6);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3494,7 +3728,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_24;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3507,7 +3741,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_26;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3519,7 +3753,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_26;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3532,7 +3766,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_27;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3544,7 +3778,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_27;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3557,7 +3791,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_30;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3569,7 +3803,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_30;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3582,7 +3816,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_31;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3594,7 +3828,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_31;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3615,7 +3849,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_31;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3628,7 +3862,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_28;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3639,7 +3873,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_28;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3652,7 +3886,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_33;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3664,7 +3898,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_33;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3686,7 +3920,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_method_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3715,7 +3949,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_32;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3728,7 +3962,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_36;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3740,7 +3974,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_36;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3753,7 +3987,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_37;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3765,7 +3999,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_37;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3786,7 +4020,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_37;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3803,7 +4037,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_35;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3816,7 +4050,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_39;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3828,7 +4062,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_39;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3841,7 +4075,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_40;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3853,7 +4087,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_40;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3866,7 +4100,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_41;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 7);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 7);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3878,7 +4112,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_41;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3903,7 +4137,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_41;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3916,7 +4150,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_42;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 4);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 4);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3928,7 +4162,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_42;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3941,7 +4175,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_45;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3953,7 +4187,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_45;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3966,7 +4200,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_47;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -3978,7 +4212,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_47;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -3991,7 +4225,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_48;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -4003,7 +4237,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_48;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4024,7 +4258,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_48;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4037,7 +4271,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_req_49;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 8);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 8);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -4049,7 +4283,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_req_49;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4074,7 +4308,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_49;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4091,7 +4325,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_44;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4164,7 +4398,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_start_req_43;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_43;
+          goto s_n_llhttp__internal__n_error_46;
         }
       }
       /* UNREACHABLE */;
@@ -4249,7 +4483,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_res_status_start;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_37;
+          goto s_n_llhttp__internal__n_error_40;
         }
       }
       /* UNREACHABLE */;
@@ -4329,7 +4563,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_update_status_code;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_38;
+          goto s_n_llhttp__internal__n_error_41;
         }
       }
       /* UNREACHABLE */;
@@ -4392,7 +4626,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_http_minor_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_39;
+          goto s_n_llhttp__internal__n_error_42;
         }
       }
       /* UNREACHABLE */;
@@ -4409,7 +4643,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_res_http_minor;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_40;
+          goto s_n_llhttp__internal__n_error_43;
         }
       }
       /* UNREACHABLE */;
@@ -4472,7 +4706,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_invoke_store_http_major_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_41;
+          goto s_n_llhttp__internal__n_error_44;
         }
       }
       /* UNREACHABLE */;
@@ -4485,7 +4719,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_start_res;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 5);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 5);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -4496,7 +4730,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_start_res;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_44;
+          goto s_n_llhttp__internal__n_error_47;
         }
       }
       /* UNREACHABLE */;
@@ -4509,7 +4743,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_req_or_res_method_2;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 2);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 2);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -4521,7 +4755,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_req_or_res_method_2;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_42;
+          goto s_n_llhttp__internal__n_error_45;
         }
       }
       /* UNREACHABLE */;
@@ -4534,7 +4768,7 @@ static llparse_state_t llhttp__internal__run(
       if (p == endp) {
         return s_n_llhttp__internal__n_req_or_res_method_3;
       }
-      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3);
+      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 3);
       p = match_seq.current;
       switch (match_seq.status) {
         case kMatchComplete: {
@@ -4545,7 +4779,7 @@ static llparse_state_t llhttp__internal__run(
           return s_n_llhttp__internal__n_req_or_res_method_3;
         }
         case kMatchMismatch: {
-          goto s_n_llhttp__internal__n_error_42;
+          goto s_n_llhttp__internal__n_error_45;
         }
       }
       /* UNREACHABLE */;
@@ -4566,7 +4800,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_or_res_method_3;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_42;
+          goto s_n_llhttp__internal__n_error_45;
         }
       }
       /* UNREACHABLE */;
@@ -4583,7 +4817,7 @@ static llparse_state_t llhttp__internal__run(
           goto s_n_llhttp__internal__n_req_or_res_method_1;
         }
         default: {
-          goto s_n_llhttp__internal__n_error_42;
+          goto s_n_llhttp__internal__n_error_45;
         }
       }
       /* UNREACHABLE */;
@@ -4643,7 +4877,7 @@ static llparse_state_t llhttp__internal__run(
       /* UNREACHABLE */
       abort();
   }
-  s_n_llhttp__internal__n_error_31: {
+  s_n_llhttp__internal__n_error_34: {
     state->error = 0x7;
     state->reason = "Invalid characters in url";
     state->error_pos = (const char*) p;
@@ -4652,8 +4886,16 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_invoke_update_finish_1: {
+    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {
+      default:
+        goto s_n_llhttp__internal__n_start;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_pause_5: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_message_complete pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade;
@@ -4662,7 +4904,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_9: {
-    state->error = 0x11;
+    state->error = 0x12;
     state->reason = "`on_message_complete` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4671,7 +4913,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_7: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_chunk_complete pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;
@@ -4679,8 +4921,8 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_11: {
-    state->error = 0x13;
+  s_n_llhttp__internal__n_error_13: {
+    state->error = 0x14;
     state->reason = "`on_chunk_complete` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4692,15 +4934,24 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_chunk_complete(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_7;
       default:
-        goto s_n_llhttp__internal__n_error_11;
+        goto s_n_llhttp__internal__n_error_13;
     }
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_10: {
+  s_n_llhttp__internal__n_error_11: {
+    state->error = 0x4;
+    state->reason = "Content-Length can't be present with Transfer-Encoding";
+    state->error_pos = (const char*) p;
+    state->_current = (void*) (intptr_t) s_error;
+    return s_error;
+    /* UNREACHABLE */;
+    abort();
+  }
+  s_n_llhttp__internal__n_error_12: {
     state->error = 0x4;
     state->reason = "Content-Length can't be present with chunked encoding";
     state->error_pos = (const char*) p;
@@ -4710,7 +4961,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_2: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_message_complete pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1;
@@ -4719,7 +4970,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_3: {
-    state->error = 0x11;
+    state->error = 0x12;
     state->reason = "`on_message_complete` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4731,7 +4982,7 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_message_complete(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_pause_1;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_2;
       default:
         goto s_n_llhttp__internal__n_error_3;
@@ -4749,7 +5000,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_3: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_chunk_complete pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length;
@@ -4758,7 +5009,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_5: {
-    state->error = 0x13;
+    state->error = 0x14;
     state->reason = "`on_chunk_complete` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4770,7 +5021,7 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_chunk_complete(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_invoke_update_content_length;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_3;
       default:
         goto s_n_llhttp__internal__n_error_5;
@@ -4804,7 +5055,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_4: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_chunk_header pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length;
@@ -4813,7 +5064,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_4: {
-    state->error = 0x12;
+    state->error = 0x13;
     state->reason = "`on_chunk_header` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4825,7 +5076,7 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_chunk_header(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_invoke_is_equal_content_length;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_4;
       default:
         goto s_n_llhttp__internal__n_error_4;
@@ -4878,16 +5129,25 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_update_finish_1: {
-    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {
+  s_n_llhttp__internal__n_invoke_update_finish_2: {
+    switch (llhttp__internal__c_update_finish_2(state, p, endp)) {
       default:
-        goto s_n_llhttp__internal__n_eof;
+        goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;
     }
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_error_10: {
+    state->error = 0xf;
+    state->reason = "Request has invalid `Transfer-Encoding`";
+    state->error_pos = (const char*) p;
+    state->_current = (void*) (intptr_t) s_error;
+    return s_error;
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_pause: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_message_complete pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;
@@ -4896,7 +5156,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_2: {
-    state->error = 0x11;
+    state->error = 0x12;
     state->reason = "`on_message_complete` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4908,7 +5168,7 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_message_complete(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause;
       default:
         goto s_n_llhttp__internal__n_error_2;
@@ -4941,7 +5201,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_6: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "Paused by on_headers_complete";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;
@@ -4950,7 +5210,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error_1: {
-    state->error = 0x10;
+    state->error = 0x11;
     state->reason = "User callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -4966,7 +5226,7 @@ static llparse_state_t llhttp__internal__run(
         goto s_n_llhttp__internal__n_invoke_or_flags_1;
       case 2:
         goto s_n_llhttp__internal__n_invoke_update_upgrade;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_6;
       default:
         goto s_n_llhttp__internal__n_error_1;
@@ -4982,10 +5242,32 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_invoke_test_flags_3: {
+    switch (llhttp__internal__c_test_flags_3(state, p, endp)) {
+      case 1:
+        goto s_n_llhttp__internal__n_error_12;
+      default:
+        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
+  s_n_llhttp__internal__n_invoke_test_flags_2: {
+    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {
+      case 0:
+        goto s_n_llhttp__internal__n_error_11;
+      case 1:
+        goto s_n_llhttp__internal__n_invoke_test_flags_3;
+      default:
+        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_invoke_test_flags_1: {
     switch (llhttp__internal__c_test_flags_1(state, p, endp)) {
       case 1:
-        goto s_n_llhttp__internal__n_error_10;
+        goto s_n_llhttp__internal__n_invoke_test_flags_2;
       default:
         goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;
     }
@@ -5002,6 +5284,15 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_error_14: {
+    state->error = 0xb;
+    state->reason = "Empty Content-Length";
+    state->error_pos = (const char*) p;
+    state->_current = (void*) (intptr_t) s_error;
+    return s_error;
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_span_end_llhttp__on_header_value: {
     const unsigned char* start;
     int err;
@@ -5059,7 +5350,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_load_header_state: {
+  s_n_llhttp__internal__n_invoke_load_header_state_1: {
     switch (llhttp__internal__c_load_header_state(state, p, endp)) {
       case 5:
         goto s_n_llhttp__internal__n_invoke_or_flags_3;
@@ -5075,6 +5366,16 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_invoke_load_header_state: {
+    switch (llhttp__internal__c_load_header_state(state, p, endp)) {
+      case 2:
+        goto s_n_llhttp__internal__n_error_14;
+      default:
+        goto s_n_llhttp__internal__n_invoke_load_header_state_1;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_invoke_update_header_state_1: {
     switch (llhttp__internal__c_update_header_state(state, p, endp)) {
       default:
@@ -5115,7 +5416,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_load_header_state_2: {
+  s_n_llhttp__internal__n_invoke_load_header_state_3: {
     switch (llhttp__internal__c_load_header_state(state, p, endp)) {
       case 5:
         goto s_n_llhttp__internal__n_invoke_or_flags_7;
@@ -5131,7 +5432,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_12: {
+  s_n_llhttp__internal__n_error_15: {
     state->error = 0x3;
     state->reason = "Missing expected LF after header value";
     state->error_pos = (const char*) p;
@@ -5175,7 +5476,25 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_13: {
+  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {
+    const unsigned char* start;
+    int err;
+    
+    start = state->_span_pos0;
+    state->_span_pos0 = NULL;
+    err = llhttp__on_header_value(state, start, p);
+    if (err != 0) {
+      state->error = err;
+      state->error_pos = (const char*) (p + 1);
+      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;
+      return s_error;
+    }
+    p++;
+    goto s_n_llhttp__internal__n_header_value_almost_done;
+    /* UNREACHABLE */;
+    abort();
+  }
+  s_n_llhttp__internal__n_error_16: {
     state->error = 0xa;
     state->reason = "Invalid header value char";
     state->error_pos = (const char*) p;
@@ -5184,6 +5503,16 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
+  s_n_llhttp__internal__n_invoke_test_flags_4: {
+    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {
+      case 1:
+        goto s_n_llhttp__internal__n_header_value_lenient;
+      default:
+        goto s_n_llhttp__internal__n_error_16;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
   s_n_llhttp__internal__n_invoke_update_header_state_3: {
     switch (llhttp__internal__c_update_header_state(state, p, endp)) {
       default:
@@ -5224,7 +5553,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_load_header_state_3: {
+  s_n_llhttp__internal__n_invoke_load_header_state_4: {
     switch (llhttp__internal__c_load_header_state(state, p, endp)) {
       case 5:
         goto s_n_llhttp__internal__n_invoke_or_flags_11;
@@ -5272,7 +5601,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {
+  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {
     const unsigned char* start;
     int err;
     
@@ -5282,17 +5611,17 @@ static llparse_state_t llhttp__internal__run(
     if (err != 0) {
       state->error = err;
       state->error_pos = (const char*) p;
-      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_15;
+      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_18;
       return s_error;
     }
-    goto s_n_llhttp__internal__n_error_15;
+    goto s_n_llhttp__internal__n_error_18;
     /* UNREACHABLE */;
     abort();
   }
   s_n_llhttp__internal__n_invoke_mul_add_content_length_1: {
     switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) {
       case 1:
-        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;
+        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4;
       default:
         goto s_n_llhttp__internal__n_header_value_content_length;
     }
@@ -5315,7 +5644,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {
+  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: {
     const unsigned char* start;
     int err;
     
@@ -5325,14 +5654,14 @@ static llparse_state_t llhttp__internal__run(
     if (err != 0) {
       state->error = err;
       state->error_pos = (const char*) p;
-      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_16;
+      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_19;
       return s_error;
     }
-    goto s_n_llhttp__internal__n_error_16;
+    goto s_n_llhttp__internal__n_error_19;
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_14: {
+  s_n_llhttp__internal__n_error_17: {
     state->error = 0x4;
     state->reason = "Duplicate Content-Length";
     state->error_pos = (const char*) p;
@@ -5341,12 +5670,12 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_test_flags_2: {
-    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {
+  s_n_llhttp__internal__n_invoke_test_flags_5: {
+    switch (llhttp__internal__c_test_flags_5(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_header_value_content_length;
       default:
-        goto s_n_llhttp__internal__n_error_14;
+        goto s_n_llhttp__internal__n_error_17;
     }
     /* UNREACHABLE */;
     abort();
@@ -5354,7 +5683,7 @@ static llparse_state_t llhttp__internal__run(
   s_n_llhttp__internal__n_invoke_update_header_state_8: {
     switch (llhttp__internal__c_update_header_state_8(state, p, endp)) {
       default:
-        goto s_n_llhttp__internal__n_header_value_discard_rws;
+        goto s_n_llhttp__internal__n_header_value_otherwise;
     }
     /* UNREACHABLE */;
     abort();
@@ -5362,21 +5691,29 @@ static llparse_state_t llhttp__internal__run(
   s_n_llhttp__internal__n_invoke_or_flags_16: {
     switch (llhttp__internal__c_or_flags_16(state, p, endp)) {
       default:
+        goto s_n_llhttp__internal__n_header_value_te_chunked;
+    }
+    /* UNREACHABLE */;
+    abort();
+  }
+  s_n_llhttp__internal__n_invoke_or_flags_17: {
+    switch (llhttp__internal__c_or_flags_17(state, p, endp)) {
+      default:
         goto s_n_llhttp__internal__n_invoke_update_header_state_7;
     }
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_invoke_load_header_state_1: {
+  s_n_llhttp__internal__n_invoke_load_header_state_2: {
     switch (llhttp__internal__c_load_header_state(state, p, endp)) {
       case 1:
         goto s_n_llhttp__internal__n_header_value_connection;
       case 2:
-        goto s_n_llhttp__internal__n_invoke_test_flags_2;
+        goto s_n_llhttp__internal__n_invoke_test_flags_5;
       case 3:
-        goto s_n_llhttp__internal__n_header_value_te_chunked;
-      case 4:
         goto s_n_llhttp__internal__n_invoke_or_flags_16;
+      case 4:
+        goto s_n_llhttp__internal__n_invoke_or_flags_17;
       default:
         goto s_n_llhttp__internal__n_header_value;
     }
@@ -5419,7 +5756,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_17: {
+  s_n_llhttp__internal__n_error_20: {
     state->error = 0xa;
     state->reason = "Invalid header token";
     state->error_pos = (const char*) p;
@@ -5485,7 +5822,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_18: {
+  s_n_llhttp__internal__n_error_21: {
     state->error = 0x7;
     state->reason = "Expected CRLF";
     state->error_pos = (const char*) p;
@@ -5511,7 +5848,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_19: {
+  s_n_llhttp__internal__n_error_22: {
     state->error = 0x9;
     state->reason = "Expected CRLF after version";
     state->error_pos = (const char*) p;
@@ -5528,7 +5865,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_20: {
+  s_n_llhttp__internal__n_error_23: {
     state->error = 0x9;
     state->reason = "Invalid minor version";
     state->error_pos = (const char*) p;
@@ -5537,7 +5874,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_21: {
+  s_n_llhttp__internal__n_error_24: {
     state->error = 0x9;
     state->reason = "Expected dot";
     state->error_pos = (const char*) p;
@@ -5554,7 +5891,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_22: {
+  s_n_llhttp__internal__n_error_25: {
     state->error = 0x9;
     state->reason = "Invalid major version";
     state->error_pos = (const char*) p;
@@ -5563,7 +5900,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_24: {
+  s_n_llhttp__internal__n_error_27: {
     state->error = 0x8;
     state->reason = "Expected HTTP/";
     state->error_pos = (const char*) p;
@@ -5572,7 +5909,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_23: {
+  s_n_llhttp__internal__n_error_26: {
     state->error = 0x8;
     state->reason = "Expected SOURCE method for ICE/x.x request";
     state->error_pos = (const char*) p;
@@ -5584,7 +5921,7 @@ static llparse_state_t llhttp__internal__run(
   s_n_llhttp__internal__n_invoke_is_equal_method_1: {
     switch (llhttp__internal__c_is_equal_method_1(state, p, endp)) {
       case 0:
-        goto s_n_llhttp__internal__n_error_23;
+        goto s_n_llhttp__internal__n_error_26;
       default:
         goto s_n_llhttp__internal__n_req_http_major;
     }
@@ -5659,7 +5996,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_25: {
+  s_n_llhttp__internal__n_error_28: {
     state->error = 0x7;
     state->reason = "Invalid char in url fragment start";
     state->error_pos = (const char*) p;
@@ -5719,7 +6056,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_26: {
+  s_n_llhttp__internal__n_error_29: {
     state->error = 0x7;
     state->reason = "Invalid char in url query";
     state->error_pos = (const char*) p;
@@ -5728,7 +6065,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_27: {
+  s_n_llhttp__internal__n_error_30: {
     state->error = 0x7;
     state->reason = "Invalid char in url path";
     state->error_pos = (const char*) p;
@@ -5839,7 +6176,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_28: {
+  s_n_llhttp__internal__n_error_31: {
     state->error = 0x7;
     state->reason = "Double @ in url";
     state->error_pos = (const char*) p;
@@ -5848,7 +6185,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_29: {
+  s_n_llhttp__internal__n_error_32: {
     state->error = 0x7;
     state->reason = "Unexpected char in url server";
     state->error_pos = (const char*) p;
@@ -5857,7 +6194,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_30: {
+  s_n_llhttp__internal__n_error_33: {
     state->error = 0x7;
     state->reason = "Unexpected char in url server";
     state->error_pos = (const char*) p;
@@ -5866,7 +6203,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_32: {
+  s_n_llhttp__internal__n_error_35: {
     state->error = 0x7;
     state->reason = "Unexpected char in url schema";
     state->error_pos = (const char*) p;
@@ -5875,7 +6212,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_33: {
+  s_n_llhttp__internal__n_error_36: {
     state->error = 0x7;
     state->reason = "Unexpected char in url schema";
     state->error_pos = (const char*) p;
@@ -5884,7 +6221,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_34: {
+  s_n_llhttp__internal__n_error_37: {
     state->error = 0x7;
     state->reason = "Unexpected start char in url";
     state->error_pos = (const char*) p;
@@ -5903,7 +6240,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_35: {
+  s_n_llhttp__internal__n_error_38: {
     state->error = 0x6;
     state->reason = "Expected space after method";
     state->error_pos = (const char*) p;
@@ -5920,7 +6257,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_43: {
+  s_n_llhttp__internal__n_error_46: {
     state->error = 0x6;
     state->reason = "Invalid method encountered";
     state->error_pos = (const char*) p;
@@ -5929,7 +6266,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_36: {
+  s_n_llhttp__internal__n_error_39: {
     state->error = 0xd;
     state->reason = "Response overflow";
     state->error_pos = (const char*) p;
@@ -5941,7 +6278,7 @@ static llparse_state_t llhttp__internal__run(
   s_n_llhttp__internal__n_invoke_mul_add_status_code: {
     switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {
       case 1:
-        goto s_n_llhttp__internal__n_error_36;
+        goto s_n_llhttp__internal__n_error_39;
       default:
         goto s_n_llhttp__internal__n_res_status_code;
     }
@@ -5984,7 +6321,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_37: {
+  s_n_llhttp__internal__n_error_40: {
     state->error = 0xd;
     state->reason = "Invalid response status";
     state->error_pos = (const char*) p;
@@ -6001,7 +6338,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_38: {
+  s_n_llhttp__internal__n_error_41: {
     state->error = 0x9;
     state->reason = "Expected space after version";
     state->error_pos = (const char*) p;
@@ -6018,7 +6355,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_39: {
+  s_n_llhttp__internal__n_error_42: {
     state->error = 0x9;
     state->reason = "Invalid minor version";
     state->error_pos = (const char*) p;
@@ -6027,7 +6364,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_40: {
+  s_n_llhttp__internal__n_error_43: {
     state->error = 0x9;
     state->reason = "Expected dot";
     state->error_pos = (const char*) p;
@@ -6044,7 +6381,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_41: {
+  s_n_llhttp__internal__n_error_44: {
     state->error = 0x9;
     state->reason = "Invalid major version";
     state->error_pos = (const char*) p;
@@ -6053,7 +6390,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_44: {
+  s_n_llhttp__internal__n_error_47: {
     state->error = 0x8;
     state->reason = "Expected HTTP/";
     state->error_pos = (const char*) p;
@@ -6078,7 +6415,7 @@ static llparse_state_t llhttp__internal__run(
     /* UNREACHABLE */;
     abort();
   }
-  s_n_llhttp__internal__n_error_42: {
+  s_n_llhttp__internal__n_error_45: {
     state->error = 0x8;
     state->reason = "Invalid word encountered";
     state->error_pos = (const char*) p;
@@ -6104,7 +6441,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_pause_8: {
-    state->error = 0x14;
+    state->error = 0x15;
     state->reason = "on_message_begin pause";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type;
@@ -6113,7 +6450,7 @@ static llparse_state_t llhttp__internal__run(
     abort();
   }
   s_n_llhttp__internal__n_error: {
-    state->error = 0xf;
+    state->error = 0x10;
     state->reason = "`on_message_begin` callback error";
     state->error_pos = (const char*) p;
     state->_current = (void*) (intptr_t) s_error;
@@ -6125,7 +6462,7 @@ static llparse_state_t llhttp__internal__run(
     switch (llhttp__on_message_begin(state, p, endp)) {
       case 0:
         goto s_n_llhttp__internal__n_invoke_load_type;
-      case 20:
+      case 21:
         goto s_n_llhttp__internal__n_pause_8;
       default:
         goto s_n_llhttp__internal__n_error;