mirror of
https://gitee.com/openharmony/third_party_nghttp2
synced 2024-11-26 17:40:25 +00:00
!78 Nghttp2 upgrade to version 1.58.0
Merge pull request !78 from Aurora/240407_nghttp2
This commit is contained in:
commit
ecd80a7274
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"
|
22
.github/workflows/build.yml
vendored
22
.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: v1.0.0
|
||||
NGTCP2_VERSION: v1.0.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
|
||||
@ -467,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
|
||||
|
1
AUTHORS
1
AUTHORS
@ -17,6 +17,7 @@ github issues [2].
|
||||
Adam Gołębiowski
|
||||
Alek Storm
|
||||
Alex Nalivko
|
||||
Alexandr Vlasov
|
||||
Alexandros Konstantinakis-Karmis
|
||||
Alexis La Goutte
|
||||
Amir Livneh
|
||||
|
@ -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.58.0)
|
||||
|
||||
# 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 1)
|
||||
set(LT_AGE 25)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
include(Version)
|
||||
@ -273,6 +273,7 @@ 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)
|
||||
@ -342,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)
|
||||
@ -505,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
|
||||
|
@ -3,7 +3,7 @@
|
||||
"Name" : "nghttp2",
|
||||
"License" : "The MIT License",
|
||||
"License File" : "COPYING",
|
||||
"Version Number" : "1.55.0",
|
||||
"Version Number" : "1.58.0",
|
||||
"Owner" : "zhuwenchao@huawei.com",
|
||||
"Upstream URL" : "https://nghttp2.org",
|
||||
"Description" : "nghttp2 is an implementation of HTTP/2 and its header compression algorithm HPACK in C."
|
||||
|
26
README.rst
26
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>`_ >= 1.0.0
|
||||
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 1.0.0
|
||||
|
||||
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 v1.0.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 v1.0.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 ..
|
||||
@ -1456,12 +1456,10 @@ released, or mitigation is worked out.
|
||||
|
||||
In the future, we may setup a dedicated mail address for this purpose.
|
||||
|
||||
Release schedule
|
||||
----------------
|
||||
Versioning
|
||||
----------
|
||||
|
||||
In general, we follow `Semantic Versioning <http://semver.org/>`_. We
|
||||
release MINOR version update every month, and usually we ship it
|
||||
around 25th day of every month.
|
||||
In general, we follow `Semantic Versioning <http://semver.org/>`_.
|
||||
|
||||
We may release PATCH releases between the regular releases, mainly for
|
||||
severe security bug fixes.
|
||||
|
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()
|
@ -67,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
|
||||
|
||||
|
17
configure.ac
17
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], [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, 1)
|
||||
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"`
|
||||
@ -233,7 +233,7 @@ fi
|
||||
save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS=
|
||||
|
||||
AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
|
||||
AX_CXX_COMPILE_STDCXX([14], [], [optional])
|
||||
|
||||
CXX1XCXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$save_CXXFLAGS"
|
||||
@ -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 >= 1.0.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 >= 1.0.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 >= 1.0.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 \
|
||||
|
@ -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 27, 2023" "1.58.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 27, 2023" "1.58.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 27, 2023" "1.58.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 27, 2023" "1.58.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
|
||||
@ -1832,8 +1834,8 @@ NEW_TOKEN frame in the previous connection.
|
||||
.TP
|
||||
.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.
|
||||
QUIC connection. <CC> should be either \(dqcubic\(dq or
|
||||
\(dqbbr\(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>
|
||||
@ -1673,8 +1675,8 @@ HTTP/3 and QUIC
|
||||
.. option:: --frontend-quic-congestion-controller=<CC>
|
||||
|
||||
Specify a congestion controller algorithm for a frontend
|
||||
QUIC connection. <CC> should be one of "cubic", "bbr",
|
||||
and "bbr2".
|
||||
QUIC connection. <CC> should be either "cubic" or
|
||||
"bbr".
|
||||
|
||||
Default: ``cubic``
|
||||
|
||||
|
@ -20,19 +20,14 @@ privately. We also discuss the disclosure date to the public.
|
||||
We make a new release with the fix at the same time when the
|
||||
vulnerability is disclosed to public.
|
||||
|
||||
At least 7 days before the public disclosure date, we will post
|
||||
security advisory (which includes all the details of the vulnerability
|
||||
and the possible mitigation strategies) and the patches to fix the
|
||||
issue to `distros@openwall
|
||||
<https://oss-security.openwall.org/wiki/mailing-lists/distros>`_
|
||||
mailing list. We also open a new issue on `nghttp2 issue tracker
|
||||
At least 7 days before the public disclosure date, we open a new issue
|
||||
on `nghttp2 issue tracker
|
||||
<https://github.com/nghttp2/nghttp2/issues>`_ which notifies that the
|
||||
upcoming release will have a security fix. The ``SECURITY`` label is
|
||||
attached to this kind of issue.
|
||||
attached to this kind of issue. The issue is not opened if a
|
||||
vulnerability is already disclosed, and it is publicly known that
|
||||
nghttp2 is affected by that.
|
||||
|
||||
Before few hours of new release, we merge the fixes to the master
|
||||
branch (and/or a release branch if necessary) and make a new release.
|
||||
Security advisory is disclosed on GitHub. We also post the
|
||||
vulnerability information to `oss-security
|
||||
<https://oss-security.openwall.org/wiki/mailing-lists/oss-security>`_
|
||||
mailing list.
|
||||
Security advisory is disclosed on GitHub.
|
||||
|
@ -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 v1.0.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 v1.0.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=
|
||||
|
@ -2,6 +2,7 @@ set(GO_FILES
|
||||
nghttpx_http1_test.go
|
||||
nghttpx_http2_test.go
|
||||
server_tester.go
|
||||
server_tester_http3.go
|
||||
)
|
||||
|
||||
# XXX unused
|
||||
@ -40,7 +41,11 @@ if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(ENABLE_HTTP3)
|
||||
set(GO_TEST_TAGS quic)
|
||||
endif()
|
||||
|
||||
add_custom_target(it
|
||||
COMMAND sh setenv go test -v
|
||||
COMMAND sh setenv go test -v --tags=${GO_TEST_TAGS}
|
||||
DEPENDS ${GO_BUILD_FILES}
|
||||
)
|
||||
|
@ -25,7 +25,8 @@ GO_FILES = \
|
||||
nghttpx_http1_test.go \
|
||||
nghttpx_http2_test.go \
|
||||
nghttpx_http3_test.go \
|
||||
server_tester.go
|
||||
server_tester.go \
|
||||
server_tester_http3.go
|
||||
|
||||
EXTRA_DIST = \
|
||||
CMakeLists.txt \
|
||||
|
@ -1490,3 +1490,142 @@ func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
|
||||
t.Fatal("st.http1() should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestH1H1RequestMalformedTransferEncoding tests that server rejects
|
||||
// request which contains malformed transfer-encoding.
|
||||
func TestH1H1RequestMalformedTransferEncoding(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Errorf("server should not forward bad request")
|
||||
},
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
if _, err := io.WriteString(st.conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %v\r\nTest-Case: TestH1H1RequestMalformedTransferEncoding\r\nTransfer-Encoding: ,chunked\r\n\r\n",
|
||||
st.authority)); err != nil {
|
||||
t.Fatalf("Error io.WriteString() = %v", err)
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH1H1ResponseMalformedTransferEncoding tests a request fails if
|
||||
// its response contains malformed transfer-encoding.
|
||||
func TestH1H1ResponseMalformedTransferEncoding(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
conn, bufrw, err := hj.Hijack()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
if _, err := bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: ,chunked\r\n\r\n"); err != nil {
|
||||
t.Fatalf("Error bufrw.WriteString() = %v", err)
|
||||
}
|
||||
bufrw.Flush()
|
||||
},
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
res, err := st.http1(requestParam{
|
||||
name: "TestH1H1ResponseMalformedTransferEncoding",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Error st.http1() = %v", err)
|
||||
}
|
||||
if got, want := res.status, http.StatusBadGateway; got != want {
|
||||
t.Errorf("res.status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH1H1ResponseUnknownTransferEncoding tests a request succeeds if
|
||||
// its response contains unknown transfer-encoding.
|
||||
func TestH1H1ResponseUnknownTransferEncoding(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
hj, ok := w.(http.Hijacker)
|
||||
if !ok {
|
||||
http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
conn, bufrw, err := hj.Hijack()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
if _, err := bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: foo\r\n\r\n"); err != nil {
|
||||
t.Fatalf("Error bufrw.WriteString() = %v", err)
|
||||
}
|
||||
bufrw.Flush()
|
||||
},
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
if _, err := io.WriteString(st.conn, fmt.Sprintf("GET / HTTP/1.1\r\nHost: %v\r\nTest-Case: TestH1H1ResponseUnknownTransferEncoding\r\n\r\n",
|
||||
st.authority)); err != nil {
|
||||
t.Fatalf("Error: io.WriteString() = %v", err)
|
||||
}
|
||||
|
||||
r := bufio.NewReader(st.conn)
|
||||
|
||||
resp := make([]byte, 4096)
|
||||
|
||||
resplen, err := r.Read(resp)
|
||||
if err != nil {
|
||||
t.Fatalf("Error: r.Read() = %v", err)
|
||||
}
|
||||
|
||||
resp = resp[:resplen]
|
||||
|
||||
const expect = "HTTP/1.1 200 OK\r\nTransfer-Encoding: foo\r\nConnection: close\r\nServer: nghttpx\r\nVia: 1.1 nghttpx\r\n\r\n"
|
||||
|
||||
if got, want := string(resp), expect; got != want {
|
||||
t.Errorf("resp = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestH1H1RequestHTTP10TransferEncoding tests that server rejects
|
||||
// HTTP/1.0 request which contains transfer-encoding.
|
||||
func TestH1H1RequestHTTP10TransferEncoding(t *testing.T) {
|
||||
opts := options{
|
||||
handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
t.Errorf("server should not forward bad request")
|
||||
},
|
||||
}
|
||||
st := newServerTester(t, opts)
|
||||
defer st.Close()
|
||||
|
||||
if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1RequestHTTP10TransferEncoding\r\nTransfer-Encoding: chunked\r\n\r\n"); err != nil {
|
||||
t.Fatalf("Error io.WriteString() = %v", err)
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Error http.ReadResponse() = %v", err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if got, want := resp.StatusCode, http.StatusBadRequest; got != want {
|
||||
t.Errorf("status: %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"github.com/tatsuhiro-t/go-nghttp2"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
@ -390,81 +389,6 @@ func (st *serverTester) websocket(rp requestParam) *serverResponse {
|
||||
return res
|
||||
}
|
||||
|
||||
func (st *serverTester) http3(rp requestParam) (*serverResponse, error) {
|
||||
rt := &http3.RoundTripper{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
|
||||
defer rt.Close()
|
||||
|
||||
c := &http.Client{
|
||||
Transport: rt,
|
||||
}
|
||||
|
||||
method := "GET"
|
||||
if rp.method != "" {
|
||||
method = rp.method
|
||||
}
|
||||
|
||||
var body io.Reader
|
||||
|
||||
if rp.body != nil {
|
||||
body = bytes.NewBuffer(rp.body)
|
||||
}
|
||||
|
||||
reqURL := st.url
|
||||
|
||||
if rp.path != "" {
|
||||
u, err := url.Parse(st.url)
|
||||
if err != nil {
|
||||
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
|
||||
}
|
||||
u.Path = ""
|
||||
u.RawQuery = ""
|
||||
reqURL = u.String() + rp.path
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, reqURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, h := range rp.header {
|
||||
req.Header.Add(h.Name, h.Value)
|
||||
}
|
||||
|
||||
req.Header.Add("Test-Case", rp.name)
|
||||
|
||||
// TODO http3 package does not support trailer at the time of
|
||||
// this writing.
|
||||
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &serverResponse{
|
||||
status: resp.StatusCode,
|
||||
header: resp.Header,
|
||||
body: respBody,
|
||||
connClose: resp.Close,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (st *serverTester) http1(rp requestParam) (*serverResponse, error) {
|
||||
method := "GET"
|
||||
if rp.method != "" {
|
||||
|
90
integration-tests/server_tester_http3.go
Normal file
90
integration-tests/server_tester_http3.go
Normal file
@ -0,0 +1,90 @@
|
||||
//go:build quic
|
||||
|
||||
package nghttp2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
)
|
||||
|
||||
func (st *serverTester) http3(rp requestParam) (*serverResponse, error) {
|
||||
rt := &http3.RoundTripper{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
}
|
||||
|
||||
defer rt.Close()
|
||||
|
||||
c := &http.Client{
|
||||
Transport: rt,
|
||||
}
|
||||
|
||||
method := "GET"
|
||||
if rp.method != "" {
|
||||
method = rp.method
|
||||
}
|
||||
|
||||
var body io.Reader
|
||||
|
||||
if rp.body != nil {
|
||||
body = bytes.NewBuffer(rp.body)
|
||||
}
|
||||
|
||||
reqURL := st.url
|
||||
|
||||
if rp.path != "" {
|
||||
u, err := url.Parse(st.url)
|
||||
if err != nil {
|
||||
st.t.Fatalf("Error parsing URL from st.url %v: %v", st.url, err)
|
||||
}
|
||||
u.Path = ""
|
||||
u.RawQuery = ""
|
||||
reqURL = u.String() + rp.path
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, method, reqURL, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, h := range rp.header {
|
||||
req.Header.Add(h.Name, h.Value)
|
||||
}
|
||||
|
||||
req.Header.Add("Test-Case", rp.name)
|
||||
|
||||
// TODO http3 package does not support trailer at the time of
|
||||
// this writing.
|
||||
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := &serverResponse{
|
||||
status: resp.StatusCode,
|
||||
header: resp.Header,
|
||||
body: respBody,
|
||||
connClose: resp.Close,
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
@ -29,7 +29,7 @@
|
||||
* @macro
|
||||
* Version number of the nghttp2 library release
|
||||
*/
|
||||
#define NGHTTP2_VERSION "1.55.0"
|
||||
#define NGHTTP2_VERSION "1.58.0"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
@ -37,6 +37,6 @@
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define NGHTTP2_VERSION_NUM 0x013700
|
||||
#define NGHTTP2_VERSION_NUM 0x013A00
|
||||
|
||||
#endif /* NGHTTP2VER_H */
|
||||
|
@ -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 */
|
||||
|
@ -126,6 +126,7 @@ static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
|
||||
bkt->data = data;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
void nghttp2_map_print_distance(nghttp2_map *map) {
|
||||
uint32_t i;
|
||||
size_t idx;
|
||||
@ -145,6 +146,7 @@ void nghttp2_map_print_distance(nghttp2_map *map) {
|
||||
distance(map->tablelen, map->tablelenbits, bkt, idx));
|
||||
}
|
||||
}
|
||||
#endif /* !WIN32 */
|
||||
|
||||
static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
|
||||
uint32_t tablelenbits, uint32_t hash,
|
||||
|
@ -131,6 +131,8 @@ size_t nghttp2_map_size(nghttp2_map *map);
|
||||
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
#ifndef WIN32
|
||||
void nghttp2_map_print_distance(nghttp2_map *map);
|
||||
#endif /* !WIN32 */
|
||||
|
||||
#endif /* NGHTTP2_MAP_H */
|
||||
|
@ -948,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);
|
||||
@ -962,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,
|
||||
@ -983,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,
|
||||
@ -1487,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
|
||||
@ -2232,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;
|
||||
@ -2257,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;
|
||||
|
||||
@ -2344,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;
|
||||
@ -2365,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);
|
||||
@ -2384,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);
|
||||
@ -2410,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;
|
||||
}
|
||||
@ -2918,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
|
||||
@ -3154,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;
|
||||
@ -3187,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 */
|
||||
@ -3207,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. */
|
||||
@ -3219,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,
|
||||
@ -3307,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));
|
||||
@ -3349,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. */
|
||||
@ -3465,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) {
|
||||
@ -3473,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;
|
||||
@ -3517,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);
|
||||
@ -3545,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 */
|
||||
|
||||
@ -4435,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;
|
||||
@ -5126,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);
|
||||
}
|
||||
@ -7840,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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
129
src/http2.cc
129
src/http2.cc
@ -1044,12 +1044,39 @@ InputIt skip_to_right_dquote(InputIt first, InputIt last) {
|
||||
switch (*first) {
|
||||
case '"':
|
||||
return first;
|
||||
// quoted-pair
|
||||
case '\\':
|
||||
++first;
|
||||
if (first == last) {
|
||||
return first;
|
||||
}
|
||||
|
||||
switch (*first) {
|
||||
case '\t':
|
||||
case ' ':
|
||||
break;
|
||||
default:
|
||||
if ((0x21 <= *first && *first <= 0x7e) /* VCHAR */ ||
|
||||
(0x80 <= *first && *first <= 0xff) /* obs-text */) {
|
||||
break;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
break;
|
||||
// qdtext
|
||||
case '\t':
|
||||
case ' ':
|
||||
case '!':
|
||||
break;
|
||||
default:
|
||||
if ((0x23 <= *first && *first <= 0x5b) ||
|
||||
(0x5d <= *first && *first <= 0x7e)) {
|
||||
break;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
++first;
|
||||
}
|
||||
@ -1957,6 +1984,108 @@ bool legacy_http1(int major, int minor) {
|
||||
return major <= 0 || (major == 1 && minor == 0);
|
||||
}
|
||||
|
||||
bool check_transfer_encoding(const StringRef &s) {
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = std::begin(s);
|
||||
|
||||
for (;;) {
|
||||
// token
|
||||
if (!util::in_token(*it)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
|
||||
for (; it != std::end(s) && util::in_token(*it); ++it)
|
||||
;
|
||||
|
||||
if (it == std::end(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// OWS
|
||||
it = skip_lws(it, std::end(s));
|
||||
if (it == std::end(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*it == ',') {
|
||||
++it;
|
||||
|
||||
it = skip_lws(it, std::end(s));
|
||||
if (it == std::end(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it != ';') {
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
|
||||
// transfer-parameter follows
|
||||
|
||||
// OWS
|
||||
it = skip_lws(it, std::end(s));
|
||||
if (it == std::end(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// token
|
||||
if (!util::in_token(*it)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
|
||||
for (; it != std::end(s) && util::in_token(*it); ++it)
|
||||
;
|
||||
|
||||
if (it == std::end(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// No BWS allowed
|
||||
if (*it != '=') {
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
|
||||
if (util::in_token(*it)) {
|
||||
// token
|
||||
++it;
|
||||
|
||||
for (; it != std::end(s) && util::in_token(*it); ++it)
|
||||
;
|
||||
} else if (*it == '"') {
|
||||
// quoted-string
|
||||
++it;
|
||||
|
||||
it = skip_to_right_dquote(it, std::end(s));
|
||||
if (it == std::end(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (it == std::end(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
@ -444,6 +444,11 @@ StringRef make_websocket_accept_token(uint8_t *dest, const StringRef &key);
|
||||
// HTTP/0.9 or HTTP/1.0).
|
||||
bool legacy_http1(int major, int minor);
|
||||
|
||||
// Returns true if transfer-encoding field value |s| conforms RFC
|
||||
// strictly. This function does not allow empty value, BWS, and empty
|
||||
// list elements.
|
||||
bool check_transfer_encoding(const StringRef &s);
|
||||
|
||||
} // namespace http2
|
||||
|
||||
} // namespace nghttp2
|
||||
|
@ -1189,4 +1189,61 @@ void test_http2_contains_trailers(void) {
|
||||
CU_ASSERT(http2::contains_trailers(StringRef::from_lit(",trailers")));
|
||||
}
|
||||
|
||||
void test_http2_check_transfer_encoding(void) {
|
||||
CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("chunked")));
|
||||
CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("foo,chunked")));
|
||||
CU_ASSERT(
|
||||
http2::check_transfer_encoding(StringRef::from_lit("foo, chunked")));
|
||||
CU_ASSERT(
|
||||
http2::check_transfer_encoding(StringRef::from_lit("foo , chunked")));
|
||||
CU_ASSERT(
|
||||
http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar")));
|
||||
CU_ASSERT(
|
||||
http2::check_transfer_encoding(StringRef::from_lit("chunked ; foo=bar")));
|
||||
CU_ASSERT(http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="bar")")));
|
||||
CU_ASSERT(http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="\bar\"";FOO=BAR)")));
|
||||
CU_ASSERT(
|
||||
http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="")")));
|
||||
CU_ASSERT(http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="bar" , gzip)")));
|
||||
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef{}));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(",chunked")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked,")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked, ")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit("foo,,chunked")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit("chunked;foo")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar;")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit("chunked;?=bar")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit("chunked;=bar")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;;")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked?")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(",")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(" ")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(";")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("\"")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="bar)")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="bar\)")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="bar\)"
|
||||
"\x0a"
|
||||
R"(")")));
|
||||
CU_ASSERT(
|
||||
!http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo=")"
|
||||
"\x0a"
|
||||
R"(")")));
|
||||
CU_ASSERT(!http2::check_transfer_encoding(
|
||||
StringRef::from_lit(R"(chunked;foo="bar",,gzip)")));
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -47,6 +47,7 @@ void test_http2_rewrite_clean_path(void);
|
||||
void test_http2_get_pure_path_component(void);
|
||||
void test_http2_construct_push_component(void);
|
||||
void test_http2_contains_trailers(void);
|
||||
void test_http2_check_transfer_encoding(void);
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
|
@ -109,6 +109,8 @@ int main(int argc, char *argv[]) {
|
||||
shrpx::test_http2_construct_push_component) ||
|
||||
!CU_add_test(pSuite, "http2_contains_trailers",
|
||||
shrpx::test_http2_contains_trailers) ||
|
||||
!CU_add_test(pSuite, "http2_check_transfer_encoding",
|
||||
shrpx::test_http2_check_transfer_encoding) ||
|
||||
!CU_add_test(pSuite, "downstream_field_store_append_last_header",
|
||||
shrpx::test_downstream_field_store_append_last_header) ||
|
||||
!CU_add_test(pSuite, "downstream_field_store_header",
|
||||
|
29
src/shrpx.cc
29
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
|
||||
@ -3520,15 +3522,12 @@ HTTP/3 and QUIC:
|
||||
NEW_TOKEN frame in the previous connection.
|
||||
--frontend-quic-congestion-controller=<CC>
|
||||
Specify a congestion controller algorithm for a frontend
|
||||
QUIC connection. <CC> should be one of "cubic", "bbr",
|
||||
and "bbr2".
|
||||
QUIC connection. <CC> should be either "cubic" or
|
||||
"bbr".
|
||||
Default: )"
|
||||
<< (config->quic.upstream.congestion_controller == NGTCP2_CC_ALGO_CUBIC
|
||||
? "cubic"
|
||||
: (config->quic.upstream.congestion_controller ==
|
||||
NGTCP2_CC_ALGO_BBR
|
||||
? "bbr"
|
||||
: "bbr2"))
|
||||
: "bbr")
|
||||
<< R"(
|
||||
--frontend-quic-secret-file=<PATH>
|
||||
Path to file that contains secure random data to be used
|
||||
|
@ -4116,10 +4116,8 @@ 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 {
|
||||
LOG(ERROR) << opt << ": must be one of cubic, bbr, and bbr2";
|
||||
LOG(ERROR) << opt << ": must be either cubic or bbr";
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -864,9 +864,6 @@ void Downstream::inspect_http1_request() {
|
||||
auto transfer_encoding = req_.fs.header(http2::HD_TRANSFER_ENCODING);
|
||||
if (transfer_encoding) {
|
||||
req_.fs.content_length = -1;
|
||||
if (util::iends_with_l(transfer_encoding->value, "chunked")) {
|
||||
chunked_request_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto expect = req_.fs.header(http2::HD_EXPECT);
|
||||
@ -879,9 +876,6 @@ void Downstream::inspect_http1_response() {
|
||||
auto transfer_encoding = resp_.fs.header(http2::HD_TRANSFER_ENCODING);
|
||||
if (transfer_encoding) {
|
||||
resp_.fs.content_length = -1;
|
||||
if (util::iends_with_l(transfer_encoding->value, "chunked")) {
|
||||
chunked_response_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -929,6 +929,11 @@ int htp_hdrs_completecb(llhttp_t *htp) {
|
||||
|
||||
for (auto &kv : resp.fs.headers()) {
|
||||
kv.value = util::rstrip(balloc, kv.value);
|
||||
|
||||
if (kv.token == http2::HD_TRANSFER_ENCODING &&
|
||||
!http2::check_transfer_encoding(kv.value)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto config = get_config();
|
||||
@ -1004,6 +1009,16 @@ int htp_hdrs_completecb(llhttp_t *htp) {
|
||||
resp.connection_close = !llhttp_should_keep_alive(htp);
|
||||
downstream->set_response_state(DownstreamState::HEADER_COMPLETE);
|
||||
downstream->inspect_http1_response();
|
||||
|
||||
if (htp->flags & F_CHUNKED) {
|
||||
downstream->set_chunked_response(true);
|
||||
}
|
||||
|
||||
auto transfer_encoding = resp.fs.header(http2::HD_TRANSFER_ENCODING);
|
||||
if (transfer_encoding && !downstream->get_chunked_response()) {
|
||||
resp.connection_close = true;
|
||||
}
|
||||
|
||||
if (downstream->get_upgraded()) {
|
||||
// content-length must be ignored for upgraded connection.
|
||||
resp.fs.content_length = -1;
|
||||
|
@ -345,6 +345,11 @@ int htp_hdrs_completecb(llhttp_t *htp) {
|
||||
|
||||
for (auto &kv : req.fs.headers()) {
|
||||
kv.value = util::rstrip(balloc, kv.value);
|
||||
|
||||
if (kv.token == http2::HD_TRANSFER_ENCODING &&
|
||||
!http2::check_transfer_encoding(kv.value)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto lgconf = log_config();
|
||||
@ -414,6 +419,16 @@ int htp_hdrs_completecb(llhttp_t *htp) {
|
||||
|
||||
downstream->inspect_http1_request();
|
||||
|
||||
if (htp->flags & F_CHUNKED) {
|
||||
downstream->set_chunked_request(true);
|
||||
}
|
||||
|
||||
auto transfer_encoding = req.fs.header(http2::HD_TRANSFER_ENCODING);
|
||||
if (transfer_encoding &&
|
||||
http2::legacy_http1(req.http_major, req.http_minor)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto faddr = handler->get_upstream_addr();
|
||||
auto config = get_config();
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
121
src/util.cc
121
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>
|
||||
@ -102,17 +105,34 @@ int nghttp2_inet_pton(int af, const char *src, void *dst) {
|
||||
const char UPPER_XDIGITS[] = "0123456789ABCDEF";
|
||||
|
||||
bool in_rfc3986_unreserved_chars(const char c) {
|
||||
static constexpr char unreserved[] = {'-', '.', '_', '~'};
|
||||
return is_alpha(c) || is_digit(c) ||
|
||||
std::find(std::begin(unreserved), std::end(unreserved), c) !=
|
||||
std::end(unreserved);
|
||||
switch (c) {
|
||||
case '-':
|
||||
case '.':
|
||||
case '_':
|
||||
case '~':
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_alpha(c) || is_digit(c);
|
||||
}
|
||||
|
||||
bool in_rfc3986_sub_delims(const char c) {
|
||||
static constexpr char sub_delims[] = {'!', '$', '&', '\'', '(', ')',
|
||||
'*', '+', ',', ';', '='};
|
||||
return std::find(std::begin(sub_delims), std::end(sub_delims), c) !=
|
||||
std::end(sub_delims);
|
||||
switch (c) {
|
||||
case '!':
|
||||
case '$':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case '+':
|
||||
case ',':
|
||||
case ';':
|
||||
case '=':
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string percent_encode(const unsigned char *target, size_t len) {
|
||||
@ -137,16 +157,37 @@ std::string percent_encode(const std::string &target) {
|
||||
}
|
||||
|
||||
bool in_token(char c) {
|
||||
static constexpr char extra[] = {'!', '#', '$', '%', '&', '\'', '*', '+',
|
||||
'-', '.', '^', '_', '`', '|', '~'};
|
||||
return is_alpha(c) || is_digit(c) ||
|
||||
std::find(std::begin(extra), std::end(extra), c) != std::end(extra);
|
||||
switch (c) {
|
||||
case '!':
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '*':
|
||||
case '+':
|
||||
case '-':
|
||||
case '.':
|
||||
case '^':
|
||||
case '_':
|
||||
case '`':
|
||||
case '|':
|
||||
case '~':
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_alpha(c) || is_digit(c);
|
||||
}
|
||||
|
||||
bool in_attr_char(char c) {
|
||||
static constexpr char bad[] = {'*', '\'', '%'};
|
||||
return util::in_token(c) &&
|
||||
std::find(std::begin(bad), std::end(bad), c) == std::end(bad);
|
||||
switch (c) {
|
||||
case '*':
|
||||
case '\'':
|
||||
case '%':
|
||||
return false;
|
||||
}
|
||||
|
||||
return util::in_token(c);
|
||||
}
|
||||
|
||||
StringRef percent_encode_token(BlockAllocator &balloc,
|
||||
@ -1680,11 +1721,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 +1736,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 +1752,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 +1772,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 +1801,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
|
||||
|
@ -81,6 +81,7 @@ AM_CFLAGS = $(WARNCFLAGS) \
|
||||
-I${top_srcdir}/lib/includes \
|
||||
-I${top_builddir}/lib/includes \
|
||||
-DBUILDING_NGHTTP2 \
|
||||
-DNGHTTP2_STATICLIB \
|
||||
@CUNIT_CFLAGS@ @DEFS@
|
||||
|
||||
TESTS = main
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
2
third-party/neverbleed
vendored
2
third-party/neverbleed
vendored
@ -1 +1 @@
|
||||
Subproject commit ab9ac5ecb30188683cf29b45c0e66ca2c94394f9
|
||||
Subproject commit 4cf9b993b2cb3d5fbf1a34b86119f298edd00f1d
|
Loading…
Reference in New Issue
Block a user