From 3573d4dee401fc721d6c0401f2cf9ad03843ab5c Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Wed, 10 Jun 2020 14:00:43 +0900 Subject: [PATCH] Imported Upstream version 1.41.0 Change-Id: I8982758c4e5db3aaf3aa4b4c3de419df99ba7118 --- AUTHORS | 5 + CMakeLists.txt | 6 +- ChangeLog | 495 ++++++++--------- configure | 30 +- configure.ac | 6 +- doc/CMakeLists.txt | 1 + doc/Makefile.am | 1 + doc/Makefile.in | 1 + doc/bash_completion/h2load | 2 +- doc/enums.rst | 5 + doc/h2load.1 | 8 +- doc/h2load.1.rst | 5 + doc/macros.rst | 4 + doc/nghttp.1 | 2 +- doc/nghttp2_option_set_max_settings.rst | 16 + doc/nghttpd.1 | 2 +- doc/nghttpx.1 | 4 +- doc/nghttpx.1.rst | 2 +- doc/sources/contribute.rst | 4 +- doc/sources/nghttpx-howto.rst | 3 + doc/sources/tutorial-client.rst | 2 +- integration-tests/nghttpx_http2_test.go | 230 ++++++++ integration-tests/server_tester.go | 91 +++ lib/CMakeLists.txt | 2 +- lib/includes/nghttp2/nghttp2.h | 23 + lib/includes/nghttp2/nghttp2ver.h | 4 +- lib/nghttp2_helper.c | 2 + lib/nghttp2_option.c | 5 + lib/nghttp2_option.h | 5 + lib/nghttp2_session.c | 88 ++- lib/nghttp2_session.h | 34 ++ lib/nghttp2_submit.c | 18 +- ltmain.sh | 10 +- m4/libtool.m4 | 6 +- python/Makefile.in | 2 +- src/h2load.cc | 29 +- src/h2load.h | 2 + src/shrpx-unittest.cc | 2 + src/shrpx.cc | 2 +- src/shrpx_client_handler.cc | 182 +++++- src/shrpx_client_handler.h | 1 + src/shrpx_tls.cc | 14 +- src/util.cc | 35 ++ src/util.h | 7 + src/util_test.cc | 24 + src/util_test.h | 1 + tests/main.c | 4 + tests/nghttp2_session_test.c | 121 +++- tests/nghttp2_session_test.h | 1 + third-party/llhttp/include/llhttp.h | 60 +- third-party/llhttp/src/api.c | 9 + third-party/llhttp/src/http.c | 34 +- third-party/llhttp/src/llhttp.c | 953 +++++++++++++++++++++----------- 53 files changed, 1897 insertions(+), 708 deletions(-) create mode 100644 doc/nghttp2_option_set_max_settings.rst diff --git a/AUTHORS b/AUTHORS index 4da9664..4536741 100644 --- 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 741d449..69c2c7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,13 +24,13 @@ 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) diff --git a/ChangeLog b/ChangeLog index c17e088..3e04f08 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,375 +1,342 @@ -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 -AuthorDate: 2019-11-15 +AuthorDate: 2020-06-02 Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-11-15 +CommitDate: 2020-06-02 + + Update bash_completion + +commit 83086ba91a20a444a3b151bd5e0f55037795a31a +Author: Tatsuhiro Tsujikawa +AuthorDate: 2020-06-02 +Commit: Tatsuhiro Tsujikawa +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 +CommitDate: 2020-06-02 + + Merge pull request from GHSA-q5wr-xfw9-q7xr + + Implement max settings option + +commit 3eecc2ca45530024abb687bf808ec768eaa5e98a Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-11-15 +AuthorDate: 2020-06-02 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-11-15 +AuthorDate: 2020-06-02 Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-11-15 +CommitDate: 2020-06-02 + + Update AUTHORS + +commit f8da73bd042f810f34d19f9eae02b46d870af394 +Author: James M Snell +AuthorDate: 2020-04-19 +Commit: James M Snell +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 +AuthorDate: 2020-04-17 +Commit: James M Snell +CommitDate: 2020-05-05 + + Implement max settings option + +commit ef41583614e95efd12b6cce821e34837c1b28ed0 Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-11-09 +AuthorDate: 2020-04-22 Commit: Tatsuhiro Tsujikawa -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 -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 -AuthorDate: 2019-11-02 +AuthorDate: 2020-04-21 Commit: Tatsuhiro Tsujikawa -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 -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 +AuthorDate: 2020-04-18 Commit: GitHub -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 -AuthorDate: 2019-10-29 +AuthorDate: 2020-04-18 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-10-29 -Commit: Richard Wolfert -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 -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 -AuthorDate: 2019-10-08 +AuthorDate: 2020-04-18 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-10-08 +AuthorDate: 2020-04-18 Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-10-12 +CommitDate: 2020-04-18 - Faster huffman encoding + Update doc -commit 6f967c6ef3ea5799b59a5cea6b6f4bec10d25b04 +commit 49cd8e6e733a74d52d442a3d2667fd130d6437c8 Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-21 +AuthorDate: 2020-04-17 Commit: Tatsuhiro Tsujikawa -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 -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 -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 -AuthorDate: 2019-09-16 -Commit: William A Rowe Jr -CommitDate: 2019-09-16 +commit 4922bb41d604a15483e12f1b33bac2bf6628d866 +Author: Jacky Tian +AuthorDate: 2020-03-31 +Commit: Jacky Tian +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 - Signed-off-by: Yechiel Kalmenson + static_cast size parameter in StringRef constructor to size_t -commit 1dd966f1897421fe10d1ad91cfe466526636fcad -Merge: f8933fe5 fe8946dd -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-17 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-09-17 +commit aad8697575d90b1763c31ad06986be0550917aac +Author: Jacky Tian +AuthorDate: 2020-03-30 +Commit: Jacky Tian +CommitDate: 2020-03-31 - Merge branch 'fix-nghttpx-mruby' + Fix get_x509_serial for long serial numbers -commit fe8946ddc7c081eb0b2f376fc99279121a3f2a8b -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-16 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-09-16 +commit dc7a7df61c7cd1cc05c9c09f827e564495c2bebe +Author: Leo Neat +AuthorDate: 2020-03-18 +Commit: Leo Neat +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 -AuthorDate: 2019-09-14 -Commit: William A Rowe Jr -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 +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 - Signed-off-by: Yechiel Kalmenson + Fix receiving stream data stall -commit f8933fe50468413eb149df7e331e7335400f1649 -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-07 -Commit: Tatsuhiro Tsujikawa -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 +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 -AuthorDate: 2019-09-07 +AuthorDate: 2020-02-19 Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-09-07 - - Update neverbleed +CommitDate: 2020-02-20 -commit 7079dc5e753c1881aa6f162bbb4a9bb6d44e79ed -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-06 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-09-06 - - Update neverbleed to fix memory leak - -commit 5080db84e267d9b036c08ac7b2de8b7696c4d6b2 -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-06 -Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-09-03 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-09-03 - - nghttpx: Returns 408 if backend timed out before sending headers - -commit 8a59ce6d37471ec7a437d4700cabd98c55115b1e -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-09-03 -Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-08-19 -Commit: Tatsuhiro Tsujikawa -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 +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 -AuthorDate: 2019-06-25 +AuthorDate: 2020-02-11 Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-08-14 +CommitDate: 2020-02-11 - Don't read too greedily + Bump llhttp to 2.0.4 -commit 0a6ce87c22c69438ecbffe52a2859c3a32f1620f -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-06-25 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-08-14 +commit 866eadb5de0f859d30272f5359a79c195271cd6c +Author: Geoff Hill +AuthorDate: 2020-01-23 +Commit: Geoff Hill +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 -AuthorDate: 2019-08-14 +AuthorDate: 2019-12-21 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-08-06 +AuthorDate: 2019-12-21 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-08-06 +commit df575f968fa3d82fb40c2637e7d3e245def43766 +Author: lucas +AuthorDate: 2019-12-12 Commit: Tatsuhiro Tsujikawa -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 -AuthorDate: 2019-08-06 +AuthorDate: 2019-12-18 Commit: Tatsuhiro Tsujikawa -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 -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 -AuthorDate: 2019-07-29 -Commit: Andrew Penkrat -CommitDate: 2019-07-29 - - cmake: Support building nghttpx with systemd - -commit 7a5908933e55297ce2d8a0217391663ddf0c3f31 -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-06-22 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-06-22 - - Fix clang-8 warning - -commit ee4431344511886efc66395a38b9bf5dddd7151b -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-06-11 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-06-11 - - Fix FPE with default backend + lib/CMakeLists.txt: Make hard-coded static lib suffix optional -commit abef9b90ef2ba35ec25adbca7cb8d0b9a6c2d044 -Author: Tatsuhiro Tsujikawa -AuthorDate: 2019-06-11 -Commit: Tatsuhiro Tsujikawa -CommitDate: 2019-06-11 +commit 9bc2c75e388fbb5e6e694ef4471bd63521c966ae +Author: Viktor Szakats +AuthorDate: 2019-11-15 +Commit: Viktor Szakats +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 -AuthorDate: 2019-06-11 +AuthorDate: 2019-11-15 Commit: Tatsuhiro Tsujikawa -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 diff --git a/configure b/configure index 696af86..6d789f7 100755 --- 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 . # @@ -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 @@ -12925,11 +12925,11 @@ fi 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\\" diff --git a/configure.ac b/configure.ac index 08a7bee..961b78d 100644 --- a/configure.ac +++ b/configure.ac @@ -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"` diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 34c0279..f3aec84 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -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 diff --git a/doc/Makefile.am b/doc/Makefile.am index 4d73cef..f073bfa 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -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 \ diff --git a/doc/Makefile.in b/doc/Makefile.in index 0c30bf2..db35c52 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -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 \ diff --git a/doc/bash_completion/h2load b/doc/bash_completion/h2load index 3022d45..a737a49 100644 --- a/doc/bash_completion/h2load +++ b/doc/bash_completion/h2load @@ -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 diff --git a/doc/enums.rst b/doc/enums.rst index 866b2b9..cfdb5d4 100644 --- a/doc/enums.rst +++ b/doc/enums.rst @@ -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``) diff --git a/doc/h2load.1 b/doc/h2load.1 index d47e8b8..1070ebb 100644 --- a/doc/h2load.1 +++ b/doc/h2load.1 @@ -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 and port to connect instead of using the authority +in . +.UNINDENT +.INDENT 0.0 +.TP .B \-v, \-\-verbose Output debug information. .UNINDENT diff --git a/doc/h2load.1.rst b/doc/h2load.1.rst index 3edc9d9..265ae83 100644 --- a/doc/h2load.1.rst +++ b/doc/h2load.1.rst @@ -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 and port to connect instead of using the authority + in . + .. option:: -v, --verbose Output debug information. diff --git a/doc/macros.rst b/doc/macros.rst index 1c2b15e..583e745 100644 --- a/doc/macros.rst +++ b/doc/macros.rst @@ -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 diff --git a/doc/nghttp.1 b/doc/nghttp.1 index d34cf1e..8b8237d 100644 --- a/doc/nghttp.1 +++ b/doc/nghttp.1 @@ -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 index 0000000..ba325e7 --- /dev/null +++ b/doc/nghttp2_option_set_max_settings.rst @@ -0,0 +1,16 @@ + +nghttp2_option_set_max_settings +=============================== + +Synopsis +-------- + +*#include * + +.. 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. diff --git a/doc/nghttpd.1 b/doc/nghttpd.1 index 315d50b..fb46e54 100644 --- a/doc/nghttpd.1 +++ b/doc/nghttpd.1 @@ -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 . diff --git a/doc/nghttpx.1 b/doc/nghttpx.1 index 9f18c70..c101661 100644 --- a/doc/nghttpx.1 +++ b/doc/nghttpx.1 @@ -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 diff --git a/doc/nghttpx.1.rst b/doc/nghttpx.1.rst index 67ebff0..5259eb9 100644 --- a/doc/nghttpx.1.rst +++ b/doc/nghttpx.1.rst @@ -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. diff --git a/doc/sources/contribute.rst b/doc/sources/contribute.rst index bea72b1..b2aa9d0 100644 --- a/doc/sources/contribute.rst +++ b/doc/sources/contribute.rst @@ -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. diff --git a/doc/sources/nghttpx-howto.rst b/doc/sources/nghttpx-howto.rst index 11d3eb0..bbb7c20 100644 --- a/doc/sources/nghttpx-howto.rst +++ b/doc/sources/nghttpx-howto.rst @@ -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 ---------------- diff --git a/doc/sources/tutorial-client.rst b/doc/sources/tutorial-client.rst index 46fc34b..7c086a8 100644 --- a/doc/sources/tutorial-client.rst +++ b/doc/sources/tutorial-client.rst @@ -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 diff --git a/integration-tests/nghttpx_http2_test.go b/integration-tests/nghttpx_http2_test.go index 0698dd2..84646fa 100644 --- a/integration-tests/nghttpx_http2_test.go +++ b/integration-tests/nghttpx_http2_test.go @@ -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) { diff --git a/integration-tests/server_tester.go b/integration-tests/server_tester.go index 89e7f29..113e27d 100644 --- a/integration-tests/server_tester.go +++ b/integration-tests/server_tester.go @@ -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) +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4e3f5da..4dc2fcd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -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) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index e3aeb9f..9be6eea 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -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 diff --git a/lib/includes/nghttp2/nghttp2ver.h b/lib/includes/nghttp2/nghttp2ver.h index 45d21e2..795a44c 100644 --- a/lib/includes/nghttp2/nghttp2ver.h +++ b/lib/includes/nghttp2/nghttp2ver.h @@ -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 */ diff --git a/lib/nghttp2_helper.c b/lib/nghttp2_helper.c index 91136a6..0bd5414 100644 --- a/lib/nghttp2_helper.c +++ b/lib/nghttp2_helper.c @@ -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"; } diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c index e53f22d..34348e6 100644 --- a/lib/nghttp2_option.c +++ b/lib/nghttp2_option.c @@ -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; +} diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h index 1f740aa..939729f 100644 --- a/lib/nghttp2_option.h +++ b/lib/nghttp2_option.h @@ -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. */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 9df3d6f..39f81f4 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -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) { diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 90ead9c..07bfbb6 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -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 */ diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index f604eff..744a49c 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -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; diff --git a/ltmain.sh b/ltmain.sh index d11f1e0..0cb7f90 100644 --- 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" diff --git a/m4/libtool.m4 b/m4/libtool.m4 index 9d6dd9f..a6d21ae 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -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]) diff --git a/python/Makefile.in b/python/Makefile.in index 5d1d63f..709bc6f 100644 --- a/python/Makefile.in +++ b/python/Makefile.in @@ -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 diff --git a/src/h2load.cc b/src/h2load.cc index 334b1e2..2f08cac 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -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 and port to connect instead of using the authority + in . -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(":authority", ":host", ":method", ":scheme", "user-agent"); diff --git a/src/h2load.h b/src/h2load.h index a5de461..ca68997 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -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; diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index dd4fadf..3cf3816 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -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) || diff --git a/src/shrpx.cc b/src/shrpx.cc index 2dd0493..4ff5e47 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -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. diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index e118008..2b6638a 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -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 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; diff --git a/src/shrpx_client_handler.h b/src/shrpx_client_handler.h index c31b1ee..bc56d48 100644 --- a/src/shrpx_client_handler.h +++ b/src/shrpx_client_handler.h @@ -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(). diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index 746311f..c562530 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -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(&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(n)}); } namespace { diff --git a/src/util.cc b/src/util.cc index bb30fcd..187fd3a 100644 --- a/src/util.cc +++ b/src/util.cc @@ -1537,6 +1537,41 @@ StringRef extract_host(const StringRef &hostport) { return StringRef{std::begin(hostport), p}; } +std::pair 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()); diff --git a/src/util.h b/src/util.h index 38761e0..3443fe0 100644 --- a/src/util.h +++ b/src/util.h @@ -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 split_hostport(const StringRef &hostport); + // Returns new std::mt19937 object. std::mt19937 make_mt19937(); diff --git a/src/util_test.cc b/src/util_test.cc index d375b43..6ad313d 100644 --- a/src/util_test.cc +++ b/src/util_test.cc @@ -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 diff --git a/src/util_test.h b/src/util_test.h index 41ba9fe..cc34f7d 100644 --- a/src/util_test.h +++ b/src/util_test.h @@ -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 diff --git a/tests/main.c b/tests/main.c index 46e9b1c..67eb4a1 100644 --- a/tests/main.c +++ b/tests/main.c @@ -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", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index b366a6a..33ee3ad 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -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) { diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index e872c5d..818c808 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -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); diff --git a/third-party/llhttp/include/llhttp.h b/third-party/llhttp/include/llhttp.h index f9e008c..3be7d12 100644 --- a/third-party/llhttp/include/llhttp.h +++ b/third-party/llhttp/include/llhttp.h @@ -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 diff --git a/third-party/llhttp/src/api.c b/third-party/llhttp/src/api.c index 45227b3..6f72465 100644 --- a/third-party/llhttp/src/api.c +++ b/third-party/llhttp/src/api.c @@ -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 */ diff --git a/third-party/llhttp/src/http.c b/third-party/llhttp/src/http.c index 67834c2..6e4906d 100644 --- a/third-party/llhttp/src/http.c +++ b/third-party/llhttp/src/http.c @@ -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; } diff --git a/third-party/llhttp/src/llhttp.c b/third-party/llhttp/src/llhttp.c index dc363aa..2a44fa6 100644 --- a/third-party/llhttp/src/llhttp.c +++ b/third-party/llhttp/src/llhttp.c @@ -2,6 +2,20 @@ #include #include +#ifdef __SSE4_2__ + #ifdef _MSC_VER + #include + #else /* !_MSC_VER */ + #include + #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; -- 2.7.4