mirror of
https://github.com/nghttp2/nghttp2.git
synced 2026-03-29 01:09:17 +08:00
Compare commits
69 Commits
v1.55.0
...
invoke-res
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a166099ff4 | ||
|
|
bd92902560 | ||
|
|
10a77ce888 | ||
|
|
81c199dd9b | ||
|
|
3b82572b9e | ||
|
|
9d85ab415f | ||
|
|
d0358c0063 | ||
|
|
e103726f4d | ||
|
|
4262c90148 | ||
|
|
bf8f419ca9 | ||
|
|
cccb6ad2c9 | ||
|
|
6f41cc7271 | ||
|
|
9b781ca734 | ||
|
|
aa0973caf5 | ||
|
|
72b4af6143 | ||
|
|
d40829b133 | ||
|
|
939506b68b | ||
|
|
e62ef924fb | ||
|
|
8bad736d48 | ||
|
|
e761014ca5 | ||
|
|
e6ca4ff173 | ||
|
|
62d58bdabc | ||
|
|
e37fe5543f | ||
|
|
d54750b365 | ||
|
|
8ebe7b10fc | ||
|
|
5c1b0f261e | ||
|
|
0866ceffc7 | ||
|
|
3c6f94258f | ||
|
|
959a55f95f | ||
|
|
7d0d8775c9 | ||
|
|
52cb8c35c8 | ||
|
|
d19bc4bb67 | ||
|
|
1ee16fdeca | ||
|
|
b809beacab | ||
|
|
8cafb048be | ||
|
|
627b2408e5 | ||
|
|
0d36a2a050 | ||
|
|
06da18089f | ||
|
|
19697bd44a | ||
|
|
2e6c8ddd15 | ||
|
|
b7f9853968 | ||
|
|
80d05fe917 | ||
|
|
08c472230a | ||
|
|
47ecf35737 | ||
|
|
b48355b67e | ||
|
|
0f768bdaab | ||
|
|
05f93ca729 | ||
|
|
d70f0013d6 | ||
|
|
d5cb882e62 | ||
|
|
2a382a2ce9 | ||
|
|
c13b08f861 | ||
|
|
298f71ce4e | ||
|
|
4114507587 | ||
|
|
060d0ac455 | ||
|
|
9a3c345f60 | ||
|
|
98eb01aa3f | ||
|
|
de47400a48 | ||
|
|
871cf8e5a2 | ||
|
|
6ace578e5b | ||
|
|
7273ec17d3 | ||
|
|
07b69bb06f | ||
|
|
98df5b59e5 | ||
|
|
cdfb517528 | ||
|
|
b16d4e951e | ||
|
|
feb5ff560a | ||
|
|
ce385d3f55 | ||
|
|
82fc1163c6 | ||
|
|
79d2b7f931 | ||
|
|
4c1f1b0efc |
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@@ -5,12 +5,12 @@ on: [push, pull_request]
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
LIBBPF_VERSION: v1.2.0
|
||||
OPENSSL1_VERSION: 1_1_1u+quic
|
||||
OPENSSL3_VERSION: 3.1.0+quic
|
||||
BORINGSSL_VERSION: 80dcb67d4481fb1194b9669917e35580c32dc388
|
||||
NGHTTP3_VERSION: v0.13.0
|
||||
NGTCP2_VERSION: v0.17.0
|
||||
LIBBPF_VERSION: v1.2.2
|
||||
OPENSSL1_VERSION: 1_1_1w+quic
|
||||
OPENSSL3_VERSION: 3.1.2+quic
|
||||
BORINGSSL_VERSION: 6ca49385b168f47a50e7172d82a590b218f55e4d
|
||||
NGHTTP3_VERSION: v0.15.0
|
||||
NGTCP2_VERSION: v0.19.1
|
||||
|
||||
jobs:
|
||||
build-cache:
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Restore libbpf cache
|
||||
id: cache-libbpf
|
||||
uses: actions/cache@v3
|
||||
@@ -200,7 +200,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Linux setup
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
@@ -394,7 +394,7 @@ jobs:
|
||||
cd $NGHTTP2_CMAKE_DIR
|
||||
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)"
|
||||
make -j"$(nproc 2> /dev/null || sysctl -n hw.ncpu)" check
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v4
|
||||
if: matrix.buildtool == 'cmake'
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
@@ -417,7 +417,7 @@ jobs:
|
||||
HOST: ${{ matrix.host }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Linux setup
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
@@ -442,7 +442,8 @@ jobs:
|
||||
run: |
|
||||
autoreconf -i && \
|
||||
./configure --enable-werror --enable-lib-only --with-cunit \
|
||||
--host="$HOST" PKG_CONFIG_PATH="$PWD/CUnit-2.1-3/build/lib/pkgconfig"
|
||||
--host="$HOST" PKG_CONFIG_PATH="$PWD/CUnit-2.1-3/build/lib/pkgconfig" \
|
||||
CFLAGS="-g -O2 -D_WIN32_WINNT=0x0600"
|
||||
- name: Build nghttp2
|
||||
run: |
|
||||
make -j$(nproc)
|
||||
@@ -466,7 +467,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: microsoft/setup-msbuild@v1
|
||||
- run: |
|
||||
vcpkg --triplet=${{ matrix.arch }}-windows install cunit
|
||||
|
||||
2
.github/workflows/fuzz.yml
vendored
2
.github/workflows/fuzz.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
@@ -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.55.0)
|
||||
project(nghttp2 VERSION 1.57.90)
|
||||
|
||||
# See versioning rule:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
set(LT_CURRENT 38)
|
||||
set(LT_REVISION 2)
|
||||
set(LT_AGE 24)
|
||||
set(LT_CURRENT 39)
|
||||
set(LT_REVISION 0)
|
||||
set(LT_AGE 25)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
include(Version)
|
||||
@@ -273,9 +273,11 @@ check_include_file("inttypes.h" HAVE_INTTYPES_H)
|
||||
check_include_file("limits.h" HAVE_LIMITS_H)
|
||||
check_include_file("netdb.h" HAVE_NETDB_H)
|
||||
check_include_file("netinet/in.h" HAVE_NETINET_IN_H)
|
||||
check_include_file("netinet/ip.h" HAVE_NETINET_IP_H)
|
||||
check_include_file("pwd.h" HAVE_PWD_H)
|
||||
check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H)
|
||||
check_include_file("sys/time.h" HAVE_SYS_TIME_H)
|
||||
check_include_file("sysinfoapi.h" HAVE_SYSINFOAPI_H)
|
||||
check_include_file("syslog.h" HAVE_SYSLOG_H)
|
||||
check_include_file("time.h" HAVE_TIME_H)
|
||||
check_include_file("unistd.h" HAVE_UNISTD_H)
|
||||
@@ -316,8 +318,11 @@ check_type_size("time_t" SIZEOF_TIME_T)
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(_Exit HAVE__EXIT)
|
||||
check_function_exists(accept4 HAVE_ACCEPT4)
|
||||
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
|
||||
check_function_exists(mkostemp HAVE_MKOSTEMP)
|
||||
|
||||
check_symbol_exists(GetTickCount64 sysinfoapi.h HAVE_GETTICKCOUNT64)
|
||||
|
||||
include(CheckSymbolExists)
|
||||
# XXX does this correctly detect initgroups (un)availability on cygwin?
|
||||
check_symbol_exists(initgroups grp.h HAVE_DECL_INITGROUPS)
|
||||
@@ -338,74 +343,12 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||
endif()
|
||||
else()
|
||||
if(ENABLE_WERROR)
|
||||
extract_valid_c_flags(WARNCFLAGS -Werror)
|
||||
extract_valid_c_flags(WARNCXXFLAGS -Werror)
|
||||
set(WARNCFLAGS "-Werror")
|
||||
set(WARNCXXFLAGS "-Werror")
|
||||
endif()
|
||||
|
||||
# For C compiler
|
||||
extract_valid_c_flags(WARNCFLAGS
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wmissing-prototypes
|
||||
-Wstrict-prototypes
|
||||
-Wmissing-declarations
|
||||
-Wpointer-arith
|
||||
-Wdeclaration-after-statement
|
||||
-Wformat-security
|
||||
-Wwrite-strings
|
||||
-Wshadow
|
||||
-Winline
|
||||
-Wnested-externs
|
||||
-Wfloat-equal
|
||||
-Wundef
|
||||
-Wendif-labels
|
||||
-Wempty-body
|
||||
-Wcast-align
|
||||
-Wclobbered
|
||||
-Wvla
|
||||
-Wpragmas
|
||||
-Wunreachable-code
|
||||
-Waddress
|
||||
-Wattributes
|
||||
-Wdiv-by-zero
|
||||
-Wshorten-64-to-32
|
||||
|
||||
-Wconversion
|
||||
-Wextended-offsetof
|
||||
-Wformat-nonliteral
|
||||
-Wlanguage-extension-token
|
||||
-Wmissing-field-initializers
|
||||
-Wmissing-noreturn
|
||||
-Wmissing-variable-declarations
|
||||
# Not used because we cannot change public structs
|
||||
# -Wpadded
|
||||
-Wsign-conversion
|
||||
# Not used because this basically disallows default case
|
||||
# -Wswitch-enum
|
||||
-Wunreachable-code-break
|
||||
-Wunused-macros
|
||||
-Wunused-parameter
|
||||
-Wredundant-decls
|
||||
# Only work with Clang for the moment
|
||||
-Wheader-guard
|
||||
# This is required because we pass format string as "const char*.
|
||||
-Wno-format-nonliteral
|
||||
)
|
||||
|
||||
extract_valid_cxx_flags(WARNCXXFLAGS
|
||||
# For C++ compiler
|
||||
-Wall
|
||||
-Wformat-security
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_STATIC_CRT)
|
||||
foreach(lang C CXX)
|
||||
foreach(suffix "" _DEBUG _MINSIZEREL _RELEASE _RELWITHDEBINFO)
|
||||
set(var "CMAKE_${lang}_FLAGS${suffix}")
|
||||
string(REPLACE "/MD" "/MT" ${var} "${${var}}")
|
||||
endforeach()
|
||||
endforeach()
|
||||
include(PickyWarningsC)
|
||||
include(PickyWarningsCXX)
|
||||
endif()
|
||||
|
||||
if(ENABLE_DEBUG)
|
||||
@@ -501,6 +444,7 @@ message(STATUS "summary of build options:
|
||||
CXXFLAGS: ${CMAKE_CXX_FLAGS_${_build_type}} ${CMAKE_CXX_FLAGS}
|
||||
WARNCFLAGS: ${WARNCFLAGS}
|
||||
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
||||
WARNCXXFLAGS: ${WARNCXXFLAGS}
|
||||
Python:
|
||||
Python: ${Python3_EXECUTABLE}
|
||||
Python3_VERSION: ${Python3_VERSION}
|
||||
|
||||
@@ -44,7 +44,9 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-env \
|
||||
cmake/FindLibbpf.cmake \
|
||||
cmake/FindLibnghttp3.cmake \
|
||||
cmake/FindLibngtcp2.cmake \
|
||||
cmake/FindLibngtcp2_crypto_quictls.cmake
|
||||
cmake/FindLibngtcp2_crypto_quictls.cmake \
|
||||
cmake/PickyWarningsC.cmake \
|
||||
cmake/PickyWarningsCXX.cmake
|
||||
|
||||
.PHONY: clang-format
|
||||
|
||||
@@ -55,5 +57,5 @@ clang-format:
|
||||
CLANGFORMAT=`git config --get clangformat.binary`; \
|
||||
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
||||
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
|
||||
src/*.{c,cc,h} examples/*.{c,cc} \
|
||||
src/*.{c,cc,h} examples/*.c \
|
||||
tests/*.{c,h} bpf/*.c fuzz/*.cc
|
||||
|
||||
18
README.rst
18
README.rst
@@ -127,11 +127,11 @@ To enable the experimental HTTP/3 support for h2load and nghttpx, the
|
||||
following libraries are required:
|
||||
|
||||
* `OpenSSL with QUIC support
|
||||
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1u+quic>`_; or
|
||||
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1w+quic>`_; or
|
||||
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
|
||||
b0341041b03ea71d8371a9692aedae263fc06ee9)
|
||||
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ 0.17.x
|
||||
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ 0.13.x
|
||||
6ca49385b168f47a50e7172d82a590b218f55e4d)
|
||||
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ 0.19.x
|
||||
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ 0.15.x
|
||||
|
||||
Use ``--enable-http3`` configure option to enable HTTP/3 feature for
|
||||
h2load and nghttpx.
|
||||
@@ -146,7 +146,7 @@ Use ``--with-libbpf`` configure option to build eBPF program.
|
||||
libelf-dev is needed to build libbpf.
|
||||
|
||||
For Ubuntu 20.04, you can build libbpf from `the source code
|
||||
<https://github.com/libbpf/libbpf/releases/tag/v1.2.0>`_. nghttpx
|
||||
<https://github.com/libbpf/libbpf/releases/tag/v1.2.2>`_. nghttpx
|
||||
requires eBPF program for reloading its configuration and hot swapping
|
||||
its executable.
|
||||
|
||||
@@ -343,7 +343,7 @@ Build custom OpenSSL:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b OpenSSL_1_1_1u+quic https://github.com/quictls/openssl
|
||||
$ git clone --depth 1 -b OpenSSL_1_1_1w+quic https://github.com/quictls/openssl
|
||||
$ cd openssl
|
||||
$ ./config --prefix=$PWD/build --openssldir=/etc/ssl
|
||||
$ make -j$(nproc)
|
||||
@@ -354,7 +354,7 @@ Build nghttp3:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v0.13.0 https://github.com/ngtcp2/nghttp3
|
||||
$ git clone --depth 1 -b v0.15.0 https://github.com/ngtcp2/nghttp3
|
||||
$ cd nghttp3
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only
|
||||
@@ -366,7 +366,7 @@ Build ngtcp2:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v0.17.0 https://github.com/ngtcp2/ngtcp2
|
||||
$ git clone --depth 1 -b v0.19.1 https://github.com/ngtcp2/ngtcp2
|
||||
$ cd ngtcp2
|
||||
$ autoreconf -i
|
||||
$ ./configure --prefix=$PWD/build --enable-lib-only \
|
||||
@@ -380,7 +380,7 @@ from source:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ git clone --depth 1 -b v1.2.0 https://github.com/libbpf/libbpf
|
||||
$ git clone --depth 1 -b v1.2.2 https://github.com/libbpf/libbpf
|
||||
$ cd libbpf
|
||||
$ PREFIX=$PWD/build make -C src install
|
||||
$ cd ..
|
||||
|
||||
163
cmake/PickyWarningsC.cmake
Normal file
163
cmake/PickyWarningsC.cmake
Normal file
@@ -0,0 +1,163 @@
|
||||
# nghttp2
|
||||
#
|
||||
# Copyright (c) 2023 nghttp2 contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# C
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
|
||||
|
||||
# WPICKY_ENABLE = Options we want to enable as-is.
|
||||
# WPICKY_DETECT = Options we want to test first and enable if available.
|
||||
|
||||
# Prefer the -Wextra alias with clang.
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(WPICKY_ENABLE "-Wextra")
|
||||
else()
|
||||
set(WPICKY_ENABLE "-W")
|
||||
endif()
|
||||
|
||||
list(APPEND WPICKY_ENABLE
|
||||
-Wall
|
||||
)
|
||||
|
||||
# ----------------------------------
|
||||
# Add new options here, if in doubt:
|
||||
# ----------------------------------
|
||||
set(WPICKY_DETECT
|
||||
)
|
||||
|
||||
# Assume these options always exist with both clang and gcc.
|
||||
# Require clang 3.0 / gcc 2.95 or later.
|
||||
list(APPEND WPICKY_ENABLE
|
||||
-Wconversion # clang 3.0 gcc 2.95
|
||||
-Winline # clang 1.0 gcc 1.0
|
||||
-Wmissing-declarations # clang 1.0 gcc 2.7
|
||||
-Wmissing-prototypes # clang 1.0 gcc 1.0
|
||||
-Wnested-externs # clang 1.0 gcc 2.7
|
||||
-Wpointer-arith # clang 1.0 gcc 1.4
|
||||
-Wshadow # clang 1.0 gcc 2.95
|
||||
-Wundef # clang 1.0 gcc 2.95
|
||||
-Wwrite-strings # clang 1.0 gcc 1.4
|
||||
)
|
||||
|
||||
# Always enable with clang, version dependent with gcc
|
||||
set(WPICKY_COMMON_OLD
|
||||
-Waddress # clang 3.0 gcc 4.3
|
||||
-Wattributes # clang 3.0 gcc 4.1
|
||||
-Wcast-align # clang 1.0 gcc 4.2
|
||||
-Wdeclaration-after-statement # clang 1.0 gcc 3.4
|
||||
-Wdiv-by-zero # clang 3.0 gcc 4.1
|
||||
-Wempty-body # clang 3.0 gcc 4.3
|
||||
-Wendif-labels # clang 1.0 gcc 3.3
|
||||
-Wfloat-equal # clang 1.0 gcc 2.96 (3.0)
|
||||
-Wformat-nonliteral # clang 3.0 gcc 4.1
|
||||
-Wformat-security # clang 3.0 gcc 4.1
|
||||
-Wmissing-field-initializers # clang 3.0 gcc 4.1
|
||||
-Wmissing-noreturn # clang 3.0 gcc 4.1
|
||||
-Wno-format-nonliteral # clang 1.0 gcc 2.96 (3.0) # This is required because we pass format string as "const char*"
|
||||
# -Wpadded # clang 3.0 gcc 4.1 # Not used because we cannot change public structs
|
||||
-Wredundant-decls # clang 3.0 gcc 4.1
|
||||
-Wsign-conversion # clang 3.0 gcc 4.3
|
||||
-Wstrict-prototypes # clang 1.0 gcc 3.3
|
||||
# -Wswitch-enum # clang 3.0 gcc 4.1 # Not used because this basically disallows default case
|
||||
-Wunreachable-code # clang 3.0 gcc 4.1
|
||||
-Wunused-macros # clang 3.0 gcc 4.1
|
||||
-Wunused-parameter # clang 3.0 gcc 4.1
|
||||
-Wvla # clang 2.8 gcc 4.3
|
||||
)
|
||||
|
||||
set(WPICKY_COMMON
|
||||
-Wpragmas # clang 3.5 gcc 4.1 appleclang 6.0
|
||||
)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON_OLD}
|
||||
-Wshorten-64-to-32 # clang 1.0
|
||||
-Wlanguage-extension-token # clang 3.0
|
||||
)
|
||||
# Enable based on compiler version
|
||||
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
|
||||
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON}
|
||||
-Wunreachable-code-break # clang 3.5 appleclang 6.0
|
||||
-Wheader-guard # clang 3.4 appleclang 5.1
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR
|
||||
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
-Wmissing-variable-declarations # clang 3.2 appleclang 4.6
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0) OR
|
||||
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.4))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0) OR
|
||||
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
endif()
|
||||
else() # gcc
|
||||
list(APPEND WPICKY_DETECT
|
||||
${WPICKY_COMMON}
|
||||
)
|
||||
# Enable based on compiler version
|
||||
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON_OLD}
|
||||
-Wclobbered # gcc 4.3
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
unset(_wpicky)
|
||||
|
||||
foreach(_CCOPT IN LISTS WPICKY_ENABLE)
|
||||
set(_wpicky "${_wpicky} ${_CCOPT}")
|
||||
endforeach()
|
||||
|
||||
foreach(_CCOPT IN LISTS WPICKY_DETECT)
|
||||
# surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
|
||||
# test result in.
|
||||
string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
|
||||
# GCC only warns about unknown -Wno- options if there are also other diagnostic messages,
|
||||
# so test for the positive form instead
|
||||
string(REPLACE "-Wno-" "-W" _CCOPT_ON "${_CCOPT}")
|
||||
check_c_compiler_flag(${_CCOPT_ON} ${_optvarname})
|
||||
if(${_optvarname})
|
||||
set(_wpicky "${_wpicky} ${_CCOPT}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(WARNCFLAGS "${WARNCFLAGS} ${_wpicky}")
|
||||
endif()
|
||||
117
cmake/PickyWarningsCXX.cmake
Normal file
117
cmake/PickyWarningsCXX.cmake
Normal file
@@ -0,0 +1,117 @@
|
||||
# nghttp2
|
||||
#
|
||||
# Copyright (c) 2023 nghttp2 contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# C++
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
|
||||
# https://clang.llvm.org/docs/DiagnosticsReference.html
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
|
||||
|
||||
# WPICKY_ENABLE = Options we want to enable as-is.
|
||||
# WPICKY_DETECT = Options we want to test first and enable if available.
|
||||
|
||||
set(WPICKY_ENABLE "-Wall")
|
||||
|
||||
# ----------------------------------
|
||||
# Add new options here, if in doubt:
|
||||
# ----------------------------------
|
||||
set(WPICKY_DETECT
|
||||
)
|
||||
|
||||
# Assume these options always exist with both clang and gcc.
|
||||
# Require clang 3.0 / gcc 2.95 or later.
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
|
||||
# Always enable with clang, version dependent with gcc
|
||||
set(WPICKY_COMMON_OLD
|
||||
-Wformat-security # clang 3.0 gcc 4.1
|
||||
)
|
||||
|
||||
set(WPICKY_COMMON
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON_OLD}
|
||||
)
|
||||
# Enable based on compiler version
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON}
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9) OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.4))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
endif()
|
||||
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) OR
|
||||
(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.3))
|
||||
list(APPEND WPICKY_ENABLE
|
||||
)
|
||||
endif()
|
||||
else() # gcc
|
||||
list(APPEND WPICKY_DETECT
|
||||
${WPICKY_COMMON}
|
||||
)
|
||||
# Enable based on compiler version
|
||||
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.3)
|
||||
list(APPEND WPICKY_ENABLE
|
||||
${WPICKY_COMMON_OLD}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
|
||||
unset(_wpicky)
|
||||
|
||||
foreach(_CCOPT IN LISTS WPICKY_ENABLE)
|
||||
set(_wpicky "${_wpicky} ${_CCOPT}")
|
||||
endforeach()
|
||||
|
||||
foreach(_CCOPT IN LISTS WPICKY_DETECT)
|
||||
# surprisingly, CHECK_CXX_COMPILER_FLAG needs a new variable to store each new
|
||||
# test result in.
|
||||
string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
|
||||
# GCC only warns about unknown -Wno- options if there are also other diagnostic messages,
|
||||
# so test for the positive form instead
|
||||
string(REPLACE "-Wno-" "-W" _CCOPT_ON "${_CCOPT}")
|
||||
check_cxx_compiler_flag(${_CCOPT_ON} ${_optvarname})
|
||||
if(${_optvarname})
|
||||
set(_wpicky "${_wpicky} ${_CCOPT}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(WARNCXXFLAGS "${WARNCXXFLAGS} ${_wpicky}")
|
||||
endif()
|
||||
@@ -31,9 +31,15 @@
|
||||
/* Define to 1 if you have the `accept4` function. */
|
||||
#cmakedefine HAVE_ACCEPT4 1
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime` function. */
|
||||
#cmakedefine HAVE_CLOCK_GETTIME 1
|
||||
|
||||
/* Define to 1 if you have the `mkostemp` function. */
|
||||
#cmakedefine HAVE_MKOSTEMP 1
|
||||
|
||||
/* Define to 1 if you have the `GetTickCount64` function. */
|
||||
#cmakedefine HAVE_GETTICKCOUNT64 1
|
||||
|
||||
/* Define to 1 if you have the `initgroups` function. */
|
||||
#cmakedefine01 HAVE_DECL_INITGROUPS
|
||||
|
||||
@@ -61,6 +67,9 @@
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/ip.h> header file. */
|
||||
#cmakedefine HAVE_NETINET_IP_H 1
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#cmakedefine HAVE_PWD_H 1
|
||||
|
||||
@@ -70,6 +79,9 @@
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sysinfoapi.h> header file. */
|
||||
#cmakedefine HAVE_SYSINFOAPI_H 1
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#cmakedefine HAVE_SYSLOG_H 1
|
||||
|
||||
|
||||
36
configure.ac
36
configure.ac
@@ -25,7 +25,7 @@ dnl Do not change user variables!
|
||||
dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [1.55.0], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [1.58.0-DEV], [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 https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 38)
|
||||
AC_SUBST(LT_REVISION, 2)
|
||||
AC_SUBST(LT_AGE, 24)
|
||||
AC_SUBST(LT_CURRENT, 39)
|
||||
AC_SUBST(LT_REVISION, 0)
|
||||
AC_SUBST(LT_AGE, 25)
|
||||
|
||||
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"`
|
||||
@@ -508,7 +508,7 @@ fi
|
||||
# ngtcp2 (for src)
|
||||
have_libngtcp2=no
|
||||
if test "x${request_libngtcp2}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.17.0], [have_libngtcp2=yes],
|
||||
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.19.0], [have_libngtcp2=yes],
|
||||
[have_libngtcp2=no])
|
||||
if test "x${have_libngtcp2}" = "xno"; then
|
||||
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
|
||||
@@ -525,7 +525,7 @@ have_libngtcp2_crypto_quictls=no
|
||||
if test "x${have_ssl_is_quic}" = "xyes" &&
|
||||
test "x${request_libngtcp2}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_QUICTLS],
|
||||
[libngtcp2_crypto_quictls >= 0.17.0],
|
||||
[libngtcp2_crypto_quictls >= 0.19.0],
|
||||
[have_libngtcp2_crypto_quictls=yes],
|
||||
[have_libngtcp2_crypto_quictls=no])
|
||||
if test "x${have_libngtcp2_crypto_quictls}" = "xno"; then
|
||||
@@ -567,7 +567,7 @@ fi
|
||||
# nghttp3 (for src)
|
||||
have_libnghttp3=no
|
||||
if test "x${request_libnghttp3}" != "xno"; then
|
||||
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.13.0], [have_libnghttp3=yes],
|
||||
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.15.0], [have_libnghttp3=yes],
|
||||
[have_libnghttp3=no])
|
||||
if test "x${have_libnghttp3}" = "xno"; then
|
||||
AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS)
|
||||
@@ -847,6 +847,7 @@ AC_CHECK_HEADERS([ \
|
||||
limits.h \
|
||||
netdb.h \
|
||||
netinet/in.h \
|
||||
netinet/ip.h \
|
||||
pwd.h \
|
||||
stddef.h \
|
||||
stdint.h \
|
||||
@@ -854,6 +855,7 @@ AC_CHECK_HEADERS([ \
|
||||
string.h \
|
||||
sys/socket.h \
|
||||
sys/time.h \
|
||||
sysinfoapi.h \
|
||||
syslog.h \
|
||||
time.h \
|
||||
unistd.h \
|
||||
@@ -928,6 +930,7 @@ AC_FUNC_STRNLEN
|
||||
AC_CHECK_FUNCS([ \
|
||||
_Exit \
|
||||
accept4 \
|
||||
clock_gettime \
|
||||
dup2 \
|
||||
getcwd \
|
||||
getpwnam \
|
||||
@@ -953,6 +956,25 @@ AC_CHECK_FUNCS([ \
|
||||
AC_CHECK_FUNC([timerfd_create],
|
||||
[have_timerfd_create=yes], [have_timerfd_create=no])
|
||||
|
||||
AC_MSG_CHECKING([checking for GetTickCount64])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <sysinfoapi.h>
|
||||
]],
|
||||
[[
|
||||
GetTickCount64();
|
||||
]])],
|
||||
[have_gettickcount64=yes],
|
||||
[have_gettickcount64=no])
|
||||
|
||||
if test "x${have_gettickcount64}" = "xyes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_GETTICKCOUNT64], [1],
|
||||
[Define to 1 if you have `GetTickCount64` function.])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
# For cygwin: we can link initgroups, so AC_CHECK_FUNCS succeeds, but
|
||||
# cygwin disables initgroups due to feature test macro magic with our
|
||||
# configuration. FreeBSD declares initgroups() in unistd.h.
|
||||
|
||||
@@ -75,6 +75,7 @@ APIDOCS= \
|
||||
nghttp2_option_set_user_recv_extension_type.rst \
|
||||
nghttp2_option_set_max_outbound_ack.rst \
|
||||
nghttp2_option_set_max_settings.rst \
|
||||
nghttp2_option_set_stream_reset_rate_limit.rst \
|
||||
nghttp2_pack_settings_payload.rst \
|
||||
nghttp2_priority_spec_check_default.rst \
|
||||
nghttp2_priority_spec_default_init.rst \
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "H2LOAD" "1" "Jul 12, 2023" "1.55.0" "nghttp2"
|
||||
.TH "H2LOAD" "1" "Oct 10, 2023" "1.57.0" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTP" "1" "Jul 12, 2023" "1.55.0" "nghttp2"
|
||||
.TH "NGHTTP" "1" "Oct 10, 2023" "1.57.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 client
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPD" "1" "Jul 12, 2023" "1.55.0" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "Oct 10, 2023" "1.57.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPX" "1" "Jul 12, 2023" "1.55.0" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "Oct 10, 2023" "1.57.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 proxy
|
||||
.SH SYNOPSIS
|
||||
@@ -1546,18 +1546,20 @@ in HTTP/2 frontend.
|
||||
.TP
|
||||
.B \-\-add\-request\-header=<HEADER>
|
||||
Specify additional header field to add to request header
|
||||
set. This option just appends header field and won\(aqt
|
||||
replace anything already set. This option can be used
|
||||
several times to specify multiple header fields.
|
||||
set. The field name must be lowercase. This option
|
||||
just appends header field and won\(aqt replace anything
|
||||
already set. This option can be used several times to
|
||||
specify multiple header fields.
|
||||
Example: \fI\%\-\-add\-request\-header\fP=\(dqfoo: bar\(dq
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-add\-response\-header=<HEADER>
|
||||
Specify additional header field to add to response
|
||||
header set. This option just appends header field and
|
||||
won\(aqt replace anything already set. This option can be
|
||||
used several times to specify multiple header fields.
|
||||
header set. The field name must be lowercase. This
|
||||
option just appends header field and won\(aqt replace
|
||||
anything already set. This option can be used several
|
||||
times to specify multiple header fields.
|
||||
Example: \fI\%\-\-add\-response\-header\fP=\(dqfoo: bar\(dq
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -1833,7 +1835,7 @@ NEW_TOKEN frame in the previous connection.
|
||||
.B \-\-frontend\-quic\-congestion\-controller=<CC>
|
||||
Specify a congestion controller algorithm for a frontend
|
||||
QUIC connection. <CC> should be one of \(dqcubic\(dq, \(dqbbr\(dq,
|
||||
and \(dqbbr2\(dq.
|
||||
and \(dqbbrv2\(dq.
|
||||
.sp
|
||||
Default: \fBcubic\fP
|
||||
.UNINDENT
|
||||
|
||||
@@ -1402,17 +1402,19 @@ HTTP
|
||||
.. option:: --add-request-header=<HEADER>
|
||||
|
||||
Specify additional header field to add to request header
|
||||
set. This option just appends header field and won't
|
||||
replace anything already set. This option can be used
|
||||
several times to specify multiple header fields.
|
||||
set. The field name must be lowercase. This option
|
||||
just appends header field and won't replace anything
|
||||
already set. This option can be used several times to
|
||||
specify multiple header fields.
|
||||
Example: :option:`--add-request-header`\="foo: bar"
|
||||
|
||||
.. option:: --add-response-header=<HEADER>
|
||||
|
||||
Specify additional header field to add to response
|
||||
header set. This option just appends header field and
|
||||
won't replace anything already set. This option can be
|
||||
used several times to specify multiple header fields.
|
||||
header set. The field name must be lowercase. This
|
||||
option just appends header field and won't replace
|
||||
anything already set. This option can be used several
|
||||
times to specify multiple header fields.
|
||||
Example: :option:`--add-response-header`\="foo: bar"
|
||||
|
||||
.. option:: --request-header-field-buffer=<SIZE>
|
||||
@@ -1674,7 +1676,7 @@ HTTP/3 and QUIC
|
||||
|
||||
Specify a congestion controller algorithm for a frontend
|
||||
QUIC connection. <CC> should be one of "cubic", "bbr",
|
||||
and "bbr2".
|
||||
and "bbrv2".
|
||||
|
||||
Default: ``cubic``
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:11 as build
|
||||
FROM debian:12 as build
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
@@ -7,7 +7,7 @@ RUN apt-get update && \
|
||||
zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
|
||||
libelf-dev
|
||||
|
||||
RUN git clone --depth 1 -b OpenSSL_1_1_1u+quic https://github.com/quictls/openssl && \
|
||||
RUN git clone --depth 1 -b OpenSSL_1_1_1w+quic https://github.com/quictls/openssl && \
|
||||
cd openssl && \
|
||||
./config --openssldir=/etc/ssl && \
|
||||
make -j$(nproc) && \
|
||||
@@ -15,7 +15,7 @@ RUN git clone --depth 1 -b OpenSSL_1_1_1u+quic https://github.com/quictls/openss
|
||||
cd .. && \
|
||||
rm -rf openssl
|
||||
|
||||
RUN git clone --depth 1 -b v0.13.0 https://github.com/ngtcp2/nghttp3 && \
|
||||
RUN git clone --depth 1 -b v0.15.0 https://github.com/ngtcp2/nghttp3 && \
|
||||
cd nghttp3 && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-lib-only && \
|
||||
@@ -24,7 +24,7 @@ RUN git clone --depth 1 -b v0.13.0 https://github.com/ngtcp2/nghttp3 && \
|
||||
cd .. && \
|
||||
rm -rf nghttp3
|
||||
|
||||
RUN git clone --depth 1 -b v0.17.0 https://github.com/ngtcp2/ngtcp2 && \
|
||||
RUN git clone --depth 1 -b v0.19.1 https://github.com/ngtcp2/ngtcp2 && \
|
||||
cd ngtcp2 && \
|
||||
autoreconf -i && \
|
||||
./configure --enable-lib-only \
|
||||
@@ -36,7 +36,7 @@ RUN git clone --depth 1 -b v0.17.0 https://github.com/ngtcp2/ngtcp2 && \
|
||||
cd .. && \
|
||||
rm -rf ngtcp2
|
||||
|
||||
RUN git clone --depth 1 -b v1.2.0 https://github.com/libbpf/libbpf && \
|
||||
RUN git clone --depth 1 -b v1.2.2 https://github.com/libbpf/libbpf && \
|
||||
cd libbpf && \
|
||||
PREFIX=/usr/local make -C src install && \
|
||||
cd .. && \
|
||||
@@ -63,7 +63,7 @@ RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
|
||||
cd .. && \
|
||||
rm -rf nghttp2
|
||||
|
||||
FROM gcr.io/distroless/base-debian11
|
||||
FROM gcr.io/distroless/base-debian12
|
||||
|
||||
COPY --from=build \
|
||||
/usr/local/share/nghttp2/ \
|
||||
|
||||
8
go.mod
8
go.mod
@@ -6,7 +6,7 @@ require (
|
||||
github.com/bradfitz/gomemcache v0.0.0-20230124162541-5f7a7d875746
|
||||
github.com/quic-go/quic-go v0.35.1
|
||||
github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20150408091349-4742878d9c90
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/net v0.17.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -17,10 +17,10 @@ require (
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@@ -36,8 +36,8 @@ github.com/tatsuhiro-t/go-nghttp2 v0.0.0-20150408091349-4742878d9c90/go.mod h1:Y
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
@@ -46,8 +46,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -56,13 +56,13 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
|
||||
@@ -24,6 +24,8 @@ set(NGHTTP2_SOURCES
|
||||
nghttp2_http.c
|
||||
nghttp2_rcbuf.c
|
||||
nghttp2_extpri.c
|
||||
nghttp2_ratelim.c
|
||||
nghttp2_time.c
|
||||
nghttp2_debug.c
|
||||
sfparse.c
|
||||
)
|
||||
|
||||
@@ -51,6 +51,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
||||
nghttp2_http.c \
|
||||
nghttp2_rcbuf.c \
|
||||
nghttp2_extpri.c \
|
||||
nghttp2_ratelim.c \
|
||||
nghttp2_time.c \
|
||||
nghttp2_debug.c \
|
||||
sfparse.c
|
||||
|
||||
@@ -69,6 +71,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_http.h \
|
||||
nghttp2_rcbuf.h \
|
||||
nghttp2_extpri.h \
|
||||
nghttp2_ratelim.h \
|
||||
nghttp2_time.h \
|
||||
nghttp2_debug.h \
|
||||
sfparse.h
|
||||
|
||||
|
||||
@@ -2756,6 +2756,23 @@ NGHTTP2_EXTERN void
|
||||
nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
|
||||
nghttp2_option *option, int val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* This function sets the rate limit for the incoming stream reset
|
||||
* (RST_STREAM frame). It is server use only. It is a token-bucket
|
||||
* based rate limiter. |burst| specifies the number of tokens that is
|
||||
* initially available. The maximum number of tokens is capped to
|
||||
* this value. |rate| specifies the number of tokens that are
|
||||
* regenerated per second. An incoming RST_STREAM consumes one token.
|
||||
* If there is no token available, GOAWAY is sent to tear down the
|
||||
* connection. |burst| and |rate| default to 1000 and 33
|
||||
* respectively.
|
||||
*/
|
||||
NGHTTP2_EXTERN void
|
||||
nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option,
|
||||
uint64_t burst, uint64_t rate);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
||||
@@ -418,8 +418,8 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive);
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload) {
|
||||
void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload) {
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
|
||||
} else {
|
||||
@@ -428,11 +428,9 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
|
||||
frame->nva = NULL;
|
||||
frame->nvlen = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
|
||||
void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@@ -448,8 +446,6 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
|
||||
nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec);
|
||||
|
||||
buf->last += NGHTTP2_PRIORITY_SPECLEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
@@ -457,8 +453,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload);
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame) {
|
||||
void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@@ -473,8 +469,6 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
|
||||
nghttp2_put_uint32be(buf->last, frame->error_code);
|
||||
buf->last += 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||
@@ -592,16 +586,15 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
return frame_pack_headers_shared(bufs, &frame->hd);
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload) {
|
||||
void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload) {
|
||||
frame->promised_stream_id =
|
||||
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||
frame->nva = NULL;
|
||||
frame->nvlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
|
||||
void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@@ -616,8 +609,6 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
|
||||
|
||||
buf->last =
|
||||
nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||
@@ -697,8 +688,8 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame) {
|
||||
void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@@ -713,8 +704,6 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
|
||||
nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment);
|
||||
buf->last += 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
@@ -723,7 +712,7 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
@@ -752,8 +741,6 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len);
|
||||
|
||||
assert(rv == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
@@ -901,8 +888,8 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||
nghttp2_extension *frame) {
|
||||
void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||
nghttp2_extension *frame) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_ext_priority_update *priority_update;
|
||||
@@ -927,8 +914,6 @@ int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||
priority_update->field_value_len);
|
||||
|
||||
assert(rv == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
|
||||
@@ -1186,14 +1171,14 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) {
|
||||
buf->last += trail_padlen;
|
||||
}
|
||||
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only) {
|
||||
void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
if (padlen == 0) {
|
||||
DEBUGF("send: padlen = 0, nothing to do\n");
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1226,6 +1211,4 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
hd->flags |= NGHTTP2_FLAG_PADDED;
|
||||
|
||||
DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -143,11 +143,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
||||
* Unpacks HEADERS frame byte sequence into |frame|. This function
|
||||
* only unapcks bytes that come before name/value header block and
|
||||
* after possible Pad Length field.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload);
|
||||
void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PRIORITY frame |frame| in wire format and store it in
|
||||
@@ -155,10 +153,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
||||
void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PRIORITY wire format into |frame|.
|
||||
@@ -172,11 +168,9 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame);
|
||||
void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Unpacks RST_STREAM frame byte sequence into |frame|.
|
||||
@@ -265,15 +259,9 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This
|
||||
* function only unapcks bytes that come before name/value header
|
||||
* block and after possible Pad Length field.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_PROTO
|
||||
* TODO END_HEADERS flag is not set
|
||||
*/
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload);
|
||||
void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PING frame |frame| in wire format and store it in
|
||||
@@ -281,10 +269,8 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
|
||||
void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PING wire format into |frame|.
|
||||
@@ -343,11 +329,9 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame);
|
||||
void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame);
|
||||
|
||||
/*
|
||||
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
|
||||
@@ -361,17 +345,13 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC wire format into |frame|. The |payload| of
|
||||
* |payloadlen| bytes contains frame payload. This function assumes
|
||||
* that frame->payload points to the nghttp2_ext_altsvc object.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
size_t origin_len, uint8_t *payload,
|
||||
@@ -431,19 +411,15 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||
nghttp2_extension *ext);
|
||||
void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||
nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of
|
||||
* |payloadlen| bytes contains frame payload. This function assumes
|
||||
* that frame->payload points to the nghttp2_ext_priority_update
|
||||
* object.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
|
||||
uint8_t *payload,
|
||||
@@ -654,16 +630,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
||||
* |padlen| including Pad Length field. The |hd| is the frame header
|
||||
* for the serialized data. This function fills zeros padding region
|
||||
* unless framehd_only is nonzero.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the resulting frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only);
|
||||
void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only);
|
||||
|
||||
#endif /* NGHTTP2_FRAME_H */
|
||||
|
||||
@@ -143,3 +143,10 @@ void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
|
||||
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
|
||||
option->no_rfc9113_leading_and_trailing_ws_validation = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option,
|
||||
uint64_t burst, uint64_t rate) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT;
|
||||
option->stream_reset_burst = burst;
|
||||
option->stream_reset_rate = rate;
|
||||
}
|
||||
|
||||
@@ -70,12 +70,18 @@ typedef enum {
|
||||
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
|
||||
NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
|
||||
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
|
||||
NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
* Struct to store option values for nghttp2_session.
|
||||
*/
|
||||
struct nghttp2_option {
|
||||
/**
|
||||
* NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT
|
||||
*/
|
||||
uint64_t stream_reset_burst;
|
||||
uint64_t stream_reset_rate;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
|
||||
*/
|
||||
|
||||
75
lib/nghttp2_ratelim.c
Normal file
75
lib/nghttp2_ratelim.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_ratelim.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) {
|
||||
rl->val = rl->burst = burst;
|
||||
rl->rate = rate;
|
||||
rl->tstamp = 0;
|
||||
}
|
||||
|
||||
void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) {
|
||||
uint64_t d, gain;
|
||||
|
||||
if (tstamp == rl->tstamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tstamp > rl->tstamp) {
|
||||
d = tstamp - rl->tstamp;
|
||||
} else {
|
||||
d = 1;
|
||||
}
|
||||
|
||||
rl->tstamp = tstamp;
|
||||
|
||||
if (UINT64_MAX / d < rl->rate) {
|
||||
rl->val = rl->burst;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gain = rl->rate * d;
|
||||
|
||||
if (UINT64_MAX - gain < rl->val) {
|
||||
rl->val = rl->burst;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rl->val += gain;
|
||||
rl->val = nghttp2_min(rl->val, rl->burst);
|
||||
}
|
||||
|
||||
int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) {
|
||||
if (rl->val < n) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rl->val -= n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
57
lib/nghttp2_ratelim.h
Normal file
57
lib/nghttp2_ratelim.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_RATELIM_H
|
||||
#define NGHTTP2_RATELIM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
typedef struct nghttp2_ratelim {
|
||||
/* burst is the maximum value of val. */
|
||||
uint64_t burst;
|
||||
/* rate is the amount of value that is regenerated per 1 tstamp. */
|
||||
uint64_t rate;
|
||||
/* val is the amount of value available to drain. */
|
||||
uint64_t val;
|
||||
/* tstamp is the last timestamp in second resolution that is known
|
||||
to this object. */
|
||||
uint64_t tstamp;
|
||||
} nghttp2_ratelim;
|
||||
|
||||
/* nghttp2_ratelim_init initializes |rl| with the given parameters. */
|
||||
void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate);
|
||||
|
||||
/* nghttp2_ratelim_update updates rl->val with the current |tstamp|
|
||||
given in second resolution. */
|
||||
void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp);
|
||||
|
||||
/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it
|
||||
succeeds, or -1. */
|
||||
int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n);
|
||||
|
||||
#endif /* NGHTTP2_RATELIM_H */
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "nghttp2_http.h"
|
||||
#include "nghttp2_pq.h"
|
||||
#include "nghttp2_extpri.h"
|
||||
#include "nghttp2_time.h"
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
/*
|
||||
@@ -475,6 +476,10 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
(*session_ptr)->pending_enable_push = 1;
|
||||
(*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
|
||||
|
||||
nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
|
||||
NGHTTP2_DEFAULT_STREAM_RESET_BURST,
|
||||
NGHTTP2_DEFAULT_STREAM_RESET_RATE);
|
||||
|
||||
if (server) {
|
||||
(*session_ptr)->server = 1;
|
||||
}
|
||||
@@ -573,6 +578,12 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
(*session_ptr)->opt_flags |=
|
||||
NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
|
||||
}
|
||||
|
||||
if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) {
|
||||
nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim,
|
||||
option->stream_reset_burst,
|
||||
option->stream_reset_rate);
|
||||
}
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
|
||||
@@ -937,8 +948,8 @@ static int session_ob_data_push(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_ob_data_remove(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
static void session_ob_data_remove(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
uint32_t urgency;
|
||||
|
||||
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
||||
@@ -951,8 +962,6 @@ static int session_ob_data_remove(nghttp2_session *session,
|
||||
nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry);
|
||||
|
||||
stream->queued = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_attach_stream_item(nghttp2_session *session,
|
||||
@@ -972,38 +981,28 @@ static int session_attach_stream_item(nghttp2_session *session,
|
||||
return session_ob_data_push(session, stream);
|
||||
}
|
||||
|
||||
static int session_detach_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
static void session_detach_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream_detach_item(stream);
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
!stream->queued) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return session_ob_data_remove(session, stream);
|
||||
session_ob_data_remove(session, stream);
|
||||
}
|
||||
|
||||
static int session_defer_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream, uint8_t flags) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_defer_item(stream, flags);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
static void session_defer_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream, uint8_t flags) {
|
||||
nghttp2_stream_defer_item(stream, flags);
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
!stream->queued) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return session_ob_data_remove(session, stream);
|
||||
session_ob_data_remove(session, stream);
|
||||
}
|
||||
|
||||
static int session_resume_deferred_stream_item(nghttp2_session *session,
|
||||
@@ -1476,11 +1475,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||
|
||||
item = stream->item;
|
||||
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
|
||||
/* If item is queued, it will be deleted when it is popped
|
||||
(nghttp2_session_prep_frame() will fail). If session->aob.item
|
||||
@@ -2221,7 +2216,6 @@ static ssize_t session_call_select_padding(nghttp2_session *session,
|
||||
frame->push_promise has also padlen in the same position. */
|
||||
static int session_headers_add_pad(nghttp2_session *session,
|
||||
nghttp2_frame *frame) {
|
||||
int rv;
|
||||
ssize_t padded_payloadlen;
|
||||
nghttp2_active_outbound_item *aob;
|
||||
nghttp2_bufs *framebufs;
|
||||
@@ -2246,11 +2240,7 @@ static int session_headers_add_pad(nghttp2_session *session,
|
||||
DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n",
|
||||
padded_payloadlen, padlen);
|
||||
|
||||
rv = nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0);
|
||||
|
||||
frame->headers.padlen = padlen;
|
||||
|
||||
@@ -2333,13 +2323,7 @@ static int session_prep_frame(nghttp2_session *session,
|
||||
// Search stream including closed again.
|
||||
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
|
||||
if (stream) {
|
||||
int rv2;
|
||||
|
||||
rv2 = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@@ -2354,12 +2338,8 @@ static int session_prep_frame(nghttp2_session *session,
|
||||
queue when session->remote_window_size > 0 */
|
||||
assert(session->remote_window_size > 0);
|
||||
|
||||
rv = session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
session->aob.item = NULL;
|
||||
active_outbound_item_reset(&session->aob, mem);
|
||||
@@ -2373,23 +2353,15 @@ static int session_prep_frame(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
if (rv == NGHTTP2_ERR_DEFERRED) {
|
||||
rv = session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||
|
||||
session->aob.item = NULL;
|
||||
active_outbound_item_reset(&session->aob, mem);
|
||||
return NGHTTP2_ERR_DEFERRED;
|
||||
}
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
|
||||
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
@@ -2399,13 +2371,7 @@ static int session_prep_frame(nghttp2_session *session,
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
if (rv != 0) {
|
||||
int rv2;
|
||||
|
||||
rv2 = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -2907,10 +2873,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
|
||||
}
|
||||
|
||||
if (stream && aux_data->eof) {
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
|
||||
/* Call on_frame_send_callback after
|
||||
nghttp2_stream_detach_item(), so that application can issue
|
||||
@@ -3143,17 +3106,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
|
||||
/*
|
||||
* Called after a frame is sent and session_after_frame_sent1. This
|
||||
* function is responsible to reset session->aob.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
static int session_after_frame_sent2(nghttp2_session *session) {
|
||||
int rv;
|
||||
static void session_after_frame_sent2(nghttp2_session *session) {
|
||||
nghttp2_active_outbound_item *aob = &session->aob;
|
||||
nghttp2_outbound_item *item = aob->item;
|
||||
nghttp2_bufs *framebufs = &aob->framebufs;
|
||||
@@ -3176,13 +3130,13 @@ static int session_after_frame_sent2(nghttp2_session *session) {
|
||||
DEBUGF("send: next CONTINUATION frame, %zu bytes\n",
|
||||
nghttp2_buf_len(&framebufs->cur->buf));
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
active_outbound_item_reset(&session->aob, mem);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* DATA frame */
|
||||
@@ -3196,7 +3150,7 @@ static int session_after_frame_sent2(nghttp2_session *session) {
|
||||
if (aux_data->eof) {
|
||||
active_outbound_item_reset(aob, mem);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset no_copy here because next write may not use this. */
|
||||
@@ -3208,22 +3162,18 @@ static int session_after_frame_sent2(nghttp2_session *session) {
|
||||
further data. */
|
||||
if (nghttp2_session_predicate_data_send(session, stream) != 0) {
|
||||
if (stream) {
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
}
|
||||
|
||||
active_outbound_item_reset(aob, mem);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
aob->item = NULL;
|
||||
active_outbound_item_reset(&session->aob, mem);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static int session_call_send_data(nghttp2_session *session,
|
||||
@@ -3296,6 +3246,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
if (rv < 0) {
|
||||
int32_t opened_stream_id = 0;
|
||||
uint32_t error_code = NGHTTP2_INTERNAL_ERROR;
|
||||
int rv2 = 0;
|
||||
|
||||
DEBUGF("send: frame preparation failed with %s\n",
|
||||
nghttp2_strerror(rv));
|
||||
@@ -3338,19 +3289,18 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
}
|
||||
if (opened_stream_id) {
|
||||
/* careful not to override rv */
|
||||
int rv2;
|
||||
rv2 = nghttp2_session_close_stream(session, opened_stream_id,
|
||||
error_code);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_free(item, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
active_outbound_item_reset(aob, mem);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_HEADER_COMP) {
|
||||
/* If header compression error occurred, should terminiate
|
||||
connection. */
|
||||
@@ -3454,7 +3404,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
|
||||
/* Frame has completely sent */
|
||||
if (fast_cb) {
|
||||
rv = session_after_frame_sent2(session);
|
||||
session_after_frame_sent2(session);
|
||||
} else {
|
||||
rv = session_after_frame_sent1(session);
|
||||
if (rv < 0) {
|
||||
@@ -3462,12 +3412,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
assert(nghttp2_is_fatal(rv));
|
||||
return rv;
|
||||
}
|
||||
rv = session_after_frame_sent2(session);
|
||||
}
|
||||
if (rv < 0) {
|
||||
/* FATAL */
|
||||
assert(nghttp2_is_fatal(rv));
|
||||
return rv;
|
||||
session_after_frame_sent2(session);
|
||||
}
|
||||
/* We have already adjusted the next state */
|
||||
break;
|
||||
@@ -3506,11 +3451,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
session_detach_stream_item(session, stream);
|
||||
|
||||
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
@@ -3534,11 +3475,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||
assert(nghttp2_is_fatal(rv));
|
||||
return rv;
|
||||
}
|
||||
rv = session_after_frame_sent2(session);
|
||||
if (rv < 0) {
|
||||
assert(nghttp2_is_fatal(rv));
|
||||
return rv;
|
||||
}
|
||||
session_after_frame_sent2(session);
|
||||
|
||||
/* We have already adjusted the next state */
|
||||
|
||||
@@ -4424,17 +4361,12 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||
}
|
||||
|
||||
static int session_process_headers_frame(nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos);
|
||||
nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos);
|
||||
|
||||
if (rv != 0) {
|
||||
return nghttp2_session_terminate_session_with_reason(
|
||||
session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: could not unpack");
|
||||
}
|
||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||
if (!stream) {
|
||||
frame->headers.cat = NGHTTP2_HCAT_REQUEST;
|
||||
@@ -4528,6 +4460,23 @@ static int session_process_priority_frame(nghttp2_session *session) {
|
||||
return nghttp2_session_on_priority_received(session, frame);
|
||||
}
|
||||
|
||||
static int session_update_stream_reset_ratelim(nghttp2_session *session) {
|
||||
if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_ratelim_update(&session->stream_reset_ratelim,
|
||||
nghttp2_time_now_sec());
|
||||
|
||||
if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return nghttp2_session_add_goaway(session, session->last_recv_stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR, NULL, 0,
|
||||
NGHTTP2_GOAWAY_AUX_NONE);
|
||||
}
|
||||
|
||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame) {
|
||||
int rv;
|
||||
@@ -4557,7 +4506,8 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return session_update_stream_reset_ratelim(session);
|
||||
}
|
||||
|
||||
static int session_process_rst_stream_frame(nghttp2_session *session) {
|
||||
@@ -5097,17 +5047,11 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||
}
|
||||
|
||||
static int session_process_push_promise_frame(nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
|
||||
rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
|
||||
iframe->sbuf.pos);
|
||||
|
||||
if (rv != 0) {
|
||||
return nghttp2_session_terminate_session_with_reason(
|
||||
session, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: could not unpack");
|
||||
}
|
||||
nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
|
||||
iframe->sbuf.pos);
|
||||
|
||||
return nghttp2_session_on_push_promise_received(session, frame);
|
||||
}
|
||||
@@ -7519,6 +7463,9 @@ int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7808,11 +7755,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||
|
||||
rv = nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen,
|
||||
aux_data->no_copy);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen,
|
||||
aux_data->no_copy);
|
||||
|
||||
session_reschedule_stream(session, stream);
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_callbacks.h"
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_ratelim.h"
|
||||
|
||||
/* The global variable for tests where we want to disable strict
|
||||
preface handling. */
|
||||
@@ -105,6 +106,10 @@ typedef struct {
|
||||
/* The default value of maximum number of concurrent streams. */
|
||||
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
|
||||
|
||||
/* The default values for stream reset rate limiter. */
|
||||
#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000
|
||||
#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33
|
||||
|
||||
/* Internal state when receiving incoming frame */
|
||||
typedef enum {
|
||||
/* Receiving frame header */
|
||||
@@ -178,7 +183,9 @@ typedef enum {
|
||||
/* Flag means GOAWAY was sent */
|
||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||
/* Flag means GOAWAY was received */
|
||||
NGHTTP2_GOAWAY_RECV = 0x8
|
||||
NGHTTP2_GOAWAY_RECV = 0x8,
|
||||
/* Flag means GOAWAY has been submitted at least once */
|
||||
NGHTTP2_GOAWAY_SUBMITTED = 0x10
|
||||
} nghttp2_goaway_flag;
|
||||
|
||||
/* nghttp2_inflight_settings stores the SETTINGS entries which local
|
||||
@@ -235,6 +242,9 @@ struct nghttp2_session {
|
||||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||
considered as in-flight. */
|
||||
nghttp2_inflight_settings *inflight_settings_head;
|
||||
/* Stream reset rate limiter. If receiving excessive amount of
|
||||
stream resets, GOAWAY will be sent. */
|
||||
nghttp2_ratelim stream_reset_ratelim;
|
||||
/* Sequential number across all streams to process streams in
|
||||
FIFO. */
|
||||
uint64_t stream_seq;
|
||||
|
||||
@@ -465,14 +465,12 @@ static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
|
||||
static void stream_update_dep_on_detach_item(nghttp2_stream *stream) {
|
||||
if (nghttp2_pq_empty(&stream->obq)) {
|
||||
stream_obq_remove(stream);
|
||||
}
|
||||
|
||||
validate_tree(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
@@ -503,20 +501,20 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_detach_item(nghttp2_stream *stream) {
|
||||
void nghttp2_stream_detach_item(nghttp2_stream *stream) {
|
||||
DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
|
||||
|
||||
stream->item = NULL;
|
||||
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
assert(stream->item);
|
||||
|
||||
DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
|
||||
@@ -525,10 +523,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
stream->flags |= flags;
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
|
||||
@@ -258,14 +258,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
|
||||
* more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates
|
||||
* the reason of this action.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
|
||||
void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Put back deferred data in this stream to active state. The |flags|
|
||||
@@ -379,14 +373,8 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
/*
|
||||
* Detaches |stream->item|. This function does not free
|
||||
* |stream->item|. The caller must free it.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_detach_item(nghttp2_stream *stream);
|
||||
void nghttp2_stream_detach_item(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
|
||||
62
lib/nghttp2_time.c
Normal file
62
lib/nghttp2_time.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_time.h"
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
# include <time.h>
|
||||
#endif /* HAVE_TIME_H */
|
||||
|
||||
#ifdef HAVE_SYSINFOAPI_H
|
||||
# include <sysinfoapi.h>
|
||||
#endif /* HAVE_SYSINFOAPI_H */
|
||||
|
||||
#ifndef HAVE_GETTICKCOUNT64
|
||||
static uint64_t time_now_sec(void) {
|
||||
time_t t = time(NULL);
|
||||
|
||||
if (t == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)t;
|
||||
}
|
||||
#endif /* HAVE_GETTICKCOUNT64 */
|
||||
|
||||
#ifdef HAVE_GETTICKCOUNT64
|
||||
uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; }
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
uint64_t nghttp2_time_now_sec(void) {
|
||||
struct timespec tp;
|
||||
int rv = clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
|
||||
if (rv == -1) {
|
||||
return time_now_sec();
|
||||
}
|
||||
|
||||
return (uint64_t)tp.tv_sec;
|
||||
}
|
||||
#else /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
|
||||
uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); }
|
||||
#endif /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */
|
||||
38
lib/nghttp2_time.h
Normal file
38
lib/nghttp2_time.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_TIME_H
|
||||
#define NGHTTP2_TIME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/* nghttp2_time_now_sec returns seconds from implementation-specific
|
||||
timepoint. If it is unable to get seconds, it returns 0. */
|
||||
uint64_t nghttp2_time_now_sec(void);
|
||||
|
||||
#endif /* NGHTTP2_TIME_H */
|
||||
@@ -754,37 +754,37 @@ int Http2Handler::read_tls() {
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
for (;;) {
|
||||
auto rv = SSL_read(ssl_, buf.data(), buf.size());
|
||||
auto rv = SSL_read(ssl_, buf.data(), buf.size());
|
||||
|
||||
if (rv <= 0) {
|
||||
auto err = SSL_get_error(ssl_, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return write_(*this);
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// renegotiation started
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto nread = rv;
|
||||
|
||||
if (get_config()->hexdump) {
|
||||
util::hexdump(stdout, buf.data(), nread);
|
||||
}
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||
if (rv < 0) {
|
||||
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
|
||||
std::cerr << "nghttp2_session_mem_recv() returned error: "
|
||||
<< nghttp2_strerror(rv) << std::endl;
|
||||
}
|
||||
if (rv <= 0) {
|
||||
auto err = SSL_get_error(ssl_, rv);
|
||||
switch (err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return write_(*this);
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
// renegotiation started
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto nread = rv;
|
||||
|
||||
if (get_config()->hexdump) {
|
||||
util::hexdump(stdout, buf.data(), nread);
|
||||
}
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buf.data(), nread);
|
||||
if (rv < 0) {
|
||||
if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
|
||||
std::cerr << "nghttp2_session_mem_recv() returned error: "
|
||||
<< nghttp2_strerror(rv) << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return write_(*this);
|
||||
}
|
||||
|
||||
int Http2Handler::write_tls() {
|
||||
|
||||
@@ -1469,7 +1469,8 @@ int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
|
||||
cm->cmsg_level = SOL_UDP;
|
||||
cm->cmsg_type = UDP_SEGMENT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
|
||||
*(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
|
||||
uint16_t n = gso_size;
|
||||
memcpy(CMSG_DATA(cm), &n, sizeof(n));
|
||||
}
|
||||
# endif // UDP_SEGMENT
|
||||
|
||||
|
||||
24
src/shrpx.cc
24
src/shrpx.cc
@@ -1675,10 +1675,10 @@ pid_t fork_worker_process(
|
||||
}
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
close(worker_process_ready_ipc_fd[0]);
|
||||
shutdown_worker_process_ready_ipc_watcher(EV_DEFAULT);
|
||||
|
||||
if (!config->single_process) {
|
||||
close(worker_process_ready_ipc_fd[0]);
|
||||
shutdown_worker_process_ready_ipc_watcher(EV_DEFAULT);
|
||||
|
||||
shutdown_signal_watchers(EV_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -3324,15 +3324,17 @@ HTTP:
|
||||
in HTTP/2 frontend.
|
||||
--add-request-header=<HEADER>
|
||||
Specify additional header field to add to request header
|
||||
set. This option just appends header field and won't
|
||||
replace anything already set. This option can be used
|
||||
several times to specify multiple header fields.
|
||||
set. The field name must be lowercase. This option
|
||||
just appends header field and won't replace anything
|
||||
already set. This option can be used several times to
|
||||
specify multiple header fields.
|
||||
Example: --add-request-header="foo: bar"
|
||||
--add-response-header=<HEADER>
|
||||
Specify additional header field to add to response
|
||||
header set. This option just appends header field and
|
||||
won't replace anything already set. This option can be
|
||||
used several times to specify multiple header fields.
|
||||
header set. The field name must be lowercase. This
|
||||
option just appends header field and won't replace
|
||||
anything already set. This option can be used several
|
||||
times to specify multiple header fields.
|
||||
Example: --add-response-header="foo: bar"
|
||||
--request-header-field-buffer=<SIZE>
|
||||
Set maximum buffer size for incoming HTTP request header
|
||||
@@ -3521,14 +3523,14 @@ HTTP/3 and QUIC:
|
||||
--frontend-quic-congestion-controller=<CC>
|
||||
Specify a congestion controller algorithm for a frontend
|
||||
QUIC connection. <CC> should be one of "cubic", "bbr",
|
||||
and "bbr2".
|
||||
and "bbrv2".
|
||||
Default: )"
|
||||
<< (config->quic.upstream.congestion_controller == NGTCP2_CC_ALGO_CUBIC
|
||||
? "cubic"
|
||||
: (config->quic.upstream.congestion_controller ==
|
||||
NGTCP2_CC_ALGO_BBR
|
||||
? "bbr"
|
||||
: "bbr2"))
|
||||
: "bbrv2"))
|
||||
<< R"(
|
||||
--frontend-quic-secret-file=<PATH>
|
||||
Path to file that contains secure random data to be used
|
||||
|
||||
@@ -4116,10 +4116,10 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||
config->quic.upstream.congestion_controller = NGTCP2_CC_ALGO_CUBIC;
|
||||
} else if (util::strieq_l("bbr", optarg)) {
|
||||
config->quic.upstream.congestion_controller = NGTCP2_CC_ALGO_BBR;
|
||||
} else if (util::strieq_l("bbr2", optarg)) {
|
||||
config->quic.upstream.congestion_controller = NGTCP2_CC_ALGO_BBR2;
|
||||
} else if (util::strieq_l("bbrv2", optarg)) {
|
||||
config->quic.upstream.congestion_controller = NGTCP2_CC_ALGO_BBR_V2;
|
||||
} else {
|
||||
LOG(ERROR) << opt << ": must be one of cubic, bbr, and bbr2";
|
||||
LOG(ERROR) << opt << ": must be one of cubic, bbr, and bbrv2";
|
||||
return -1;
|
||||
}
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
@@ -1019,6 +1019,10 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
||||
tls.last_readlen = 0;
|
||||
}
|
||||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
auto via_bio =
|
||||
tls.server_handshake && !tlsconf.session_cache.memcached.host.empty();
|
||||
|
||||
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||
if (!tls.early_data_finish) {
|
||||
// TLSv1.3 handshake is still going on.
|
||||
@@ -1056,6 +1060,11 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
||||
// We may have stopped write watcher in write_tls.
|
||||
wlimit.startw();
|
||||
}
|
||||
|
||||
if (!via_bio) {
|
||||
rlimit.drain(nread);
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
#endif // OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||
@@ -1088,6 +1097,10 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!via_bio) {
|
||||
rlimit.drain(rv);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -421,7 +421,7 @@ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
|
||||
void *stream_user_data) {
|
||||
auto upstream = static_cast<Http3Upstream *>(user_data);
|
||||
|
||||
if (upstream->http_shutdown_stream_read(stream_id) != 0) {
|
||||
if (upstream->stream_reset(stream_id) != 0) {
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
@@ -429,6 +429,24 @@ int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int Http3Upstream::stream_reset(int64_t stream_id) {
|
||||
if (http_shutdown_stream_read(stream_id) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngtcp2_is_bidi_stream(stream_id)) {
|
||||
auto rv = ngtcp2_conn_shutdown_stream_write(conn_, 0, stream_id,
|
||||
NGHTTP3_H3_NO_ERROR);
|
||||
if (rv != 0) {
|
||||
ULOG(ERROR, this) << "ngtcp2_conn_shutdown_stream_write: "
|
||||
<< ngtcp2_strerror(rv);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Http3Upstream::http_shutdown_stream_read(int64_t stream_id) {
|
||||
if (!httpconn_) {
|
||||
return 0;
|
||||
@@ -551,7 +569,7 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
const Address &local_addr,
|
||||
const ngtcp2_pkt_hd &initial_hd,
|
||||
const ngtcp2_cid *odcid, const uint8_t *token,
|
||||
size_t tokenlen) {
|
||||
size_t tokenlen, ngtcp2_token_type token_type) {
|
||||
int rv;
|
||||
|
||||
auto worker = handler_->get_worker();
|
||||
@@ -638,6 +656,7 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
settings.rand_ctx.native_handle = &worker->get_randgen();
|
||||
settings.token = token;
|
||||
settings.tokenlen = tokenlen;
|
||||
settings.token_type = token_type;
|
||||
settings.initial_pkt_num = std::uniform_int_distribution<uint32_t>(
|
||||
0, std::numeric_limits<int32_t>::max())(worker->get_randgen());
|
||||
|
||||
@@ -1559,9 +1578,7 @@ void Http3Upstream::on_handler_delete() {
|
||||
auto cw = std::make_unique<CloseWait>(worker, std::move(scids),
|
||||
std::move(conn_close_), d);
|
||||
|
||||
quic_conn_handler->add_close_wait(cw.get());
|
||||
|
||||
cw.release();
|
||||
quic_conn_handler->add_close_wait(cw.release());
|
||||
}
|
||||
|
||||
int Http3Upstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
|
||||
|
||||
@@ -89,7 +89,8 @@ public:
|
||||
|
||||
int init(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
const Address &local_addr, const ngtcp2_pkt_hd &initial_hd,
|
||||
const ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen);
|
||||
const ngtcp2_cid *odcid, const uint8_t *token, size_t tokenlen,
|
||||
ngtcp2_token_type token_type);
|
||||
|
||||
int on_read(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
const Address &local_addr, const ngtcp2_pkt_info &pi,
|
||||
@@ -124,6 +125,7 @@ public:
|
||||
void consume(int64_t stream_id, size_t nconsumed);
|
||||
void remove_downstream(Downstream *downstream);
|
||||
int stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||
int stream_reset(int64_t stream_id);
|
||||
void log_response_headers(Downstream *downstream,
|
||||
const std::vector<nghttp3_nv> &nva) const;
|
||||
int http_acked_stream_data(Downstream *downstream, uint64_t datalen);
|
||||
|
||||
@@ -66,11 +66,11 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||
msg.msg_iov = &msg_iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
uint8_t msg_ctrl[
|
||||
uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) +
|
||||
#ifdef UDP_SEGMENT
|
||||
CMSG_SPACE(sizeof(uint16_t)) +
|
||||
CMSG_SPACE(sizeof(uint16_t)) +
|
||||
#endif // UDP_SEGMENT
|
||||
CMSG_SPACE(sizeof(in6_pktinfo))];
|
||||
CMSG_SPACE(sizeof(in6_pktinfo))];
|
||||
|
||||
memset(msg_ctrl, 0, sizeof(msg_ctrl));
|
||||
|
||||
@@ -87,11 +87,12 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||
cm->cmsg_level = IPPROTO_IP;
|
||||
cm->cmsg_type = IP_PKTINFO;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
|
||||
auto pktinfo = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cm));
|
||||
memset(pktinfo, 0, sizeof(in_pktinfo));
|
||||
in_pktinfo pktinfo{};
|
||||
auto addrin =
|
||||
reinterpret_cast<sockaddr_in *>(const_cast<sockaddr *>(local_sa));
|
||||
pktinfo->ipi_spec_dst = addrin->sin_addr;
|
||||
pktinfo.ipi_spec_dst = addrin->sin_addr;
|
||||
memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo));
|
||||
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
@@ -99,11 +100,12 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_PKTINFO;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
|
||||
auto pktinfo = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cm));
|
||||
memset(pktinfo, 0, sizeof(in6_pktinfo));
|
||||
in6_pktinfo pktinfo{};
|
||||
auto addrin =
|
||||
reinterpret_cast<sockaddr_in6 *>(const_cast<sockaddr *>(local_sa));
|
||||
pktinfo->ipi6_addr = addrin->sin6_addr;
|
||||
pktinfo.ipi6_addr = addrin->sin6_addr;
|
||||
memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -117,13 +119,33 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
|
||||
cm->cmsg_level = SOL_UDP;
|
||||
cm->cmsg_type = UDP_SEGMENT;
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
|
||||
*(reinterpret_cast<uint16_t *>(CMSG_DATA(cm))) = gso_size;
|
||||
uint16_t n = gso_size;
|
||||
memcpy(CMSG_DATA(cm), &n, sizeof(n));
|
||||
}
|
||||
#endif // UDP_SEGMENT
|
||||
|
||||
msg.msg_controllen = controllen;
|
||||
controllen += CMSG_SPACE(sizeof(int));
|
||||
cm = CMSG_NXTHDR(&msg, cm);
|
||||
cm->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
unsigned int tos = pi.ecn;
|
||||
memcpy(CMSG_DATA(cm), &tos, sizeof(tos));
|
||||
|
||||
util::fd_set_send_ecn(faddr->fd, local_sa->sa_family, pi.ecn);
|
||||
switch (local_sa->sa_family) {
|
||||
case AF_INET:
|
||||
cm->cmsg_level = IPPROTO_IP;
|
||||
cm->cmsg_type = IP_TOS;
|
||||
|
||||
break;
|
||||
case AF_INET6:
|
||||
cm->cmsg_level = IPPROTO_IPV6;
|
||||
cm->cmsg_type = IPV6_TCLASS;
|
||||
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
msg.msg_controllen = controllen;
|
||||
|
||||
ssize_t nwrite;
|
||||
|
||||
|
||||
@@ -172,6 +172,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||
ngtcp2_cid odcid, *podcid = nullptr;
|
||||
const uint8_t *token = nullptr;
|
||||
size_t tokenlen = 0;
|
||||
ngtcp2_token_type token_type = NGTCP2_TOKEN_TYPE_UNKNOWN;
|
||||
|
||||
switch (ngtcp2_accept(&hd, data, datalen)) {
|
||||
case 0: {
|
||||
@@ -249,6 +250,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||
podcid = &odcid;
|
||||
token = hd.token;
|
||||
tokenlen = hd.tokenlen;
|
||||
token_type = NGTCP2_TOKEN_TYPE_RETRY;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -303,6 +305,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||
|
||||
token = hd.token;
|
||||
tokenlen = hd.tokenlen;
|
||||
token_type = NGTCP2_TOKEN_TYPE_NEW_TOKEN;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -342,7 +345,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||
}
|
||||
|
||||
handler = handle_new_connection(faddr, remote_addr, local_addr, hd, podcid,
|
||||
token, tokenlen);
|
||||
token, tokenlen, token_type);
|
||||
if (handler == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@@ -364,7 +367,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr,
|
||||
ClientHandler *QUICConnectionHandler::handle_new_connection(
|
||||
const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
const Address &local_addr, const ngtcp2_pkt_hd &hd, const ngtcp2_cid *odcid,
|
||||
const uint8_t *token, size_t tokenlen) {
|
||||
const uint8_t *token, size_t tokenlen, ngtcp2_token_type token_type) {
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
std::array<char, NI_MAXSERV> service;
|
||||
int rv;
|
||||
@@ -415,8 +418,8 @@ ClientHandler *QUICConnectionHandler::handle_new_connection(
|
||||
StringRef{service.data()}, remote_addr.su.sa.sa_family, faddr);
|
||||
|
||||
auto upstream = std::make_unique<Http3Upstream>(handler.get());
|
||||
if (upstream->init(faddr, remote_addr, local_addr, hd, odcid, token,
|
||||
tokenlen) != 0) {
|
||||
if (upstream->init(faddr, remote_addr, local_addr, hd, odcid, token, tokenlen,
|
||||
token_type) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -526,9 +529,7 @@ int QUICConnectionHandler::send_retry(
|
||||
auto cw = std::make_unique<CloseWait>(worker_, std::vector<ngtcp2_cid>{idcid},
|
||||
std::move(buf), d);
|
||||
|
||||
add_close_wait(cw.get());
|
||||
|
||||
cw.release();
|
||||
add_close_wait(cw.release());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -116,12 +116,11 @@ public:
|
||||
const Address &remote_addr,
|
||||
const Address &local_addr, uint64_t error_code,
|
||||
size_t max_pktlen);
|
||||
ClientHandler *handle_new_connection(const UpstreamAddr *faddr,
|
||||
const Address &remote_addr,
|
||||
const Address &local_addr,
|
||||
const ngtcp2_pkt_hd &hd,
|
||||
const ngtcp2_cid *odcid,
|
||||
const uint8_t *token, size_t tokenlen);
|
||||
ClientHandler *
|
||||
handle_new_connection(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||
const Address &local_addr, const ngtcp2_pkt_hd &hd,
|
||||
const ngtcp2_cid *odcid, const uint8_t *token,
|
||||
size_t tokenlen, ngtcp2_token_type token_type);
|
||||
void add_connection_id(const ngtcp2_cid &cid, ClientHandler *handler);
|
||||
void remove_connection_id(const ngtcp2_cid &cid);
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@ void QUICListener::on_read() {
|
||||
msg.msg_iov = &msg_iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint8_t)) +
|
||||
CMSG_SPACE(sizeof(in6_pktinfo)) +
|
||||
uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(in6_pktinfo)) +
|
||||
CMSG_SPACE(sizeof(uint16_t))];
|
||||
msg.msg_control = msg_ctrl;
|
||||
|
||||
|
||||
@@ -67,8 +67,7 @@ template <typename F, typename... T> struct Defer {
|
||||
Defer(Defer &&o) noexcept : f(std::move(o.f)) {}
|
||||
~Defer() { f(); }
|
||||
|
||||
using ResultType = typename std::result_of<typename std::decay<F>::type(
|
||||
typename std::decay<T>::type...)>::type;
|
||||
using ResultType = std::invoke_result_t<F, T...>;
|
||||
std::function<ResultType()> f;
|
||||
};
|
||||
|
||||
|
||||
53
src/util.cc
53
src/util.cc
@@ -41,6 +41,9 @@
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif // HAVE_NETINET_IN_H
|
||||
#ifdef HAVE_NETINET_IP_H
|
||||
# include <netinet/ip.h>
|
||||
#endif // HAVE_NETINET_IP_H
|
||||
#include <netinet/udp.h>
|
||||
#ifdef _WIN32
|
||||
# include <ws2tcpip.h>
|
||||
@@ -1680,11 +1683,12 @@ int msghdr_get_local_addr(Address &dest, msghdr *msg, int family) {
|
||||
case AF_INET:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
|
||||
auto pktinfo = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsg));
|
||||
in_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
dest.len = sizeof(dest.su.in);
|
||||
auto &sa = dest.su.in;
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_addr = pktinfo->ipi_addr;
|
||||
sa.sin_addr = pktinfo.ipi_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1694,11 +1698,12 @@ int msghdr_get_local_addr(Address &dest, msghdr *msg, int family) {
|
||||
case AF_INET6:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
|
||||
auto pktinfo = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsg));
|
||||
in6_pktinfo pktinfo;
|
||||
memcpy(&pktinfo, CMSG_DATA(cmsg), sizeof(pktinfo));
|
||||
dest.len = sizeof(dest.su.in6);
|
||||
auto &sa = dest.su.in6;
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_addr = pktinfo->ipi6_addr;
|
||||
sa.sin6_addr = pktinfo.ipi6_addr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1709,13 +1714,18 @@ int msghdr_get_local_addr(Address &dest, msghdr *msg, int family) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int msghdr_get_ecn(msghdr *msg, int family) {
|
||||
uint8_t msghdr_get_ecn(msghdr *msg, int family) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TOS &&
|
||||
cmsg->cmsg_len) {
|
||||
return *reinterpret_cast<uint8_t *>(CMSG_DATA(cmsg));
|
||||
if (cmsg->cmsg_level == IPPROTO_IP &&
|
||||
# ifdef __APPLE__
|
||||
cmsg->cmsg_type == IP_RECVTOS
|
||||
# else // !__APPLE__
|
||||
cmsg->cmsg_type == IP_TOS
|
||||
# endif // !__APPLE__
|
||||
&& cmsg->cmsg_len) {
|
||||
return *reinterpret_cast<uint8_t *>(CMSG_DATA(cmsg)) & IPTOS_ECN_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1724,7 +1734,11 @@ unsigned int msghdr_get_ecn(msghdr *msg, int family) {
|
||||
for (auto cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_TCLASS &&
|
||||
cmsg->cmsg_len) {
|
||||
return *reinterpret_cast<uint8_t *>(CMSG_DATA(cmsg));
|
||||
unsigned int tos;
|
||||
|
||||
memcpy(&tos, CMSG_DATA(cmsg), sizeof(tos));
|
||||
|
||||
return tos & IPTOS_ECN_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1749,27 +1763,6 @@ size_t msghdr_get_udp_gro(msghdr *msg) {
|
||||
|
||||
return gso_size;
|
||||
}
|
||||
|
||||
int fd_set_send_ecn(int fd, int family, unsigned int ecn) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &ecn,
|
||||
static_cast<socklen_t>(sizeof(ecn))) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case AF_INET6:
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &ecn,
|
||||
static_cast<socklen_t>(sizeof(ecn))) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -957,13 +957,11 @@ StringRef rstrip(BlockAllocator &balloc, const StringRef &s);
|
||||
#ifdef ENABLE_HTTP3
|
||||
int msghdr_get_local_addr(Address &dest, msghdr *msg, int family);
|
||||
|
||||
unsigned int msghdr_get_ecn(msghdr *msg, int family);
|
||||
uint8_t msghdr_get_ecn(msghdr *msg, int family);
|
||||
|
||||
// msghdr_get_udp_gro returns UDP_GRO value from |msg|. If UDP_GRO is
|
||||
// not found, or UDP_GRO is not supported, this function returns 0.
|
||||
size_t msghdr_get_udp_gro(msghdr *msg);
|
||||
|
||||
int fd_set_send_ecn(int fd, int family, unsigned int ecn);
|
||||
#endif // ENABLE_HTTP3
|
||||
|
||||
} // namespace util
|
||||
|
||||
@@ -22,6 +22,7 @@ if(HAVE_CUNIT)
|
||||
nghttp2_buf_test.c
|
||||
nghttp2_http_test.c
|
||||
nghttp2_extpri_test.c
|
||||
nghttp2_ratelim_test.c
|
||||
)
|
||||
|
||||
add_executable(main EXCLUDE_FROM_ALL
|
||||
|
||||
@@ -42,7 +42,8 @@ OBJECTS = main.c nghttp2_pq_test.c nghttp2_map_test.c nghttp2_queue_test.c \
|
||||
nghttp2_helper_test.c \
|
||||
nghttp2_buf_test.c \
|
||||
nghttp2_http_test.c \
|
||||
nghttp2_extpri_test.c
|
||||
nghttp2_extpri_test.c \
|
||||
nghttp2_ratelim_test.c
|
||||
|
||||
HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
|
||||
nghttp2_session_test.h \
|
||||
@@ -51,7 +52,8 @@ HFILES = nghttp2_pq_test.h nghttp2_map_test.h nghttp2_queue_test.h \
|
||||
nghttp2_test_helper.h \
|
||||
nghttp2_buf_test.h \
|
||||
nghttp2_http_test.h \
|
||||
nghttp2_extpri_test.h
|
||||
nghttp2_extpri_test.h \
|
||||
nghttp2_ratelim_test.h
|
||||
|
||||
main_SOURCES = $(HFILES) $(OBJECTS)
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "nghttp2_buf_test.h"
|
||||
#include "nghttp2_http_test.h"
|
||||
#include "nghttp2_extpri_test.h"
|
||||
#include "nghttp2_ratelim_test.h"
|
||||
|
||||
extern int nghttp2_enable_strict_preface;
|
||||
|
||||
@@ -343,6 +344,8 @@ int main(void) {
|
||||
test_nghttp2_session_no_rfc7540_priorities) ||
|
||||
!CU_add_test(pSuite, "session_server_fallback_rfc7540_priorities",
|
||||
test_nghttp2_session_server_fallback_rfc7540_priorities) ||
|
||||
!CU_add_test(pSuite, "session_stream_reset_ratelim",
|
||||
test_nghttp2_session_stream_reset_ratelim) ||
|
||||
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||
test_nghttp2_http_mandatory_headers) ||
|
||||
!CU_add_test(pSuite, "http_content_length",
|
||||
@@ -449,7 +452,9 @@ int main(void) {
|
||||
!CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc) ||
|
||||
!CU_add_test(pSuite, "http_parse_priority",
|
||||
test_nghttp2_http_parse_priority) ||
|
||||
!CU_add_test(pSuite, "extpri_to_uint8", test_nghttp2_extpri_to_uint8)) {
|
||||
!CU_add_test(pSuite, "extpri_to_uint8", test_nghttp2_extpri_to_uint8) ||
|
||||
!CU_add_test(pSuite, "ratelim_update", test_nghttp2_ratelim_update) ||
|
||||
!CU_add_test(pSuite, "ratelim_drain", test_nghttp2_ratelim_drain)) {
|
||||
CU_cleanup_registry();
|
||||
return (int)CU_get_error();
|
||||
}
|
||||
|
||||
@@ -210,7 +210,6 @@ void test_nghttp2_frame_pack_priority(void) {
|
||||
nghttp2_priority frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
int rv;
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
@@ -218,9 +217,8 @@ void test_nghttp2_frame_pack_priority(void) {
|
||||
nghttp2_priority_spec_init(&pri_spec, 1000000009, 12, 1);
|
||||
|
||||
nghttp2_frame_priority_init(&frame, 1000000007, &pri_spec);
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame);
|
||||
nghttp2_frame_pack_priority(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + 5 == nghttp2_bufs_len(&bufs));
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame *)&oframe, &bufs));
|
||||
check_frame_header(5, NGHTTP2_PRIORITY, NGHTTP2_FLAG_NONE, 1000000007,
|
||||
@@ -240,14 +238,12 @@ void test_nghttp2_frame_pack_priority(void) {
|
||||
void test_nghttp2_frame_pack_rst_stream(void) {
|
||||
nghttp2_rst_stream frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
int rv;
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
nghttp2_frame_rst_stream_init(&frame, 1000000007, NGHTTP2_PROTOCOL_ERROR);
|
||||
rv = nghttp2_frame_pack_rst_stream(&bufs, &frame);
|
||||
nghttp2_frame_pack_rst_stream(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4 == nghttp2_bufs_len(&bufs));
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame *)&oframe, &bufs));
|
||||
check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007,
|
||||
@@ -259,9 +255,8 @@ void test_nghttp2_frame_pack_rst_stream(void) {
|
||||
|
||||
/* Unknown error code is passed to callback as is */
|
||||
frame.error_code = 1000000009;
|
||||
rv = nghttp2_frame_pack_rst_stream(&bufs, &frame);
|
||||
nghttp2_frame_pack_rst_stream(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame *)&oframe, &bufs));
|
||||
|
||||
check_frame_header(4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1000000007,
|
||||
@@ -365,14 +360,12 @@ void test_nghttp2_frame_pack_ping(void) {
|
||||
nghttp2_ping frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
const uint8_t opaque_data[] = "01234567";
|
||||
int rv;
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
nghttp2_frame_ping_init(&frame, NGHTTP2_FLAG_ACK, opaque_data);
|
||||
rv = nghttp2_frame_pack_ping(&bufs, &frame);
|
||||
nghttp2_frame_pack_ping(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + 8 == nghttp2_bufs_len(&bufs));
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame *)&oframe, &bufs));
|
||||
check_frame_header(8, NGHTTP2_PING, NGHTTP2_FLAG_ACK, 0, &oframe.hd);
|
||||
@@ -435,14 +428,12 @@ void test_nghttp2_frame_pack_goaway(void) {
|
||||
void test_nghttp2_frame_pack_window_update(void) {
|
||||
nghttp2_window_update frame, oframe;
|
||||
nghttp2_bufs bufs;
|
||||
int rv;
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
nghttp2_frame_window_update_init(&frame, NGHTTP2_FLAG_NONE, 1000000007, 4096);
|
||||
rv = nghttp2_frame_pack_window_update(&bufs, &frame);
|
||||
nghttp2_frame_pack_window_update(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4 == nghttp2_bufs_len(&bufs));
|
||||
CU_ASSERT(0 == unpack_framebuf((nghttp2_frame *)&oframe, &bufs));
|
||||
check_frame_header(4, NGHTTP2_WINDOW_UPDATE, NGHTTP2_FLAG_NONE, 1000000007,
|
||||
@@ -485,9 +476,8 @@ void test_nghttp2_frame_pack_altsvc(void) {
|
||||
|
||||
payloadlen = 2 + sizeof(origin) - 1 + sizeof(field_value) - 1;
|
||||
|
||||
rv = nghttp2_frame_pack_altsvc(&bufs, &frame);
|
||||
nghttp2_frame_pack_altsvc(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + payloadlen == nghttp2_bufs_len(&bufs));
|
||||
|
||||
rv = unpack_framebuf((nghttp2_frame *)&oframe, &bufs);
|
||||
@@ -618,9 +608,8 @@ void test_nghttp2_frame_pack_priority_update(void) {
|
||||
|
||||
payloadlen = 4 + sizeof(field_value) - 1;
|
||||
|
||||
rv = nghttp2_frame_pack_priority_update(&bufs, &frame);
|
||||
nghttp2_frame_pack_priority_update(&bufs, &frame);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(NGHTTP2_FRAME_HDLEN + payloadlen == nghttp2_bufs_len(&bufs));
|
||||
|
||||
rv = unpack_framebuf((nghttp2_frame *)&oframe, &bufs);
|
||||
|
||||
101
tests/nghttp2_ratelim_test.c
Normal file
101
tests/nghttp2_ratelim_test.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_ratelim_test.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <CUnit/CUnit.h>
|
||||
|
||||
#include "nghttp2_ratelim.h"
|
||||
|
||||
void test_nghttp2_ratelim_update(void) {
|
||||
nghttp2_ratelim rl;
|
||||
|
||||
nghttp2_ratelim_init(&rl, 1000, 21);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
CU_ASSERT(1000 == rl.burst);
|
||||
CU_ASSERT(21 == rl.rate);
|
||||
CU_ASSERT(0 == rl.tstamp);
|
||||
|
||||
nghttp2_ratelim_update(&rl, 999);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
CU_ASSERT(999 == rl.tstamp);
|
||||
|
||||
nghttp2_ratelim_drain(&rl, 100);
|
||||
|
||||
CU_ASSERT(900 == rl.val);
|
||||
|
||||
nghttp2_ratelim_update(&rl, 1000);
|
||||
|
||||
CU_ASSERT(921 == rl.val);
|
||||
|
||||
nghttp2_ratelim_update(&rl, 1002);
|
||||
|
||||
CU_ASSERT(963 == rl.val);
|
||||
|
||||
nghttp2_ratelim_update(&rl, 1004);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
CU_ASSERT(1004 == rl.tstamp);
|
||||
|
||||
/* timer skew */
|
||||
nghttp2_ratelim_init(&rl, 1000, 21);
|
||||
nghttp2_ratelim_update(&rl, 1);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
|
||||
nghttp2_ratelim_update(&rl, 0);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
|
||||
/* rate * duration overflow */
|
||||
nghttp2_ratelim_init(&rl, 1000, 100);
|
||||
nghttp2_ratelim_drain(&rl, 999);
|
||||
|
||||
CU_ASSERT(1 == rl.val);
|
||||
|
||||
nghttp2_ratelim_update(&rl, UINT64_MAX);
|
||||
|
||||
CU_ASSERT(1000 == rl.val);
|
||||
|
||||
/* val + rate * duration overflow */
|
||||
nghttp2_ratelim_init(&rl, UINT64_MAX - 1, 2);
|
||||
nghttp2_ratelim_update(&rl, 1);
|
||||
|
||||
CU_ASSERT(UINT64_MAX - 1 == rl.val);
|
||||
}
|
||||
|
||||
void test_nghttp2_ratelim_drain(void) {
|
||||
nghttp2_ratelim rl;
|
||||
|
||||
nghttp2_ratelim_init(&rl, 100, 7);
|
||||
|
||||
CU_ASSERT(-1 == nghttp2_ratelim_drain(&rl, 101));
|
||||
CU_ASSERT(0 == nghttp2_ratelim_drain(&rl, 51));
|
||||
CU_ASSERT(0 == nghttp2_ratelim_drain(&rl, 49));
|
||||
CU_ASSERT(-1 == nghttp2_ratelim_drain(&rl, 1));
|
||||
}
|
||||
35
tests/nghttp2_ratelim_test.h
Normal file
35
tests/nghttp2_ratelim_test.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2023 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_RATELIM_TEST_H
|
||||
#define NGHTTP2_RATELIM_TEST_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
void test_nghttp2_ratelim_update(void);
|
||||
void test_nghttp2_ratelim_drain(void);
|
||||
|
||||
#endif /* NGHTTP2_RATELIM_TEST_H */
|
||||
@@ -584,6 +584,15 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fatal_error_on_stream_close_callback(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code,
|
||||
void *user_data) {
|
||||
on_stream_close_callback(session, stream_id, error_code, user_data);
|
||||
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
static ssize_t pack_extension_callback(nghttp2_session *session, uint8_t *buf,
|
||||
size_t len, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
@@ -720,9 +729,7 @@ void test_nghttp2_session_recv(void) {
|
||||
/* Receive PRIORITY */
|
||||
nghttp2_frame_priority_init(&frame.priority, 5, &pri_spec_default);
|
||||
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
nghttp2_frame_priority_free(&frame.priority);
|
||||
|
||||
@@ -746,9 +753,7 @@ void test_nghttp2_session_recv(void) {
|
||||
/* Receive PING with too large payload */
|
||||
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
|
||||
|
||||
rv = nghttp2_frame_pack_ping(&bufs, &frame.ping);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
nghttp2_frame_pack_ping(&bufs, &frame.ping);
|
||||
|
||||
/* Add extra 16 bytes */
|
||||
nghttp2_bufs_seek_last_present(&bufs);
|
||||
@@ -1401,9 +1406,8 @@ void test_nghttp2_session_recv_continuation(void) {
|
||||
nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
|
||||
|
||||
memcpy(data + datalen, buf->pos, nghttp2_buf_len(buf));
|
||||
@@ -4296,6 +4300,8 @@ void test_nghttp2_session_on_goaway_received(void) {
|
||||
nghttp2_frame frame;
|
||||
int i;
|
||||
nghttp2_mem *mem;
|
||||
const uint8_t *data;
|
||||
ssize_t datalen;
|
||||
|
||||
mem = nghttp2_mem_default();
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
@@ -4337,6 +4343,29 @@ void test_nghttp2_session_on_goaway_received(void) {
|
||||
|
||||
nghttp2_frame_goaway_free(&frame.goaway, mem);
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Make sure that no memory leak when stream_close callback fails
|
||||
with a fatal error */
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.on_stream_close_callback = fatal_error_on_stream_close_callback;
|
||||
|
||||
memset(&user_data, 0, sizeof(user_data));
|
||||
|
||||
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||
|
||||
nghttp2_frame_goaway_init(&frame.goaway, 0, NGHTTP2_NO_ERROR, NULL, 0);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_on_goaway_received(session, &frame));
|
||||
|
||||
nghttp2_submit_request(session, NULL, reqnv, ARRLEN(reqnv), NULL, NULL);
|
||||
|
||||
datalen = nghttp2_session_mem_send(session, &data);
|
||||
|
||||
CU_ASSERT(NGHTTP2_ERR_CALLBACK_FAILURE == datalen);
|
||||
CU_ASSERT(1 == user_data.stream_close_cb_called);
|
||||
|
||||
nghttp2_frame_goaway_free(&frame.goaway, mem);
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_on_window_update_received(void) {
|
||||
@@ -4372,8 +4401,7 @@ void test_nghttp2_session_on_window_update_received(void) {
|
||||
CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 16 * 1024 ==
|
||||
stream->remote_window_size);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_stream_defer_item(
|
||||
stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL));
|
||||
nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
|
||||
CU_ASSERT(2 == user_data.frame_recv_cb_called);
|
||||
@@ -9639,9 +9667,7 @@ void test_nghttp2_session_stream_get_state(void) {
|
||||
/* Create idle stream by PRIORITY frame */
|
||||
nghttp2_frame_priority_init(&frame.priority, 7, &pri_spec_default);
|
||||
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
nghttp2_frame_priority_free(&frame.priority);
|
||||
|
||||
@@ -11847,9 +11873,7 @@ void test_nghttp2_session_server_fallback_rfc7540_priorities(void) {
|
||||
nghttp2_priority_spec_init(&pri_spec, 5, 1, 0);
|
||||
nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
nghttp2_frame_priority_free(&frame.priority);
|
||||
|
||||
@@ -11944,6 +11968,109 @@ void test_nghttp2_session_server_fallback_rfc7540_priorities(void) {
|
||||
nghttp2_bufs_free(&bufs);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_stream_reset_ratelim(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_frame frame;
|
||||
ssize_t rv;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_mem *mem;
|
||||
size_t i;
|
||||
nghttp2_hd_deflater deflater;
|
||||
size_t nvlen;
|
||||
nghttp2_nv *nva;
|
||||
int32_t stream_id;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_option *option;
|
||||
|
||||
mem = nghttp2_mem_default();
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
nghttp2_option_new(&option);
|
||||
nghttp2_option_set_stream_reset_rate_limit(
|
||||
option, NGHTTP2_DEFAULT_STREAM_RESET_BURST, 0);
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, NULL, 0);
|
||||
rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
nghttp2_frame_settings_free(&frame.settings, mem);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||
|
||||
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
|
||||
|
||||
/* Send SETTINGS ACK */
|
||||
rv = nghttp2_session_send(session);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
nghttp2_hd_deflate_init(&deflater, mem);
|
||||
|
||||
for (i = 0; i < NGHTTP2_DEFAULT_STREAM_RESET_BURST + 2; ++i) {
|
||||
stream_id = (int32_t)(i * 2 + 1);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
/* HEADERS */
|
||||
nvlen = ARRLEN(reqnv);
|
||||
nghttp2_nv_array_copy(&nva, reqnv, nvlen, mem);
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
|
||||
stream_id, NGHTTP2_HCAT_HEADERS, NULL, nva,
|
||||
nvlen);
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||
|
||||
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
/* RST_STREAM */
|
||||
nghttp2_frame_rst_stream_init(&frame.rst_stream, stream_id,
|
||||
NGHTTP2_NO_ERROR);
|
||||
nghttp2_frame_pack_rst_stream(&bufs, &frame.rst_stream);
|
||||
nghttp2_frame_rst_stream_free(&frame.rst_stream);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||
|
||||
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
|
||||
|
||||
if (i < NGHTTP2_DEFAULT_STREAM_RESET_BURST) {
|
||||
CU_ASSERT(0 == nghttp2_outbound_queue_size(&session->ob_reg));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CU_ASSERT(1 == nghttp2_outbound_queue_size(&session->ob_reg));
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
|
||||
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||
CU_ASSERT(NGHTTP2_DEFAULT_STREAM_RESET_BURST * 2 + 1 ==
|
||||
item->frame.goaway.last_stream_id);
|
||||
}
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_bufs_free(&bufs);
|
||||
nghttp2_option_del(option);
|
||||
}
|
||||
|
||||
static void check_nghttp2_http_recv_headers_fail(
|
||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
||||
|
||||
@@ -168,6 +168,7 @@ void test_nghttp2_session_no_closed_streams(void);
|
||||
void test_nghttp2_session_set_stream_user_data(void);
|
||||
void test_nghttp2_session_no_rfc7540_priorities(void);
|
||||
void test_nghttp2_session_server_fallback_rfc7540_priorities(void);
|
||||
void test_nghttp2_session_stream_reset_ratelim(void);
|
||||
void test_nghttp2_http_mandatory_headers(void);
|
||||
void test_nghttp2_http_content_length(void);
|
||||
void test_nghttp2_http_content_length_mismatch(void);
|
||||
|
||||
@@ -54,8 +54,7 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
payloadoff = ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
|
||||
rv = nghttp2_frame_unpack_headers_payload(&frame->headers,
|
||||
payload + payloadoff);
|
||||
nghttp2_frame_unpack_headers_payload(&frame->headers, payload + payloadoff);
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_unpack_priority_payload(&frame->priority, payload);
|
||||
@@ -68,8 +67,7 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) {
|
||||
&frame->settings.iv, &frame->settings.niv, payload, payloadlen, mem);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
|
||||
payload);
|
||||
nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, payload);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
nghttp2_frame_unpack_ping_payload(&frame->ping, payload);
|
||||
|
||||
54
third-party/llhttp/README.md
vendored
54
third-party/llhttp/README.md
vendored
@@ -287,7 +287,7 @@ 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!**
|
||||
**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled)`
|
||||
|
||||
@@ -300,23 +300,22 @@ conjunction with `Content-Length`.
|
||||
This error is important to prevent HTTP request smuggling, but may be less desirable
|
||||
for small number of cases involving legacy servers.
|
||||
|
||||
**USE AT YOUR OWN RISK!**
|
||||
**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled)`
|
||||
|
||||
Enables/disables lenient handling of `Connection: close` and HTTP/1.0
|
||||
requests responses.
|
||||
|
||||
Normally `llhttp` would error on (in strict mode) or discard (in loose mode)
|
||||
the HTTP request/response after the request/response with `Connection: close`
|
||||
and `Content-Length`.
|
||||
Normally `llhttp` would error the HTTP request/response
|
||||
after the request/response with `Connection: close` and `Content-Length`.
|
||||
|
||||
This is important to prevent cache poisoning attacks,
|
||||
but might interact badly with outdated and insecure clients.
|
||||
|
||||
With this flag the extra request/response will be parsed normally.
|
||||
|
||||
**USE AT YOUR OWN RISK!**
|
||||
**Enabling this flag can pose a security issue since you will be exposed to poisoning attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled)`
|
||||
|
||||
@@ -331,7 +330,48 @@ avoid request smuggling.
|
||||
|
||||
With this flag the extra value will be parsed normally.
|
||||
|
||||
**USE AT YOUR OWN RISK!**
|
||||
**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_version(llhttp_t* parser, int enabled)`
|
||||
|
||||
Enables/disables lenient handling of HTTP version.
|
||||
|
||||
Normally `llhttp` would error when the HTTP version in the request or status line
|
||||
is not `0.9`, `1.0`, `1.1` or `2.0`.
|
||||
With this flag the extra value will be parsed normally.
|
||||
|
||||
**Enabling this flag can pose a security issue since you will allow unsupported HTTP versions. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled)`
|
||||
|
||||
Enables/disables lenient handling of additional data received after a message ends
|
||||
and keep-alive is disabled.
|
||||
|
||||
Normally `llhttp` would error when additional unexpected data is received if the message
|
||||
contains the `Connection` header with `close` value.
|
||||
With this flag the extra data will discarded without throwing an error.
|
||||
|
||||
**Enabling this flag can pose a security issue since you will be exposed to poisoning attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled)`
|
||||
|
||||
Enables/disables lenient handling of incomplete CRLF sequences.
|
||||
|
||||
Normally `llhttp` would error when a CR is not followed by LF when terminating the
|
||||
request line, the status line, the headers or a chunk header.
|
||||
With this flag only a CR is required to terminate such sections.
|
||||
|
||||
**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**
|
||||
|
||||
### `void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled)`
|
||||
|
||||
Enables/disables lenient handling of chunks not separated via CRLF.
|
||||
|
||||
Normally `llhttp` would error when after a chunk data a CRLF is missing before
|
||||
starting a new chunk.
|
||||
With this flag the new chunk can start immediately after the previous one.
|
||||
|
||||
**Enabling this flag can pose a security issue since you will be exposed to request smuggling attacks. USE WITH CAUTION!**
|
||||
|
||||
## Build Instructions
|
||||
|
||||
|
||||
78
third-party/llhttp/include/llhttp.h
vendored
78
third-party/llhttp/include/llhttp.h
vendored
@@ -1,14 +1,11 @@
|
||||
|
||||
#ifndef INCLUDE_LLHTTP_H_
|
||||
#define INCLUDE_LLHTTP_H_
|
||||
|
||||
#define LLHTTP_VERSION_MAJOR 8
|
||||
#define LLHTTP_VERSION_MINOR 1
|
||||
#define LLHTTP_VERSION_MAJOR 9
|
||||
#define LLHTTP_VERSION_MINOR 0
|
||||
#define LLHTTP_VERSION_PATCH 1
|
||||
|
||||
#ifndef LLHTTP_STRICT_MODE
|
||||
# define LLHTTP_STRICT_MODE 0
|
||||
#endif
|
||||
|
||||
#ifndef INCLUDE_LLHTTP_ITSELF_H_
|
||||
#define INCLUDE_LLHTTP_ITSELF_H_
|
||||
#ifdef __cplusplus
|
||||
@@ -50,6 +47,7 @@ int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* e
|
||||
#endif
|
||||
#endif /* INCLUDE_LLHTTP_ITSELF_H_ */
|
||||
|
||||
|
||||
#ifndef LLLLHTTP_C_HEADERS_
|
||||
#define LLLLHTTP_C_HEADERS_
|
||||
#ifdef __cplusplus
|
||||
@@ -114,7 +112,10 @@ enum llhttp_lenient_flags {
|
||||
LENIENT_CHUNKED_LENGTH = 0x2,
|
||||
LENIENT_KEEP_ALIVE = 0x4,
|
||||
LENIENT_TRANSFER_ENCODING = 0x8,
|
||||
LENIENT_VERSION = 0x10
|
||||
LENIENT_VERSION = 0x10,
|
||||
LENIENT_DATA_AFTER_CLOSE = 0x20,
|
||||
LENIENT_OPTIONAL_LF_AFTER_CR = 0x40,
|
||||
LENIENT_OPTIONAL_CRLF_AFTER_CHUNK = 0x80
|
||||
};
|
||||
typedef enum llhttp_lenient_flags llhttp_lenient_flags_t;
|
||||
|
||||
@@ -534,6 +535,7 @@ typedef enum llhttp_status llhttp_status_t;
|
||||
#endif
|
||||
#endif /* LLLLHTTP_C_HEADERS_ */
|
||||
|
||||
|
||||
#ifndef INCLUDE_LLHTTP_API_H_
|
||||
#define INCLUDE_LLHTTP_API_H_
|
||||
#ifdef __cplusplus
|
||||
@@ -759,7 +761,8 @@ const char* llhttp_status_name(llhttp_status_t status);
|
||||
* `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when
|
||||
* lenient parsing is "on".
|
||||
*
|
||||
* **(USE AT YOUR OWN RISK)**
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* request smuggling attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
|
||||
@@ -773,7 +776,8 @@ void llhttp_set_lenient_headers(llhttp_t* parser, int enabled);
|
||||
* request smuggling, but may be less desirable for small number of cases
|
||||
* involving legacy servers.
|
||||
*
|
||||
* **(USE AT YOUR OWN RISK)**
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* request smuggling attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
|
||||
@@ -788,7 +792,8 @@ void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled);
|
||||
* but might interact badly with outdated and insecure clients. With this flag
|
||||
* the extra request/response will be parsed normally.
|
||||
*
|
||||
* **(USE AT YOUR OWN RISK)**
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* poisoning attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
|
||||
@@ -802,14 +807,65 @@ void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled);
|
||||
* avoid request smuggling.
|
||||
* With this flag the extra value will be parsed normally.
|
||||
*
|
||||
* **(USE AT YOUR OWN RISK)**
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* request smuggling attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled);
|
||||
|
||||
/* Enables/disables lenient handling of HTTP version.
|
||||
*
|
||||
* Normally `llhttp` would error when the HTTP version in the request or status line
|
||||
* is not `0.9`, `1.0`, `1.1` or `2.0`.
|
||||
* With this flag the invalid value will be parsed normally.
|
||||
*
|
||||
* **Enabling this flag can pose a security issue since you will allow unsupported
|
||||
* HTTP versions. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_version(llhttp_t* parser, int enabled);
|
||||
|
||||
/* Enables/disables lenient handling of additional data received after a message ends
|
||||
* and keep-alive is disabled.
|
||||
*
|
||||
* Normally `llhttp` would error when additional unexpected data is received if the message
|
||||
* contains the `Connection` header with `close` value.
|
||||
* With this flag the extra data will discarded without throwing an error.
|
||||
*
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* poisoning attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled);
|
||||
|
||||
/* Enables/disables lenient handling of incomplete CRLF sequences.
|
||||
*
|
||||
* Normally `llhttp` would error when a CR is not followed by LF when terminating the
|
||||
* request line, the status line, the headers or a chunk header.
|
||||
* With this flag only a CR is required to terminate such sections.
|
||||
*
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* request smuggling attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled);
|
||||
|
||||
/* Enables/disables lenient handling of chunks not separated via CRLF.
|
||||
*
|
||||
* Normally `llhttp` would error when after a chunk data a CRLF is missing before
|
||||
* starting a new chunk.
|
||||
* With this flag the new chunk can start immediately after the previous one.
|
||||
*
|
||||
* **Enabling this flag can pose a security issue since you will be exposed to
|
||||
* request smuggling attacks. USE WITH CAUTION!**
|
||||
*/
|
||||
LLHTTP_EXPORT
|
||||
void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
#endif /* INCLUDE_LLHTTP_API_H_ */
|
||||
|
||||
|
||||
#endif /* INCLUDE_LLHTTP_H_ */
|
||||
|
||||
32
third-party/llhttp/src/api.c
vendored
32
third-party/llhttp/src/api.c
vendored
@@ -283,6 +283,38 @@ void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) {
|
||||
}
|
||||
}
|
||||
|
||||
void llhttp_set_lenient_version(llhttp_t* parser, int enabled) {
|
||||
if (enabled) {
|
||||
parser->lenient_flags |= LENIENT_VERSION;
|
||||
} else {
|
||||
parser->lenient_flags &= ~LENIENT_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled) {
|
||||
if (enabled) {
|
||||
parser->lenient_flags |= LENIENT_DATA_AFTER_CLOSE;
|
||||
} else {
|
||||
parser->lenient_flags &= ~LENIENT_DATA_AFTER_CLOSE;
|
||||
}
|
||||
}
|
||||
|
||||
void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled) {
|
||||
if (enabled) {
|
||||
parser->lenient_flags |= LENIENT_OPTIONAL_LF_AFTER_CR;
|
||||
} else {
|
||||
parser->lenient_flags &= ~LENIENT_OPTIONAL_LF_AFTER_CR;
|
||||
}
|
||||
}
|
||||
|
||||
void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled) {
|
||||
if (enabled) {
|
||||
parser->lenient_flags |= LENIENT_OPTIONAL_CRLF_AFTER_CHUNK;
|
||||
} else {
|
||||
parser->lenient_flags &= ~LENIENT_OPTIONAL_CRLF_AFTER_CHUNK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Callbacks */
|
||||
|
||||
|
||||
|
||||
9865
third-party/llhttp/src/llhttp.c
vendored
9865
third-party/llhttp/src/llhttp.c
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user