mirror of
https://github.com/nghttp2/nghttp2.git
synced 2026-03-29 09:19:18 +08:00
Compare commits
385 Commits
quic
...
254f2b3c42
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
254f2b3c42 | ||
|
|
633691e164 | ||
|
|
01bcc72f66 | ||
|
|
7ca255ff54 | ||
|
|
6430c98e86 | ||
|
|
32c2557bb7 | ||
|
|
3122a83900 | ||
|
|
75272a817e | ||
|
|
809d5af43e | ||
|
|
3b549caf90 | ||
|
|
42b659354d | ||
|
|
2275327794 | ||
|
|
02a5649343 | ||
|
|
3b0b9a458c | ||
|
|
6e6388e7c2 | ||
|
|
ea6f0c641d | ||
|
|
c883b18f2d | ||
|
|
97e69f7416 | ||
|
|
ad0c9eebf7 | ||
|
|
8a552631b4 | ||
|
|
cff8106908 | ||
|
|
4eb49ac28e | ||
|
|
deb390cf85 | ||
|
|
d91ae6987d | ||
|
|
8ddb2273b9 | ||
|
|
e1446fd57a | ||
|
|
02e6cad121 | ||
|
|
0b053e06d8 | ||
|
|
c3c0403dfa | ||
|
|
abc15c696d | ||
|
|
344d300cf9 | ||
|
|
dec233b9ef | ||
|
|
f695dc999b | ||
|
|
f92f81c05a | ||
|
|
3c4449c046 | ||
|
|
918e4ea46b | ||
|
|
d14d97ab68 | ||
|
|
2aed077761 | ||
|
|
68b2295f4e | ||
|
|
528d177847 | ||
|
|
deae6c95b1 | ||
|
|
7eb179069d | ||
|
|
47c33b8d03 | ||
|
|
94372fbe2a | ||
|
|
9e154297ff | ||
|
|
c4828dbd7c | ||
|
|
0d16db2c65 | ||
|
|
fb63ef305d | ||
|
|
089fc81d72 | ||
|
|
c20d175ff2 | ||
|
|
3985957c4d | ||
|
|
845a20b582 | ||
|
|
7af0c508be | ||
|
|
f8474b25f0 | ||
|
|
15a8d913ea | ||
|
|
65d3c9047f | ||
|
|
8c36971ea9 | ||
|
|
ba1dff187b | ||
|
|
8ecacc8ed2 | ||
|
|
9d41896663 | ||
|
|
18d4a9e4ff | ||
|
|
1745a30644 | ||
|
|
0cc7c598ff | ||
|
|
8c4fbb86d8 | ||
|
|
693431312c | ||
|
|
f3fca2a19a | ||
|
|
1ce9efc644 | ||
|
|
7055501efd | ||
|
|
c790ee64a4 | ||
|
|
9fb05d5ea2 | ||
|
|
3742acaf39 | ||
|
|
d8282de229 | ||
|
|
3a721a9dd5 | ||
|
|
0b6092446b | ||
|
|
59a76c6d39 | ||
|
|
fa7a916ef3 | ||
|
|
69c4187100 | ||
|
|
07128719c4 | ||
|
|
7471fa627d | ||
|
|
d7af5924ff | ||
|
|
a48e9d3d80 | ||
|
|
474a6db00c | ||
|
|
cb6aea9aa9 | ||
|
|
f4290c6497 | ||
|
|
086b85b8f9 | ||
|
|
abee658a60 | ||
|
|
87bdc21667 | ||
|
|
3e25ee8181 | ||
|
|
0266c458a3 | ||
|
|
d9c7631dcb | ||
|
|
df064fa2ba | ||
|
|
318e0c8447 | ||
|
|
17d5503bf2 | ||
|
|
19b4da6401 | ||
|
|
886dc93f18 | ||
|
|
407df2822e | ||
|
|
f6da0d342a | ||
|
|
7271537a15 | ||
|
|
d0e8efac4d | ||
|
|
27e6d56d83 | ||
|
|
c5122c12cb | ||
|
|
282050c596 | ||
|
|
308c73bfa2 | ||
|
|
c40309ae8e | ||
|
|
1c7a4ecc7f | ||
|
|
80cc623eb2 | ||
|
|
89457fd991 | ||
|
|
257043b8fb | ||
|
|
657d94b992 | ||
|
|
06dc7d5964 | ||
|
|
b50079524b | ||
|
|
cdf1f269ff | ||
|
|
738b562f39 | ||
|
|
58499f256b | ||
|
|
afb455ef80 | ||
|
|
f4515e9034 | ||
|
|
aab07d00d7 | ||
|
|
32ecfc6a86 | ||
|
|
e866f9fae7 | ||
|
|
a029f6ed2c | ||
|
|
5b6e2cb5e0 | ||
|
|
0264847a37 | ||
|
|
d276ca0adc | ||
|
|
6a099ee50a | ||
|
|
be88846972 | ||
|
|
9a6b623c25 | ||
|
|
97b36b8c74 | ||
|
|
0df332e7b8 | ||
|
|
2d7e6fbb11 | ||
|
|
fd107ab47c | ||
|
|
1320d7efab | ||
|
|
7cdc6cfa6d | ||
|
|
095ee9683d | ||
|
|
1e2081a1c5 | ||
|
|
e167e07a9a | ||
|
|
f3b9cd8404 | ||
|
|
8f9744c07b | ||
|
|
684a219e39 | ||
|
|
e2e6d827c7 | ||
|
|
f0108ece6f | ||
|
|
789b7a5ff1 | ||
|
|
0961295a82 | ||
|
|
fd060eb9f1 | ||
|
|
1feeda4514 | ||
|
|
6d29de0f1e | ||
|
|
74162850f0 | ||
|
|
8903bd1e8a | ||
|
|
4b79a4a10d | ||
|
|
8f419a4869 | ||
|
|
fcdac50f79 | ||
|
|
4541134c88 | ||
|
|
b5e5972c2a | ||
|
|
525d59fdf6 | ||
|
|
00f65afe20 | ||
|
|
fc402f5804 | ||
|
|
f74b6d9a43 | ||
|
|
ccaf2333ca | ||
|
|
0066bf8eed | ||
|
|
bc8f88f5fa | ||
|
|
10c9d917ad | ||
|
|
cc5f752f2d | ||
|
|
39b1a51ff4 | ||
|
|
a2e2e46af3 | ||
|
|
9d53a7e0a6 | ||
|
|
7ea57eaa18 | ||
|
|
1657a425c1 | ||
|
|
e929e92245 | ||
|
|
5994e48b28 | ||
|
|
50662c9c9e | ||
|
|
addd614e94 | ||
|
|
fbb228050a | ||
|
|
9bda8e266e | ||
|
|
d977005126 | ||
|
|
8b579bc7d0 | ||
|
|
ab16a11aa3 | ||
|
|
85347e12de | ||
|
|
67afbbbaa6 | ||
|
|
b743ee21f0 | ||
|
|
72702a042e | ||
|
|
649c69fa9e | ||
|
|
9fd0b87925 | ||
|
|
1c7a001489 | ||
|
|
47edc33b0d | ||
|
|
2afad0c650 | ||
|
|
fb53a6a686 | ||
|
|
31b5b78dc1 | ||
|
|
2f941c7fb3 | ||
|
|
ba483b4032 | ||
|
|
977b0ceee4 | ||
|
|
fcc20334da | ||
|
|
83c063346d | ||
|
|
c2e29ad06f | ||
|
|
9194d40da7 | ||
|
|
002073ef57 | ||
|
|
ef3066a1bd | ||
|
|
65db5b94e4 | ||
|
|
3122038c48 | ||
|
|
54fd0efdfe | ||
|
|
f0d1e50d5a | ||
|
|
a87ea20b7c | ||
|
|
8e7e40d0cc | ||
|
|
de4d4f6609 | ||
|
|
e01d61484d | ||
|
|
51f83087f2 | ||
|
|
17012654e1 | ||
|
|
e998d125ab | ||
|
|
95601d3179 | ||
|
|
0566a5833b | ||
|
|
c50459b81a | ||
|
|
0e52cf76eb | ||
|
|
0baf725073 | ||
|
|
e77fd7ddb9 | ||
|
|
e5cb5dca61 | ||
|
|
7941b559c5 | ||
|
|
58d81dbc52 | ||
|
|
2b4dc4496f | ||
|
|
c5e9d0096a | ||
|
|
c6f9780b1b | ||
|
|
ef694923f7 | ||
|
|
8d02203bb6 | ||
|
|
1e75be3b5d | ||
|
|
7d13891066 | ||
|
|
4292bd7ad9 | ||
|
|
82cd110dbe | ||
|
|
d2729193c7 | ||
|
|
87fb325357 | ||
|
|
fb8ff7b892 | ||
|
|
5aeae7444f | ||
|
|
c9b11e9fbf | ||
|
|
0005efa508 | ||
|
|
6931cb9d65 | ||
|
|
c1bcf0f11a | ||
|
|
717e7ae8b2 | ||
|
|
bed00fb8e1 | ||
|
|
2010401b81 | ||
|
|
23e09e3b3c | ||
|
|
80c9d46b70 | ||
|
|
0aa107426c | ||
|
|
1517c77d9c | ||
|
|
51bf79bb8c | ||
|
|
d88eadff13 | ||
|
|
0d35e8e15e | ||
|
|
a0066a1ccf | ||
|
|
7a5082e8c4 | ||
|
|
dfc345756c | ||
|
|
137da6adf6 | ||
|
|
8563ec5a7a | ||
|
|
8ac4bee3bc | ||
|
|
579fb478b5 | ||
|
|
33c580ebbf | ||
|
|
ff389b3e97 | ||
|
|
50fe8e7852 | ||
|
|
cdb6d19989 | ||
|
|
29694e2945 | ||
|
|
9fe08d3913 | ||
|
|
c07a0d9005 | ||
|
|
cbd45478e0 | ||
|
|
6f243108e9 | ||
|
|
0dcdf7ae21 | ||
|
|
e7ef2bec8b | ||
|
|
4f4dce82c6 | ||
|
|
a619e7a88c | ||
|
|
102d960106 | ||
|
|
7de71b29a0 | ||
|
|
4eced8a393 | ||
|
|
710b9c35e5 | ||
|
|
f46984d218 | ||
|
|
44663a7e6e | ||
|
|
446124f378 | ||
|
|
c45f2085d5 | ||
|
|
3abf62b41a | ||
|
|
9b2982510e | ||
|
|
48bb1ebe01 | ||
|
|
fe4c6e4c56 | ||
|
|
37bd9ffc48 | ||
|
|
b0548b4944 | ||
|
|
12425556c1 | ||
|
|
3ed2da562b | ||
|
|
354f46d8c5 | ||
|
|
e70f0db83c | ||
|
|
49b8c56fde | ||
|
|
940fdd5573 | ||
|
|
ef53db201e | ||
|
|
aeb0b0728d | ||
|
|
8b2746abf1 | ||
|
|
01da060496 | ||
|
|
20cbd269c4 | ||
|
|
7c2cd43dfa | ||
|
|
de5feff720 | ||
|
|
7342de837d | ||
|
|
aa2c648918 | ||
|
|
e914b50d16 | ||
|
|
f79554f918 | ||
|
|
213cc9c4b5 | ||
|
|
05f3b8fa0f | ||
|
|
bc53624133 | ||
|
|
5944d034da | ||
|
|
df400feb61 | ||
|
|
48e10c57da | ||
|
|
1eb818b64c | ||
|
|
0954932091 | ||
|
|
e584d9cd2e | ||
|
|
4d140ea6bd | ||
|
|
09a2e50fc2 | ||
|
|
35d8ef33ef | ||
|
|
f1ff2af47a | ||
|
|
d2d2c31ec7 | ||
|
|
95102c1c6c | ||
|
|
fa8c16ae01 | ||
|
|
7ca2a8213d | ||
|
|
1c8e5046e5 | ||
|
|
68a5652733 | ||
|
|
6b4be30c64 | ||
|
|
6ce952ad4a | ||
|
|
5ae62dd9d7 | ||
|
|
51987107a2 | ||
|
|
e4a8c4813c | ||
|
|
3d708f7dc4 | ||
|
|
4b5bcb56bc | ||
|
|
10ec8c9558 | ||
|
|
3900f758ea | ||
|
|
a3346fbad8 | ||
|
|
f73d58d74e | ||
|
|
813d5e1ddf | ||
|
|
acb661df72 | ||
|
|
4bc7710de9 | ||
|
|
b8c1f4f138 | ||
|
|
387b67472c | ||
|
|
b2c099bac6 | ||
|
|
1acebb1cc4 | ||
|
|
8d89a8dcb0 | ||
|
|
a60a34331b | ||
|
|
749015eb86 | ||
|
|
4b45142e72 | ||
|
|
76009ce7b9 | ||
|
|
2722119776 | ||
|
|
c724585bce | ||
|
|
0b61e46f95 | ||
|
|
5c0da486b9 | ||
|
|
9701e5e6e4 | ||
|
|
1684091234 | ||
|
|
a93eb8b8f5 | ||
|
|
c591ab5e6f | ||
|
|
b3fbebed55 | ||
|
|
4621f88441 | ||
|
|
747edb3a99 | ||
|
|
558970e281 | ||
|
|
73fd20a608 | ||
|
|
78c2c33b9e | ||
|
|
610add1f59 | ||
|
|
655510ce28 | ||
|
|
f7414700f4 | ||
|
|
53a860a5bf | ||
|
|
1aae450303 | ||
|
|
b3a2f8837c | ||
|
|
33d2a93294 | ||
|
|
2da0db70de | ||
|
|
8b5cbf8066 | ||
|
|
9668563801 | ||
|
|
ff7067f3a3 | ||
|
|
6b8b152444 | ||
|
|
3dbe3b3e7f | ||
|
|
7aa4bff97b | ||
|
|
6002fac9f1 | ||
|
|
231c6ac862 | ||
|
|
c3eb7e1634 | ||
|
|
05a6ee2b49 | ||
|
|
94d76c042d | ||
|
|
23ccaa6191 | ||
|
|
476e9d0a48 | ||
|
|
7cd5ed6fc6 | ||
|
|
750c23f319 | ||
|
|
bb36df8b2e | ||
|
|
470c43a986 | ||
|
|
8ea78e8361 | ||
|
|
9c748d20d5 | ||
|
|
af15b22b03 | ||
|
|
80c9c705b8 | ||
|
|
138419d232 | ||
|
|
8cee15bc5a | ||
|
|
8113974b26 | ||
|
|
2b70cefd48 | ||
|
|
16054d4bfd | ||
|
|
c2d4a53b67 | ||
|
|
3448b1c78c |
93
.github/workflows/build.yml
vendored
93
.github/workflows/build.yml
vendored
@@ -11,6 +11,15 @@ jobs:
|
|||||||
os: [ubuntu-20.04, macos-10.15]
|
os: [ubuntu-20.04, macos-10.15]
|
||||||
compiler: [gcc, clang]
|
compiler: [gcc, clang]
|
||||||
buildtool: [autotools, cmake]
|
buildtool: [autotools, cmake]
|
||||||
|
http3: [http3, no-http3]
|
||||||
|
openssl: [openssl1, openssl3]
|
||||||
|
exclude:
|
||||||
|
- os: macos-10.15
|
||||||
|
openssl: openssl3
|
||||||
|
- http3: no-http3
|
||||||
|
openssl: openssl3
|
||||||
|
- os: macos-10.15
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -34,6 +43,7 @@ jobs:
|
|||||||
libjansson-dev \
|
libjansson-dev \
|
||||||
libjemalloc-dev \
|
libjemalloc-dev \
|
||||||
libc-ares-dev \
|
libc-ares-dev \
|
||||||
|
libelf-dev \
|
||||||
cmake \
|
cmake \
|
||||||
cmake-data
|
cmake-data
|
||||||
echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
|
echo 'CPPFLAGS=-fsanitize=address,undefined -fno-sanitize-recover=undefined -g' >> $GITHUB_ENV
|
||||||
@@ -52,8 +62,6 @@ jobs:
|
|||||||
pkg-config \
|
pkg-config \
|
||||||
libtool
|
libtool
|
||||||
echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV
|
echo 'PKG_CONFIG_PATH=/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig' >> $GITHUB_ENV
|
||||||
# This fixes infamous 'stdio.h not found' error.
|
|
||||||
echo 'SDKROOT='"$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV
|
|
||||||
- name: Setup clang (Linux)
|
- name: Setup clang (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.compiler == 'clang'
|
if: runner.os == 'Linux' && matrix.compiler == 'clang'
|
||||||
run: |
|
run: |
|
||||||
@@ -74,26 +82,97 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo 'CC=gcc' >> $GITHUB_ENV
|
echo 'CC=gcc' >> $GITHUB_ENV
|
||||||
echo 'CXX=g++' >> $GITHUB_ENV
|
echo 'CXX=g++' >> $GITHUB_ENV
|
||||||
|
- name: Build libbpf
|
||||||
|
if: matrix.http3 == 'http3' && matrix.compiler == 'clang' && runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
git clone -b v0.4.0 https://github.com/libbpf/libbpf
|
||||||
|
cd libbpf
|
||||||
|
PREFIX=$PWD/build make -C src install
|
||||||
|
|
||||||
|
EXTRA_AUTOTOOLS_OPTS="--with-libbpf"
|
||||||
|
EXTRA_CMAKE_OPTS="-DWITH_LIBBPF=1"
|
||||||
|
|
||||||
|
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
|
||||||
|
echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
|
||||||
|
- name: Build quictls/openssl v1.1.1
|
||||||
|
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl1'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 -b OpenSSL_1_1_1m+quic https://github.com/quictls/openssl
|
||||||
|
cd openssl
|
||||||
|
./config enable-tls1_3 --prefix=$PWD/build
|
||||||
|
make -j$(nproc)
|
||||||
|
make install_sw
|
||||||
|
- name: Build quictls/openssl v3.0.x
|
||||||
|
if: matrix.http3 == 'http3' && matrix.openssl == 'openssl3'
|
||||||
|
run: |
|
||||||
|
unset CPPFLAGS
|
||||||
|
unset LDFLAGS
|
||||||
|
|
||||||
|
git clone --depth 1 -b openssl-3.0.1+quic https://github.com/quictls/openssl
|
||||||
|
cd openssl
|
||||||
|
./config enable-tls1_3 --prefix=$PWD/build --libdir=$PWD/build/lib
|
||||||
|
make -j$(nproc)
|
||||||
|
make install_sw
|
||||||
|
- name: Build nghttp3
|
||||||
|
if: matrix.http3 == 'http3'
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/ngtcp2/nghttp3
|
||||||
|
cd nghttp3
|
||||||
|
git checkout 74a222fe0c89b7202bcdaf6ef27a232edffc85e3
|
||||||
|
autoreconf -i
|
||||||
|
./configure --prefix=$PWD/build --enable-lib-only
|
||||||
|
make -j$(nproc) check
|
||||||
|
make install
|
||||||
|
- name: Build ngtcp2
|
||||||
|
if: matrix.http3 == 'http3'
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 -b v0.1.0 https://github.com/ngtcp2/ngtcp2
|
||||||
|
cd ngtcp2
|
||||||
|
autoreconf -i
|
||||||
|
./configure --prefix=$PWD/build --enable-lib-only PKG_CONFIG_PATH="../openssl/build/lib/pkgconfig"
|
||||||
|
make -j$(nproc) check
|
||||||
|
make install
|
||||||
|
- name: Setup extra environment variables for HTTP/3
|
||||||
|
if: matrix.http3 == 'http3'
|
||||||
|
run: |
|
||||||
|
PKG_CONFIG_PATH="$PWD/openssl/build/lib/pkgconfig:$PWD/nghttp3/build/lib/pkgconfig:$PWD/ngtcp2/build/lib/pkgconfig:$PWD/libbpf/build/lib64/pkgconfig:$PKG_CONFIG_PATH"
|
||||||
|
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/openssl/build/lib -Wl,-rpath,$PWD/libbpf/build/lib64"
|
||||||
|
EXTRA_AUTOTOOLS_OPTS="--enable-http3 $EXTRA_AUTOTOOLS_OPTS"
|
||||||
|
EXTRA_CMAKE_OPTS="-DENABLE_HTTP3=1 $EXTRA_CMAKE_OPTS"
|
||||||
|
|
||||||
|
echo 'PKG_CONFIG_PATH='"$PKG_CONFIG_PATH" >> $GITHUB_ENV
|
||||||
|
echo 'LDFLAGS='"$LDFLAGS" >> $GITHUB_ENV
|
||||||
|
echo 'EXTRA_AUTOTOOLS_OPTS='"$EXTRA_AUTOTOOLS_OPTS" >> $GITHUB_ENV
|
||||||
|
echo 'EXTRA_CMAKE_OPTS='"$EXTRA_CMAKE_OPTS" >> $GITHUB_ENV
|
||||||
- name: Setup git submodules
|
- name: Setup git submodules
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
- name: Configure autotools
|
- name: Configure autotools
|
||||||
if: matrix.buildtool == 'autotools'
|
|
||||||
run: |
|
run: |
|
||||||
autoreconf -i
|
autoreconf -i
|
||||||
./configure --enable-werror --with-mruby
|
./configure
|
||||||
- name: Configure cmake
|
- name: Configure cmake
|
||||||
if: matrix.buildtool == 'cmake'
|
if: matrix.buildtool == 'cmake'
|
||||||
run: |
|
run: |
|
||||||
cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" .
|
make dist
|
||||||
|
VERSION=$(grep PACKAGE_VERSION config.h | cut -d' ' -f3 | tr -d '"')
|
||||||
|
tar xf nghttp2-$VERSION.tar.gz
|
||||||
|
cd nghttp2-$VERSION
|
||||||
|
echo 'NGHTTP2_CMAKE_DIR='"$PWD" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# This fixes infamous 'stdio.h not found' error.
|
||||||
|
echo 'SDKROOT='"$(xcrun --sdk macosx --show-sdk-path)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DENABLE_APP=1 $EXTRA_CMAKE_OPTS -DCPPFLAGS="$CPPFLAGS" -DLDFLAGS="$LDFLAGS" .
|
||||||
- name: Build nghttp2 with autotools
|
- name: Build nghttp2 with autotools
|
||||||
if: matrix.buildtool == 'autotools'
|
if: matrix.buildtool == 'autotools'
|
||||||
run: |
|
run: |
|
||||||
make distcheck \
|
make distcheck \
|
||||||
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
|
DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --with-libev --enable-werror $EXTRA_AUTOTOOLS_OPTS CPPFLAGS=\"$CPPFLAGS\" LDFLAGS=\"$LDFLAGS\""
|
||||||
- name: Build nghttp2 with cmake
|
- name: Build nghttp2 with cmake
|
||||||
if: matrix.buildtool == 'cmake'
|
if: matrix.buildtool == 'cmake'
|
||||||
run: |
|
run: |
|
||||||
|
cd $NGHTTP2_CMAKE_DIR
|
||||||
make
|
make
|
||||||
make check
|
make check
|
||||||
- name: Integration test
|
- name: Integration test
|
||||||
@@ -101,5 +180,5 @@ jobs:
|
|||||||
# artifacts.
|
# artifacts.
|
||||||
if: matrix.buildtool == 'cmake'
|
if: matrix.buildtool == 'cmake'
|
||||||
run: |
|
run: |
|
||||||
cd integration-tests
|
cd $NGHTTP2_CMAKE_DIR/integration-tests
|
||||||
make itprep it
|
make itprep it
|
||||||
|
|||||||
89
.travis.yml
89
.travis.yml
@@ -1,89 +0,0 @@
|
|||||||
dist: xenial
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
- gcc
|
|
||||||
env:
|
|
||||||
matrix:
|
|
||||||
- CI_BUILD=cmake
|
|
||||||
- CI_BUILD=autotools
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: osx
|
|
||||||
compiler: clang
|
|
||||||
osx_image: xcode10.2
|
|
||||||
env: CI_BUILD=autotools
|
|
||||||
language: cpp
|
|
||||||
sudo: required
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
sources:
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
packages:
|
|
||||||
- g++-8
|
|
||||||
- autoconf
|
|
||||||
- automake
|
|
||||||
- autotools-dev
|
|
||||||
- libtool
|
|
||||||
- pkg-config
|
|
||||||
- zlib1g-dev
|
|
||||||
- libcunit1-dev
|
|
||||||
- libssl-dev
|
|
||||||
- libxml2-dev
|
|
||||||
- libev-dev
|
|
||||||
- libevent-dev
|
|
||||||
- libjansson-dev
|
|
||||||
- libjemalloc-dev
|
|
||||||
- libc-ares-dev
|
|
||||||
- cmake
|
|
||||||
- cmake-data
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- libev
|
|
||||||
- libevent
|
|
||||||
- c-ares
|
|
||||||
- cunit
|
|
||||||
- libressl
|
|
||||||
before_install:
|
|
||||||
- $CC --version
|
|
||||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-8" CC="gcc-8"; fi
|
|
||||||
- $CC --version
|
|
||||||
- go version
|
|
||||||
- cmake --version
|
|
||||||
before_script:
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
|
||||||
CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -fuse-ld=gold"
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
|
||||||
PKG_CONFIG_PATH="/usr/local/opt/libressl/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig"
|
|
||||||
fi
|
|
||||||
# Now build nghttp2
|
|
||||||
- git submodule update --init
|
|
||||||
- |
|
|
||||||
if [ "$CI_BUILD" = "autotools" ]; then
|
|
||||||
autoreconf -i && ./configure --with-mruby PKG_CONFIG_PATH=$PKG_CONFIG_PATH
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$CI_BUILD" = "cmake" ]; then
|
|
||||||
cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1
|
|
||||||
fi
|
|
||||||
script:
|
|
||||||
- |
|
|
||||||
if [ "$CI_BUILD" = "autotools" ]; then
|
|
||||||
make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror CPPFLAGS=$CPPFLAGS LDFLAGS=\"$LDFLAGS\" PKG_CONFIG_PATH=$PKG_CONFIG_PATH"
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$CI_BUILD" = "cmake" ]; then
|
|
||||||
make && make check
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
if [ "$CI_BUILD" = "cmake" ]; then
|
|
||||||
# Integration tests for nghttpx; autotools build erases build
|
|
||||||
# for packaging test.
|
|
||||||
cd integration-tests
|
|
||||||
export GO111MODULE=on
|
|
||||||
make it
|
|
||||||
fi
|
|
||||||
8
AUTHORS
8
AUTHORS
@@ -19,6 +19,7 @@ Alek Storm
|
|||||||
Alex Nalivko
|
Alex Nalivko
|
||||||
Alexandros Konstantinakis-Karmis
|
Alexandros Konstantinakis-Karmis
|
||||||
Alexis La Goutte
|
Alexis La Goutte
|
||||||
|
Amir Livneh
|
||||||
Amir Pakdel
|
Amir Pakdel
|
||||||
Anders Bakken
|
Anders Bakken
|
||||||
Andreas Pohl
|
Andreas Pohl
|
||||||
@@ -34,11 +35,13 @@ Bernard Spil
|
|||||||
Brendan Heinonen
|
Brendan Heinonen
|
||||||
Brian Card
|
Brian Card
|
||||||
Brian Suh
|
Brian Suh
|
||||||
|
Daniel Bevenius
|
||||||
Daniel Evers
|
Daniel Evers
|
||||||
Daniel Stenberg
|
Daniel Stenberg
|
||||||
Dave Reisner
|
Dave Reisner
|
||||||
David Beitey
|
David Beitey
|
||||||
David Weekly
|
David Weekly
|
||||||
|
Dmitri Tikhonov
|
||||||
Dmitriy Vetutnev
|
Dmitriy Vetutnev
|
||||||
Don
|
Don
|
||||||
Dylan Plecki
|
Dylan Plecki
|
||||||
@@ -48,9 +51,12 @@ Fabian Wiesel
|
|||||||
Gabi Davar
|
Gabi Davar
|
||||||
Gaël PORTAY
|
Gaël PORTAY
|
||||||
Geoff Hill
|
Geoff Hill
|
||||||
|
George Liu
|
||||||
Gitai
|
Gitai
|
||||||
Google Inc.
|
Google Inc.
|
||||||
|
Hajime Fujita
|
||||||
Jacky Tian
|
Jacky Tian
|
||||||
|
Jacky_Yin
|
||||||
Jacob Champion
|
Jacob Champion
|
||||||
James M Snell
|
James M Snell
|
||||||
Jan Kundrát
|
Jan Kundrát
|
||||||
@@ -76,6 +82,7 @@ MATSUMOTO Ryosuke
|
|||||||
Marc Bachmann
|
Marc Bachmann
|
||||||
Matt Rudary
|
Matt Rudary
|
||||||
Matt Way
|
Matt Way
|
||||||
|
Michael Kaufmann
|
||||||
Mike Conlen
|
Mike Conlen
|
||||||
Mike Frysinger
|
Mike Frysinger
|
||||||
Mike Lothian
|
Mike Lothian
|
||||||
@@ -127,6 +134,7 @@ es
|
|||||||
fangdingjun
|
fangdingjun
|
||||||
jwchoi
|
jwchoi
|
||||||
kumagi
|
kumagi
|
||||||
|
lhuang04
|
||||||
lstefani
|
lstefani
|
||||||
makovich
|
makovich
|
||||||
mod-h2-dev
|
mod-h2-dev
|
||||||
|
|||||||
@@ -24,13 +24,13 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
# XXX using 1.8.90 instead of 1.9.0-DEV
|
# XXX using 1.8.90 instead of 1.9.0-DEV
|
||||||
project(nghttp2 VERSION 1.44.90)
|
project(nghttp2 VERSION 1.46.90)
|
||||||
|
|
||||||
# See versioning rule:
|
# See versioning rule:
|
||||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
set(LT_CURRENT 34)
|
set(LT_CURRENT 35)
|
||||||
set(LT_REVISION 2)
|
set(LT_REVISION 1)
|
||||||
set(LT_AGE 20)
|
set(LT_AGE 21)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
include(Version)
|
include(Version)
|
||||||
@@ -61,6 +61,18 @@ find_package(OpenSSL 1.0.1)
|
|||||||
find_package(Libev 4.11)
|
find_package(Libev 4.11)
|
||||||
find_package(Libcares 1.7.5)
|
find_package(Libcares 1.7.5)
|
||||||
find_package(ZLIB 1.2.3)
|
find_package(ZLIB 1.2.3)
|
||||||
|
find_package(Libngtcp2 0.0.0)
|
||||||
|
find_package(Libngtcp2_crypto_openssl 0.0.0)
|
||||||
|
if(LIBNGTCP2_CRYPTO_OPENSSL_FOUND)
|
||||||
|
set(HAVE_LIBNGTCP2_CRYPTO_OPENSSL 1)
|
||||||
|
endif()
|
||||||
|
find_package(Libnghttp3 0.0.0)
|
||||||
|
if(WITH_LIBBPF)
|
||||||
|
find_package(Libbpf 0.4.0)
|
||||||
|
if(NOT LIBBPF_FOUND)
|
||||||
|
message(FATAL_ERROR "libbpf was requested (WITH_LIBBPF=1) but not found.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
if(OPENSSL_FOUND AND LIBEV_FOUND AND ZLIB_FOUND)
|
if(OPENSSL_FOUND AND LIBEV_FOUND AND ZLIB_FOUND)
|
||||||
set(ENABLE_APP_DEFAULT ON)
|
set(ENABLE_APP_DEFAULT ON)
|
||||||
else()
|
else()
|
||||||
@@ -167,7 +179,7 @@ endif()
|
|||||||
# case "$host" in
|
# case "$host" in
|
||||||
# *android*)
|
# *android*)
|
||||||
# android_build=yes
|
# android_build=yes
|
||||||
# # android does not need -pthread, but needs followng 3 libs for C++
|
# # android does not need -pthread, but needs following 3 libs for C++
|
||||||
# APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
|
# APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
|
||||||
|
|
||||||
# dl: openssl requires libdl when it is statically linked.
|
# dl: openssl requires libdl when it is statically linked.
|
||||||
@@ -182,9 +194,18 @@ if(HAVE_CUNIT)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# openssl (for src)
|
# openssl (for src)
|
||||||
|
include(CheckSymbolExists)
|
||||||
set(HAVE_OPENSSL ${OPENSSL_FOUND})
|
set(HAVE_OPENSSL ${OPENSSL_FOUND})
|
||||||
if(OPENSSL_FOUND)
|
if(OPENSSL_FOUND)
|
||||||
set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
|
set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
|
||||||
|
cmake_push_check_state()
|
||||||
|
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
|
||||||
|
set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
|
||||||
|
check_symbol_exists(SSL_is_quic "openssl/ssl.h" HAVE_SSL_IS_QUIC)
|
||||||
|
if(NOT HAVE_SSL_IS_QUIC)
|
||||||
|
message(WARNING "OpenSSL in ${OPENSSL_LIBRARIES} dose not have SSL_is_quic. HTTP/3 support cannot be enabled")
|
||||||
|
endif()
|
||||||
|
cmake_pop_check_state()
|
||||||
else()
|
else()
|
||||||
set(OPENSSL_INCLUDE_DIRS "")
|
set(OPENSSL_INCLUDE_DIRS "")
|
||||||
set(OPENSSL_LIBRARIES "")
|
set(OPENSSL_LIBRARIES "")
|
||||||
@@ -223,11 +244,31 @@ if(ENABLE_ASIO_LIB)
|
|||||||
find_package(Boost 1.54.0 REQUIRED system thread)
|
find_package(Boost 1.54.0 REQUIRED system thread)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# libbpf (for bpf)
|
||||||
|
set(HAVE_LIBBPF ${LIBBPF_FOUND})
|
||||||
|
if(LIBBPF_FOUND)
|
||||||
|
set(BPFCFLAGS -Wall -O2 -g)
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
# For Debian/Ubuntu
|
||||||
|
set(EXTRABPFCFLAGS -I/usr/include/${CMAKE_SYSTEM_PROCESSOR}-linux-gnu)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_c_source_compiles("
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
int main() { enum bpf_stats_type foo; (void)foo; }" HAVE_BPF_STATS_TYPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL and libev
|
# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL and libev
|
||||||
if(ENABLE_APP AND NOT (ZLIB_FOUND AND OPENSSL_FOUND AND LIBEV_FOUND))
|
if(ENABLE_APP AND NOT (ZLIB_FOUND AND OPENSSL_FOUND AND LIBEV_FOUND))
|
||||||
message(FATAL_ERROR "Applications were requested (ENABLE_APP=1) but dependencies are not met.")
|
message(FATAL_ERROR "Applications were requested (ENABLE_APP=1) but dependencies are not met.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# HTTP/3 requires quictls/openssl, libngtcp2, libngtcp2_crypto_openssl
|
||||||
|
# and libnghttp3.
|
||||||
|
if(ENABLE_HTTP3 AND NOT (HAVE_SSL_IS_QUIC AND LIBNGTCP2_FOUND AND LIBNGTCP2_CRYPTO_OPENSSL_FOUND AND LIBNGHTTP3_FOUND))
|
||||||
|
message(FATAL_ERROR "HTTP/3 was requested (ENABLE_HTTP3=1) but dependencies are not met.")
|
||||||
|
endif()
|
||||||
|
|
||||||
# HPACK tools requires jansson
|
# HPACK tools requires jansson
|
||||||
if(ENABLE_HPACK_TOOLS AND NOT HAVE_JANSSON)
|
if(ENABLE_HPACK_TOOLS AND NOT HAVE_JANSSON)
|
||||||
message(FATAL_ERROR "HPACK tools were requested (ENABLE_HPACK_TOOLS=1) but dependencies are not met.")
|
message(FATAL_ERROR "HPACK tools were requested (ENABLE_HPACK_TOOLS=1) but dependencies are not met.")
|
||||||
@@ -448,11 +489,16 @@ foreach(name
|
|||||||
configure_file("${name}.in" "${name}" @ONLY)
|
configure_file("${name}.in" "${name}" @ONLY)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
add_definitions(-D__APPLE_USE_RFC_3542)
|
||||||
|
endif()
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}" # for config.h
|
"${CMAKE_CURRENT_BINARY_DIR}" # for config.h
|
||||||
)
|
)
|
||||||
# For use in src/CMakeLists.txt
|
# For use in src/CMakeLists.txt
|
||||||
set(PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}")
|
set(PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/${CMAKE_PROJECT_NAME}")
|
||||||
|
set(PKGLIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}/${CMAKE_PROJECT_NAME}")
|
||||||
|
|
||||||
install(FILES README.rst DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
install(FILES README.rst DESTINATION "${CMAKE_INSTALL_DOCDIR}")
|
||||||
|
|
||||||
@@ -469,6 +515,7 @@ add_subdirectory(integration-tests)
|
|||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
add_subdirectory(contrib)
|
add_subdirectory(contrib)
|
||||||
add_subdirectory(script)
|
add_subdirectory(script)
|
||||||
|
add_subdirectory(bpf)
|
||||||
|
|
||||||
|
|
||||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type)
|
string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type)
|
||||||
@@ -499,6 +546,10 @@ message(STATUS "summary of build options:
|
|||||||
Libxml2: ${HAVE_LIBXML2} (LIBS='${LIBXML2_LIBRARIES}')
|
Libxml2: ${HAVE_LIBXML2} (LIBS='${LIBXML2_LIBRARIES}')
|
||||||
Libev: ${HAVE_LIBEV} (LIBS='${LIBEV_LIBRARIES}')
|
Libev: ${HAVE_LIBEV} (LIBS='${LIBEV_LIBRARIES}')
|
||||||
Libc-ares: ${HAVE_LIBCARES} (LIBS='${LIBCARES_LIBRARIES}')
|
Libc-ares: ${HAVE_LIBCARES} (LIBS='${LIBCARES_LIBRARIES}')
|
||||||
|
Libngtcp2: ${HAVE_LIBNGTCP2} (LIBS='${LIBNGTCP2_LIBRARIES}')
|
||||||
|
Libngtcp2_crypto_openssl: ${HAVE_LIBNGTCP2_CRYPTO_OPENSSL} (LIBS='${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES}')
|
||||||
|
Libnghttp3: ${HAVE_LIBNGHTTP3} (LIBS='${LIBNGHTTP3_LIBRARIES}')
|
||||||
|
Libbpf: ${HAVE_LIBBPF} (LIBS='${LIBBPF_LIBRARIES}')
|
||||||
Libevent(SSL): ${HAVE_LIBEVENT_OPENSSL} (LIBS='${LIBEVENT_OPENSSL_LIBRARIES}')
|
Libevent(SSL): ${HAVE_LIBEVENT_OPENSSL} (LIBS='${LIBEVENT_OPENSSL_LIBRARIES}')
|
||||||
Jansson: ${HAVE_JANSSON} (LIBS='${JANSSON_LIBRARIES}')
|
Jansson: ${HAVE_JANSSON} (LIBS='${JANSSON_LIBRARIES}')
|
||||||
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
|
Jemalloc: ${HAVE_JEMALLOC} (LIBS='${JEMALLOC_LIBRARIES}')
|
||||||
@@ -517,6 +568,7 @@ message(STATUS "summary of build options:
|
|||||||
Examples: ${ENABLE_EXAMPLES}
|
Examples: ${ENABLE_EXAMPLES}
|
||||||
Python bindings:${ENABLE_PYTHON_BINDINGS}
|
Python bindings:${ENABLE_PYTHON_BINDINGS}
|
||||||
Threading: ${ENABLE_THREADS}
|
Threading: ${ENABLE_THREADS}
|
||||||
|
HTTP/3(EXPERIMENTAL): ${ENABLE_HTTP3}
|
||||||
")
|
")
|
||||||
if(ENABLE_LIB_ONLY_DISABLED_OTHERS)
|
if(ENABLE_LIB_ONLY_DISABLED_OTHERS)
|
||||||
message("Only the library will be built. To build other components "
|
message("Only the library will be built. To build other components "
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ option(ENABLE_LIB_ONLY "Build libnghttp2 only. This is a short hand for -DENAB
|
|||||||
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also")
|
option(ENABLE_STATIC_LIB "Build libnghttp2 in static mode also")
|
||||||
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
option(ENABLE_SHARED_LIB "Build libnghttp2 as a shared library" ON)
|
||||||
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
option(ENABLE_STATIC_CRT "Build libnghttp2 against the MS LIBCMT[d]")
|
||||||
|
option(ENABLE_HTTP3 "Enable HTTP/3 support" OFF)
|
||||||
|
|
||||||
option(WITH_LIBXML2 "Use libxml2"
|
option(WITH_LIBXML2 "Use libxml2"
|
||||||
${WITH_LIBXML2_DEFAULT})
|
${WITH_LIBXML2_DEFAULT})
|
||||||
option(WITH_JEMALLOC "Use jemalloc"
|
option(WITH_JEMALLOC "Use jemalloc"
|
||||||
${WITH_JEMALLOC_DEFAULT})
|
${WITH_JEMALLOC_DEFAULT})
|
||||||
option(WITH_SPDYLAY "Use spdylay"
|
|
||||||
${WITH_SPDYLAY_DEFAULT})
|
|
||||||
option(WITH_MRUBY "Use mruby")
|
option(WITH_MRUBY "Use mruby")
|
||||||
option(WITH_NEVERBLEED "Use neverbleed")
|
option(WITH_NEVERBLEED "Use neverbleed")
|
||||||
|
option(WITH_LIBBPF "Use libbpf")
|
||||||
|
|
||||||
# vim: ft=cmake:
|
# vim: ft=cmake:
|
||||||
|
|||||||
12
Makefile.am
12
Makefile.am
@@ -20,7 +20,7 @@
|
|||||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
SUBDIRS = lib third-party src examples python tests integration-tests \
|
SUBDIRS = lib third-party src bpf examples python tests integration-tests \
|
||||||
doc contrib script
|
doc contrib script
|
||||||
|
|
||||||
# Now with python setuptools, make uninstall will leave many files we
|
# Now with python setuptools, make uninstall will leave many files we
|
||||||
@@ -46,16 +46,20 @@ EXTRA_DIST = nghttpx.conf.sample proxy.pac.sample android-config android-make \
|
|||||||
cmake/FindLibevent.cmake \
|
cmake/FindLibevent.cmake \
|
||||||
cmake/FindJansson.cmake \
|
cmake/FindJansson.cmake \
|
||||||
cmake/FindLibcares.cmake \
|
cmake/FindLibcares.cmake \
|
||||||
cmake/FindSystemd.cmake
|
cmake/FindSystemd.cmake \
|
||||||
|
cmake/FindLibbpf.cmake \
|
||||||
|
cmake/FindLibnghttp3.cmake \
|
||||||
|
cmake/FindLibngtcp2.cmake \
|
||||||
|
cmake/FindLibngtcp2_crypto_openssl.cmake
|
||||||
|
|
||||||
.PHONY: clang-format
|
.PHONY: clang-format
|
||||||
|
|
||||||
# Format source files using clang-format. Don't format source files
|
# Format source files using clang-format. Don't format source files
|
||||||
# under third-party directory since we are not responsible for thier
|
# under third-party directory since we are not responsible for their
|
||||||
# coding style.
|
# coding style.
|
||||||
clang-format:
|
clang-format:
|
||||||
CLANGFORMAT=`git config --get clangformat.binary`; \
|
CLANGFORMAT=`git config --get clangformat.binary`; \
|
||||||
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
test -z $${CLANGFORMAT} && CLANGFORMAT="clang-format"; \
|
||||||
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
|
$${CLANGFORMAT} -i lib/*.{c,h} lib/includes/nghttp2/*.h \
|
||||||
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
|
src/*.{c,cc,h} src/includes/nghttp2/*.h examples/*.{c,cc} \
|
||||||
tests/*.{c,h}
|
tests/*.{c,h} bpf/*.c
|
||||||
|
|||||||
148
README.rst
148
README.rst
@@ -32,12 +32,14 @@ Public Test Server
|
|||||||
The following endpoints are available to try out our nghttp2
|
The following endpoints are available to try out our nghttp2
|
||||||
implementation.
|
implementation.
|
||||||
|
|
||||||
* https://nghttp2.org/ (TLS + ALPN/NPN)
|
* https://nghttp2.org/ (TLS + ALPN/NPN and HTTP/3)
|
||||||
|
|
||||||
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
|
This endpoint supports ``h2``, ``h2-16``, ``h2-14``, and
|
||||||
``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
``http/1.1`` via ALPN/NPN and requires TLSv1.2 for HTTP/2
|
||||||
connection.
|
connection.
|
||||||
|
|
||||||
|
It also supports HTTP/3.
|
||||||
|
|
||||||
* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)
|
* http://nghttp2.org/ (HTTP Upgrade and HTTP/2 Direct)
|
||||||
|
|
||||||
``h2c`` and ``http/1.1``.
|
``h2c`` and ``http/1.1``.
|
||||||
@@ -145,6 +147,33 @@ minimizes the risk of private key leakage when serious bug like
|
|||||||
Heartbleed is exploited. The neverbleed is disabled by default. To
|
Heartbleed is exploited. The neverbleed is disabled by default. To
|
||||||
enable it, use ``--with-neverbleed`` configure option.
|
enable it, use ``--with-neverbleed`` configure option.
|
||||||
|
|
||||||
|
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_1m+quic>`_; or
|
||||||
|
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
|
||||||
|
f6ef1c560ae5af51e2df5d8d2175bed207b28b8f)
|
||||||
|
* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_
|
||||||
|
* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_
|
||||||
|
|
||||||
|
Use ``--enable-http3`` configure option to enable HTTP/3 feature for
|
||||||
|
h2load and nghttpx.
|
||||||
|
|
||||||
|
In order to build optional eBPF program to direct an incoming QUIC UDP
|
||||||
|
datagram to a correct socket for nghttpx, the following libraries are
|
||||||
|
required:
|
||||||
|
|
||||||
|
* libbpf-dev >= 0.4.0
|
||||||
|
|
||||||
|
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/v0.4.0>`_. nghttpx
|
||||||
|
requires eBPF program for reloading its configuration and hot swapping
|
||||||
|
its executable.
|
||||||
|
|
||||||
Compiling libnghttp2 C source code requires a C99 compiler. gcc 4.8
|
Compiling libnghttp2 C source code requires a C99 compiler. gcc 4.8
|
||||||
is known to be adequate. In order to compile the C++ source code, gcc
|
is known to be adequate. In order to compile the C++ source code, gcc
|
||||||
>= 6.0 or clang >= 6.0 is required. C++ source code requires C++14
|
>= 6.0 or clang >= 6.0 is required. C++ source code requires C++14
|
||||||
@@ -307,6 +336,89 @@ The generated documents will not be installed with ``make install``.
|
|||||||
The online documentation is available at
|
The online documentation is available at
|
||||||
https://nghttp2.org/documentation/
|
https://nghttp2.org/documentation/
|
||||||
|
|
||||||
|
Build HTTP/3 enabled h2load and nghttpx
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
To build h2load and nghttpx with HTTP/3 feature enabled, run the
|
||||||
|
configure script with ``--enable-http3``.
|
||||||
|
|
||||||
|
For nghttpx to reload configurations and swapping its executable while
|
||||||
|
gracefully terminating old worker processes, eBPF is required. Run
|
||||||
|
the configure script with ``--enable-http3 --with-libbpf`` to build
|
||||||
|
eBPF program. The QUIC keying material must be set with
|
||||||
|
``--frontend-quic-secret-file`` in order to keep the existing
|
||||||
|
connections alive during reload.
|
||||||
|
|
||||||
|
The detailed steps to build HTTP/3 enabled h2load and nghttpx follow.
|
||||||
|
|
||||||
|
Build custom OpenSSL:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git clone --depth 1 -b OpenSSL_1_1_1m+quic https://github.com/quictls/openssl
|
||||||
|
$ cd openssl
|
||||||
|
$ ./config --prefix=$PWD/build --openssldir=/etc/ssl
|
||||||
|
$ make -j$(nproc)
|
||||||
|
$ make install_sw
|
||||||
|
$ cd ..
|
||||||
|
|
||||||
|
Build nghttp3:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git clone https://github.com/ngtcp2/nghttp3
|
||||||
|
$ cd nghttp3
|
||||||
|
$ git checkout 74a222fe0c89b7202bcdaf6ef27a232edffc85e3
|
||||||
|
$ autoreconf -i
|
||||||
|
$ ./configure --prefix=$PWD/build --enable-lib-only
|
||||||
|
$ make -j$(nproc)
|
||||||
|
$ make install
|
||||||
|
$ cd ..
|
||||||
|
|
||||||
|
Build ngtcp2:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git clone --depth 1 -b v0.1.0 https://github.com/ngtcp2/ngtcp2
|
||||||
|
$ cd ngtcp2
|
||||||
|
$ autoreconf -i
|
||||||
|
$ ./configure --prefix=$PWD/build --enable-lib-only \
|
||||||
|
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig"
|
||||||
|
$ make -j$(nproc)
|
||||||
|
$ make install
|
||||||
|
$ cd ..
|
||||||
|
|
||||||
|
If your Linux distribution does not have libbpf-dev >= 0.4.0, build
|
||||||
|
from source:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git clone --depth 1 -b v0.4.0 https://github.com/libbpf/libbpf
|
||||||
|
$ cd libbpf
|
||||||
|
$ PREFIX=$PWD/build make -C src install
|
||||||
|
$ cd ..
|
||||||
|
|
||||||
|
Build nghttp2:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ git clone https://github.com/nghttp2/nghttp2
|
||||||
|
$ cd nghttp2
|
||||||
|
$ git submodule update --init
|
||||||
|
$ autoreconf -i
|
||||||
|
$ ./configure --with-mruby --with-neverbleed --enable-http3 --with-libbpf \
|
||||||
|
--disable-python-bindings \
|
||||||
|
CC=clang-12 CXX=clang++-12 \
|
||||||
|
PKG_CONFIG_PATH="$PWD/../openssl/build/lib/pkgconfig:$PWD/../nghttp3/build/lib/pkgconfig:$PWD/../ngtcp2/build/lib/pkgconfig:$PWD/../libbpf/build/lib64/pkgconfig" \
|
||||||
|
LDFLAGS="$LDFLAGS -Wl,-rpath,$PWD/../openssl/build/lib -Wl,-rpath,$PWD/../libbpf/build/lib64"
|
||||||
|
$ make -j$(nproc)
|
||||||
|
|
||||||
|
The eBPF program ``reuseport_kern.o`` should be found under bpf
|
||||||
|
directory. Pass ``--quic-bpf-program-file=bpf/reuseport_kern.o``
|
||||||
|
option to nghttpx to load it. See also `HTTP/3 section in nghttpx -
|
||||||
|
HTTP/2 proxy - HOW-TO
|
||||||
|
<https://nghttp2.org/documentation/nghttpx-howto.html#http-3>`_.
|
||||||
|
|
||||||
Unit tests
|
Unit tests
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@@ -734,7 +846,7 @@ information. Here is sample output from ``nghttpd``:
|
|||||||
nghttpx - proxy
|
nghttpx - proxy
|
||||||
+++++++++++++++
|
+++++++++++++++
|
||||||
|
|
||||||
``nghttpx`` is a multi-threaded reverse proxy for HTTP/2, and
|
``nghttpx`` is a multi-threaded reverse proxy for HTTP/3, HTTP/2, and
|
||||||
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
|
HTTP/1.1, and powers http://nghttp2.org and supports HTTP/2 server
|
||||||
push.
|
push.
|
||||||
|
|
||||||
@@ -755,16 +867,16 @@ ticket keys among multiple ``nghttpx`` instances via memcached.
|
|||||||
|
|
||||||
``nghttpx`` has 2 operation modes:
|
``nghttpx`` has 2 operation modes:
|
||||||
|
|
||||||
================== ================ ================ =============
|
================== ======================== ================ =============
|
||||||
Mode option Frontend Backend Note
|
Mode option Frontend Backend Note
|
||||||
================== ================ ================ =============
|
================== ======================== ================ =============
|
||||||
default mode HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
|
default mode HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Reverse proxy
|
||||||
``--http2-proxy`` HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
|
``--http2-proxy`` HTTP/3, HTTP/2, HTTP/1.1 HTTP/1.1, HTTP/2 Forward proxy
|
||||||
================== ================ ================ =============
|
================== ======================== ================ =============
|
||||||
|
|
||||||
The interesting mode at the moment is the default mode. It works like
|
The interesting mode at the moment is the default mode. It works like
|
||||||
a reverse proxy and listens for HTTP/2, and HTTP/1.1 and can be
|
a reverse proxy and listens for HTTP/3, HTTP/2, and HTTP/1.1 and can
|
||||||
deployed as a SSL/TLS terminator for existing web server.
|
be deployed as a SSL/TLS terminator for existing web server.
|
||||||
|
|
||||||
In all modes, the frontend connections are encrypted by SSL/TLS by
|
In all modes, the frontend connections are encrypted by SSL/TLS by
|
||||||
default. To disable encryption, use the ``no-tls`` keyword in
|
default. To disable encryption, use the ``no-tls`` keyword in
|
||||||
@@ -782,7 +894,7 @@ server:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
|
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1, HTTP/2) --> Web Server
|
||||||
[reverse proxy]
|
[reverse proxy]
|
||||||
|
|
||||||
With the ``--http2-proxy`` option, it works as forward proxy, and it
|
With the ``--http2-proxy`` option, it works as forward proxy, and it
|
||||||
@@ -790,7 +902,7 @@ is so called secure HTTP/2 proxy:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/1.1) --> Proxy
|
||||||
[secure proxy] (e.g., Squid, ATS)
|
[secure proxy] (e.g., Squid, ATS)
|
||||||
|
|
||||||
The ``Client`` in the above example needs to be configured to use
|
The ``Client`` in the above example needs to be configured to use
|
||||||
@@ -823,7 +935,7 @@ proxy through an HTTP proxy:
|
|||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
Client <-- (HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
Client <-- (HTTP/3, HTTP/2, HTTP/1.1) --> nghttpx <-- (HTTP/2) --
|
||||||
|
|
||||||
--===================---> HTTP/2 Proxy
|
--===================---> HTTP/2 Proxy
|
||||||
(HTTP proxy tunnel) (e.g., nghttpx -s)
|
(HTTP proxy tunnel) (e.g., nghttpx -s)
|
||||||
@@ -831,8 +943,8 @@ proxy through an HTTP proxy:
|
|||||||
Benchmarking tool
|
Benchmarking tool
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The ``h2load`` program is a benchmarking tool for HTTP/2. The UI of
|
The ``h2load`` program is a benchmarking tool for HTTP/3, HTTP/2, and
|
||||||
``h2load`` is heavily inspired by ``weighttp``
|
HTTP/1.1. The UI of ``h2load`` is heavily inspired by ``weighttp``
|
||||||
(https://github.com/lighttpd/weighttp). The typical usage is as
|
(https://github.com/lighttpd/weighttp). The typical usage is as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@@ -875,6 +987,14 @@ threads to avoid saturating a single core on client side.
|
|||||||
considered a DOS attack. Please only use it against your private
|
considered a DOS attack. Please only use it against your private
|
||||||
servers.
|
servers.
|
||||||
|
|
||||||
|
If the experimental HTTP/3 is enabled, h2load can send requests to
|
||||||
|
HTTP/3 server. To do this, specify ``h3`` to ``--npn-list`` option
|
||||||
|
like so:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ h2load --npn-list h3 https://127.0.0.1:4433
|
||||||
|
|
||||||
HPACK tools
|
HPACK tools
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
13
bpf/CMakeLists.txt
Normal file
13
bpf/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
if(LIBBPF_FOUND)
|
||||||
|
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
|
||||||
|
COMMAND ${CMAKE_C_COMPILER} ${BPFCFLAGS} ${EXTRABPFCFLAGS} -I${LIBBPF_INCLUDE_DIRS} -target bpf -c reuseport_kern.c -o "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
add_custom_target(bpf ALL
|
||||||
|
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/reuseport_kern.o"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/${CMAKE_PROJECT_NAME}")
|
||||||
|
endif()
|
||||||
40
bpf/Makefile.am
Normal file
40
bpf/Makefile.am
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# nghttp2 - HTTP/2 C Library
|
||||||
|
|
||||||
|
# Copyright (c) 2021 Tatsuhiro Tsujikawa
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
EXTRA_DIST = CMakeLists.txt reuseport_kern.c
|
||||||
|
|
||||||
|
if HAVE_LIBBPF
|
||||||
|
|
||||||
|
bpf_pkglibdir = $(pkglibdir)
|
||||||
|
bpf_pkglib_DATA = reuseport_kern.o
|
||||||
|
|
||||||
|
all: $(builddir)/reuseport_kern.o
|
||||||
|
|
||||||
|
$(builddir)/reuseport_kern.o: reuseport_kern.c
|
||||||
|
$(CC) @LIBBPF_CFLAGS@ @BPFCFLAGS@ @EXTRABPFCFLAGS@ \
|
||||||
|
-target bpf -c $< -o $@
|
||||||
|
|
||||||
|
clean-local:
|
||||||
|
-rm -f reuseport_kern.o
|
||||||
|
|
||||||
|
endif # HAVE_LIBBPF
|
||||||
663
bpf/reuseport_kern.c
Normal file
663
bpf/reuseport_kern.c
Normal file
@@ -0,0 +1,663 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How to compile:
|
||||||
|
*
|
||||||
|
* clang-12 -O2 -Wall -target bpf -g -c reuseport_kern.c -o reuseport_kern.o \
|
||||||
|
* -I/path/to/kernel/include
|
||||||
|
*
|
||||||
|
* See
|
||||||
|
* https://www.kernel.org/doc/Documentation/kbuild/headers_install.txt
|
||||||
|
* how to install kernel header files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* AES_CBC_decrypt_buffer: https://github.com/kokke/tiny-AES-c
|
||||||
|
License is Public Domain. Commit hash:
|
||||||
|
12e7744b4919e9d55de75b7ab566326a1c8e7a67 */
|
||||||
|
|
||||||
|
#define AES_BLOCKLEN \
|
||||||
|
16 /* Block length in bytes - AES is 128b block \
|
||||||
|
only */
|
||||||
|
|
||||||
|
#define AES_KEYLEN 16 /* Key length in bytes */
|
||||||
|
#define AES_keyExpSize 176
|
||||||
|
|
||||||
|
struct AES_ctx {
|
||||||
|
__u8 RoundKey[AES_keyExpSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The number of columns comprising a state in AES. This is a constant
|
||||||
|
in AES. Value=4 */
|
||||||
|
#define Nb 4
|
||||||
|
|
||||||
|
#define Nk 4 /* The number of 32 bit words in a key. */
|
||||||
|
#define Nr 10 /* The number of rounds in AES Cipher. */
|
||||||
|
|
||||||
|
/* state - array holding the intermediate results during
|
||||||
|
decryption. */
|
||||||
|
typedef __u8 state_t[4][4];
|
||||||
|
|
||||||
|
/* The lookup-tables are marked const so they can be placed in
|
||||||
|
read-only storage instead of RAM The numbers below can be computed
|
||||||
|
dynamically trading ROM for RAM - This can be useful in (embedded)
|
||||||
|
bootloader applications, where ROM is often limited. */
|
||||||
|
static const __u8 sbox[256] = {
|
||||||
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
|
||||||
|
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||||
|
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
|
||||||
|
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
|
||||||
|
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||||
|
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
|
||||||
|
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
|
||||||
|
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||||
|
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
|
||||||
|
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
|
||||||
|
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||||
|
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
|
||||||
|
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
|
||||||
|
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||||
|
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
|
||||||
|
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
|
||||||
|
0xb0, 0x54, 0xbb, 0x16};
|
||||||
|
|
||||||
|
static const __u8 rsbox[256] = {
|
||||||
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
|
||||||
|
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
||||||
|
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
|
||||||
|
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||||
|
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
|
||||||
|
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||||
|
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
|
||||||
|
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||||
|
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
|
||||||
|
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
||||||
|
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
|
||||||
|
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||||
|
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
|
||||||
|
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
||||||
|
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
|
||||||
|
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||||
|
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
|
||||||
|
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
||||||
|
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
|
||||||
|
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||||
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
|
||||||
|
0x55, 0x21, 0x0c, 0x7d};
|
||||||
|
|
||||||
|
/* The round constant word array, Rcon[i], contains the values given
|
||||||
|
by x to the power (i-1) being powers of x (x is denoted as {02}) in
|
||||||
|
the field GF(2^8) */
|
||||||
|
static const __u8 Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
|
||||||
|
0x20, 0x40, 0x80, 0x1b, 0x36};
|
||||||
|
|
||||||
|
#define getSBoxValue(num) (sbox[(num)])
|
||||||
|
|
||||||
|
/* This function produces Nb(Nr+1) round keys. The round keys are used
|
||||||
|
in each round to decrypt the states. */
|
||||||
|
static void KeyExpansion(__u8 *RoundKey, const __u8 *Key) {
|
||||||
|
unsigned i, j, k;
|
||||||
|
__u8 tempa[4]; /* Used for the column/row operations */
|
||||||
|
|
||||||
|
/* The first round key is the key itself. */
|
||||||
|
for (i = 0; i < Nk; ++i) {
|
||||||
|
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||||
|
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||||
|
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||||
|
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All other round keys are found from the previous round keys. */
|
||||||
|
for (i = Nk; i < Nb * (Nr + 1); ++i) {
|
||||||
|
{
|
||||||
|
k = (i - 1) * 4;
|
||||||
|
tempa[0] = RoundKey[k + 0];
|
||||||
|
tempa[1] = RoundKey[k + 1];
|
||||||
|
tempa[2] = RoundKey[k + 2];
|
||||||
|
tempa[3] = RoundKey[k + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % Nk == 0) {
|
||||||
|
/* This function shifts the 4 bytes in a word to the left once.
|
||||||
|
[a0,a1,a2,a3] becomes [a1,a2,a3,a0] */
|
||||||
|
|
||||||
|
/* Function RotWord() */
|
||||||
|
{
|
||||||
|
const __u8 u8tmp = tempa[0];
|
||||||
|
tempa[0] = tempa[1];
|
||||||
|
tempa[1] = tempa[2];
|
||||||
|
tempa[2] = tempa[3];
|
||||||
|
tempa[3] = u8tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SubWord() is a function that takes a four-byte input word and
|
||||||
|
applies the S-box to each of the four bytes to produce an
|
||||||
|
output word. */
|
||||||
|
|
||||||
|
/* Function Subword() */
|
||||||
|
{
|
||||||
|
tempa[0] = getSBoxValue(tempa[0]);
|
||||||
|
tempa[1] = getSBoxValue(tempa[1]);
|
||||||
|
tempa[2] = getSBoxValue(tempa[2]);
|
||||||
|
tempa[3] = getSBoxValue(tempa[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempa[0] = tempa[0] ^ Rcon[i / Nk];
|
||||||
|
}
|
||||||
|
j = i * 4;
|
||||||
|
k = (i - Nk) * 4;
|
||||||
|
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||||
|
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||||
|
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||||
|
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AES_init_ctx(struct AES_ctx *ctx, const __u8 *key) {
|
||||||
|
KeyExpansion(ctx->RoundKey, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function adds the round key to state. The round key is added
|
||||||
|
to the state by an XOR function. */
|
||||||
|
static void AddRoundKey(__u8 round, state_t *state, const __u8 *RoundKey) {
|
||||||
|
__u8 i, j;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __u8 xtime(__u8 x) { return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); }
|
||||||
|
|
||||||
|
#define Multiply(x, y) \
|
||||||
|
(((y & 1) * x) ^ ((y >> 1 & 1) * xtime(x)) ^ \
|
||||||
|
((y >> 2 & 1) * xtime(xtime(x))) ^ \
|
||||||
|
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||||
|
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))))
|
||||||
|
|
||||||
|
#define getSBoxInvert(num) (rsbox[(num)])
|
||||||
|
|
||||||
|
/* MixColumns function mixes the columns of the state matrix. The
|
||||||
|
method used to multiply may be difficult to understand for the
|
||||||
|
inexperienced. Please use the references to gain more
|
||||||
|
information. */
|
||||||
|
static void InvMixColumns(state_t *state) {
|
||||||
|
int i;
|
||||||
|
__u8 a, b, c, d;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
a = (*state)[i][0];
|
||||||
|
b = (*state)[i][1];
|
||||||
|
c = (*state)[i][2];
|
||||||
|
d = (*state)[i][3];
|
||||||
|
|
||||||
|
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^
|
||||||
|
Multiply(d, 0x09);
|
||||||
|
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^
|
||||||
|
Multiply(d, 0x0d);
|
||||||
|
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^
|
||||||
|
Multiply(d, 0x0b);
|
||||||
|
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^
|
||||||
|
Multiply(d, 0x0e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern __u32 LINUX_KERNEL_VERSION __kconfig;
|
||||||
|
|
||||||
|
/* The SubBytes Function Substitutes the values in the state matrix
|
||||||
|
with values in an S-box. */
|
||||||
|
static void InvSubBytes(state_t *state) {
|
||||||
|
__u8 i, j;
|
||||||
|
if (LINUX_KERNEL_VERSION < KERNEL_VERSION(5, 10, 0)) {
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
/* Ubuntu 20.04 LTS kernel 5.4.0 needs this workaround
|
||||||
|
otherwise "math between map_value pointer and register with
|
||||||
|
unbounded min value is not allowed". 5.10.0 is a kernel
|
||||||
|
version that works but it might not be the minimum
|
||||||
|
version. */
|
||||||
|
__u8 k = (*state)[j][i];
|
||||||
|
(*state)[j][i] = k ? getSBoxInvert(k) : getSBoxInvert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
for (j = 0; j < 4; ++j) {
|
||||||
|
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvShiftRows(state_t *state) {
|
||||||
|
__u8 temp;
|
||||||
|
|
||||||
|
/* Rotate first row 1 columns to right */
|
||||||
|
temp = (*state)[3][1];
|
||||||
|
(*state)[3][1] = (*state)[2][1];
|
||||||
|
(*state)[2][1] = (*state)[1][1];
|
||||||
|
(*state)[1][1] = (*state)[0][1];
|
||||||
|
(*state)[0][1] = temp;
|
||||||
|
|
||||||
|
/* Rotate second row 2 columns to right */
|
||||||
|
temp = (*state)[0][2];
|
||||||
|
(*state)[0][2] = (*state)[2][2];
|
||||||
|
(*state)[2][2] = temp;
|
||||||
|
|
||||||
|
temp = (*state)[1][2];
|
||||||
|
(*state)[1][2] = (*state)[3][2];
|
||||||
|
(*state)[3][2] = temp;
|
||||||
|
|
||||||
|
/* Rotate third row 3 columns to right */
|
||||||
|
temp = (*state)[0][3];
|
||||||
|
(*state)[0][3] = (*state)[1][3];
|
||||||
|
(*state)[1][3] = (*state)[2][3];
|
||||||
|
(*state)[2][3] = (*state)[3][3];
|
||||||
|
(*state)[3][3] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InvCipher(state_t *state, const __u8 *RoundKey) {
|
||||||
|
/* Add the First round key to the state before starting the
|
||||||
|
rounds. */
|
||||||
|
AddRoundKey(Nr, state, RoundKey);
|
||||||
|
|
||||||
|
/* There will be Nr rounds. The first Nr-1 rounds are identical.
|
||||||
|
These Nr rounds are executed in the loop below. Last one without
|
||||||
|
InvMixColumn() */
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 1, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 2, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 3, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 4, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 5, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 6, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 7, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 8, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 9, state, RoundKey);
|
||||||
|
InvMixColumns(state);
|
||||||
|
|
||||||
|
InvShiftRows(state);
|
||||||
|
InvSubBytes(state);
|
||||||
|
AddRoundKey(Nr - 10, state, RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AES_ECB_decrypt(const struct AES_ctx *ctx, __u8 *buf) {
|
||||||
|
/* The next function call decrypts the PlainText with the Key using
|
||||||
|
AES algorithm. */
|
||||||
|
InvCipher((state_t *)buf, ctx->RoundKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rol32: From linux kernel source code */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rol32 - rotate a 32-bit value left
|
||||||
|
* @word: value to rotate
|
||||||
|
* @shift: bits to roll
|
||||||
|
*/
|
||||||
|
static inline __u32 rol32(__u32 word, unsigned int shift) {
|
||||||
|
return (word << shift) | (word >> ((-shift) & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* jhash.h: Jenkins hash support.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||||
|
*
|
||||||
|
* https://burtleburtle.net/bob/hash/
|
||||||
|
*
|
||||||
|
* These are the credits from Bob's sources:
|
||||||
|
*
|
||||||
|
* lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||||
|
*
|
||||||
|
* These are functions for producing 32-bit hashes for hash table lookup.
|
||||||
|
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||||
|
* are externally useful functions. Routines to test the hash are included
|
||||||
|
* if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||||
|
* the public domain. It has no warranty.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* I've modified Bob's hash to be useful in the Linux kernel, and
|
||||||
|
* any bugs present are my fault.
|
||||||
|
* Jozsef
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
|
||||||
|
#define __jhash_final(a, b, c) \
|
||||||
|
{ \
|
||||||
|
c ^= b; \
|
||||||
|
c -= rol32(b, 14); \
|
||||||
|
a ^= c; \
|
||||||
|
a -= rol32(c, 11); \
|
||||||
|
b ^= a; \
|
||||||
|
b -= rol32(a, 25); \
|
||||||
|
c ^= b; \
|
||||||
|
c -= rol32(b, 16); \
|
||||||
|
a ^= c; \
|
||||||
|
a -= rol32(c, 4); \
|
||||||
|
b ^= a; \
|
||||||
|
b -= rol32(a, 14); \
|
||||||
|
c ^= b; \
|
||||||
|
c -= rol32(b, 24); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */
|
||||||
|
static inline __u32 __jhash_nwords(__u32 a, __u32 b, __u32 c, __u32 initval) {
|
||||||
|
a += initval;
|
||||||
|
b += initval;
|
||||||
|
c += initval;
|
||||||
|
|
||||||
|
__jhash_final(a, b, c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* An arbitrary initial parameter */
|
||||||
|
#define JHASH_INITVAL 0xdeadbeef
|
||||||
|
|
||||||
|
static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval) {
|
||||||
|
return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bpf_map_def SEC("maps") cid_prefix_map = {
|
||||||
|
.type = BPF_MAP_TYPE_HASH,
|
||||||
|
.max_entries = 255,
|
||||||
|
.key_size = sizeof(__u64),
|
||||||
|
.value_size = sizeof(__u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_map_def SEC("maps") reuseport_array = {
|
||||||
|
.type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
|
||||||
|
.max_entries = 255,
|
||||||
|
.key_size = sizeof(__u32),
|
||||||
|
.value_size = sizeof(__u32),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bpf_map_def SEC("maps") sk_info = {
|
||||||
|
.type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.max_entries = 3,
|
||||||
|
.key_size = sizeof(__u32),
|
||||||
|
.value_size = sizeof(__u64),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct quic_hd {
|
||||||
|
__u8 *dcid;
|
||||||
|
__u32 dcidlen;
|
||||||
|
__u32 dcid_offset;
|
||||||
|
__u8 type;
|
||||||
|
} quic_hd;
|
||||||
|
|
||||||
|
#define SV_DCIDLEN 20
|
||||||
|
#define MAX_DCIDLEN 20
|
||||||
|
#define MIN_DCIDLEN 8
|
||||||
|
#define CID_PREFIXLEN 8
|
||||||
|
#define CID_PREFIX_OFFSET 1
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NGTCP2_PKT_INITIAL = 0x0,
|
||||||
|
NGTCP2_PKT_0RTT = 0x1,
|
||||||
|
NGTCP2_PKT_HANDSHAKE = 0x2,
|
||||||
|
NGTCP2_PKT_SHORT = 0x40,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int parse_quic(quic_hd *qhd, __u8 *data, __u8 *data_end) {
|
||||||
|
__u8 *p;
|
||||||
|
__u64 dcidlen;
|
||||||
|
|
||||||
|
if (*data & 0x80) {
|
||||||
|
p = data + 1 + 4;
|
||||||
|
|
||||||
|
/* Do not check the actual DCID length because we might not buffer
|
||||||
|
entire DCID here. */
|
||||||
|
dcidlen = *p;
|
||||||
|
|
||||||
|
if (dcidlen > MAX_DCIDLEN || dcidlen < MIN_DCIDLEN) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
qhd->type = (*data & 0x30) >> 4;
|
||||||
|
qhd->dcid = p;
|
||||||
|
qhd->dcidlen = dcidlen;
|
||||||
|
qhd->dcid_offset = 6;
|
||||||
|
} else {
|
||||||
|
qhd->type = NGTCP2_PKT_SHORT;
|
||||||
|
qhd->dcid = data + 1;
|
||||||
|
qhd->dcidlen = SV_DCIDLEN;
|
||||||
|
qhd->dcid_offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __u32 hash(const __u8 *data, __u32 datalen, __u32 initval) {
|
||||||
|
__u32 a, b;
|
||||||
|
|
||||||
|
a = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||||
|
b = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
|
||||||
|
|
||||||
|
return jhash_2words(a, b, initval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static __u32 sk_index_from_dcid(const quic_hd *qhd,
|
||||||
|
const struct sk_reuseport_md *reuse_md,
|
||||||
|
__u64 num_socks) {
|
||||||
|
__u32 len = qhd->dcidlen;
|
||||||
|
__u32 h = reuse_md->hash;
|
||||||
|
__u8 hbuf[8];
|
||||||
|
|
||||||
|
if (len > 16) {
|
||||||
|
__builtin_memset(hbuf, 0, sizeof(hbuf));
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 20:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 16, 4);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 16, 3);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 16, 2);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 16, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = hash(hbuf, sizeof(hbuf), h);
|
||||||
|
len = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 8) {
|
||||||
|
__builtin_memset(hbuf, 0, sizeof(hbuf));
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 16:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 8);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 7);
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 6);
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 5);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 4);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 3);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 2);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
__builtin_memcpy(hbuf, qhd->dcid + 8, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = hash(hbuf, sizeof(hbuf), h);
|
||||||
|
len = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash(qhd->dcid, len, h) % num_socks;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEC("sk_reuseport")
|
||||||
|
int select_reuseport(struct sk_reuseport_md *reuse_md) {
|
||||||
|
__u32 sk_index, *psk_index;
|
||||||
|
__u64 *pnum_socks, *pkey;
|
||||||
|
__u32 zero = 0, key_high_idx = 1, key_low_idx = 2;
|
||||||
|
int rv;
|
||||||
|
quic_hd qhd;
|
||||||
|
__u8 qpktbuf[6 + MAX_DCIDLEN];
|
||||||
|
struct AES_ctx aes_ctx;
|
||||||
|
__u8 key[AES_KEYLEN];
|
||||||
|
__u8 *cid_prefix;
|
||||||
|
|
||||||
|
if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr), qpktbuf,
|
||||||
|
sizeof(qpktbuf)) != 0) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
pnum_socks = bpf_map_lookup_elem(&sk_info, &zero);
|
||||||
|
if (pnum_socks == NULL) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = bpf_map_lookup_elem(&sk_info, &key_high_idx);
|
||||||
|
if (pkey == NULL) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
__builtin_memcpy(key, pkey, sizeof(*pkey));
|
||||||
|
|
||||||
|
pkey = bpf_map_lookup_elem(&sk_info, &key_low_idx);
|
||||||
|
if (pkey == NULL) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
__builtin_memcpy(key + sizeof(*pkey), pkey, sizeof(*pkey));
|
||||||
|
|
||||||
|
rv = parse_quic(&qhd, qpktbuf, qpktbuf + sizeof(qpktbuf));
|
||||||
|
if (rv != 0) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
AES_init_ctx(&aes_ctx, key);
|
||||||
|
|
||||||
|
switch (qhd.type) {
|
||||||
|
case NGTCP2_PKT_INITIAL:
|
||||||
|
case NGTCP2_PKT_0RTT:
|
||||||
|
if (qhd.dcidlen == SV_DCIDLEN) {
|
||||||
|
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
|
||||||
|
AES_ECB_decrypt(&aes_ctx, cid_prefix);
|
||||||
|
|
||||||
|
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
|
||||||
|
if (psk_index != NULL) {
|
||||||
|
sk_index = *psk_index;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NGTCP2_PKT_HANDSHAKE:
|
||||||
|
case NGTCP2_PKT_SHORT:
|
||||||
|
if (qhd.dcidlen != SV_DCIDLEN) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
cid_prefix = qhd.dcid + CID_PREFIX_OFFSET;
|
||||||
|
AES_ECB_decrypt(&aes_ctx, cid_prefix);
|
||||||
|
|
||||||
|
psk_index = bpf_map_lookup_elem(&cid_prefix_map, cid_prefix);
|
||||||
|
if (psk_index == NULL) {
|
||||||
|
sk_index = sk_index_from_dcid(&qhd, reuse_md, *pnum_socks);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_index = *psk_index;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = bpf_sk_select_reuseport(reuse_md, &reuseport_array, &sk_index, 0);
|
||||||
|
if (rv != 0) {
|
||||||
|
return SK_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SK_PASS;
|
||||||
|
}
|
||||||
32
cmake/FindLibbpf.cmake
Normal file
32
cmake/FindLibbpf.cmake
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# - Try to find libbpf
|
||||||
|
# Once done this will define
|
||||||
|
# LIBBPF_FOUND - System has libbpf
|
||||||
|
# LIBBPF_INCLUDE_DIRS - The libbpf include directories
|
||||||
|
# LIBBPF_LIBRARIES - The libraries needed to use libbpf
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(PC_LIBBPF QUIET libbpf)
|
||||||
|
|
||||||
|
find_path(LIBBPF_INCLUDE_DIR
|
||||||
|
NAMES bpf/bpf.h
|
||||||
|
HINTS ${PC_LIBBPF_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
find_library(LIBBPF_LIBRARY
|
||||||
|
NAMES bpf
|
||||||
|
HINTS ${PC_LIBBPF_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set LIBBPF_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE and the requested version
|
||||||
|
# matches.
|
||||||
|
find_package_handle_standard_args(Libbpf REQUIRED_VARS
|
||||||
|
LIBBPF_LIBRARY LIBBPF_INCLUDE_DIR
|
||||||
|
VERSION_VAR LIBBPF_VERSION)
|
||||||
|
|
||||||
|
if(LIBBPF_FOUND)
|
||||||
|
set(LIBBPF_LIBRARIES ${LIBBPF_LIBRARY})
|
||||||
|
set(LIBBPF_INCLUDE_DIRS ${LIBBPF_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(LIBBPF_INCLUDE_DIR LIBBPF_LIBRARY)
|
||||||
41
cmake/FindLibnghttp3.cmake
Normal file
41
cmake/FindLibnghttp3.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# - Try to find libnghttp3
|
||||||
|
# Once done this will define
|
||||||
|
# LIBNGHTTP3_FOUND - System has libnghttp3
|
||||||
|
# LIBNGHTTP3_INCLUDE_DIRS - The libnghttp3 include directories
|
||||||
|
# LIBNGHTTP3_LIBRARIES - The libraries needed to use libnghttp3
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(PC_LIBNGHTTP3 QUIET libnghttp3)
|
||||||
|
|
||||||
|
find_path(LIBNGHTTP3_INCLUDE_DIR
|
||||||
|
NAMES nghttp3/nghttp3.h
|
||||||
|
HINTS ${PC_LIBNGHTTP3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
find_library(LIBNGHTTP3_LIBRARY
|
||||||
|
NAMES nghttp3
|
||||||
|
HINTS ${PC_LIBNGHTTP3_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(LIBNGHTTP3_INCLUDE_DIR)
|
||||||
|
set(_version_regex "^#define[ \t]+NGHTTP3_VERSION[ \t]+\"([^\"]+)\".*")
|
||||||
|
file(STRINGS "${LIBNGHTTP3_INCLUDE_DIR}/nghttp3/version.h"
|
||||||
|
LIBNGHTTP3_VERSION REGEX "${_version_regex}")
|
||||||
|
string(REGEX REPLACE "${_version_regex}" "\\1"
|
||||||
|
LIBNGHTTP3_VERSION "${LIBNGHTTP3_VERSION}")
|
||||||
|
unset(_version_regex)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set LIBNGHTTP3_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE and the requested version
|
||||||
|
# matches.
|
||||||
|
find_package_handle_standard_args(Libnghttp3 REQUIRED_VARS
|
||||||
|
LIBNGHTTP3_LIBRARY LIBNGHTTP3_INCLUDE_DIR
|
||||||
|
VERSION_VAR LIBNGHTTP3_VERSION)
|
||||||
|
|
||||||
|
if(LIBNGHTTP3_FOUND)
|
||||||
|
set(LIBNGHTTP3_LIBRARIES ${LIBNGHTTP3_LIBRARY})
|
||||||
|
set(LIBNGHTTP3_INCLUDE_DIRS ${LIBNGHTTP3_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(LIBNGHTTP3_INCLUDE_DIR LIBNGHTTP3_LIBRARY)
|
||||||
41
cmake/FindLibngtcp2.cmake
Normal file
41
cmake/FindLibngtcp2.cmake
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# - Try to find libngtcp2
|
||||||
|
# Once done this will define
|
||||||
|
# LIBNGTCP2_FOUND - System has libngtcp2
|
||||||
|
# LIBNGTCP2_INCLUDE_DIRS - The libngtcp2 include directories
|
||||||
|
# LIBNGTCP2_LIBRARIES - The libraries needed to use libngtcp2
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(PC_LIBNGTCP2 QUIET libngtcp2)
|
||||||
|
|
||||||
|
find_path(LIBNGTCP2_INCLUDE_DIR
|
||||||
|
NAMES ngtcp2/ngtcp2.h
|
||||||
|
HINTS ${PC_LIBNGTCP2_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
find_library(LIBNGTCP2_LIBRARY
|
||||||
|
NAMES ngtcp2
|
||||||
|
HINTS ${PC_LIBNGTCP2_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(LIBNGTCP2_INCLUDE_DIR)
|
||||||
|
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
|
||||||
|
file(STRINGS "${LIBNGTCP2_INCLUDE_DIR}/ngtcp2/version.h"
|
||||||
|
LIBNGTCP2_VERSION REGEX "${_version_regex}")
|
||||||
|
string(REGEX REPLACE "${_version_regex}" "\\1"
|
||||||
|
LIBNGTCP2_VERSION "${LIBNGTCP2_VERSION}")
|
||||||
|
unset(_version_regex)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set LIBNGTCP2_FOUND
|
||||||
|
# to TRUE if all listed variables are TRUE and the requested version
|
||||||
|
# matches.
|
||||||
|
find_package_handle_standard_args(Libngtcp2 REQUIRED_VARS
|
||||||
|
LIBNGTCP2_LIBRARY LIBNGTCP2_INCLUDE_DIR
|
||||||
|
VERSION_VAR LIBNGTCP2_VERSION)
|
||||||
|
|
||||||
|
if(LIBNGTCP2_FOUND)
|
||||||
|
set(LIBNGTCP2_LIBRARIES ${LIBNGTCP2_LIBRARY})
|
||||||
|
set(LIBNGTCP2_INCLUDE_DIRS ${LIBNGTCP2_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(LIBNGTCP2_INCLUDE_DIR LIBNGTCP2_LIBRARY)
|
||||||
43
cmake/FindLibngtcp2_crypto_openssl.cmake
Normal file
43
cmake/FindLibngtcp2_crypto_openssl.cmake
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# - Try to find libngtcp2_crypto_openssl
|
||||||
|
# Once done this will define
|
||||||
|
# LIBNGTCP2_CRYPTO_OPENSSL_FOUND - System has libngtcp2_crypto_openssl
|
||||||
|
# LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS - The libngtcp2_crypto_openssl include directories
|
||||||
|
# LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES - The libraries needed to use libngtcp2_crypto_openssl
|
||||||
|
|
||||||
|
find_package(PkgConfig QUIET)
|
||||||
|
pkg_check_modules(PC_LIBNGTCP2_CRYPTO_OPENSSL QUIET libngtcp2_crypto_openssl)
|
||||||
|
|
||||||
|
find_path(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
|
||||||
|
NAMES ngtcp2/ngtcp2_crypto_openssl.h
|
||||||
|
HINTS ${PC_LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
find_library(LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY
|
||||||
|
NAMES ngtcp2_crypto_openssl
|
||||||
|
HINTS ${PC_LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR)
|
||||||
|
set(_version_regex "^#define[ \t]+NGTCP2_VERSION[ \t]+\"([^\"]+)\".*")
|
||||||
|
file(STRINGS "${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR}/ngtcp2/version.h"
|
||||||
|
LIBNGTCP2_CRYPTO_OPENSSL_VERSION REGEX "${_version_regex}")
|
||||||
|
string(REGEX REPLACE "${_version_regex}" "\\1"
|
||||||
|
LIBNGTCP2_CRYPTO_OPENSSL_VERSION "${LIBNGTCP2_CRYPTO_OPENSSL_VERSION}")
|
||||||
|
unset(_version_regex)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
# handle the QUIETLY and REQUIRED arguments and set
|
||||||
|
# LIBNGTCP2_CRYPTO_OPENSSL_FOUND to TRUE if all listed variables are
|
||||||
|
# TRUE and the requested version matches.
|
||||||
|
find_package_handle_standard_args(Libngtcp2_crypto_openssl REQUIRED_VARS
|
||||||
|
LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY
|
||||||
|
LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
|
||||||
|
VERSION_VAR LIBNGTCP2_CRYPTO_OPENSSL_VERSION)
|
||||||
|
|
||||||
|
if(LIBNGTCP2_CRYPTO_OPENSSL_FOUND)
|
||||||
|
set(LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES ${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY})
|
||||||
|
set(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS ${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIR
|
||||||
|
LIBNGTCP2_CRYPTO_OPENSSL_LIBRARY)
|
||||||
@@ -15,5 +15,5 @@ find_library(SYSTEMD_LIBRARIES NAMES systemd ${PC_SYSTEMD_LIBRARY_DIRS})
|
|||||||
find_path(SYSTEMD_INCLUDE_DIRS systemd/sd-login.h HINTS ${PC_SYSTEMD_INCLUDE_DIRS})
|
find_path(SYSTEMD_INCLUDE_DIRS systemd/sd-login.h HINTS ${PC_SYSTEMD_INCLUDE_DIRS})
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(SYSTEMD DEFAULT_MSG SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
|
find_package_handle_standard_args(Systemd DEFAULT_MSG SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
|
||||||
mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
|
mark_as_advanced(SYSTEMD_INCLUDE_DIRS SYSTEMD_LIBRARIES)
|
||||||
|
|||||||
@@ -78,3 +78,15 @@
|
|||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
#cmakedefine HAVE_UNISTD_H 1
|
#cmakedefine HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if HTTP/3 is enabled. */
|
||||||
|
#cmakedefine ENABLE_HTTP3 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have `libbpf` library. */
|
||||||
|
#cmakedefine HAVE_LIBBPF 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have enum bpf_stats_type in linux/bpf.h. */
|
||||||
|
#cmakedefine HAVE_BPF_STATS_TYPE 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have `libngtcp2_crypto_openssl` library. */
|
||||||
|
#cmakedefine HAVE_LIBNGTCP2_CRYPTO_OPENSSL
|
||||||
|
|||||||
236
configure.ac
236
configure.ac
@@ -22,10 +22,10 @@ dnl OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|||||||
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
dnl WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
dnl Do not change user variables!
|
dnl Do not change user variables!
|
||||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([nghttp2], [1.45.0-DEV], [t-tujikawa@users.sourceforge.net])
|
AC_INIT([nghttp2], [1.47.0-DEV], [t-tujikawa@users.sourceforge.net])
|
||||||
AC_CONFIG_AUX_DIR([.])
|
AC_CONFIG_AUX_DIR([.])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
@@ -43,10 +43,10 @@ AM_INIT_AUTOMAKE([subdir-objects])
|
|||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
dnl See versioning rule:
|
dnl See versioning rule:
|
||||||
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
dnl https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
AC_SUBST(LT_CURRENT, 34)
|
AC_SUBST(LT_CURRENT, 35)
|
||||||
AC_SUBST(LT_REVISION, 2)
|
AC_SUBST(LT_REVISION, 1)
|
||||||
AC_SUBST(LT_AGE, 20)
|
AC_SUBST(LT_AGE, 21)
|
||||||
|
|
||||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
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"`
|
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
|
||||||
@@ -107,6 +107,11 @@ AC_ARG_ENABLE([lib-only],
|
|||||||
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
|
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
|
||||||
[request_lib_only=$enableval], [request_lib_only=no])
|
[request_lib_only=$enableval], [request_lib_only=no])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([http3],
|
||||||
|
[AS_HELP_STRING([--enable-http3],
|
||||||
|
[(EXPERIMENTAL) Enable HTTP/3. This requires ngtcp2, nghttp3, and a custom OpenSSL.])],
|
||||||
|
[request_http3=$enableval], [request_http3=no])
|
||||||
|
|
||||||
AC_ARG_WITH([libxml2],
|
AC_ARG_WITH([libxml2],
|
||||||
[AS_HELP_STRING([--with-libxml2],
|
[AS_HELP_STRING([--with-libxml2],
|
||||||
[Use libxml2 [default=check]])],
|
[Use libxml2 [default=check]])],
|
||||||
@@ -172,6 +177,21 @@ AC_ARG_WITH([cython],
|
|||||||
[Use cython in given PATH])],
|
[Use cython in given PATH])],
|
||||||
[cython_path=$withval], [])
|
[cython_path=$withval], [])
|
||||||
|
|
||||||
|
AC_ARG_WITH([libngtcp2],
|
||||||
|
[AS_HELP_STRING([--with-libngtcp2],
|
||||||
|
[Use libngtcp2 [default=check]])],
|
||||||
|
[request_libngtcp2=$withval], [request_libngtcp2=check])
|
||||||
|
|
||||||
|
AC_ARG_WITH([libnghttp3],
|
||||||
|
[AS_HELP_STRING([--with-libnghttp3],
|
||||||
|
[Use libnghttp3 [default=check]])],
|
||||||
|
[request_libnghttp3=$withval], [request_libnghttp3=check])
|
||||||
|
|
||||||
|
AC_ARG_WITH([libbpf],
|
||||||
|
[AS_HELP_STRING([--with-libbpf],
|
||||||
|
[Use libbpf [default=no]])],
|
||||||
|
[request_libbpf=$withval], [request_libbpf=no])
|
||||||
|
|
||||||
dnl Define variables
|
dnl Define variables
|
||||||
AC_ARG_VAR([CYTHON], [the Cython executable])
|
AC_ARG_VAR([CYTHON], [the Cython executable])
|
||||||
|
|
||||||
@@ -185,6 +205,8 @@ AC_ARG_VAR([JEMALLOC_LIBS], [linker flags for jemalloc, skipping any checks])
|
|||||||
AC_ARG_VAR([LIBTOOL_LDFLAGS],
|
AC_ARG_VAR([LIBTOOL_LDFLAGS],
|
||||||
[libtool specific flags (e.g., -static-libtool-libs)])
|
[libtool specific flags (e.g., -static-libtool-libs)])
|
||||||
|
|
||||||
|
AC_ARG_VAR([BPFCFLAGS], [C compiler flags for bpf program])
|
||||||
|
|
||||||
dnl Checks for programs
|
dnl Checks for programs
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
@@ -198,6 +220,11 @@ PKG_PROG_PKG_CONFIG([0.20])
|
|||||||
|
|
||||||
AM_PATH_PYTHON([3.8],, [:])
|
AM_PATH_PYTHON([3.8],, [:])
|
||||||
|
|
||||||
|
if test "x$request_python_bindings" = "xyes" &&
|
||||||
|
test "x$PYTHON" = "x:"; then
|
||||||
|
AC_MSG_ERROR([python was requested (enable-python-bindings) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
if [test "x$request_lib_only" = "xyes"]; then
|
if [test "x$request_lib_only" = "xyes"]; then
|
||||||
request_app=no
|
request_app=no
|
||||||
request_hpack_tools=no
|
request_hpack_tools=no
|
||||||
@@ -205,8 +232,10 @@ if [test "x$request_lib_only" = "xyes"]; then
|
|||||||
request_python_bindings=no
|
request_python_bindings=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [test "x$request_python_bindings" != "xno"]; then
|
if test "x$request_python_bindings" != "xno" &&
|
||||||
AX_PYTHON_DEVEL([>= '3.8'])
|
test "x$PYTHON" != "x:"; then
|
||||||
|
# version check is broken
|
||||||
|
AX_PYTHON_DEVEL()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x${cython_path}" = "x"; then
|
if test "x${cython_path}" = "x"; then
|
||||||
@@ -245,6 +274,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
|||||||
]],
|
]],
|
||||||
[[
|
[[
|
||||||
std::vector<std::future<int>> v;
|
std::vector<std::future<int>> v;
|
||||||
|
(void)v;
|
||||||
]])],
|
]])],
|
||||||
[AC_DEFINE([HAVE_STD_FUTURE], [1],
|
[AC_DEFINE([HAVE_STD_FUTURE], [1],
|
||||||
[Define to 1 if you have the `std::future`.])
|
[Define to 1 if you have the `std::future`.])
|
||||||
@@ -319,7 +349,7 @@ APPLDFLAGS=
|
|||||||
case "$host_os" in
|
case "$host_os" in
|
||||||
*android*)
|
*android*)
|
||||||
android_build=yes
|
android_build=yes
|
||||||
# android does not need -pthread, but needs followng 3 libs for C++
|
# android does not need -pthread, but needs following 3 libs for C++
|
||||||
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
|
APPLDFLAGS="$APPLDFLAGS -lstdc++ -latomic -lsupc++"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -334,6 +364,13 @@ case "$host_os" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
case "${build}" in
|
||||||
|
*-apple-darwin*)
|
||||||
|
EXTRA_DEFS="-D__APPLE_USE_RFC_3542"
|
||||||
|
AC_SUBST([EXTRA_DEFS])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
# zlib
|
# zlib
|
||||||
have_zlib=no
|
have_zlib=no
|
||||||
if test "x${request_zlib}" != "xno"; then
|
if test "x${request_zlib}" != "xno"; then
|
||||||
@@ -431,6 +468,37 @@ if test "x${request_openssl}" != "xno"; then
|
|||||||
[have_openssl=yes], [have_openssl=no])
|
[have_openssl=yes], [have_openssl=no])
|
||||||
if test "x${have_openssl}" = "xno"; then
|
if test "x${have_openssl}" = "xno"; then
|
||||||
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
|
AC_MSG_NOTICE($OPENSSL_PKG_ERRORS)
|
||||||
|
else
|
||||||
|
save_CFLAGS="$CFLAGS"
|
||||||
|
save_LIBS="$LIBS"
|
||||||
|
CFLAGS="$OPENSSL_CFLAGS $CFLAGS"
|
||||||
|
LIBS="$OPENSSL_LIBS $LIBS"
|
||||||
|
|
||||||
|
# quictls/openssl has SSL_is_quic.
|
||||||
|
have_ssl_is_quic=no
|
||||||
|
AC_MSG_CHECKING([for SSL_is_quic])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
]], [[
|
||||||
|
SSL *ssl = NULL;
|
||||||
|
SSL_is_quic(ssl);
|
||||||
|
]])],
|
||||||
|
[AC_MSG_RESULT([yes]); have_ssl_is_quic=yes],
|
||||||
|
[AC_MSG_RESULT([no]); have_ssl_is_quic=no])
|
||||||
|
|
||||||
|
# boringssl has SSL_set_quic_early_data_context.
|
||||||
|
AC_MSG_CHECKING([for SSL_set_quic_early_data_context])
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
]], [[
|
||||||
|
SSL *ssl = NULL;
|
||||||
|
SSL_set_quic_early_data_context(ssl, NULL, 0);
|
||||||
|
]])],
|
||||||
|
[AC_MSG_RESULT([yes]); have_boringssl_quic=yes],
|
||||||
|
[AC_MSG_RESULT([no]); have_boringssl_quic=no])
|
||||||
|
|
||||||
|
CFLAGS="$save_CFLAGS"
|
||||||
|
LIBS="$save_LIBS"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -454,6 +522,125 @@ if test "x${request_libcares}" = "xyes" &&
|
|||||||
AC_MSG_ERROR([libcares was requested (--with-libcares) but not found])
|
AC_MSG_ERROR([libcares was requested (--with-libcares) but not found])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ngtcp2 (for src)
|
||||||
|
have_libngtcp2=no
|
||||||
|
if test "x${request_libngtcp2}" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBNGTCP2], [libngtcp2 >= 0.1.0], [have_libngtcp2=yes],
|
||||||
|
[have_libngtcp2=no])
|
||||||
|
if test "x${have_libngtcp2}" = "xno"; then
|
||||||
|
AC_MSG_NOTICE($LIBNGTCP2_PKG_ERRORS)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${request_libngtcp2}" = "xyes" &&
|
||||||
|
test "x${have_libngtcp2}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([libngtcp2 was requested (--with-libngtcp2) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ngtcp2_crypto_openssl (for src)
|
||||||
|
have_libngtcp2_crypto_openssl=no
|
||||||
|
if test "x${have_ssl_is_quic}" = "xyes" &&
|
||||||
|
test "x${request_libngtcp2}" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_OPENSSL],
|
||||||
|
[libngtcp2_crypto_openssl >= 0.0.0],
|
||||||
|
[have_libngtcp2_crypto_openssl=yes],
|
||||||
|
[have_libngtcp2_crypto_openssl=no])
|
||||||
|
if test "x${have_libngtcp2_crypto_openssl}" = "xno"; then
|
||||||
|
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_OPENSSL_PKG_ERRORS)
|
||||||
|
else
|
||||||
|
AC_DEFINE([HAVE_LIBNGTCP2_CRYPTO_OPENSSL], [1],
|
||||||
|
[Define to 1 if you have `libngtcp2_crypto_openssl` library.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${have_ssl_is_quic}" = "xyes" &&
|
||||||
|
test "x${request_libngtcp2}" = "xyes" &&
|
||||||
|
test "x${have_libngtcp2_crypto_openssl}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([libngtcp2_crypto_openssl was requested (--with-libngtcp2) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ngtcp2_crypto_boringssl (for src)
|
||||||
|
have_libngtcp2_crypto_boringssl=no
|
||||||
|
if test "x${have_boringssl_quic}" = "xyes" &&
|
||||||
|
test "x${request_libngtcp2}" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBNGTCP2_CRYPTO_BORINGSSL],
|
||||||
|
[libngtcp2_crypto_boringssl >= 0.0.0],
|
||||||
|
[have_libngtcp2_crypto_boringssl=yes],
|
||||||
|
[have_libngtcp2_crypto_boringssl=no])
|
||||||
|
if test "x${have_libngtcp2_crypto_boringssl}" = "xno"; then
|
||||||
|
AC_MSG_NOTICE($LIBNGTCP2_CRYPTO_BORINGSSL_PKG_ERRORS)
|
||||||
|
else
|
||||||
|
AC_DEFINE([HAVE_LIBNGTCP2_CRYPTO_BORINGSSL], [1],
|
||||||
|
[Define to 1 if you have `libngtcp2_crypto_boringssl` library.])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${have_boringssl_quic}" = "xyes" &&
|
||||||
|
test "x${request_libngtcp2}" = "xyes" &&
|
||||||
|
test "x${have_libngtcp2_crypto_boringssl}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([libngtcp2_crypto_boringssl was requested (--with-libngtcp2) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# nghttp3 (for src)
|
||||||
|
have_libnghttp3=no
|
||||||
|
if test "x${request_libnghttp3}" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBNGHTTP3], [libnghttp3 >= 0.1.0], [have_libnghttp3=yes],
|
||||||
|
[have_libnghttp3=no])
|
||||||
|
if test "x${have_libnghttp3}" = "xno"; then
|
||||||
|
AC_MSG_NOTICE($LIBNGHTTP3_PKG_ERRORS)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${request_libnghttp3}" = "xyes" &&
|
||||||
|
test "x${have_libnghttp3}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([libnghttp3 was requested (--with-libnghttp3) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# libbpf (for src)
|
||||||
|
have_libbpf=no
|
||||||
|
if test "x${request_libbpf}" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES([LIBBPF], [libbpf >= 0.4.0], [have_libbpf=yes],
|
||||||
|
[have_libbpf=no])
|
||||||
|
if test "x${have_libbpf}" = "xyes"; then
|
||||||
|
AC_DEFINE([HAVE_LIBBPF], [1], [Define to 1 if you have `libbpf` library.])
|
||||||
|
if test "x${BPFCFLAGS}" = "x"; then
|
||||||
|
BPFCFLAGS="-Wall -O2 -g"
|
||||||
|
fi
|
||||||
|
# Add the include path for Debian
|
||||||
|
EXTRABPFCFLAGS="-I/usr/include/$host_cpu-$host_os"
|
||||||
|
AC_SUBST([EXTRABPFCFLAGS])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([whether enum bpf_stats_type is defined in linux/bpf.h])
|
||||||
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
|
||||||
|
[[
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
]],
|
||||||
|
[[
|
||||||
|
enum bpf_stats_type foo;
|
||||||
|
(void)foo;
|
||||||
|
]])],
|
||||||
|
[have_bpf_stats_type=yes],
|
||||||
|
[have_bpf_stats_type=no])
|
||||||
|
|
||||||
|
if test "x${have_bpf_stats_type}" = "xyes"; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE([HAVE_BPF_STATS_TYPE], [1],
|
||||||
|
[Define to 1 if you have enum bpf_stats_type in linux/bpf.h.])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE($LIBBPF_PKG_ERRORS)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${request_libbpf}" = "xyes" &&
|
||||||
|
test "x${have_libbpf}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([libbpf was requested (--with-libbpf) but not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL([HAVE_LIBBPF], [ test "x${have_libbpf}" = "xyes" ])
|
||||||
|
|
||||||
# libevent_openssl (for examples)
|
# libevent_openssl (for examples)
|
||||||
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
# 2.0.8 is required because we use evconnlistener_set_error_cb()
|
||||||
have_libevent_openssl=no
|
have_libevent_openssl=no
|
||||||
@@ -598,6 +785,26 @@ fi
|
|||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
|
AM_CONDITIONAL([ENABLE_APP], [ test "x${enable_app}" = "xyes" ])
|
||||||
|
|
||||||
|
# Check HTTP/3 support
|
||||||
|
enable_http3=no
|
||||||
|
if test "x${request_http3}" != "xno" &&
|
||||||
|
(test "x${have_ssl_is_quic}" = "xyes" ||
|
||||||
|
test "x${have_boringssl_quic}" = "xyes") &&
|
||||||
|
test "x${have_libngtcp2}" = "xyes" &&
|
||||||
|
(test "x${have_libngtcp2_crypto_openssl}" = "xyes" ||
|
||||||
|
test "x${have_libngtcp2_crypto_boringssl}" = "xyes") &&
|
||||||
|
test "x${have_libnghttp3}" = "xyes"; then
|
||||||
|
enable_http3=yes
|
||||||
|
AC_DEFINE([ENABLE_HTTP3], [1], [Define to 1 if HTTP/3 is enabled.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x${request_http3}" = "xyes" &&
|
||||||
|
test "x${enable_http3}" != "xyes"; then
|
||||||
|
AC_MSG_ERROR([HTTP/3 was requested (--enable-http3) but dependencies are not met.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL([ENABLE_HTTP3], [ test "x${enable_http3}" = "xyes" ])
|
||||||
|
|
||||||
enable_hpack_tools=no
|
enable_hpack_tools=no
|
||||||
# HPACK tools requires jansson
|
# HPACK tools requires jansson
|
||||||
if test "x${request_hpack_tools}" != "xno" &&
|
if test "x${request_hpack_tools}" != "xno" &&
|
||||||
@@ -939,6 +1146,7 @@ AC_CONFIG_FILES([
|
|||||||
src/Makefile
|
src/Makefile
|
||||||
src/includes/Makefile
|
src/includes/Makefile
|
||||||
src/libnghttp2_asio.pc
|
src/libnghttp2_asio.pc
|
||||||
|
bpf/Makefile
|
||||||
examples/Makefile
|
examples/Makefile
|
||||||
python/Makefile
|
python/Makefile
|
||||||
python/setup.py
|
python/setup.py
|
||||||
@@ -990,7 +1198,11 @@ AC_MSG_NOTICE([summary of build options:
|
|||||||
WARNCXXFLAGS: ${WARNCXXFLAGS}
|
WARNCXXFLAGS: ${WARNCXXFLAGS}
|
||||||
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
CXX1XCXXFLAGS: ${CXX1XCXXFLAGS}
|
||||||
EXTRACFLAG: ${EXTRACFLAG}
|
EXTRACFLAG: ${EXTRACFLAG}
|
||||||
|
BPFCFLAGS: ${BPFCFLAGS}
|
||||||
|
EXTRABPFCFLAGS: ${EXTRABPFCFLAGS}
|
||||||
LIBS: ${LIBS}
|
LIBS: ${LIBS}
|
||||||
|
DEFS: ${DEFS}
|
||||||
|
EXTRA_DEFS: ${EXTRA_DEFS}
|
||||||
Library:
|
Library:
|
||||||
Shared: ${enable_shared}
|
Shared: ${enable_shared}
|
||||||
Static: ${enable_static}
|
Static: ${enable_static}
|
||||||
@@ -1011,6 +1223,11 @@ AC_MSG_NOTICE([summary of build options:
|
|||||||
Libxml2: ${have_libxml2} (CFLAGS='${LIBXML2_CFLAGS}' LIBS='${LIBXML2_LIBS}')
|
Libxml2: ${have_libxml2} (CFLAGS='${LIBXML2_CFLAGS}' LIBS='${LIBXML2_LIBS}')
|
||||||
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
|
Libev: ${have_libev} (CFLAGS='${LIBEV_CFLAGS}' LIBS='${LIBEV_LIBS}')
|
||||||
Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
|
Libc-ares: ${have_libcares} (CFLAGS='${LIBCARES_CFLAGS}' LIBS='${LIBCARES_LIBS}')
|
||||||
|
libngtcp2: ${have_libngtcp2} (CFLAGS='${LIBNGTCP2_CFLAGS}' LIBS='${LIBNGTCP2_LIBS}')
|
||||||
|
libngtcp2_crypto_openssl: ${have_libngtcp2_crypto_openssl} (CFLAGS='${LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_OPENSSL_LIBS}')
|
||||||
|
libngtcp2_crypto_boringssl: ${have_libngtcp2_crypto_boringssl} (CFLAGS='${LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS}' LIBS='${LIBNGTCP2_CRYPTO_BORINGSSL_LIBS}')
|
||||||
|
libnghttp3: ${have_libnghttp3} (CFLAGS='${LIBNGHTTP3_CFLAGS}' LIBS='${LIBNGHTTP3_LIBS}')
|
||||||
|
libbpf: ${have_libbpf} (CFLAGS='${LIBBPF_CFLAGS}' LIBS='${LIBBPF_LIBS}')
|
||||||
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
|
Libevent(SSL): ${have_libevent_openssl} (CFLAGS='${LIBEVENT_OPENSSL_CFLAGS}' LIBS='${LIBEVENT_OPENSSL_LIBS}')
|
||||||
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')
|
Jansson: ${have_jansson} (CFLAGS='${JANSSON_CFLAGS}' LIBS='${JANSSON_LIBS}')
|
||||||
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
|
Jemalloc: ${have_jemalloc} (CFLAGS='${JEMALLOC_CFLAGS}' LIBS='${JEMALLOC_LIBS}')
|
||||||
@@ -1032,4 +1249,5 @@ AC_MSG_NOTICE([summary of build options:
|
|||||||
Examples: ${enable_examples}
|
Examples: ${enable_examples}
|
||||||
Python bindings:${enable_python_bindings}
|
Python bindings:${enable_python_bindings}
|
||||||
Threading: ${enable_threads}
|
Threading: ${enable_threads}
|
||||||
|
HTTP/3 (EXPERIMENTAL): ${enable_http3}
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -184,9 +184,9 @@ set(EXTRA_DIST
|
|||||||
sources/python-apiref.rst
|
sources/python-apiref.rst
|
||||||
sources/building-android-binary.rst
|
sources/building-android-binary.rst
|
||||||
sources/contribute.rst
|
sources/contribute.rst
|
||||||
_exts/sphinxcontrib/LICENSE.rubydomain
|
_exts/rubydomain/LICENSE.rubydomain
|
||||||
_exts/sphinxcontrib/__init__.py
|
_exts/rubydomain/__init__.py
|
||||||
_exts/sphinxcontrib/rubydomain.py
|
_exts/rubydomain/rubydomain.py
|
||||||
_themes/sphinx_rtd_theme/__init__.py
|
_themes/sphinx_rtd_theme/__init__.py
|
||||||
_themes/sphinx_rtd_theme/breadcrumbs.html
|
_themes/sphinx_rtd_theme/breadcrumbs.html
|
||||||
_themes/sphinx_rtd_theme/footer.html
|
_themes/sphinx_rtd_theme/footer.html
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ APIDOCS= \
|
|||||||
nghttp2_check_authority.rst \
|
nghttp2_check_authority.rst \
|
||||||
nghttp2_check_header_name.rst \
|
nghttp2_check_header_name.rst \
|
||||||
nghttp2_check_header_value.rst \
|
nghttp2_check_header_value.rst \
|
||||||
|
nghttp2_check_method.rst \
|
||||||
|
nghttp2_check_path.rst \
|
||||||
nghttp2_hd_deflate_bound.rst \
|
nghttp2_hd_deflate_bound.rst \
|
||||||
nghttp2_hd_deflate_change_table_size.rst \
|
nghttp2_hd_deflate_change_table_size.rst \
|
||||||
nghttp2_hd_deflate_del.rst \
|
nghttp2_hd_deflate_del.rst \
|
||||||
@@ -204,9 +206,9 @@ EXTRA_DIST = \
|
|||||||
sources/building-android-binary.rst \
|
sources/building-android-binary.rst \
|
||||||
sources/contribute.rst \
|
sources/contribute.rst \
|
||||||
sources/security.rst \
|
sources/security.rst \
|
||||||
_exts/sphinxcontrib/LICENSE.rubydomain \
|
_exts/rubydomain/LICENSE.rubydomain \
|
||||||
_exts/sphinxcontrib/__init__.py \
|
_exts/rubydomain/__init__.py \
|
||||||
_exts/sphinxcontrib/rubydomain.py \
|
_exts/rubydomain/rubydomain.py \
|
||||||
_themes/sphinx_rtd_theme/__init__.py \
|
_themes/sphinx_rtd_theme/__init__.py \
|
||||||
_themes/sphinx_rtd_theme/breadcrumbs.html \
|
_themes/sphinx_rtd_theme/breadcrumbs.html \
|
||||||
_themes/sphinx_rtd_theme/footer.html \
|
_themes/sphinx_rtd_theme/footer.html \
|
||||||
@@ -270,7 +272,7 @@ EXTRA_DIST = \
|
|||||||
|
|
||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line.
|
||||||
SPHINXOPTS =
|
SPHINXOPTS =
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD ?= sphinx-build
|
||||||
PAPER =
|
PAPER =
|
||||||
BUILDDIR = manual
|
BUILDDIR = manual
|
||||||
|
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ class RubyModuleIndex(Index):
|
|||||||
# list of all modules, sorted by module name
|
# list of all modules, sorted by module name
|
||||||
modules = sorted(_iteritems(self.domain.data['modules']),
|
modules = sorted(_iteritems(self.domain.data['modules']),
|
||||||
key=lambda x: x[0].lower())
|
key=lambda x: x[0].lower())
|
||||||
# sort out collapsable modules
|
# sort out collapsible modules
|
||||||
prev_modname = ''
|
prev_modname = ''
|
||||||
num_toplevels = 0
|
num_toplevels = 0
|
||||||
for modname, (docname, synopsis, platforms, deprecated) in modules:
|
for modname, (docname, synopsis, platforms, deprecated) in modules:
|
||||||
@@ -8,7 +8,7 @@ _h2load()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --connect-to --header-table-size --requests --log-file --base-uri --h1 --threads --npn-list --rate-period --rps --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--requests --clients --threads --input-file --max-concurrent-streams --window-bits --connection-window-bits --header --ciphers --tls13-ciphers --no-tls-proto --data --rate --rate-period --duration --warm-up-time --connection-active-timeout --connection-inactivity-timeout --timing-script-file --base-uri --npn-list --h1 --header-table-size --encoder-header-table-size --log-file --qlog-file-base --connect-to --rps --groups --no-udp-gso --max-udp-payload-size --verbose --version --help ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from __future__ import print_function
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import io
|
import io
|
||||||
import re
|
import re
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttp()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--no-push --verbose --no-dep --get-assets --har --header-table-size --multiply --encoder-header-table-size --padding --hexdump --max-concurrent-streams --continuation --connection-window-bits --peer-max-concurrent-streams --timeout --data --no-content-length --version --color --cert --upgrade --remote-name --trailer --weight --help --key --null-out --window-bits --expect-continue --stat --no-verify-peer --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--verbose --null-out --remote-name --timeout --window-bits --connection-window-bits --get-assets --stat --header --trailer --cert --key --data --multiply --upgrade --weight --peer-max-concurrent-streams --header-table-size --encoder-header-table-size --padding --har --color --continuation --no-content-length --no-dep --hexdump --no-push --max-concurrent-streams --expect-continue --no-verify-peer --version --help ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttpd()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--htdocs --verbose --daemon --echo-upload --error-gzip --push --header-table-size --encoder-header-table-size --padding --hexdump --max-concurrent-streams --no-tls --connection-window-bits --mime-types-file --no-content-length --workers --version --color --early-response --dh-param-file --trailer --address --window-bits --verify-client --help ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--address --daemon --verify-client --htdocs --verbose --no-tls --header-table-size --encoder-header-table-size --color --push --padding --max-concurrent-streams --workers --error-gzip --window-bits --connection-window-bits --dh-param-file --early-response --trailer --hexdump --echo-upload --mime-types-file --no-content-length --version --help ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ _nghttpx()
|
|||||||
_get_comp_words_by_ref cur prev
|
_get_comp_words_by_ref cur prev
|
||||||
case $cur in
|
case $cur in
|
||||||
-*)
|
-*)
|
||||||
COMPREPLY=( $( compgen -W '--worker-read-rate --include --frontend-http2-dump-response-header --tls-ticket-key-file --verify-client-cacert --max-response-header-fields --backend-http2-window-size --tls13-client-ciphers --frontend-keep-alive-timeout --backend-request-buffer --max-request-header-fields --backend-connect-timeout --tls-max-proto-version --conf --dns-lookup-timeout --backend-http2-max-concurrent-streams --worker-write-burst --npn-list --dns-max-try --fetch-ocsp-response-file --tls-session-cache-memcached-cert-file --no-via --mruby-file --no-server-push --stream-read-timeout --client-ciphers --ocsp-update-interval --forwarded-for --accesslog-syslog --dns-cache-timeout --frontend-http2-read-timeout --listener-disable-timeout --ciphers --client-psk-secrets --strip-incoming-x-forwarded-for --no-server-rewrite --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --frontend-max-requests --tls-no-postpone-early-data --rlimit-nofile --no-strip-incoming-x-forwarded-proto --tls-ticket-key-memcached-cert-file --no-verify-ocsp --forwarded-by --tls-session-cache-memcached-private-key-file --error-page --ocsp-startup --backend-write-timeout --tls-dyn-rec-warmup-threshold --frontend-http2-window-size --tls-ticket-key-memcached-max-retry --http2-no-cookie-crumbling --worker-read-burst --dh-param-file --accesslog-format --errorlog-syslog --redirect-https-port --request-header-field-buffer --api-max-request-body --frontend-http2-decoder-dynamic-table-size --errorlog-file --frontend-http2-max-concurrent-streams --psk-secrets --frontend-write-timeout --tls-ticket-key-cipher --read-burst --no-add-x-forwarded-proto --backend --server-name --insecure --backend-max-backoff --log-level --host-rewrite --tls-ticket-key-memcached-interval --frontend-http2-setting-timeout --frontend-http2-connection-window-size --worker-frontend-connections --syslog-facility --fastopen --no-location-rewrite --single-thread --no-http2-cipher-block-list --tls-session-cache-memcached --no-ocsp --backend-response-buffer --tls-min-proto-version --workers --add-x-forwarded-for --add-forwarded --worker-write-rate --add-request-header --backend-http2-settings-timeout --subcert --ignore-per-pattern-mruby-error --ecdh-curves --no-kqueue --help --frontend-frame-debug --tls-sct-dir --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --backend-http2-decoder-dynamic-table-size --no-strip-incoming-early-data --user --verify-client-tolerate-expired --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --backend-connections-per-host --tls-max-early-data --response-header-field-buffer --tls-ticket-key-memcached-address-family --padding --tls-session-cache-memcached-address-family --stream-write-timeout --cacert --tls-ticket-key-memcached-private-key-file --accesslog-write-early --backend-address-family --backend-http2-connection-window-size --tls13-ciphers --client-no-http2-cipher-block-list --version --add-response-header --backend-read-timeout --frontend-http2-optimize-window-size --frontend --accesslog-file --http2-proxy --backend-http2-encoder-dynamic-table-size --client-private-key-file --single-process --client-cert-file --tls-ticket-key-memcached --tls-dyn-rec-idle-timeout --frontend-http2-optimize-write-buffer-size --verify-client --frontend-http2-encoder-dynamic-table-size --read-rate --backend-connections-per-frontend --strip-incoming-forwarded ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--backend --frontend --backlog --backend-address-family --backend-http-proxy-uri --workers --single-thread --read-rate --read-burst --write-rate --write-burst --worker-read-rate --worker-read-burst --worker-write-rate --worker-write-burst --worker-frontend-connections --backend-connections-per-host --backend-connections-per-frontend --rlimit-nofile --rlimit-memlock --backend-request-buffer --backend-response-buffer --fastopen --no-kqueue --frontend-http2-read-timeout --frontend-http3-read-timeout --frontend-read-timeout --frontend-write-timeout --frontend-keep-alive-timeout --stream-read-timeout --stream-write-timeout --backend-read-timeout --backend-write-timeout --backend-connect-timeout --backend-keep-alive-timeout --listener-disable-timeout --frontend-http2-setting-timeout --backend-http2-settings-timeout --backend-max-backoff --ciphers --tls13-ciphers --client-ciphers --tls13-client-ciphers --ecdh-curves --insecure --cacert --private-key-passwd-file --subcert --dh-param-file --npn-list --verify-client --verify-client-cacert --verify-client-tolerate-expired --client-private-key-file --client-cert-file --tls-min-proto-version --tls-max-proto-version --tls-ticket-key-file --tls-ticket-key-memcached --tls-ticket-key-memcached-address-family --tls-ticket-key-memcached-interval --tls-ticket-key-memcached-max-retry --tls-ticket-key-memcached-max-fail --tls-ticket-key-cipher --tls-ticket-key-memcached-cert-file --tls-ticket-key-memcached-private-key-file --fetch-ocsp-response-file --ocsp-update-interval --ocsp-startup --no-verify-ocsp --no-ocsp --tls-session-cache-memcached --tls-session-cache-memcached-address-family --tls-session-cache-memcached-cert-file --tls-session-cache-memcached-private-key-file --tls-dyn-rec-warmup-threshold --tls-dyn-rec-idle-timeout --no-http2-cipher-block-list --client-no-http2-cipher-block-list --tls-sct-dir --psk-secrets --client-psk-secrets --tls-no-postpone-early-data --tls-max-early-data --frontend-http2-max-concurrent-streams --backend-http2-max-concurrent-streams --frontend-http2-window-size --frontend-http2-connection-window-size --backend-http2-window-size --backend-http2-connection-window-size --http2-no-cookie-crumbling --padding --no-server-push --frontend-http2-optimize-write-buffer-size --frontend-http2-optimize-window-size --frontend-http2-encoder-dynamic-table-size --frontend-http2-decoder-dynamic-table-size --backend-http2-encoder-dynamic-table-size --backend-http2-decoder-dynamic-table-size --http2-proxy --log-level --accesslog-file --accesslog-syslog --accesslog-format --accesslog-write-early --errorlog-file --errorlog-syslog --syslog-facility --add-x-forwarded-for --strip-incoming-x-forwarded-for --no-add-x-forwarded-proto --no-strip-incoming-x-forwarded-proto --add-forwarded --strip-incoming-forwarded --forwarded-by --forwarded-for --no-via --no-strip-incoming-early-data --no-location-rewrite --host-rewrite --altsvc --http2-altsvc --add-request-header --add-response-header --request-header-field-buffer --max-request-header-fields --response-header-field-buffer --max-response-header-fields --error-page --server-name --no-server-rewrite --redirect-https-port --api-max-request-body --dns-cache-timeout --dns-lookup-timeout --dns-max-try --frontend-max-requests --frontend-http2-dump-request-header --frontend-http2-dump-response-header --frontend-frame-debug --daemon --pid-file --user --single-process --max-worker-processes --worker-process-grace-shutdown-period --mruby-file --ignore-per-pattern-mruby-error --frontend-quic-idle-timeout --frontend-quic-debug-log --quic-bpf-program-file --frontend-quic-early-data --frontend-quic-qlog-dir --frontend-quic-require-token --frontend-quic-congestion-controller --frontend-quic-secret-file --quic-server-id --frontend-quic-initial-rtt --no-quic-bpf --frontend-http3-window-size --frontend-http3-connection-window-size --frontend-http3-max-window-size --frontend-http3-max-connection-window-size --frontend-http3-max-concurrent-streams --conf --include --version --help ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import sys, os
|
|||||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#sys.path.insert(0, os.path.abspath('.'))
|
#sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
|
sys.path.insert(0, os.path.abspath('@top_srcdir@/doc/_exts'))
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinxcontrib.rubydomain']
|
extensions = ['rubydomain.rubydomain']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['@top_srcdir@/_templates']
|
templates_path = ['@top_srcdir@/_templates']
|
||||||
|
|||||||
42
doc/h2load.1
42
doc/h2load.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "H2LOAD" "1" "Jul 18, 2021" "1.45.0-DEV" "nghttp2"
|
.TH "H2LOAD" "1" "Oct 19, 2021" "1.46.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
h2load \- HTTP/2 benchmarking tool
|
h2load \- HTTP/2 benchmarking tool
|
||||||
.
|
.
|
||||||
@@ -101,6 +101,7 @@ Default: \fB1\fP
|
|||||||
.TP
|
.TP
|
||||||
.B \-w, \-\-window\-bits=<N>
|
.B \-w, \-\-window\-bits=<N>
|
||||||
Sets the stream level initial window size to (2**<N>)\-1.
|
Sets the stream level initial window size to (2**<N>)\-1.
|
||||||
|
For QUIC, <N> is capped to 26 (roughly 64MiB).
|
||||||
.sp
|
.sp
|
||||||
Default: \fB30\fP
|
Default: \fB30\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -120,13 +121,21 @@ Add/Override a header to the requests.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-ciphers=<SUITE>
|
.B \-\-ciphers=<SUITE>
|
||||||
Set allowed cipher list. The format of the string is
|
Set allowed cipher list for TLSv1.2 or ealier. The
|
||||||
described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
.sp
|
.sp
|
||||||
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
|
Default: \fBECDHE\-ECDSA\-AES256\-GCM\-SHA384:ECDHE\-RSA\-AES256\-GCM\-SHA384:ECDHE\-ECDSA\-CHACHA20\-POLY1305:ECDHE\-RSA\-CHACHA20\-POLY1305:ECDHE\-ECDSA\-AES128\-GCM\-SHA256:ECDHE\-RSA\-AES128\-GCM\-SHA256:ECDHE\-ECDSA\-AES256\-SHA384:ECDHE\-RSA\-AES256\-SHA384:ECDHE\-ECDSA\-AES128\-SHA256:ECDHE\-RSA\-AES128\-SHA256\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-tls13\-ciphers=<SUITE>
|
||||||
|
Set allowed cipher list for TLSv1.3. The format of the
|
||||||
|
string is described in OpenSSL ciphers(1).
|
||||||
|
.sp
|
||||||
|
Default: \fBTLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-p, \-\-no\-tls\-proto=<PROTOID>
|
.B \-p, \-\-no\-tls\-proto=<PROTOID>
|
||||||
Specify ALPN identifier of the protocol to be used when
|
Specify ALPN identifier of the protocol to be used when
|
||||||
accessing http URI without SSL/TLS.
|
accessing http URI without SSL/TLS.
|
||||||
@@ -285,6 +294,16 @@ to buffering. Status code is \-1 for failed streams.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-qlog\-file\-base=<PATH>
|
||||||
|
Enable qlog output and specify base file name for qlogs.
|
||||||
|
Qlog is emitted for each connection.
|
||||||
|
For a given base name "base", each output file name
|
||||||
|
becomes "base.M.N.qlog" where M is worker ID and N is
|
||||||
|
client ID (e.g. "base.0.3.qlog").
|
||||||
|
Only effective in QUIC runs.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-connect\-to=<HOST>[:<PORT>]
|
.B \-\-connect\-to=<HOST>[:<PORT>]
|
||||||
Host and port to connect instead of using the authority
|
Host and port to connect instead of using the authority
|
||||||
in <URI>.
|
in <URI>.
|
||||||
@@ -297,6 +316,23 @@ Specify request per second for each client. \fI\%\-\-rps\fP and
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-groups=<GROUPS>
|
||||||
|
Specify the supported groups.
|
||||||
|
.sp
|
||||||
|
Default: \fBX25519:P\-256:P\-384:P\-521\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-udp\-gso
|
||||||
|
Disable UDP GSO.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-max\-udp\-payload\-size=<SIZE>
|
||||||
|
Specify the maximum outgoing UDP datagram payload size.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-v, \-\-verbose
|
.B \-v, \-\-verbose
|
||||||
Output debug information.
|
Output debug information.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ OPTIONS
|
|||||||
.. option:: -w, --window-bits=<N>
|
.. option:: -w, --window-bits=<N>
|
||||||
|
|
||||||
Sets the stream level initial window size to (2\*\*<N>)-1.
|
Sets the stream level initial window size to (2\*\*<N>)-1.
|
||||||
|
For QUIC, <N> is capped to 26 (roughly 64MiB).
|
||||||
|
|
||||||
Default: ``30``
|
Default: ``30``
|
||||||
|
|
||||||
@@ -92,11 +93,18 @@ OPTIONS
|
|||||||
|
|
||||||
.. option:: --ciphers=<SUITE>
|
.. option:: --ciphers=<SUITE>
|
||||||
|
|
||||||
Set allowed cipher list. The format of the string is
|
Set allowed cipher list for TLSv1.2 or ealier. The
|
||||||
described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
|
|
||||||
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
|
Default: ``ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256``
|
||||||
|
|
||||||
|
.. option:: --tls13-ciphers=<SUITE>
|
||||||
|
|
||||||
|
Set allowed cipher list for TLSv1.3. The format of the
|
||||||
|
string is described in OpenSSL ciphers(1).
|
||||||
|
|
||||||
|
Default: ``TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256``
|
||||||
|
|
||||||
.. option:: -p, --no-tls-proto=<PROTOID>
|
.. option:: -p, --no-tls-proto=<PROTOID>
|
||||||
|
|
||||||
Specify ALPN identifier of the protocol to be used when
|
Specify ALPN identifier of the protocol to be used when
|
||||||
@@ -240,6 +248,15 @@ OPTIONS
|
|||||||
appear slightly out of order with multiple threads due
|
appear slightly out of order with multiple threads due
|
||||||
to buffering. Status code is -1 for failed streams.
|
to buffering. Status code is -1 for failed streams.
|
||||||
|
|
||||||
|
.. option:: --qlog-file-base=<PATH>
|
||||||
|
|
||||||
|
Enable qlog output and specify base file name for qlogs.
|
||||||
|
Qlog is emitted for each connection.
|
||||||
|
For a given base name "base", each output file name
|
||||||
|
becomes "base.M.N.qlog" where M is worker ID and N is
|
||||||
|
client ID (e.g. "base.0.3.qlog").
|
||||||
|
Only effective in QUIC runs.
|
||||||
|
|
||||||
.. option:: --connect-to=<HOST>[:<PORT>]
|
.. option:: --connect-to=<HOST>[:<PORT>]
|
||||||
|
|
||||||
Host and port to connect instead of using the authority
|
Host and port to connect instead of using the authority
|
||||||
@@ -250,6 +267,20 @@ OPTIONS
|
|||||||
Specify request per second for each client. :option:`--rps` and
|
Specify request per second for each client. :option:`--rps` and
|
||||||
:option:`--timing-script-file` are mutually exclusive.
|
:option:`--timing-script-file` are mutually exclusive.
|
||||||
|
|
||||||
|
.. option:: --groups=<GROUPS>
|
||||||
|
|
||||||
|
Specify the supported groups.
|
||||||
|
|
||||||
|
Default: ``X25519:P-256:P-384:P-521``
|
||||||
|
|
||||||
|
.. option:: --no-udp-gso
|
||||||
|
|
||||||
|
Disable UDP GSO.
|
||||||
|
|
||||||
|
.. option:: --max-udp-payload-size=<SIZE>
|
||||||
|
|
||||||
|
Specify the maximum outgoing UDP datagram payload size.
|
||||||
|
|
||||||
.. option:: -v, --verbose
|
.. option:: -v, --verbose
|
||||||
|
|
||||||
Output debug information.
|
Output debug information.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTP" "1" "Jul 18, 2021" "1.45.0-DEV" "nghttp2"
|
.TH "NGHTTP" "1" "Oct 19, 2021" "1.46.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttp \- HTTP/2 client
|
nghttp \- HTTP/2 client
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPD" "1" "Jul 18, 2021" "1.45.0-DEV" "nghttp2"
|
.TH "NGHTTPD" "1" "Oct 19, 2021" "1.46.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpd \- HTTP/2 server
|
nghttpd \- HTTP/2 server
|
||||||
.
|
.
|
||||||
|
|||||||
260
doc/nghttpx.1
260
doc/nghttpx.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPX" "1" "Jul 18, 2021" "1.45.0-DEV" "nghttp2"
|
.TH "NGHTTPX" "1" "Oct 19, 2021" "1.46.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpx \- HTTP/2 proxy
|
nghttpx \- HTTP/2 proxy
|
||||||
.
|
.
|
||||||
@@ -35,7 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
|||||||
\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
|
\fBnghttpx\fP [OPTIONS]... [<PRIVATE_KEY> <CERT>]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.sp
|
.sp
|
||||||
A reverse proxy for HTTP/2, and HTTP/1.
|
A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B <PRIVATE_KEY>
|
.B <PRIVATE_KEY>
|
||||||
@@ -140,12 +140,13 @@ parameters are: "proto=<PROTO>", "tls",
|
|||||||
"affinity=<METHOD>", "dns", "redirect\-if\-not\-tls",
|
"affinity=<METHOD>", "dns", "redirect\-if\-not\-tls",
|
||||||
"upgrade\-scheme", "mruby=<PATH>",
|
"upgrade\-scheme", "mruby=<PATH>",
|
||||||
"read\-timeout=<DURATION>", "write\-timeout=<DURATION>",
|
"read\-timeout=<DURATION>", "write\-timeout=<DURATION>",
|
||||||
"group=<GROUP>", "group\-weight=<N>", and "weight=<N>".
|
"group=<GROUP>", "group\-weight=<N>", "weight=<N>", and
|
||||||
The parameter consists of keyword, and optionally
|
"dnf". The parameter consists of keyword, and
|
||||||
followed by "=" and value. For example, the parameter
|
optionally followed by "=" and value. For example, the
|
||||||
"proto=h2" consists of the keyword "proto" and value
|
parameter "proto=h2" consists of the keyword "proto" and
|
||||||
"h2". The parameter "tls" consists of the keyword "tls"
|
value "h2". The parameter "tls" consists of the keyword
|
||||||
without value. Each parameter is described as follows.
|
"tls" without value. Each parameter is described as
|
||||||
|
follows.
|
||||||
.sp
|
.sp
|
||||||
The backend application protocol can be specified using
|
The backend application protocol can be specified using
|
||||||
optional "proto" parameter, and in the form of
|
optional "proto" parameter, and in the form of
|
||||||
@@ -276,6 +277,13 @@ weight than weight 2. If this parameter is omitted,
|
|||||||
weight becomes 1. "weight" is ignored if session
|
weight becomes 1. "weight" is ignored if session
|
||||||
affinity is enabled.
|
affinity is enabled.
|
||||||
.sp
|
.sp
|
||||||
|
If "dnf" parameter is specified, an incoming request is
|
||||||
|
not forwarded to a backend and just consumed along with
|
||||||
|
the request body (actually a backend server never be
|
||||||
|
contacted). It is expected that the HTTP response is
|
||||||
|
generated by mruby script (see "mruby=<PATH>" parameter
|
||||||
|
above). "dnf" is an abbreviation of "do not forward".
|
||||||
|
.sp
|
||||||
Since ";" and ":" are used as delimiter, <PATTERN> must
|
Since ";" and ":" are used as delimiter, <PATTERN> must
|
||||||
not contain these characters. In order to include ":"
|
not contain these characters. In order to include ":"
|
||||||
in <PATTERN>, one has to specify "%3A" (which is
|
in <PATTERN>, one has to specify "%3A" (which is
|
||||||
@@ -323,6 +331,12 @@ To accept PROXY protocol version 1 and 2 on frontend
|
|||||||
connection, specify "proxyproto" parameter. This is
|
connection, specify "proxyproto" parameter. This is
|
||||||
disabled by default.
|
disabled by default.
|
||||||
.sp
|
.sp
|
||||||
|
To receive HTTP/3 (QUIC) traffic, specify "quic"
|
||||||
|
parameter. It makes nghttpx listen on UDP port rather
|
||||||
|
than TCP port. UNIX domain socket, "api", and
|
||||||
|
"healthmon" parameters cannot be used with "quic"
|
||||||
|
parameter.
|
||||||
|
.sp
|
||||||
Default: \fB*,3000\fP
|
Default: \fB*,3000\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
@@ -489,6 +503,15 @@ Default: \fB0\fP
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-rlimit\-memlock=<N>
|
||||||
|
Set maximum number of bytes of memory that may be locked
|
||||||
|
into RAM. If 0 is given, nghttpx does not set the
|
||||||
|
limit.
|
||||||
|
.sp
|
||||||
|
Default: \fB0\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-backend\-request\-buffer=<SIZE>
|
.B \-\-backend\-request\-buffer=<SIZE>
|
||||||
Set buffer size used to store backend request.
|
Set buffer size used to store backend request.
|
||||||
.sp
|
.sp
|
||||||
@@ -528,6 +551,13 @@ Default: \fB3m\fP
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-read\-timeout=<DURATION>
|
||||||
|
Specify read timeout for HTTP/3 frontend connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB3m\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-frontend\-read\-timeout=<DURATION>
|
.B \-\-frontend\-read\-timeout=<DURATION>
|
||||||
Specify read timeout for HTTP/1.1 frontend connection.
|
Specify read timeout for HTTP/1.1 frontend connection.
|
||||||
.sp
|
.sp
|
||||||
@@ -1068,12 +1098,13 @@ option. But be aware its implications.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-tls\-no\-postpone\-early\-data
|
.B \-\-tls\-no\-postpone\-early\-data
|
||||||
By default, nghttpx postpones forwarding HTTP requests
|
By default, except for QUIC connections, nghttpx
|
||||||
sent in early data, including those sent in partially in
|
postpones forwarding HTTP requests sent in early data,
|
||||||
it, until TLS handshake finishes. If all backend server
|
including those sent in partially in it, until TLS
|
||||||
recognizes "Early\-Data" header field, using this option
|
handshake finishes. If all backend server recognizes
|
||||||
makes nghttpx not postpone forwarding request and get
|
"Early\-Data" header field, using this option makes
|
||||||
full potential of 0\-RTT data.
|
nghttpx not postpone forwarding request and get full
|
||||||
|
potential of 0\-RTT data.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -1478,13 +1509,21 @@ not be altered regardless of this option.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
|
.B \-\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
|
||||||
Specify protocol ID, port, host and origin of
|
Specify protocol ID, port, host and origin of
|
||||||
alternative service. <HOST> and <ORIGIN> are optional.
|
alternative service. <HOST>, <ORIGIN> and <PARAMS> are
|
||||||
They are advertised in alt\-svc header field only in
|
optional. Empty <HOST> and <ORIGIN> are allowed and
|
||||||
HTTP/1.1 frontend. This option can be used multiple
|
they are treated as nothing is specified. They are
|
||||||
times to specify multiple alternative services.
|
advertised in alt\-svc header field only in HTTP/1.1
|
||||||
Example: \fI\%\-\-altsvc\fP=h2,443
|
frontend. This option can be used multiple times to
|
||||||
|
specify multiple alternative services.
|
||||||
|
Example: \fI\%\-\-altsvc\fP="h2,443,,,ma=3600; persist=1"
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-http2\-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
|
||||||
|
Just like \fI\%\-\-altsvc\fP option, but this altsvc is only sent
|
||||||
|
in HTTP/2 frontend.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -1675,6 +1714,33 @@ process. nghttpx still spawns additional process if
|
|||||||
neverbleed is used. In the single process mode, the
|
neverbleed is used. In the single process mode, the
|
||||||
signal handling feature is disabled.
|
signal handling feature is disabled.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-max\-worker\-processes=<N>
|
||||||
|
The maximum number of worker processes. nghttpx spawns
|
||||||
|
new worker process when it reloads its configuration.
|
||||||
|
The previous worker process enters graceful termination
|
||||||
|
period and will terminate when it finishes handling the
|
||||||
|
existing connections. However, if reloading
|
||||||
|
configurations happen very frequently, the worker
|
||||||
|
processes might be piled up if they take a bit long time
|
||||||
|
to finish the existing connections. With this option,
|
||||||
|
if the number of worker processes exceeds the given
|
||||||
|
value, the oldest worker process is terminated
|
||||||
|
immediately. Specifying 0 means no limit and it is the
|
||||||
|
default behaviour.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-worker\-process\-grace\-shutdown\-period=<DURATION>
|
||||||
|
Maximum period for a worker process to terminate
|
||||||
|
gracefully. When a worker process enters in graceful
|
||||||
|
shutdown period (e.g., when nghttpx reloads its
|
||||||
|
configuration) and it does not finish handling the
|
||||||
|
existing connections in the given period of time, it is
|
||||||
|
immediately terminated. Specifying 0 means no limit and
|
||||||
|
it is the default behaviour.
|
||||||
|
.UNINDENT
|
||||||
.SS Scripting
|
.SS Scripting
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -1688,6 +1754,160 @@ Ignore mruby compile error for per\-pattern mruby script
|
|||||||
file. If error occurred, it is treated as if no mruby
|
file. If error occurred, it is treated as if no mruby
|
||||||
file were specified for the pattern.
|
file were specified for the pattern.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
.SS HTTP/3 and QUIC
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-idle\-timeout=<DURATION>
|
||||||
|
Specify an idle timeout for QUIC connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB30s\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-debug\-log
|
||||||
|
Output QUIC debug log to \fI/dev/stderr.\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-quic\-bpf\-program\-file=<PATH>
|
||||||
|
Specify a path to eBPF program file reuseport_kern.o to
|
||||||
|
direct an incoming QUIC UDP datagram to a correct
|
||||||
|
socket.
|
||||||
|
.sp
|
||||||
|
Default: \fB/usr/local/lib/nghttp2/reuseport_kern.o\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-early\-data
|
||||||
|
Enable early data on frontend QUIC connections. nghttpx
|
||||||
|
sends "Early\-Data" header field to a backend server if a
|
||||||
|
request is received in early data and handshake has not
|
||||||
|
finished. All backend servers should deal with possibly
|
||||||
|
replayed requests.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-qlog\-dir=<DIR>
|
||||||
|
Specify a directory where a qlog file is written for
|
||||||
|
frontend QUIC connections. A qlog file is created per
|
||||||
|
each QUIC connection. The file name is ISO8601 basic
|
||||||
|
format, followed by "\-", server Source Connection ID and
|
||||||
|
".qlog".
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-require\-token
|
||||||
|
Require an address validation token for a frontend QUIC
|
||||||
|
connection. Server sends a token in Retry packet or
|
||||||
|
NEW_TOKEN frame in the previous connection.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-congestion\-controller=<CC>
|
||||||
|
Specify a congestion controller algorithm for a frontend
|
||||||
|
QUIC connection. <CC> should be either "cubic" or
|
||||||
|
"bbr".
|
||||||
|
.sp
|
||||||
|
Default: \fBcubic\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-secret\-file=<PATH>
|
||||||
|
Path to file that contains secure random data to be used
|
||||||
|
as QUIC keying materials. It is used to derive keys for
|
||||||
|
encrypting tokens and Connection IDs. It is not used to
|
||||||
|
encrypt QUIC packets. Each line of this file must
|
||||||
|
contain exactly 136 bytes hex\-encoded string (when
|
||||||
|
decoded the byte string is 68 bytes long). The first 2
|
||||||
|
bits of decoded byte string are used to identify the
|
||||||
|
keying material. An empty line or a line which starts
|
||||||
|
\(aq#\(aq is ignored. The file can contain more than one
|
||||||
|
keying materials. Because the identifier is 2 bits, at
|
||||||
|
most 4 keying materials are read and the remaining data
|
||||||
|
is discarded. The first keying material in the file is
|
||||||
|
primarily used for encryption and decryption for new
|
||||||
|
connection. The other ones are used to decrypt data for
|
||||||
|
the existing connections. Specifying multiple keying
|
||||||
|
materials enables key rotation. Please note that key
|
||||||
|
rotation does not occur automatically. User should
|
||||||
|
update files or change options values and restart
|
||||||
|
nghttpx gracefully. If opening or reading given file
|
||||||
|
fails, all loaded keying materials are discarded and it
|
||||||
|
is treated as if none of this option is given. If this
|
||||||
|
option is not given or an error occurred while opening
|
||||||
|
or reading a file, a keying material is generated
|
||||||
|
internally on startup and reload.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-quic\-server\-id=<HEXSTRING>
|
||||||
|
Specify server ID encoded in Connection ID to identify
|
||||||
|
this particular server instance. Connection ID is
|
||||||
|
encrypted and this part is not visible in public. It
|
||||||
|
must be 4 bytes long and must be encoded in hex string
|
||||||
|
(which is 8 bytes long). If this option is omitted, a
|
||||||
|
random server ID is generated on startup and
|
||||||
|
configuration reload.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-quic\-initial\-rtt=<DURATION>
|
||||||
|
Specify the initial RTT of the frontend QUIC connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB333ms\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-no\-quic\-bpf
|
||||||
|
Disable eBPF.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-window\-size=<SIZE>
|
||||||
|
Sets the per\-stream initial window size of HTTP/3
|
||||||
|
frontend connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB256K\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-connection\-window\-size=<SIZE>
|
||||||
|
Sets the per\-connection window size of HTTP/3 frontend
|
||||||
|
connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB1M\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-max\-window\-size=<SIZE>
|
||||||
|
Sets the maximum per\-stream window size of HTTP/3
|
||||||
|
frontend connection. The window size is adjusted based
|
||||||
|
on the receiving rate of stream data. The initial value
|
||||||
|
is the value specified by \fI\%\-\-frontend\-http3\-window\-size\fP
|
||||||
|
and the window size grows up to <SIZE> bytes.
|
||||||
|
.sp
|
||||||
|
Default: \fB6M\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-max\-connection\-window\-size=<SIZE>
|
||||||
|
Sets the maximum per\-connection window size of HTTP/3
|
||||||
|
frontend connection. The window size is adjusted based
|
||||||
|
on the receiving rate of stream data. The initial value
|
||||||
|
is the value specified by
|
||||||
|
\fI\%\-\-frontend\-http3\-connection\-window\-size\fP and the window
|
||||||
|
size grows up to <SIZE> bytes.
|
||||||
|
.sp
|
||||||
|
Default: \fB8M\fP
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-frontend\-http3\-max\-concurrent\-streams=<N>
|
||||||
|
Set the maximum number of the concurrent streams in one
|
||||||
|
frontend HTTP/3 connection.
|
||||||
|
.sp
|
||||||
|
Default: \fB100\fP
|
||||||
|
.UNINDENT
|
||||||
.SS Misc
|
.SS Misc
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ SYNOPSIS
|
|||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
A reverse proxy for HTTP/2, and HTTP/1.
|
A reverse proxy for HTTP/3, HTTP/2, and HTTP/1.
|
||||||
|
|
||||||
.. describe:: <PRIVATE_KEY>
|
.. describe:: <PRIVATE_KEY>
|
||||||
|
|
||||||
@@ -124,12 +124,13 @@ Connections
|
|||||||
"affinity=<METHOD>", "dns", "redirect-if-not-tls",
|
"affinity=<METHOD>", "dns", "redirect-if-not-tls",
|
||||||
"upgrade-scheme", "mruby=<PATH>",
|
"upgrade-scheme", "mruby=<PATH>",
|
||||||
"read-timeout=<DURATION>", "write-timeout=<DURATION>",
|
"read-timeout=<DURATION>", "write-timeout=<DURATION>",
|
||||||
"group=<GROUP>", "group-weight=<N>", and "weight=<N>".
|
"group=<GROUP>", "group-weight=<N>", "weight=<N>", and
|
||||||
The parameter consists of keyword, and optionally
|
"dnf". The parameter consists of keyword, and
|
||||||
followed by "=" and value. For example, the parameter
|
optionally followed by "=" and value. For example, the
|
||||||
"proto=h2" consists of the keyword "proto" and value
|
parameter "proto=h2" consists of the keyword "proto" and
|
||||||
"h2". The parameter "tls" consists of the keyword "tls"
|
value "h2". The parameter "tls" consists of the keyword
|
||||||
without value. Each parameter is described as follows.
|
"tls" without value. Each parameter is described as
|
||||||
|
follows.
|
||||||
|
|
||||||
The backend application protocol can be specified using
|
The backend application protocol can be specified using
|
||||||
optional "proto" parameter, and in the form of
|
optional "proto" parameter, and in the form of
|
||||||
@@ -260,6 +261,13 @@ Connections
|
|||||||
weight becomes 1. "weight" is ignored if session
|
weight becomes 1. "weight" is ignored if session
|
||||||
affinity is enabled.
|
affinity is enabled.
|
||||||
|
|
||||||
|
If "dnf" parameter is specified, an incoming request is
|
||||||
|
not forwarded to a backend and just consumed along with
|
||||||
|
the request body (actually a backend server never be
|
||||||
|
contacted). It is expected that the HTTP response is
|
||||||
|
generated by mruby script (see "mruby=<PATH>" parameter
|
||||||
|
above). "dnf" is an abbreviation of "do not forward".
|
||||||
|
|
||||||
Since ";" and ":" are used as delimiter, <PATTERN> must
|
Since ";" and ":" are used as delimiter, <PATTERN> must
|
||||||
not contain these characters. In order to include ":"
|
not contain these characters. In order to include ":"
|
||||||
in <PATTERN>, one has to specify "%3A" (which is
|
in <PATTERN>, one has to specify "%3A" (which is
|
||||||
@@ -307,6 +315,12 @@ Connections
|
|||||||
connection, specify "proxyproto" parameter. This is
|
connection, specify "proxyproto" parameter. This is
|
||||||
disabled by default.
|
disabled by default.
|
||||||
|
|
||||||
|
To receive HTTP/3 (QUIC) traffic, specify "quic"
|
||||||
|
parameter. It makes nghttpx listen on UDP port rather
|
||||||
|
than TCP port. UNIX domain socket, "api", and
|
||||||
|
"healthmon" parameters cannot be used with "quic"
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
|
||||||
Default: ``*,3000``
|
Default: ``*,3000``
|
||||||
|
|
||||||
@@ -458,6 +472,14 @@ Performance
|
|||||||
|
|
||||||
Default: ``0``
|
Default: ``0``
|
||||||
|
|
||||||
|
.. option:: --rlimit-memlock=<N>
|
||||||
|
|
||||||
|
Set maximum number of bytes of memory that may be locked
|
||||||
|
into RAM. If 0 is given, nghttpx does not set the
|
||||||
|
limit.
|
||||||
|
|
||||||
|
Default: ``0``
|
||||||
|
|
||||||
.. option:: --backend-request-buffer=<SIZE>
|
.. option:: --backend-request-buffer=<SIZE>
|
||||||
|
|
||||||
Set buffer size used to store backend request.
|
Set buffer size used to store backend request.
|
||||||
@@ -495,6 +517,12 @@ Timeout
|
|||||||
|
|
||||||
Default: ``3m``
|
Default: ``3m``
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-read-timeout=<DURATION>
|
||||||
|
|
||||||
|
Specify read timeout for HTTP/3 frontend connection.
|
||||||
|
|
||||||
|
Default: ``3m``
|
||||||
|
|
||||||
.. option:: --frontend-read-timeout=<DURATION>
|
.. option:: --frontend-read-timeout=<DURATION>
|
||||||
|
|
||||||
Specify read timeout for HTTP/1.1 frontend connection.
|
Specify read timeout for HTTP/1.1 frontend connection.
|
||||||
@@ -983,12 +1011,13 @@ SSL/TLS
|
|||||||
|
|
||||||
.. option:: --tls-no-postpone-early-data
|
.. option:: --tls-no-postpone-early-data
|
||||||
|
|
||||||
By default, nghttpx postpones forwarding HTTP requests
|
By default, except for QUIC connections, nghttpx
|
||||||
sent in early data, including those sent in partially in
|
postpones forwarding HTTP requests sent in early data,
|
||||||
it, until TLS handshake finishes. If all backend server
|
including those sent in partially in it, until TLS
|
||||||
recognizes "Early-Data" header field, using this option
|
handshake finishes. If all backend server recognizes
|
||||||
makes nghttpx not postpone forwarding request and get
|
"Early-Data" header field, using this option makes
|
||||||
full potential of 0-RTT data.
|
nghttpx not postpone forwarding request and get full
|
||||||
|
potential of 0-RTT data.
|
||||||
|
|
||||||
.. option:: --tls-max-early-data=<SIZE>
|
.. option:: --tls-max-early-data=<SIZE>
|
||||||
|
|
||||||
@@ -1338,14 +1367,21 @@ HTTP
|
|||||||
mode. When :option:`--http2-proxy` is used, these headers will
|
mode. When :option:`--http2-proxy` is used, these headers will
|
||||||
not be altered regardless of this option.
|
not be altered regardless of this option.
|
||||||
|
|
||||||
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN]]>
|
.. option:: --altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
|
||||||
|
|
||||||
Specify protocol ID, port, host and origin of
|
Specify protocol ID, port, host and origin of
|
||||||
alternative service. <HOST> and <ORIGIN> are optional.
|
alternative service. <HOST>, <ORIGIN> and <PARAMS> are
|
||||||
They are advertised in alt-svc header field only in
|
optional. Empty <HOST> and <ORIGIN> are allowed and
|
||||||
HTTP/1.1 frontend. This option can be used multiple
|
they are treated as nothing is specified. They are
|
||||||
times to specify multiple alternative services.
|
advertised in alt-svc header field only in HTTP/1.1
|
||||||
Example: :option:`--altsvc`\=h2,443
|
frontend. This option can be used multiple times to
|
||||||
|
specify multiple alternative services.
|
||||||
|
Example: :option:`--altsvc`\="h2,443,,,ma=3600; persist=1"
|
||||||
|
|
||||||
|
.. option:: --http2-altsvc=<PROTOID,PORT[,HOST,[ORIGIN[,PARAMS]]]>
|
||||||
|
|
||||||
|
Just like :option:`--altsvc` option, but this altsvc is only sent
|
||||||
|
in HTTP/2 frontend.
|
||||||
|
|
||||||
.. option:: --add-request-header=<HEADER>
|
.. option:: --add-request-header=<HEADER>
|
||||||
|
|
||||||
@@ -1526,6 +1562,31 @@ Process
|
|||||||
neverbleed is used. In the single process mode, the
|
neverbleed is used. In the single process mode, the
|
||||||
signal handling feature is disabled.
|
signal handling feature is disabled.
|
||||||
|
|
||||||
|
.. option:: --max-worker-processes=<N>
|
||||||
|
|
||||||
|
The maximum number of worker processes. nghttpx spawns
|
||||||
|
new worker process when it reloads its configuration.
|
||||||
|
The previous worker process enters graceful termination
|
||||||
|
period and will terminate when it finishes handling the
|
||||||
|
existing connections. However, if reloading
|
||||||
|
configurations happen very frequently, the worker
|
||||||
|
processes might be piled up if they take a bit long time
|
||||||
|
to finish the existing connections. With this option,
|
||||||
|
if the number of worker processes exceeds the given
|
||||||
|
value, the oldest worker process is terminated
|
||||||
|
immediately. Specifying 0 means no limit and it is the
|
||||||
|
default behaviour.
|
||||||
|
|
||||||
|
.. option:: --worker-process-grace-shutdown-period=<DURATION>
|
||||||
|
|
||||||
|
Maximum period for a worker process to terminate
|
||||||
|
gracefully. When a worker process enters in graceful
|
||||||
|
shutdown period (e.g., when nghttpx reloads its
|
||||||
|
configuration) and it does not finish handling the
|
||||||
|
existing connections in the given period of time, it is
|
||||||
|
immediately terminated. Specifying 0 means no limit and
|
||||||
|
it is the default behaviour.
|
||||||
|
|
||||||
|
|
||||||
Scripting
|
Scripting
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
@@ -1541,6 +1602,147 @@ Scripting
|
|||||||
file were specified for the pattern.
|
file were specified for the pattern.
|
||||||
|
|
||||||
|
|
||||||
|
HTTP/3 and QUIC
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-idle-timeout=<DURATION>
|
||||||
|
|
||||||
|
Specify an idle timeout for QUIC connection.
|
||||||
|
|
||||||
|
Default: ``30s``
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-debug-log
|
||||||
|
|
||||||
|
Output QUIC debug log to */dev/stderr.*
|
||||||
|
|
||||||
|
.. option:: --quic-bpf-program-file=<PATH>
|
||||||
|
|
||||||
|
Specify a path to eBPF program file reuseport_kern.o to
|
||||||
|
direct an incoming QUIC UDP datagram to a correct
|
||||||
|
socket.
|
||||||
|
|
||||||
|
Default: ``/usr/local/lib/nghttp2/reuseport_kern.o``
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-early-data
|
||||||
|
|
||||||
|
Enable early data on frontend QUIC connections. nghttpx
|
||||||
|
sends "Early-Data" header field to a backend server if a
|
||||||
|
request is received in early data and handshake has not
|
||||||
|
finished. All backend servers should deal with possibly
|
||||||
|
replayed requests.
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-qlog-dir=<DIR>
|
||||||
|
|
||||||
|
Specify a directory where a qlog file is written for
|
||||||
|
frontend QUIC connections. A qlog file is created per
|
||||||
|
each QUIC connection. The file name is ISO8601 basic
|
||||||
|
format, followed by "-", server Source Connection ID and
|
||||||
|
".qlog".
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-require-token
|
||||||
|
|
||||||
|
Require an address validation token for a frontend QUIC
|
||||||
|
connection. Server sends a token in Retry packet or
|
||||||
|
NEW_TOKEN frame in the previous connection.
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-congestion-controller=<CC>
|
||||||
|
|
||||||
|
Specify a congestion controller algorithm for a frontend
|
||||||
|
QUIC connection. <CC> should be either "cubic" or
|
||||||
|
"bbr".
|
||||||
|
|
||||||
|
Default: ``cubic``
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-secret-file=<PATH>
|
||||||
|
|
||||||
|
Path to file that contains secure random data to be used
|
||||||
|
as QUIC keying materials. It is used to derive keys for
|
||||||
|
encrypting tokens and Connection IDs. It is not used to
|
||||||
|
encrypt QUIC packets. Each line of this file must
|
||||||
|
contain exactly 136 bytes hex-encoded string (when
|
||||||
|
decoded the byte string is 68 bytes long). The first 2
|
||||||
|
bits of decoded byte string are used to identify the
|
||||||
|
keying material. An empty line or a line which starts
|
||||||
|
'#' is ignored. The file can contain more than one
|
||||||
|
keying materials. Because the identifier is 2 bits, at
|
||||||
|
most 4 keying materials are read and the remaining data
|
||||||
|
is discarded. The first keying material in the file is
|
||||||
|
primarily used for encryption and decryption for new
|
||||||
|
connection. The other ones are used to decrypt data for
|
||||||
|
the existing connections. Specifying multiple keying
|
||||||
|
materials enables key rotation. Please note that key
|
||||||
|
rotation does not occur automatically. User should
|
||||||
|
update files or change options values and restart
|
||||||
|
nghttpx gracefully. If opening or reading given file
|
||||||
|
fails, all loaded keying materials are discarded and it
|
||||||
|
is treated as if none of this option is given. If this
|
||||||
|
option is not given or an error occurred while opening
|
||||||
|
or reading a file, a keying material is generated
|
||||||
|
internally on startup and reload.
|
||||||
|
|
||||||
|
.. option:: --quic-server-id=<HEXSTRING>
|
||||||
|
|
||||||
|
Specify server ID encoded in Connection ID to identify
|
||||||
|
this particular server instance. Connection ID is
|
||||||
|
encrypted and this part is not visible in public. It
|
||||||
|
must be 4 bytes long and must be encoded in hex string
|
||||||
|
(which is 8 bytes long). If this option is omitted, a
|
||||||
|
random server ID is generated on startup and
|
||||||
|
configuration reload.
|
||||||
|
|
||||||
|
.. option:: --frontend-quic-initial-rtt=<DURATION>
|
||||||
|
|
||||||
|
Specify the initial RTT of the frontend QUIC connection.
|
||||||
|
|
||||||
|
Default: ``333ms``
|
||||||
|
|
||||||
|
.. option:: --no-quic-bpf
|
||||||
|
|
||||||
|
Disable eBPF.
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-window-size=<SIZE>
|
||||||
|
|
||||||
|
Sets the per-stream initial window size of HTTP/3
|
||||||
|
frontend connection.
|
||||||
|
|
||||||
|
Default: ``256K``
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-connection-window-size=<SIZE>
|
||||||
|
|
||||||
|
Sets the per-connection window size of HTTP/3 frontend
|
||||||
|
connection.
|
||||||
|
|
||||||
|
Default: ``1M``
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-max-window-size=<SIZE>
|
||||||
|
|
||||||
|
Sets the maximum per-stream window size of HTTP/3
|
||||||
|
frontend connection. The window size is adjusted based
|
||||||
|
on the receiving rate of stream data. The initial value
|
||||||
|
is the value specified by :option:`--frontend-http3-window-size`
|
||||||
|
and the window size grows up to <SIZE> bytes.
|
||||||
|
|
||||||
|
Default: ``6M``
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-max-connection-window-size=<SIZE>
|
||||||
|
|
||||||
|
Sets the maximum per-connection window size of HTTP/3
|
||||||
|
frontend connection. The window size is adjusted based
|
||||||
|
on the receiving rate of stream data. The initial value
|
||||||
|
is the value specified by
|
||||||
|
:option:`--frontend-http3-connection-window-size` and the window
|
||||||
|
size grows up to <SIZE> bytes.
|
||||||
|
|
||||||
|
Default: ``8M``
|
||||||
|
|
||||||
|
.. option:: --frontend-http3-max-concurrent-streams=<N>
|
||||||
|
|
||||||
|
Set the maximum number of the concurrent streams in one
|
||||||
|
frontend HTTP/3 connection.
|
||||||
|
|
||||||
|
Default: ``100``
|
||||||
|
|
||||||
|
|
||||||
Misc
|
Misc
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Architecture
|
|||||||
|
|
||||||
The most notable point in nghttp2 library architecture is it does not
|
The most notable point in nghttp2 library architecture is it does not
|
||||||
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
|
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
|
||||||
input byte strings. It will calls callback functions set by
|
input byte strings. It will call callback functions set by
|
||||||
applications while processing input. The output of nghttp2 is just
|
applications while processing input. The output of nghttp2 is just
|
||||||
byte string. An application is responsible to send these output to
|
byte string. An application is responsible to send these output to
|
||||||
the remote peer. The callback functions may be called while producing
|
the remote peer. The callback functions may be called while producing
|
||||||
|
|||||||
@@ -131,3 +131,12 @@ specify ``unix:`` followed by the path to UNIX domain socket. For
|
|||||||
example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
|
example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
|
||||||
``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
|
``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
|
||||||
port in the first URI in command-line or input file.
|
port in the first URI in command-line or input file.
|
||||||
|
|
||||||
|
HTTP/3
|
||||||
|
------
|
||||||
|
|
||||||
|
h2load supports HTTP/3 if it is built with HTTP/3 enabled. HTTP/3
|
||||||
|
support is experimental.
|
||||||
|
|
||||||
|
In order to send HTTP/3 request, specify ``h3`` to
|
||||||
|
:option:`--npn-list`.
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ Default mode
|
|||||||
|
|
||||||
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
|
If nghttpx is invoked without :option:`--http2-proxy`, it operates in
|
||||||
default mode. In this mode, it works as reverse proxy (gateway) for
|
default mode. In this mode, it works as reverse proxy (gateway) for
|
||||||
both HTTP/2 and HTTP/1 clients to backend servers. This is also known
|
HTTP/3, HTTP/2 and HTTP/1 clients to backend servers. This is also
|
||||||
as "HTTP/2 router".
|
known as "HTTP/2 router".
|
||||||
|
|
||||||
By default, frontend connection is encrypted using SSL/TLS. So
|
By default, frontend connection is encrypted using SSL/TLS. So
|
||||||
server's private key and certificate must be supplied to the command
|
server's private key and certificate must be supplied to the command
|
||||||
@@ -28,6 +28,9 @@ the frontend, and an HTTP/1 connection can be upgraded to HTTP/2 using
|
|||||||
HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
|
HTTP Upgrade. Starting HTTP/2 connection by sending HTTP/2 connection
|
||||||
preface is also supported.
|
preface is also supported.
|
||||||
|
|
||||||
|
In order to receive HTTP/3 traffic, use ``quic`` parameter in
|
||||||
|
:option:`--frontend` option (.e.g, ``--frontend='*,443;quic'``)
|
||||||
|
|
||||||
nghttpx can listen on multiple frontend addresses. This is achieved
|
nghttpx can listen on multiple frontend addresses. This is achieved
|
||||||
by using multiple :option:`--frontend` options. For each frontend
|
by using multiple :option:`--frontend` options. For each frontend
|
||||||
address, TLS can be enabled or disabled.
|
address, TLS can be enabled or disabled.
|
||||||
@@ -509,6 +512,60 @@ Bootstrapping WebSockets with HTTP/2 for both frontend and backend
|
|||||||
connections. This feature is enabled by default and no configuration
|
connections. This feature is enabled by default and no configuration
|
||||||
is required.
|
is required.
|
||||||
|
|
||||||
|
WebSockets over HTTP/3 is also supported.
|
||||||
|
|
||||||
|
HTTP/3
|
||||||
|
------
|
||||||
|
|
||||||
|
nghttpx supports HTTP/3 if it is built with HTTP/3 support enabled.
|
||||||
|
HTTP/3 support is experimental.
|
||||||
|
|
||||||
|
In order to listen UDP port to receive HTTP/3 traffic,
|
||||||
|
:option:`--frontend` option must have ``quic`` parameter:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
frontend=*,443;quic
|
||||||
|
|
||||||
|
The above example makes nghttpx receive HTTP/3 traffic on UDP
|
||||||
|
port 443.
|
||||||
|
|
||||||
|
nghttpx does not support HTTP/3 on backend connection.
|
||||||
|
|
||||||
|
Hot swapping (SIGUSR2) or configuration reload (SIGHUP) require eBPF
|
||||||
|
program. Without eBPF, old worker processes keep getting HTTP/3
|
||||||
|
traffic and do not work as intended. The QUIC keying material to
|
||||||
|
encrypt Connection ID must be set with
|
||||||
|
:option:`--frontend-quic-secret-file` and must provide the existing
|
||||||
|
keys in order to keep the existing connections alive during reload.
|
||||||
|
|
||||||
|
The construction of Connection ID closely follows Block Cipher CID
|
||||||
|
Algorithm described in `QUIC-LB draft
|
||||||
|
<https://datatracker.ietf.org/doc/html/draft-ietf-quic-load-balancers>`_.
|
||||||
|
A Connection ID that nghttpx generates is always 20 bytes long. It
|
||||||
|
uses first 2 bits as a configuration ID. The remaining bits in the
|
||||||
|
first byte are reserved and random. The next 4 bytes are server ID.
|
||||||
|
The next 4 bytes are used to route UDP datagram to a correct
|
||||||
|
``SO_REUSEPORT`` socket. The remaining bytes are randomly generated.
|
||||||
|
The server ID and the next 12 bytes are encrypted with AES-ECB. The
|
||||||
|
key is derived from the keying materials stored in a file specified by
|
||||||
|
:option:`--frontend-quic-secret-file`. The first 2 bits of keying
|
||||||
|
material in the file is used as a configuration ID. The remaining
|
||||||
|
bits and following 3 bytes are reserved and unused. The next 32 bytes
|
||||||
|
are used as an initial secret. The remaining 32 bytes are used as a
|
||||||
|
salt. The encryption key is generated by `HKDF
|
||||||
|
<https://datatracker.ietf.org/doc/html/rfc5869>`_ with SHA256 and
|
||||||
|
these keying materials and ``connection id encryption key`` as info.
|
||||||
|
|
||||||
|
In order announce that HTTP/3 endpoint is available, you should
|
||||||
|
specify alt-svc header field. For example, the following options send
|
||||||
|
alt-svc header field in HTTP/1.1 and HTTP/2 response:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
altsvc=h3,443,,,ma=3600
|
||||||
|
http2-altsvc=h3,443,,,ma=3600
|
||||||
|
|
||||||
Migration from nghttpx v1.18.x or earlier
|
Migration from nghttpx v1.18.x or earlier
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
|
|||||||
78
docker/Dockerfile
Normal file
78
docker/Dockerfile
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
FROM debian:11 as build
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
git clang make binutils autoconf automake autotools-dev libtool \
|
||||||
|
pkg-config \
|
||||||
|
zlib1g-dev libev-dev libjemalloc-dev ruby-dev libc-ares-dev bison \
|
||||||
|
libelf-dev
|
||||||
|
|
||||||
|
RUN git clone --depth 1 -b OpenSSL_1_1_1m+quic https://github.com/quictls/openssl && \
|
||||||
|
cd openssl && \
|
||||||
|
./config --openssldir=/etc/ssl && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install_sw && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf openssl
|
||||||
|
|
||||||
|
RUN git clone --depth 1 https://github.com/ngtcp2/nghttp3 && \
|
||||||
|
cd nghttp3 && \
|
||||||
|
autoreconf -i && \
|
||||||
|
./configure --enable-lib-only && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install-strip && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf nghttp3
|
||||||
|
|
||||||
|
RUN git clone --depth 1 -b v0.1.0 https://github.com/ngtcp2/ngtcp2 && \
|
||||||
|
cd ngtcp2 && \
|
||||||
|
autoreconf -i && \
|
||||||
|
./configure --enable-lib-only \
|
||||||
|
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
||||||
|
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -lpthread" \
|
||||||
|
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
|
||||||
|
make -j$(nproc) && \
|
||||||
|
make install-strip && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf ngtcp2
|
||||||
|
|
||||||
|
RUN git clone --depth 1 -b v0.4.0 https://github.com/libbpf/libbpf && \
|
||||||
|
cd libbpf && \
|
||||||
|
PREFIX=/usr/local make -C src install && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf libbpf
|
||||||
|
|
||||||
|
RUN git clone --depth 1 https://github.com/nghttp2/nghttp2.git && \
|
||||||
|
cd nghttp2 && \
|
||||||
|
git submodule update --init && \
|
||||||
|
autoreconf -i && \
|
||||||
|
./configure --disable-examples --disable-hpack-tools \
|
||||||
|
--disable-python-bindings --with-mruby --with-neverbleed \
|
||||||
|
--enable-http3 --with-libbpf \
|
||||||
|
CC=clang CXX=clang++ \
|
||||||
|
LIBTOOL_LDFLAGS="-static-libtool-libs" \
|
||||||
|
OPENSSL_LIBS="-l:libssl.a -l:libcrypto.a -ldl -pthread" \
|
||||||
|
LIBEV_LIBS="-l:libev.a" \
|
||||||
|
JEMALLOC_LIBS="-l:libjemalloc.a" \
|
||||||
|
LIBCARES_LIBS="-l:libcares.a" \
|
||||||
|
ZLIB_LIBS="-l:libz.a" \
|
||||||
|
LIBBPF_LIBS="-L/usr/local/lib64 -l:libbpf.a -l:libelf.a" \
|
||||||
|
LDFLAGS="-static-libgcc -static-libstdc++" \
|
||||||
|
PKG_CONFIG_PATH="/usr/local/lib64/pkgconfig" && \
|
||||||
|
make -j$(nproc) install-strip && \
|
||||||
|
cd .. && \
|
||||||
|
rm -rf nghttp2
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/base-debian11
|
||||||
|
|
||||||
|
COPY --from=build \
|
||||||
|
/usr/local/share/nghttp2/ \
|
||||||
|
/usr/local/share/nghttp2/
|
||||||
|
COPY --from=build \
|
||||||
|
/usr/local/bin/h2load \
|
||||||
|
/usr/local/bin/nghttpx \
|
||||||
|
/usr/local/bin/nghttp \
|
||||||
|
/usr/local/bin/nghttpd \
|
||||||
|
/usr/local/bin/
|
||||||
|
COPY --from=build /usr/local/lib/nghttp2/reuseport_kern.o \
|
||||||
|
/usr/local/lib/nghttp2/
|
||||||
25
docker/README.rst
Normal file
25
docker/README.rst
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Dockerfile
|
||||||
|
==========
|
||||||
|
|
||||||
|
Dockerfile creates the applications bundled with nghttp2.
|
||||||
|
These applications are:
|
||||||
|
|
||||||
|
- nghttp
|
||||||
|
- nghttpd
|
||||||
|
- nghttpx
|
||||||
|
- h2load
|
||||||
|
|
||||||
|
HTTP/3 and eBPF features are enabled.
|
||||||
|
|
||||||
|
In order to run nghttpx with HTTP/3 endpoint, you need to run the
|
||||||
|
image with the escalated privilege and higher memlock value. Here is
|
||||||
|
the example command-line to run nghttpx to listen to HTTP/3 on port
|
||||||
|
443, assuming that the current directory contains a private key and a
|
||||||
|
certificate in server.key and server.crt respectively :
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
$ docker run --rm -it -v $PWD:/shared --net=host --privileged \
|
||||||
|
nghttp2 nghttpx \
|
||||||
|
/shared/server.key /shared/server.crt \
|
||||||
|
-f'*,443;quic' --rlimit-memlock 524288
|
||||||
@@ -380,6 +380,10 @@ static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
|
|||||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||||
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
#endif /* !OPENSSL_NO_NEXTPROTONEG */
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
SSL_CTX_set_alpn_protos(ssl_ctx, (const unsigned char *)"\x02h2", 3);
|
||||||
|
#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ssl_handshake(SSL *ssl, int fd) {
|
static void ssl_handshake(SSL *ssl, int fd) {
|
||||||
@@ -544,7 +548,7 @@ static void fetch_uri(const struct URI *uri) {
|
|||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
die("Could not open file descriptor");
|
die("Could not open file descriptor");
|
||||||
}
|
}
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||||
if (ssl_ctx == NULL) {
|
if (ssl_ctx == NULL) {
|
||||||
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
|
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
@@ -715,8 +719,18 @@ int main(int argc, char **argv) {
|
|||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &act, 0);
|
sigaction(SIGPIPE, &act, 0);
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
/* No explicit initialization is required. */
|
||||||
|
#elif defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
CRYPTO_library_init();
|
||||||
|
#else /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
OPENSSL_config(NULL);
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
|
||||||
rv = parse_uri(&uri, argv[1]);
|
rv = parse_uri(&uri, argv[1]);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
|||||||
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
||||||
size_t inlen, int final);
|
size_t inlen, int final);
|
||||||
|
|
||||||
int main() {
|
int main(void) {
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_hd_deflater *deflater;
|
nghttp2_hd_deflater *deflater;
|
||||||
nghttp2_hd_inflater *inflater;
|
nghttp2_hd_inflater *inflater;
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ static int select_next_proto_cb(SSL *ssl, unsigned char **out,
|
|||||||
/* Create SSL_CTX. */
|
/* Create SSL_CTX. */
|
||||||
static SSL_CTX *create_ssl_ctx(void) {
|
static SSL_CTX *create_ssl_ctx(void) {
|
||||||
SSL_CTX *ssl_ctx;
|
SSL_CTX *ssl_ctx;
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||||
if (!ssl_ctx) {
|
if (!ssl_ctx) {
|
||||||
errx(1, "Could not create SSL/TLS context: %s",
|
errx(1, "Could not create SSL/TLS context: %s",
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
@@ -617,8 +617,18 @@ int main(int argc, char **argv) {
|
|||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &act, NULL);
|
sigaction(SIGPIPE, &act, NULL);
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
/* No explicit initialization is required. */
|
||||||
|
#elif defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
CRYPTO_library_init();
|
||||||
|
#else /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
OPENSSL_config(NULL);
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
|
||||||
run(argv[1]);
|
run(argv[1]);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -142,9 +142,8 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
|
|||||||
/* Create SSL_CTX. */
|
/* Create SSL_CTX. */
|
||||||
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
||||||
SSL_CTX *ssl_ctx;
|
SSL_CTX *ssl_ctx;
|
||||||
EC_KEY *ecdh;
|
|
||||||
|
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
ssl_ctx = SSL_CTX_new(TLS_server_method());
|
||||||
if (!ssl_ctx) {
|
if (!ssl_ctx) {
|
||||||
errx(1, "Could not create SSL/TLS context: %s",
|
errx(1, "Could not create SSL/TLS context: %s",
|
||||||
ERR_error_string(ERR_get_error(), NULL));
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
@@ -153,7 +152,14 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
|||||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||||
SSL_OP_NO_COMPRESSION |
|
SSL_OP_NO_COMPRESSION |
|
||||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||||
|
if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
|
||||||
|
errx(1, "SSL_CTX_set1_curves_list failed: %s",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
}
|
||||||
|
#else /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */
|
||||||
|
{
|
||||||
|
EC_KEY *ecdh;
|
||||||
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||||
if (!ecdh) {
|
if (!ecdh) {
|
||||||
errx(1, "EC_KEY_new_by_curv_name failed: %s",
|
errx(1, "EC_KEY_new_by_curv_name failed: %s",
|
||||||
@@ -161,6 +167,8 @@ static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
|||||||
}
|
}
|
||||||
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
||||||
EC_KEY_free(ecdh);
|
EC_KEY_free(ecdh);
|
||||||
|
}
|
||||||
|
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */
|
||||||
|
|
||||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
|
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
|
||||||
errx(1, "Could not read private key file %s", key_file);
|
errx(1, "Could not read private key file %s", key_file);
|
||||||
@@ -809,8 +817,18 @@ int main(int argc, char **argv) {
|
|||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &act, NULL);
|
sigaction(SIGPIPE, &act, NULL);
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||||
|
/* No explicit initialization is required. */
|
||||||
|
#elif defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
CRYPTO_library_init();
|
||||||
|
#else /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
OPENSSL_config(NULL);
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
#endif /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \
|
||||||
|
!defined(OPENSSL_IS_BORINGSSL) */
|
||||||
|
|
||||||
run(argv[1], argv[2], argv[3]);
|
run(argv[1], argv[2], argv[3]);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
29
genmethodchartbl.py
Executable file
29
genmethodchartbl.py
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def name(i):
|
||||||
|
if i < 0x21:
|
||||||
|
return \
|
||||||
|
['NUL ', 'SOH ', 'STX ', 'ETX ', 'EOT ', 'ENQ ', 'ACK ', 'BEL ',
|
||||||
|
'BS ', 'HT ', 'LF ', 'VT ', 'FF ', 'CR ', 'SO ', 'SI ',
|
||||||
|
'DLE ', 'DC1 ', 'DC2 ', 'DC3 ', 'DC4 ', 'NAK ', 'SYN ', 'ETB ',
|
||||||
|
'CAN ', 'EM ', 'SUB ', 'ESC ', 'FS ', 'GS ', 'RS ', 'US ',
|
||||||
|
'SPC '][i]
|
||||||
|
elif i == 0x7f:
|
||||||
|
return 'DEL '
|
||||||
|
|
||||||
|
for i in range(256):
|
||||||
|
if chr(i) in ["!" , "#" , "$" , "%" , "&" , "'" , "*",
|
||||||
|
"+" , "-" , "." , "^" , "_" , "`" , "|" , "~"] or\
|
||||||
|
('0' <= chr(i) and chr(i) <= '9') or \
|
||||||
|
('A' <= chr(i) and chr(i) <= 'Z') or \
|
||||||
|
('a' <= chr(i) and chr(i) <= 'z'):
|
||||||
|
sys.stdout.write('1 /* {} */, '.format(chr(i)))
|
||||||
|
elif (0x21 <= i and i < 0x7f):
|
||||||
|
sys.stdout.write('0 /* {} */, '.format(chr(i)))
|
||||||
|
elif 0x80 <= i:
|
||||||
|
sys.stdout.write('0 /* {} */, '.format(hex(i)))
|
||||||
|
else:
|
||||||
|
sys.stdout.write('0 /* {} */, '.format(name(i)))
|
||||||
|
if (i + 1)%4 == 0:
|
||||||
|
sys.stdout.write('\n')
|
||||||
@@ -177,6 +177,27 @@ OPTIONS = [
|
|||||||
"tls13-ciphers",
|
"tls13-ciphers",
|
||||||
"tls13-client-ciphers",
|
"tls13-client-ciphers",
|
||||||
"no-strip-incoming-early-data",
|
"no-strip-incoming-early-data",
|
||||||
|
"quic-bpf-program-file",
|
||||||
|
"no-quic-bpf",
|
||||||
|
"http2-altsvc",
|
||||||
|
"frontend-http3-read-timeout",
|
||||||
|
"frontend-quic-idle-timeout",
|
||||||
|
"frontend-quic-debug-log",
|
||||||
|
"frontend-http3-window-size",
|
||||||
|
"frontend-http3-connection-window-size",
|
||||||
|
"frontend-http3-max-window-size",
|
||||||
|
"frontend-http3-max-connection-window-size",
|
||||||
|
"frontend-http3-max-concurrent-streams",
|
||||||
|
"frontend-quic-early-data",
|
||||||
|
"frontend-quic-qlog-dir",
|
||||||
|
"frontend-quic-require-token",
|
||||||
|
"frontend-quic-congestion-controller",
|
||||||
|
"quic-server-id",
|
||||||
|
"frontend-quic-secret-file",
|
||||||
|
"rlimit-memlock",
|
||||||
|
"max-worker-processes",
|
||||||
|
"worker-process-grace-shutdown-period",
|
||||||
|
"frontend-quic-initial-rtt",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|||||||
23
genpathchartbl.py
Executable file
23
genpathchartbl.py
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def name(i):
|
||||||
|
if i < 0x21:
|
||||||
|
return \
|
||||||
|
['NUL ', 'SOH ', 'STX ', 'ETX ', 'EOT ', 'ENQ ', 'ACK ', 'BEL ',
|
||||||
|
'BS ', 'HT ', 'LF ', 'VT ', 'FF ', 'CR ', 'SO ', 'SI ',
|
||||||
|
'DLE ', 'DC1 ', 'DC2 ', 'DC3 ', 'DC4 ', 'NAK ', 'SYN ', 'ETB ',
|
||||||
|
'CAN ', 'EM ', 'SUB ', 'ESC ', 'FS ', 'GS ', 'RS ', 'US ',
|
||||||
|
'SPC '][i]
|
||||||
|
elif i == 0x7f:
|
||||||
|
return 'DEL '
|
||||||
|
|
||||||
|
for i in range(256):
|
||||||
|
if (0x21 <= i and i < 0x7f):
|
||||||
|
sys.stdout.write('1 /* {} */, '.format(chr(i)))
|
||||||
|
elif 0x80 <= i:
|
||||||
|
sys.stdout.write('1 /* {} */, '.format(hex(i)))
|
||||||
|
else:
|
||||||
|
sys.stdout.write('0 /* {} */, '.format(name(i)))
|
||||||
|
if (i + 1)%4 == 0:
|
||||||
|
sys.stdout.write('\n')
|
||||||
@@ -20,8 +20,6 @@ for i in range(256):
|
|||||||
sys.stdout.write('1 /* {} */, '.format(chr(i)))
|
sys.stdout.write('1 /* {} */, '.format(chr(i)))
|
||||||
elif 0x80 <= i:
|
elif 0x80 <= i:
|
||||||
sys.stdout.write('1 /* {} */, '.format(hex(i)))
|
sys.stdout.write('1 /* {} */, '.format(hex(i)))
|
||||||
elif 0 == i:
|
|
||||||
sys.stdout.write('1 /* NUL */, ')
|
|
||||||
else:
|
else:
|
||||||
sys.stdout.write('0 /* {} */, '.format(name(i)))
|
sys.stdout.write('0 /* {} */, '.format(name(i)))
|
||||||
if (i + 1)%4 == 0:
|
if (i + 1)%4 == 0:
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"golang.org/x/net/http2/hpack"
|
|
||||||
"golang.org/x/net/websocket"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2/hpack"
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
|
// TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
|
||||||
@@ -34,7 +35,7 @@ func TestH1H1PlainGET(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
|
// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
|
||||||
// Connetion: close request header field works.
|
// Connection: close request header field works.
|
||||||
func TestH1H1PlainGETClose(t *testing.T) {
|
func TestH1H1PlainGETClose(t *testing.T) {
|
||||||
st := newServerTester(nil, t, noopHandler)
|
st := newServerTester(nil, t, noopHandler)
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
@@ -1171,3 +1172,31 @@ Content-Length: 1000000
|
|||||||
t.Errorf("status: %v; want %v", got, want)
|
t.Errorf("status: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH1H1ChunkedEndsPrematurely tests that an HTTP/1.1 request fails
|
||||||
|
// if the backend chunked encoded response ends prematurely.
|
||||||
|
func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, 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()
|
||||||
|
bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
|
||||||
|
bufrw.Flush()
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
_, err := st.http1(requestParam{
|
||||||
|
name: "TestH1H1ChunkedEndsPrematurely",
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("st.http1() should fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ func TestH2H1BadResponseCL(t *testing.T) {
|
|||||||
t.Fatalf("Error st.http2() = %v", err)
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
want := http2.ErrCodeProtocol
|
want := http2.ErrCodeInternal
|
||||||
if res.errCode != want {
|
if res.errCode != want {
|
||||||
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
|
t.Errorf("res.errCode = %v; want %v", res.errCode, want)
|
||||||
}
|
}
|
||||||
@@ -2838,3 +2838,35 @@ func TestH2ResponseBeforeRequestEnd(t *testing.T) {
|
|||||||
t.Errorf("res.status: %v; want %v", got, want)
|
t.Errorf("res.status: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1ChunkedEndsPrematurely tests that a stream is reset if the
|
||||||
|
// backend chunked encoded response ends prematurely.
|
||||||
|
func TestH2H1ChunkedEndsPrematurely(t *testing.T) {
|
||||||
|
st := newServerTester(nil, t, 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()
|
||||||
|
bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
|
||||||
|
bufrw.Flush()
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1ChunkedEndsPrematurely",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.errCode, http2.ErrCodeInternal; got != want {
|
||||||
|
t.Errorf("res.errCode = %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3054,7 +3054,7 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
|
|||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* Processes data |in| as an input from the remote endpoint. The
|
* Processes data |in| as an input from the remote endpoint. The
|
||||||
* |inlen| indicates the number of bytes in the |in|.
|
* |inlen| indicates the number of bytes to receive in the |in|.
|
||||||
*
|
*
|
||||||
* This function behaves like `nghttp2_session_recv()` except that it
|
* This function behaves like `nghttp2_session_recv()` except that it
|
||||||
* does not use :type:`nghttp2_recv_callback` to receive data; the
|
* does not use :type:`nghttp2_recv_callback` to receive data; the
|
||||||
@@ -3063,7 +3063,7 @@ NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
|
|||||||
* are called in the same way as they are in `nghttp2_session_recv()`.
|
* are called in the same way as they are in `nghttp2_session_recv()`.
|
||||||
*
|
*
|
||||||
* In the current implementation, this function always tries to
|
* In the current implementation, this function always tries to
|
||||||
* processes all input data unless either an error occurs or
|
* processes |inlen| bytes of input data unless either an error occurs or
|
||||||
* :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from
|
* :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` is returned from
|
||||||
* :type:`nghttp2_on_header_callback` or
|
* :type:`nghttp2_on_header_callback` or
|
||||||
* :type:`nghttp2_on_data_chunk_recv_callback`. If
|
* :type:`nghttp2_on_data_chunk_recv_callback`. If
|
||||||
@@ -4839,7 +4839,31 @@ NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
|
|||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* Returns nonzero if the |value| which is supposed to the value of
|
* Returns nonzero if the |value| which is supposed to be the value of
|
||||||
|
* the :method header field is valid according to
|
||||||
|
* https://datatracker.ietf.org/doc/html/rfc7231#section-4 and
|
||||||
|
* https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN int nghttp2_check_method(const uint8_t *value, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns nonzero if the |value| which is supposed to be the value of
|
||||||
|
* the :path header field is valid according to
|
||||||
|
* https://datatracker.ietf.org/doc/html/rfc7540#section-8.1.2.3
|
||||||
|
*
|
||||||
|
* |value| is valid if it merely consists of the allowed characters.
|
||||||
|
* In particular, it does not check whether |value| follows the syntax
|
||||||
|
* of path. The allowed characters are all characters valid by
|
||||||
|
* `nghttp2_check_header_value` minus SPC and HT.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN int nghttp2_check_path(const uint8_t *value, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns nonzero if the |value| which is supposed to be the value of the
|
||||||
* :authority or host header field is valid according to
|
* :authority or host header field is valid according to
|
||||||
* https://tools.ietf.org/html/rfc3986#section-3.2
|
* https://tools.ietf.org/html/rfc3986#section-3.2
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
|
|||||||
* |new_cap|. If extensions took place, buffer pointers in |buf| will
|
* |new_cap|. If extensions took place, buffer pointers in |buf| will
|
||||||
* change.
|
* change.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the followings
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
|||||||
@@ -654,8 +654,6 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
|||||||
var_gift_payloadlen = 0;
|
var_gift_payloadlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
payloadlen -= var_gift_payloadlen;
|
|
||||||
|
|
||||||
if (!var_gift_payloadlen) {
|
if (!var_gift_payloadlen) {
|
||||||
var_gift_payload = NULL;
|
var_gift_payload = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
||||||
|
|
||||||
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
||||||
/* The one frame buffer length for tranmission. We may use several of
|
/* The one frame buffer length for transmission. We may use several of
|
||||||
them to support CONTINUATION. To account for Pad Length field, we
|
them to support CONTINUATION. To account for Pad Length field, we
|
||||||
allocate extra 1 byte, which saves extra large memcopying. */
|
allocate extra 1 byte, which saves extra large memcopying. */
|
||||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
/* Maximum headers block size to send, calculated using
|
/* Maximum headers block size to send, calculated using
|
||||||
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
||||||
overridden by nghttp2_option_set_max_send_header_block_size(). */
|
overridden by nghttp2_option_set_max_send_header_block_length(). */
|
||||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||||
|
|
||||||
/* The number of bytes for each SETTINGS entry */
|
/* The number of bytes for each SETTINGS entry */
|
||||||
|
|||||||
@@ -1263,6 +1263,8 @@ int nghttp2_hd_inflate_change_table_size(
|
|||||||
return NGHTTP2_ERR_INVALID_STATE;
|
return NGHTTP2_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
|
|
||||||
/* It seems that encoder is not required to send dynamic table size
|
/* It seems that encoder is not required to send dynamic table size
|
||||||
update if the table size is not changed after applying
|
update if the table size is not changed after applying
|
||||||
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
|
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
|
||||||
@@ -1275,13 +1277,12 @@ int nghttp2_hd_inflate_change_table_size(
|
|||||||
/* Remember minimum value, and validate that encoder sends the
|
/* Remember minimum value, and validate that encoder sends the
|
||||||
value less than or equal to this. */
|
value less than or equal to this. */
|
||||||
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
}
|
|
||||||
|
|
||||||
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
|
||||||
|
|
||||||
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
|
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
|
|
||||||
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -507,7 +507,166 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generated by genauthroitychartbl.py */
|
/* Generated by genmethodchartbl.py */
|
||||||
|
static char VALID_METHOD_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||||
|
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||||
|
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||||
|
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||||
|
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||||
|
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||||
|
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||||
|
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
|
||||||
|
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
|
||||||
|
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||||
|
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||||
|
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||||
|
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
|
||||||
|
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||||
|
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||||
|
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||||
|
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||||
|
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||||
|
1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
|
||||||
|
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||||
|
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||||
|
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||||
|
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||||
|
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||||
|
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||||
|
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||||
|
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||||
|
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||||
|
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||||
|
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||||
|
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||||
|
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||||
|
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||||
|
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||||
|
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||||
|
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||||
|
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||||
|
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||||
|
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||||
|
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||||
|
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||||
|
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||||
|
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||||
|
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||||
|
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||||
|
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||||
|
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||||
|
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||||
|
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||||
|
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||||
|
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||||
|
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||||
|
};
|
||||||
|
|
||||||
|
int nghttp2_check_method(const uint8_t *value, size_t len) {
|
||||||
|
const uint8_t *last;
|
||||||
|
if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (last = value + len; value != last; ++value) {
|
||||||
|
if (!VALID_METHOD_CHARS[*value]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genpathchartbl.py */
|
||||||
|
static char VALID_PATH_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||||
|
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||||
|
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||||
|
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||||
|
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||||
|
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||||
|
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||||
|
0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
|
||||||
|
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||||
|
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
|
||||||
|
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||||
|
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||||
|
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||||
|
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
|
||||||
|
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||||
|
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||||
|
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||||
|
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||||
|
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||||
|
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||||
|
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||||
|
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||||
|
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||||
|
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||||
|
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||||
|
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
|
||||||
|
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||||
|
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
|
||||||
|
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
|
||||||
|
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||||
|
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
|
||||||
|
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
|
||||||
|
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
|
||||||
|
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
|
||||||
|
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||||
|
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
|
||||||
|
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
|
||||||
|
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
|
||||||
|
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
|
||||||
|
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||||
|
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
|
||||||
|
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
|
||||||
|
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
|
||||||
|
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
|
||||||
|
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||||
|
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
|
||||||
|
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
|
||||||
|
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
|
||||||
|
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
|
||||||
|
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||||
|
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
|
||||||
|
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
|
||||||
|
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
|
||||||
|
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
|
||||||
|
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||||
|
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
|
||||||
|
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
|
||||||
|
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
|
||||||
|
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
|
||||||
|
};
|
||||||
|
|
||||||
|
int nghttp2_check_path(const uint8_t *value, size_t len) {
|
||||||
|
const uint8_t *last;
|
||||||
|
for (last = value + len; value != last; ++value) {
|
||||||
|
if (!VALID_PATH_CHARS[*value]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genauthoritychartbl.py */
|
||||||
static char VALID_AUTHORITY_CHARS[] = {
|
static char VALID_AUTHORITY_CHARS[] = {
|
||||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||||
|
|||||||
@@ -360,12 +360,21 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
|||||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
|
switch (nv->token) {
|
||||||
nv->token == NGHTTP2_TOKEN_HOST) {
|
case NGHTTP2_TOKEN__METHOD:
|
||||||
|
rv = nghttp2_check_method(nv->value->base, nv->value->len);
|
||||||
|
break;
|
||||||
|
case NGHTTP2_TOKEN__PATH:
|
||||||
|
rv = nghttp2_check_path(nv->value->base, nv->value->len);
|
||||||
|
break;
|
||||||
|
case NGHTTP2_TOKEN__AUTHORITY:
|
||||||
|
case NGHTTP2_TOKEN_HOST:
|
||||||
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
|
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
|
||||||
} else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
|
break;
|
||||||
|
case NGHTTP2_TOKEN__SCHEME:
|
||||||
rv = check_scheme(nv->value->base, nv->value->len);
|
rv = check_scheme(nv->value->base, nv->value->len);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
|
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,6 +189,7 @@ static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
|
|||||||
nghttp2_map_bucket *new_table;
|
nghttp2_map_bucket *new_table;
|
||||||
nghttp2_map_bucket *bkt;
|
nghttp2_map_bucket *bkt;
|
||||||
int rv;
|
int rv;
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
new_table =
|
new_table =
|
||||||
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
|
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
/* Windows requires ws2_32 library for ntonl family functions. We
|
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||||
define inline functions for those function so that we don't have
|
define inline functions for those function so that we don't have
|
||||||
dependeny on that lib. */
|
dependency on that lib. */
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
# define STIN static __inline
|
# define STIN static __inline
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ struct nghttp2_outbound_item {
|
|||||||
to this structure to avoid frequent memory allocation. */
|
to this structure to avoid frequent memory allocation. */
|
||||||
nghttp2_ext_frame_payload ext_frame_payload;
|
nghttp2_ext_frame_payload ext_frame_payload;
|
||||||
nghttp2_aux_data aux_data;
|
nghttp2_aux_data aux_data;
|
||||||
/* The priority used in priority comparion. Smaller is served
|
/* The priority used in priority comparison. Smaller is served
|
||||||
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
||||||
response HEADERS frame) have dedicated cycle value defined above.
|
response HEADERS frame) have dedicated cycle value defined above.
|
||||||
For DATA frame, cycle is computed by taking into account of
|
For DATA frame, cycle is computed by taking into account of
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
|
|||||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
|
* Applies |fun| to each item in |pq|. The |arg| is passed as arg
|
||||||
* parameter to callback function. This function must not change the
|
* parameter to callback function. This function must not change the
|
||||||
* ordering key. If the return value from callback is nonzero, this
|
* ordering key. If the return value from callback is nonzero, this
|
||||||
* function returns 1 immediately without iterating remaining items.
|
* function returns 1 immediately without iterating remaining items.
|
||||||
|
|||||||
@@ -5341,7 +5341,7 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This function returns the effective payload length in the data of
|
* This function returns the effective payload length in the data of
|
||||||
* length |readlen| when the remaning payload is |payloadleft|. The
|
* length |readlen| when the remaining payload is |payloadleft|. The
|
||||||
* |payloadleft| does not include |readlen|. If padding was started
|
* |payloadleft| does not include |readlen|. If padding was started
|
||||||
* strictly before this data chunk, this function returns -1.
|
* strictly before this data chunk, this function returns -1.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
|||||||
uint32_t error_code);
|
uint32_t error_code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds PING frame. This is a convenient functin built on top of
|
* Adds PING frame. This is a convenient function built on top of
|
||||||
* nghttp2_session_add_frame() to add PING easily.
|
* nghttp2_session_add_frame() to add PING easily.
|
||||||
*
|
*
|
||||||
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "nghttp2_frame.h"
|
#include "nghttp2_frame.h"
|
||||||
|
|
||||||
/* Maximum distance between any two stream's cycle in the same
|
/* Maximum distance between any two stream's cycle in the same
|
||||||
prirority queue. Imagine stream A's cycle is A, and stream B's
|
priority queue. Imagine stream A's cycle is A, and stream B's
|
||||||
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
||||||
may get overflow. Because of how we calculate the next cycle
|
may get overflow. Because of how we calculate the next cycle
|
||||||
value, if B - A is less than or equals to
|
value, if B - A is less than or equals to
|
||||||
|
|||||||
@@ -492,8 +492,6 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
|||||||
return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
|
return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
|
||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
# modified version of the Autoconf Macro, you may extend this special
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
# exception to the GPL to apply to your modified version as well.
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
#serial 21
|
#serial 23
|
||||||
|
|
||||||
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
|
||||||
AC_DEFUN([AX_PYTHON_DEVEL],[
|
AC_DEFUN([AX_PYTHON_DEVEL],[
|
||||||
@@ -135,27 +135,45 @@ variable to configure. See ``configure --help'' for reference.
|
|||||||
#
|
#
|
||||||
# Check if you have distutils, else fail
|
# Check if you have distutils, else fail
|
||||||
#
|
#
|
||||||
AC_MSG_CHECKING([for the distutils Python package])
|
AC_MSG_CHECKING([for the sysconfig Python package])
|
||||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
ac_sysconfig_result=`$PYTHON -c "import sysconfig" 2>&1`
|
||||||
if test $? -eq 0; then
|
if test $? -eq 0; then
|
||||||
AC_MSG_RESULT([yes])
|
AC_MSG_RESULT([yes])
|
||||||
|
IMPORT_SYSCONFIG="import sysconfig"
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for the distutils Python package])
|
||||||
|
ac_sysconfig_result=`$PYTHON -c "from distutils import sysconfig" 2>&1`
|
||||||
|
if test $? -eq 0; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
IMPORT_SYSCONFIG="from distutils import sysconfig"
|
||||||
|
else
|
||||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||||
Please check your Python installation. The error was:
|
Please check your Python installation. The error was:
|
||||||
$ac_distutils_result])
|
$ac_sysconfig_result])
|
||||||
PYTHON_VERSION=""
|
PYTHON_VERSION=""
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check for Python include path
|
# Check for Python include path
|
||||||
#
|
#
|
||||||
AC_MSG_CHECKING([for Python include path])
|
AC_MSG_CHECKING([for Python include path])
|
||||||
if test -z "$PYTHON_CPPFLAGS"; then
|
if test -z "$PYTHON_CPPFLAGS"; then
|
||||||
python_path=`$PYTHON -c "import distutils.sysconfig; \
|
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||||
print (distutils.sysconfig.get_python_inc ());"`
|
# sysconfig module has different functions
|
||||||
plat_python_path=`$PYTHON -c "import distutils.sysconfig; \
|
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
print (distutils.sysconfig.get_python_inc (plat_specific=1));"`
|
print (sysconfig.get_path ('include'));"`
|
||||||
|
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_path ('platinclude'));"`
|
||||||
|
else
|
||||||
|
# old distutils way
|
||||||
|
python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_python_inc ());"`
|
||||||
|
plat_python_path=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_python_inc (plat_specific=1));"`
|
||||||
|
fi
|
||||||
if test -n "${python_path}"; then
|
if test -n "${python_path}"; then
|
||||||
if test "${plat_python_path}" != "${python_path}"; then
|
if test "${plat_python_path}" != "${python_path}"; then
|
||||||
python_path="-I$python_path -I$plat_python_path"
|
python_path="-I$python_path -I$plat_python_path"
|
||||||
@@ -179,7 +197,7 @@ $ac_distutils_result])
|
|||||||
|
|
||||||
# join all versioning strings, on some systems
|
# join all versioning strings, on some systems
|
||||||
# major/minor numbers could be in different list elements
|
# major/minor numbers could be in different list elements
|
||||||
from distutils.sysconfig import *
|
from sysconfig import *
|
||||||
e = get_config_var('VERSION')
|
e = get_config_var('VERSION')
|
||||||
if e is not None:
|
if e is not None:
|
||||||
print(e)
|
print(e)
|
||||||
@@ -202,8 +220,8 @@ EOD`
|
|||||||
ac_python_libdir=`cat<<EOD | $PYTHON -
|
ac_python_libdir=`cat<<EOD | $PYTHON -
|
||||||
|
|
||||||
# There should be only one
|
# There should be only one
|
||||||
import distutils.sysconfig
|
$IMPORT_SYSCONFIG
|
||||||
e = distutils.sysconfig.get_config_var('LIBDIR')
|
e = sysconfig.get_config_var('LIBDIR')
|
||||||
if e is not None:
|
if e is not None:
|
||||||
print (e)
|
print (e)
|
||||||
EOD`
|
EOD`
|
||||||
@@ -211,8 +229,8 @@ EOD`
|
|||||||
# Now, for the library:
|
# Now, for the library:
|
||||||
ac_python_library=`cat<<EOD | $PYTHON -
|
ac_python_library=`cat<<EOD | $PYTHON -
|
||||||
|
|
||||||
import distutils.sysconfig
|
$IMPORT_SYSCONFIG
|
||||||
c = distutils.sysconfig.get_config_vars()
|
c = sysconfig.get_config_vars()
|
||||||
if 'LDVERSION' in c:
|
if 'LDVERSION' in c:
|
||||||
print ('python'+c[['LDVERSION']])
|
print ('python'+c[['LDVERSION']])
|
||||||
else:
|
else:
|
||||||
@@ -231,7 +249,7 @@ EOD`
|
|||||||
else
|
else
|
||||||
# old way: use libpython from python_configdir
|
# old way: use libpython from python_configdir
|
||||||
ac_python_libdir=`$PYTHON -c \
|
ac_python_libdir=`$PYTHON -c \
|
||||||
"from distutils.sysconfig import get_python_lib as f; \
|
"from sysconfig import get_python_lib as f; \
|
||||||
import os; \
|
import os; \
|
||||||
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
|
||||||
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
|
PYTHON_LIBS="-L$ac_python_libdir -lpython$ac_python_version"
|
||||||
@@ -252,19 +270,42 @@ EOD`
|
|||||||
#
|
#
|
||||||
AC_MSG_CHECKING([for Python site-packages path])
|
AC_MSG_CHECKING([for Python site-packages path])
|
||||||
if test -z "$PYTHON_SITE_PKG"; then
|
if test -z "$PYTHON_SITE_PKG"; then
|
||||||
PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
|
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||||
print (distutils.sysconfig.get_python_lib(0,0));"`
|
PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_path('purelib'));"`
|
||||||
|
else
|
||||||
|
# distutils.sysconfig way
|
||||||
|
PYTHON_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_python_lib(0,0));"`
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||||
AC_SUBST([PYTHON_SITE_PKG])
|
AC_SUBST([PYTHON_SITE_PKG])
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for platform-specific site packages
|
||||||
|
#
|
||||||
|
AC_MSG_CHECKING([for Python platform specific site-packages path])
|
||||||
|
if test -z "$PYTHON_SITE_PKG"; then
|
||||||
|
if test "$IMPORT_SYSCONFIG" = "import sysconfig"; then
|
||||||
|
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_path('platlib'));"`
|
||||||
|
else
|
||||||
|
# distutils.sysconfig way
|
||||||
|
PYTHON_PLATFORM_SITE_PKG=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
|
print (sysconfig.get_python_lib(1,0));"`
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([$PYTHON_PLATFORM_SITE_PKG])
|
||||||
|
AC_SUBST([PYTHON_PLATFORM_SITE_PKG])
|
||||||
|
|
||||||
#
|
#
|
||||||
# libraries which must be linked in when embedding
|
# libraries which must be linked in when embedding
|
||||||
#
|
#
|
||||||
AC_MSG_CHECKING(python extra libraries)
|
AC_MSG_CHECKING(python extra libraries)
|
||||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
|
PYTHON_EXTRA_LIBS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
conf = distutils.sysconfig.get_config_var; \
|
conf = sysconfig.get_config_var; \
|
||||||
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
|
print (conf('LIBS') + ' ' + conf('SYSLIBS'))"`
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||||
@@ -275,8 +316,8 @@ EOD`
|
|||||||
#
|
#
|
||||||
AC_MSG_CHECKING(python extra linking flags)
|
AC_MSG_CHECKING(python extra linking flags)
|
||||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
|
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "$IMPORT_SYSCONFIG; \
|
||||||
conf = distutils.sysconfig.get_config_var; \
|
conf = sysconfig.get_config_var; \
|
||||||
print (conf('LINKFORSHARED'))"`
|
print (conf('LINKFORSHARED'))"`
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ cdef class _HTTP2SessionCoreBase:
|
|||||||
if outbuflen == 0:
|
if outbuflen == 0:
|
||||||
break
|
break
|
||||||
if outbuflen < 0:
|
if outbuflen < 0:
|
||||||
raise Exception('nghttp2_session_mem_send faild: {}'.format\
|
raise Exception('nghttp2_session_mem_send failed: {}'.format\
|
||||||
(_strerror(outbuflen)))
|
(_strerror(outbuflen)))
|
||||||
self.transport.write(outbuf[:outbuflen])
|
self.transport.write(outbuf[:outbuflen])
|
||||||
|
|
||||||
@@ -1057,8 +1057,7 @@ if asyncio:
|
|||||||
"""HTTP/2 request (stream) handler base class.
|
"""HTTP/2 request (stream) handler base class.
|
||||||
|
|
||||||
The class is used to handle the HTTP/2 stream. By default, it does
|
The class is used to handle the HTTP/2 stream. By default, it does
|
||||||
not nothing. It must be subclassed to handle each event callback
|
nothing. It must be subclassed to handle each event callback method.
|
||||||
method.
|
|
||||||
|
|
||||||
The first callback method invoked is on_headers(). It is called
|
The first callback method invoked is on_headers(). It is called
|
||||||
when HEADERS frame, which includes request header fields, is
|
when HEADERS frame, which includes request header fields, is
|
||||||
@@ -1084,7 +1083,7 @@ if asyncio:
|
|||||||
address.
|
address.
|
||||||
|
|
||||||
client_certificate
|
client_certificate
|
||||||
May contain the client certifcate in its non-binary form
|
May contain the client certificate in its non-binary form
|
||||||
|
|
||||||
stream_id
|
stream_id
|
||||||
Stream ID of this stream
|
Stream ID of this stream
|
||||||
|
|||||||
@@ -15,10 +15,14 @@ include_directories(
|
|||||||
${JEMALLOC_INCLUDE_DIRS}
|
${JEMALLOC_INCLUDE_DIRS}
|
||||||
${LIBXML2_INCLUDE_DIRS}
|
${LIBXML2_INCLUDE_DIRS}
|
||||||
${LIBEV_INCLUDE_DIRS}
|
${LIBEV_INCLUDE_DIRS}
|
||||||
|
${LIBNGHTTP3_INCLUDE_DIRS}
|
||||||
|
${LIBNGTCP2_INCLUDE_DIRS}
|
||||||
|
${LIBNGTCP2_CRYPTO_OPENSSL_INCLUDE_DIRS}
|
||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
${LIBCARES_INCLUDE_DIRS}
|
${LIBCARES_INCLUDE_DIRS}
|
||||||
${JANSSON_INCLUDE_DIRS}
|
${JANSSON_INCLUDE_DIRS}
|
||||||
${ZLIB_INCLUDE_DIRS}
|
${ZLIB_INCLUDE_DIRS}
|
||||||
|
${LIBBPF_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
# XXX per-target?
|
# XXX per-target?
|
||||||
@@ -27,11 +31,15 @@ link_libraries(
|
|||||||
${JEMALLOC_LIBRARIES}
|
${JEMALLOC_LIBRARIES}
|
||||||
${LIBXML2_LIBRARIES}
|
${LIBXML2_LIBRARIES}
|
||||||
${LIBEV_LIBRARIES}
|
${LIBEV_LIBRARIES}
|
||||||
|
${LIBNGHTTP3_LIBRARIES}
|
||||||
|
${LIBNGTCP2_LIBRARIES}
|
||||||
|
${LIBNGTCP2_CRYPTO_OPENSSL_LIBRARIES}
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
${LIBCARES_LIBRARIES}
|
${LIBCARES_LIBRARIES}
|
||||||
${JANSSON_LIBRARIES}
|
${JANSSON_LIBRARIES}
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
${APP_LIBRARIES}
|
${APP_LIBRARIES}
|
||||||
|
${LIBBPF_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_APP)
|
if(ENABLE_APP)
|
||||||
@@ -67,7 +75,13 @@ if(ENABLE_APP)
|
|||||||
h2load_http2_session.cc
|
h2load_http2_session.cc
|
||||||
h2load_http1_session.cc
|
h2load_http1_session.cc
|
||||||
)
|
)
|
||||||
|
if(ENABLE_HTTP3)
|
||||||
|
list(APPEND H2LOAD_SOURCES
|
||||||
|
h2load_http3_session.cc
|
||||||
|
h2load_quic.cc
|
||||||
|
quic.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Common libnhttpx sources (used for nghttpx and unit tests)
|
# Common libnhttpx sources (used for nghttpx and unit tests)
|
||||||
set(NGHTTPX_SRCS
|
set(NGHTTPX_SRCS
|
||||||
@@ -104,6 +118,7 @@ if(ENABLE_APP)
|
|||||||
shrpx_router.cc
|
shrpx_router.cc
|
||||||
shrpx_api_downstream_connection.cc
|
shrpx_api_downstream_connection.cc
|
||||||
shrpx_health_monitor_downstream_connection.cc
|
shrpx_health_monitor_downstream_connection.cc
|
||||||
|
shrpx_null_downstream_connection.cc
|
||||||
shrpx_exec.cc
|
shrpx_exec.cc
|
||||||
shrpx_dns_resolver.cc
|
shrpx_dns_resolver.cc
|
||||||
shrpx_dual_dns_resolver.cc
|
shrpx_dual_dns_resolver.cc
|
||||||
@@ -119,6 +134,16 @@ if(ENABLE_APP)
|
|||||||
shrpx_mruby_module_response.cc
|
shrpx_mruby_module_response.cc
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
if(ENABLE_HTTP3)
|
||||||
|
list(APPEND NGHTTPX_SRCS
|
||||||
|
shrpx_quic.cc
|
||||||
|
shrpx_quic_listener.cc
|
||||||
|
shrpx_quic_connection_handler.cc
|
||||||
|
shrpx_http3_upstream.cc
|
||||||
|
http3.cc
|
||||||
|
quic.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
add_library(nghttpx_static STATIC ${NGHTTPX_SRCS})
|
add_library(nghttpx_static STATIC ${NGHTTPX_SRCS})
|
||||||
set_target_properties(nghttpx_static PROPERTIES ARCHIVE_OUTPUT_NAME nghttpx)
|
set_target_properties(nghttpx_static PROPERTIES ARCHIVE_OUTPUT_NAME nghttpx)
|
||||||
|
|
||||||
@@ -189,7 +214,10 @@ if(ENABLE_APP)
|
|||||||
add_executable(nghttpx ${NGHTTPX-bin_SOURCES} $<TARGET_OBJECTS:llhttp>
|
add_executable(nghttpx ${NGHTTPX-bin_SOURCES} $<TARGET_OBJECTS:llhttp>
|
||||||
$<TARGET_OBJECTS:url-parser>
|
$<TARGET_OBJECTS:url-parser>
|
||||||
)
|
)
|
||||||
target_compile_definitions(nghttpx PRIVATE "-DPKGDATADIR=\"${PKGDATADIR}\"")
|
target_compile_definitions(nghttpx PRIVATE
|
||||||
|
"-DPKGDATADIR=\"${PKGDATADIR}\""
|
||||||
|
"-DPKGLIBDIR=\"${PKGLIBDIR}\""
|
||||||
|
)
|
||||||
target_link_libraries(nghttpx nghttpx_static)
|
target_link_libraries(nghttpx nghttpx_static)
|
||||||
add_executable(h2load ${H2LOAD_SOURCES} $<TARGET_OBJECTS:llhttp>
|
add_executable(h2load ${H2LOAD_SOURCES} $<TARGET_OBJECTS:llhttp>
|
||||||
$<TARGET_OBJECTS:url-parser>
|
$<TARGET_OBJECTS:url-parser>
|
||||||
|
|||||||
@@ -52,8 +52,13 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
#include "ssl_compat.h"
|
||||||
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
|
#if OPENSSL_3_0_0_API
|
||||||
|
# include <openssl/decoder.h>
|
||||||
|
#endif // OPENSSL_3_0_0_API
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
@@ -2105,7 +2110,7 @@ int HttpServer::run() {
|
|||||||
std::vector<unsigned char> next_proto;
|
std::vector<unsigned char> next_proto;
|
||||||
|
|
||||||
if (!config_->no_tls) {
|
if (!config_->no_tls) {
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
ssl_ctx = SSL_CTX_new(TLS_server_method());
|
||||||
if (!ssl_ctx) {
|
if (!ssl_ctx) {
|
||||||
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2138,15 +2143,13 @@ int HttpServer::run() {
|
|||||||
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
|
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_EC
|
#ifndef OPENSSL_NO_EC
|
||||||
|
# if !LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
// Disabled SSL_CTX_set_ecdh_auto, because computational cost of
|
if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
|
||||||
// chosen curve is much higher than P-256.
|
std::cerr << "SSL_CTX_set1_curves_list failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
// #if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
return -1;
|
||||||
// SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
|
}
|
||||||
// #else // OPENSSL_VERSION_NUBMER < 0x10002000L
|
# else // !(!LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||||
// Use P-256, which is sufficiently secure at the time of this
|
|
||||||
// writing.
|
|
||||||
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||||
if (ecdh == nullptr) {
|
if (ecdh == nullptr) {
|
||||||
std::cerr << "EC_KEY_new_by_curv_name failed: "
|
std::cerr << "EC_KEY_new_by_curv_name failed: "
|
||||||
@@ -2155,19 +2158,36 @@ int HttpServer::run() {
|
|||||||
}
|
}
|
||||||
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
||||||
EC_KEY_free(ecdh);
|
EC_KEY_free(ecdh);
|
||||||
// #endif // OPENSSL_VERSION_NUBMER < 0x10002000L
|
# endif // !(!LIBRESSL_LEGACY_API && OPENSSL_VERSION_NUMBER >= 0x10002000L)
|
||||||
|
|
||||||
#endif // OPENSSL_NO_EC
|
#endif // OPENSSL_NO_EC
|
||||||
|
|
||||||
if (!config_->dh_param_file.empty()) {
|
if (!config_->dh_param_file.empty()) {
|
||||||
// Read DH parameters from file
|
// Read DH parameters from file
|
||||||
auto bio = BIO_new_file(config_->dh_param_file.c_str(), "r");
|
auto bio = BIO_new_file(config_->dh_param_file.c_str(), "rb");
|
||||||
if (bio == nullptr) {
|
if (bio == nullptr) {
|
||||||
std::cerr << "BIO_new_file() failed: "
|
std::cerr << "BIO_new_file() failed: "
|
||||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_3_0_0_API
|
||||||
|
EVP_PKEY *dh = nullptr;
|
||||||
|
auto dctx = OSSL_DECODER_CTX_new_for_pkey(
|
||||||
|
&dh, "PEM", nullptr, "DH", OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
|
||||||
|
nullptr, nullptr);
|
||||||
|
|
||||||
|
if (!OSSL_DECODER_from_bio(dctx, bio)) {
|
||||||
|
std::cerr << "OSSL_DECODER_from_bio() failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, dh) != 1) {
|
||||||
|
std::cerr << "SSL_CTX_set0_tmp_dh_pkey failed: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else // !OPENSSL_3_0_0_API
|
||||||
auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
|
auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
if (dh == nullptr) {
|
if (dh == nullptr) {
|
||||||
@@ -2178,6 +2198,7 @@ int HttpServer::run() {
|
|||||||
|
|
||||||
SSL_CTX_set_tmp_dh(ssl_ctx, dh);
|
SSL_CTX_set_tmp_dh(ssl_ctx, dh);
|
||||||
DH_free(dh);
|
DH_free(dh);
|
||||||
|
#endif // !OPENSSL_3_0_0_API
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||||
uint8_t *buf, size_t length, int *eof,
|
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||||
nghttp2_data_source *source, void *user_data);
|
nghttp2_data_source *source, void *user_data);
|
||||||
|
|
||||||
} // namespace nghttp2
|
} // namespace nghttp2
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ AM_CFLAGS = $(WARNCFLAGS)
|
|||||||
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
|
AM_CXXFLAGS = $(WARNCXXFLAGS) $(CXX1XCXXFLAGS)
|
||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
-DPKGDATADIR='"$(pkgdatadir)"' \
|
-DPKGDATADIR='"$(pkgdatadir)"' \
|
||||||
|
-DPKGLIBDIR='"$(pkglibdir)"' \
|
||||||
-I$(top_srcdir)/lib/includes \
|
-I$(top_srcdir)/lib/includes \
|
||||||
-I$(top_builddir)/lib/includes \
|
-I$(top_builddir)/lib/includes \
|
||||||
-I$(top_srcdir)/lib \
|
-I$(top_srcdir)/lib \
|
||||||
@@ -44,10 +45,16 @@ AM_CPPFLAGS = \
|
|||||||
@JEMALLOC_CFLAGS@ \
|
@JEMALLOC_CFLAGS@ \
|
||||||
@LIBXML2_CFLAGS@ \
|
@LIBXML2_CFLAGS@ \
|
||||||
@LIBEV_CFLAGS@ \
|
@LIBEV_CFLAGS@ \
|
||||||
|
@LIBNGHTTP3_CFLAGS@ \
|
||||||
|
@LIBNGTCP2_CRYPTO_OPENSSL_CFLAGS@ \
|
||||||
|
@LIBNGTCP2_CRYPTO_BORINGSSL_CFLAGS@ \
|
||||||
|
@LIBNGTCP2_CFLAGS@ \
|
||||||
@OPENSSL_CFLAGS@ \
|
@OPENSSL_CFLAGS@ \
|
||||||
@LIBCARES_CFLAGS@ \
|
@LIBCARES_CFLAGS@ \
|
||||||
@JANSSON_CFLAGS@ \
|
@JANSSON_CFLAGS@ \
|
||||||
|
@LIBBPF_CFLAGS@ \
|
||||||
@ZLIB_CFLAGS@ \
|
@ZLIB_CFLAGS@ \
|
||||||
|
@EXTRA_DEFS@ \
|
||||||
@DEFS@
|
@DEFS@
|
||||||
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
|
AM_LDFLAGS = @LIBTOOL_LDFLAGS@
|
||||||
|
|
||||||
@@ -57,10 +64,15 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \
|
|||||||
@JEMALLOC_LIBS@ \
|
@JEMALLOC_LIBS@ \
|
||||||
@LIBXML2_LIBS@ \
|
@LIBXML2_LIBS@ \
|
||||||
@LIBEV_LIBS@ \
|
@LIBEV_LIBS@ \
|
||||||
|
@LIBNGHTTP3_LIBS@ \
|
||||||
|
@LIBNGTCP2_CRYPTO_OPENSSL_LIBS@ \
|
||||||
|
@LIBNGTCP2_CRYPTO_BORINGSSL_LIBS@ \
|
||||||
|
@LIBNGTCP2_LIBS@ \
|
||||||
@OPENSSL_LIBS@ \
|
@OPENSSL_LIBS@ \
|
||||||
@LIBCARES_LIBS@ \
|
@LIBCARES_LIBS@ \
|
||||||
@SYSTEMD_LIBS@ \
|
@SYSTEMD_LIBS@ \
|
||||||
@JANSSON_LIBS@ \
|
@JANSSON_LIBS@ \
|
||||||
|
@LIBBPF_LIBS@ \
|
||||||
@ZLIB_LIBS@ \
|
@ZLIB_LIBS@ \
|
||||||
@APPLDFLAGS@
|
@APPLDFLAGS@
|
||||||
|
|
||||||
@@ -99,6 +111,13 @@ h2load_SOURCES = util.cc util.h \
|
|||||||
h2load_http2_session.cc h2load_http2_session.h \
|
h2load_http2_session.cc h2load_http2_session.h \
|
||||||
h2load_http1_session.cc h2load_http1_session.h
|
h2load_http1_session.cc h2load_http1_session.h
|
||||||
|
|
||||||
|
if ENABLE_HTTP3
|
||||||
|
h2load_SOURCES += \
|
||||||
|
h2load_http3_session.cc h2load_http3_session.h \
|
||||||
|
h2load_quic.cc h2load_quic.h \
|
||||||
|
quic.cc quic.h
|
||||||
|
endif # ENABLE_HTTP3
|
||||||
|
|
||||||
NGHTTPX_SRCS = \
|
NGHTTPX_SRCS = \
|
||||||
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \
|
||||||
app_helper.cc app_helper.h \
|
app_helper.cc app_helper.h \
|
||||||
@@ -139,6 +158,7 @@ NGHTTPX_SRCS = \
|
|||||||
shrpx_api_downstream_connection.cc shrpx_api_downstream_connection.h \
|
shrpx_api_downstream_connection.cc shrpx_api_downstream_connection.h \
|
||||||
shrpx_health_monitor_downstream_connection.cc \
|
shrpx_health_monitor_downstream_connection.cc \
|
||||||
shrpx_health_monitor_downstream_connection.h \
|
shrpx_health_monitor_downstream_connection.h \
|
||||||
|
shrpx_null_downstream_connection.cc shrpx_null_downstream_connection.h \
|
||||||
shrpx_exec.cc shrpx_exec.h \
|
shrpx_exec.cc shrpx_exec.h \
|
||||||
shrpx_dns_resolver.cc shrpx_dns_resolver.h \
|
shrpx_dns_resolver.cc shrpx_dns_resolver.h \
|
||||||
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \
|
shrpx_dual_dns_resolver.cc shrpx_dual_dns_resolver.h \
|
||||||
@@ -155,6 +175,16 @@ NGHTTPX_SRCS += \
|
|||||||
shrpx_mruby_module_response.cc shrpx_mruby_module_response.h
|
shrpx_mruby_module_response.cc shrpx_mruby_module_response.h
|
||||||
endif # HAVE_MRUBY
|
endif # HAVE_MRUBY
|
||||||
|
|
||||||
|
if ENABLE_HTTP3
|
||||||
|
NGHTTPX_SRCS += \
|
||||||
|
shrpx_quic.cc shrpx_quic.h \
|
||||||
|
shrpx_quic_listener.cc shrpx_quic_listener.h \
|
||||||
|
shrpx_quic_connection_handler.cc shrpx_quic_connection_handler.h \
|
||||||
|
shrpx_http3_upstream.cc shrpx_http3_upstream.h \
|
||||||
|
http3.cc http3.h \
|
||||||
|
quic.cc quic.h
|
||||||
|
endif # ENABLE_HTTP3
|
||||||
|
|
||||||
noinst_LIBRARIES = libnghttpx.a
|
noinst_LIBRARIES = libnghttpx.a
|
||||||
libnghttpx_a_SOURCES = ${NGHTTPX_SRCS}
|
libnghttpx_a_SOURCES = ${NGHTTPX_SRCS}
|
||||||
libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS}
|
libnghttpx_a_CPPFLAGS = ${AM_CPPFLAGS}
|
||||||
|
|||||||
374
src/h2load.cc
374
src/h2load.cc
@@ -34,6 +34,8 @@
|
|||||||
#ifdef HAVE_FCNTL_H
|
#ifdef HAVE_FCNTL_H
|
||||||
# include <fcntl.h>
|
# include <fcntl.h>
|
||||||
#endif // HAVE_FCNTL_H
|
#endif // HAVE_FCNTL_H
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -48,10 +50,18 @@
|
|||||||
|
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include <ngtcp2/ngtcp2.h>
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
#include "url-parser/url_parser.h"
|
#include "url-parser/url_parser.h"
|
||||||
|
|
||||||
#include "h2load_http1_session.h"
|
#include "h2load_http1_session.h"
|
||||||
#include "h2load_http2_session.h"
|
#include "h2load_http2_session.h"
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include "h2load_http3_session.h"
|
||||||
|
# include "h2load_quic.h"
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -71,9 +81,24 @@ bool recorded(const std::chrono::steady_clock::time_point &t) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_1_API
|
||||||
|
namespace {
|
||||||
|
std::ofstream keylog_file;
|
||||||
|
void keylog_callback(const SSL *ssl, const char *line) {
|
||||||
|
keylog_file.write(line, strlen(line));
|
||||||
|
keylog_file.put('\n');
|
||||||
|
keylog_file.flush();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
#endif // OPENSSL_1_1_1_API
|
||||||
|
|
||||||
Config::Config()
|
Config::Config()
|
||||||
: ciphers(tls::DEFAULT_CIPHER_LIST),
|
: ciphers(tls::DEFAULT_CIPHER_LIST),
|
||||||
|
tls13_ciphers("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_"
|
||||||
|
"CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256"),
|
||||||
|
groups("X25519:P-256:P-384:P-521"),
|
||||||
data_length(-1),
|
data_length(-1),
|
||||||
|
data(nullptr),
|
||||||
addrs(nullptr),
|
addrs(nullptr),
|
||||||
nreqs(1),
|
nreqs(1),
|
||||||
nclients(1),
|
nclients(1),
|
||||||
@@ -81,6 +106,7 @@ Config::Config()
|
|||||||
max_concurrent_streams(1),
|
max_concurrent_streams(1),
|
||||||
window_bits(30),
|
window_bits(30),
|
||||||
connection_window_bits(30),
|
connection_window_bits(30),
|
||||||
|
max_frame_size(16_k),
|
||||||
rate(0),
|
rate(0),
|
||||||
rate_period(1.0),
|
rate_period(1.0),
|
||||||
duration(0.0),
|
duration(0.0),
|
||||||
@@ -92,6 +118,7 @@ Config::Config()
|
|||||||
encoder_header_table_size(4_k),
|
encoder_header_table_size(4_k),
|
||||||
data_fd(-1),
|
data_fd(-1),
|
||||||
log_fd(-1),
|
log_fd(-1),
|
||||||
|
qlog_file_base(),
|
||||||
port(0),
|
port(0),
|
||||||
default_port(0),
|
default_port(0),
|
||||||
connect_to_port(0),
|
connect_to_port(0),
|
||||||
@@ -99,7 +126,9 @@ Config::Config()
|
|||||||
timing_script(false),
|
timing_script(false),
|
||||||
base_uri_unix(false),
|
base_uri_unix(false),
|
||||||
unix_addr{},
|
unix_addr{},
|
||||||
rps(0.) {}
|
rps(0.),
|
||||||
|
no_udp_gso(false),
|
||||||
|
max_udp_payload_size(0) {}
|
||||||
|
|
||||||
Config::~Config() {
|
Config::~Config() {
|
||||||
if (addrs) {
|
if (addrs) {
|
||||||
@@ -119,6 +148,14 @@ bool Config::is_rate_mode() const { return (this->rate != 0); }
|
|||||||
bool Config::is_timing_based_mode() const { return (this->duration > 0); }
|
bool Config::is_timing_based_mode() const { return (this->duration > 0); }
|
||||||
bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
|
bool Config::has_base_uri() const { return (!this->base_uri.empty()); }
|
||||||
bool Config::rps_enabled() const { return this->rps > 0.0; }
|
bool Config::rps_enabled() const { return this->rps > 0.0; }
|
||||||
|
bool Config::is_quic() const {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
return !npn_list.empty() &&
|
||||||
|
(npn_list[0] == NGHTTP3_ALPN_H3 || npn_list[0] == "\x5h3-29");
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
return false;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
|
}
|
||||||
Config config;
|
Config config;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -138,7 +175,9 @@ Stats::Stats(size_t req_todo, size_t nclients)
|
|||||||
bytes_head(0),
|
bytes_head(0),
|
||||||
bytes_head_decomp(0),
|
bytes_head_decomp(0),
|
||||||
bytes_body(0),
|
bytes_body(0),
|
||||||
status() {}
|
status(),
|
||||||
|
udp_dgram_recv(0),
|
||||||
|
udp_dgram_sent(0) {}
|
||||||
|
|
||||||
Stream::Stream() : req_stat{}, status_success(-1) {}
|
Stream::Stream() : req_stat{}, status_success(-1) {}
|
||||||
|
|
||||||
@@ -195,8 +234,7 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||||||
delete client;
|
delete client;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
writecb(loop, &client->wev, revents);
|
client->signal_write();
|
||||||
// client->disconnect() and client->fail() may be called
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -409,6 +447,9 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
|
|||||||
cstat{},
|
cstat{},
|
||||||
worker(worker),
|
worker(worker),
|
||||||
ssl(nullptr),
|
ssl(nullptr),
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic{},
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
next_addr(config.addrs),
|
next_addr(config.addrs),
|
||||||
current_addr(nullptr),
|
current_addr(nullptr),
|
||||||
reqidx(0),
|
reqidx(0),
|
||||||
@@ -420,6 +461,7 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
|
|||||||
req_done(0),
|
req_done(0),
|
||||||
id(id),
|
id(id),
|
||||||
fd(-1),
|
fd(-1),
|
||||||
|
local_addr{},
|
||||||
new_connection_requested(false),
|
new_connection_requested(false),
|
||||||
final(false),
|
final(false),
|
||||||
rps_duration_started(0),
|
rps_duration_started(0),
|
||||||
@@ -449,11 +491,22 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
|
|||||||
|
|
||||||
ev_timer_init(&rps_watcher, rps_cb, 0., 0.);
|
ev_timer_init(&rps_watcher, rps_cb, 0., 0.);
|
||||||
rps_watcher.data = this;
|
rps_watcher.data = this;
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
ev_timer_init(&quic.pkt_timer, quic_pkt_timeout_cb, 0., 0.);
|
||||||
|
quic.pkt_timer.data = this;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (config.is_quic()) {
|
||||||
|
quic_free();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
SSL_free(ssl);
|
SSL_free(ssl);
|
||||||
}
|
}
|
||||||
@@ -466,6 +519,36 @@ int Client::do_read() { return readfn(*this); }
|
|||||||
int Client::do_write() { return writefn(*this); }
|
int Client::do_write() { return writefn(*this); }
|
||||||
|
|
||||||
int Client::make_socket(addrinfo *addr) {
|
int Client::make_socket(addrinfo *addr) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (config.is_quic()) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
fd = util::create_nonblock_udp_socket(addr->ai_family);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = util::bind_any_addr_udp(fd, addr->ai_family);
|
||||||
|
if (rv != 0) {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
socklen_t addrlen = sizeof(local_addr.su.storage);
|
||||||
|
rv = getsockname(fd, &local_addr.su.sa, &addrlen);
|
||||||
|
if (rv == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
local_addr.len = addrlen;
|
||||||
|
|
||||||
|
if (quic_init(&local_addr.su.sa, local_addr.len, addr->ai_addr,
|
||||||
|
addr->ai_addrlen) != 0) {
|
||||||
|
std::cerr << "quic_init failed" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
} else {
|
||||||
fd = util::create_nonblock_socket(addr->ai_family);
|
fd = util::create_nonblock_socket(addr->ai_family);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -475,17 +558,20 @@ int Client::make_socket(addrinfo *addr) {
|
|||||||
ssl = SSL_new(worker->ssl_ctx);
|
ssl = SSL_new(worker->ssl_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto config = worker->config;
|
|
||||||
|
|
||||||
if (!util::numeric_host(config->host.c_str())) {
|
|
||||||
SSL_set_tlsext_host_name(ssl, config->host.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
SSL_set_fd(ssl, fd);
|
SSL_set_fd(ssl, fd);
|
||||||
SSL_set_connect_state(ssl);
|
SSL_set_connect_state(ssl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto rv = ::connect(fd, addr->ai_addr, addr->ai_addrlen);
|
if (ssl && !util::numeric_host(config.host.c_str())) {
|
||||||
|
SSL_set_tlsext_host_name(ssl, config.host.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.is_quic()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ::connect(fd, addr->ai_addr, addr->ai_addrlen);
|
||||||
if (rv != 0 && errno != EINPROGRESS) {
|
if (rv != 0 && errno != EINPROGRESS) {
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
SSL_free(ssl);
|
SSL_free(ssl);
|
||||||
@@ -542,13 +628,22 @@ int Client::connect() {
|
|||||||
current_addr = addr;
|
current_addr = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
writefn = &Client::connected;
|
|
||||||
|
|
||||||
ev_io_set(&rev, fd, EV_READ);
|
ev_io_set(&rev, fd, EV_READ);
|
||||||
ev_io_set(&wev, fd, EV_WRITE);
|
ev_io_set(&wev, fd, EV_WRITE);
|
||||||
|
|
||||||
ev_io_start(worker->loop, &wev);
|
ev_io_start(worker->loop, &wev);
|
||||||
|
|
||||||
|
if (config.is_quic()) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
ev_io_start(worker->loop, &rev);
|
||||||
|
|
||||||
|
readfn = &Client::read_quic;
|
||||||
|
writefn = &Client::write_quic;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
} else {
|
||||||
|
writefn = &Client::connected;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,6 +698,15 @@ void Client::fail() {
|
|||||||
void Client::disconnect() {
|
void Client::disconnect() {
|
||||||
record_client_end_time();
|
record_client_end_time();
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (config.is_quic()) {
|
||||||
|
quic_close_connection();
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
ev_timer_stop(worker->loop, &quic.pkt_timer);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
ev_timer_stop(worker->loop, &conn_inactivity_watcher);
|
ev_timer_stop(worker->loop, &conn_inactivity_watcher);
|
||||||
ev_timer_stop(worker->loop, &conn_active_watcher);
|
ev_timer_stop(worker->loop, &conn_active_watcher);
|
||||||
ev_timer_stop(worker->loop, &rps_watcher);
|
ev_timer_stop(worker->loop, &rps_watcher);
|
||||||
@@ -726,6 +830,16 @@ void print_server_tmp_key(SSL *ssl) {
|
|||||||
std::cout << "DH " << EVP_PKEY_bits(key) << " bits" << std::endl;
|
std::cout << "DH " << EVP_PKEY_bits(key) << " bits" << std::endl;
|
||||||
break;
|
break;
|
||||||
case EVP_PKEY_EC: {
|
case EVP_PKEY_EC: {
|
||||||
|
# if OPENSSL_3_0_0_API
|
||||||
|
std::array<char, 64> curve_name;
|
||||||
|
const char *cname;
|
||||||
|
if (!EVP_PKEY_get_utf8_string_param(key, "group", curve_name.data(),
|
||||||
|
curve_name.size(), nullptr)) {
|
||||||
|
cname = "<unknown>";
|
||||||
|
} else {
|
||||||
|
cname = curve_name.data();
|
||||||
|
}
|
||||||
|
# else // !OPENSSL_3_0_0_API
|
||||||
auto ec = EVP_PKEY_get1_EC_KEY(key);
|
auto ec = EVP_PKEY_get1_EC_KEY(key);
|
||||||
auto ec_del = defer(EC_KEY_free, ec);
|
auto ec_del = defer(EC_KEY_free, ec);
|
||||||
auto nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
auto nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||||
@@ -733,6 +847,7 @@ void print_server_tmp_key(SSL *ssl) {
|
|||||||
if (!cname) {
|
if (!cname) {
|
||||||
cname = OBJ_nid2sn(nid);
|
cname = OBJ_nid2sn(nid);
|
||||||
}
|
}
|
||||||
|
# endif // !OPENSSL_3_0_0_API
|
||||||
|
|
||||||
std::cout << "ECDH " << cname << " " << EVP_PKEY_bits(key) << " bits"
|
std::cout << "ECDH " << cname << " " << EVP_PKEY_bits(key) << " bits"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@@ -765,7 +880,14 @@ void Client::report_app_info() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::terminate_session() {
|
void Client::terminate_session() {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (config.is_quic()) {
|
||||||
|
quic.close_requested = true;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
if (session) {
|
||||||
session->terminate();
|
session->terminate();
|
||||||
|
}
|
||||||
// http1 session needs writecb to tear down session.
|
// http1 session needs writecb to tear down session.
|
||||||
signal_write();
|
signal_write();
|
||||||
}
|
}
|
||||||
@@ -963,7 +1085,15 @@ int Client::connection_made() {
|
|||||||
|
|
||||||
if (next_proto) {
|
if (next_proto) {
|
||||||
auto proto = StringRef{next_proto, next_proto_len};
|
auto proto = StringRef{next_proto, next_proto_len};
|
||||||
if (util::check_h2_is_selected(proto)) {
|
if (config.is_quic()) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
assert(session);
|
||||||
|
if (!util::streq(StringRef{&NGHTTP3_ALPN_H3[1]}, proto) &&
|
||||||
|
!util::streq_l("h3-29", proto)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
} else if (util::check_h2_is_selected(proto)) {
|
||||||
session = std::make_unique<Http2Session>(this);
|
session = std::make_unique<Http2Session>(this);
|
||||||
} else if (util::streq(NGHTTP2_H1_1, proto)) {
|
} else if (util::streq(NGHTTP2_H1_1, proto)) {
|
||||||
session = std::make_unique<Http1Session>(this);
|
session = std::make_unique<Http1Session>(this);
|
||||||
@@ -972,6 +1102,9 @@ int Client::connection_made() {
|
|||||||
// Just assign next_proto to selected_proto anyway to show the
|
// Just assign next_proto to selected_proto anyway to show the
|
||||||
// negotiation result.
|
// negotiation result.
|
||||||
selected_proto = proto.str();
|
selected_proto = proto.str();
|
||||||
|
} else if (config.is_quic()) {
|
||||||
|
std::cerr << "QUIC requires ALPN negotiation" << std::endl;
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
std::cout << "No protocol negotiated. Fallback behaviour may be activated"
|
std::cout << "No protocol negotiated. Fallback behaviour may be activated"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@@ -1285,6 +1418,46 @@ int Client::write_tls() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
int Client::write_udp(const sockaddr *addr, socklen_t addrlen,
|
||||||
|
const uint8_t *data, size_t datalen, size_t gso_size) {
|
||||||
|
iovec msg_iov;
|
||||||
|
msg_iov.iov_base = const_cast<uint8_t *>(data);
|
||||||
|
msg_iov.iov_len = datalen;
|
||||||
|
|
||||||
|
msghdr msg{};
|
||||||
|
msg.msg_name = const_cast<sockaddr *>(addr);
|
||||||
|
msg.msg_namelen = addrlen;
|
||||||
|
msg.msg_iov = &msg_iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
# ifdef UDP_SEGMENT
|
||||||
|
std::array<uint8_t, CMSG_SPACE(sizeof(uint16_t))> msg_ctrl{};
|
||||||
|
if (gso_size && datalen > gso_size) {
|
||||||
|
msg.msg_control = msg_ctrl.data();
|
||||||
|
msg.msg_controllen = msg_ctrl.size();
|
||||||
|
|
||||||
|
auto cm = CMSG_FIRSTHDR(&msg);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
# endif // UDP_SEGMENT
|
||||||
|
|
||||||
|
auto nwrite = sendmsg(fd, &msg, 0);
|
||||||
|
if (nwrite < 0) {
|
||||||
|
std::cerr << "sendto: errno=" << errno << std::endl;
|
||||||
|
} else {
|
||||||
|
++worker->stats.udp_dgram_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ev_io_stop(worker->loop, &wev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
void Client::record_request_time(RequestStat *req_stat) {
|
void Client::record_request_time(RequestStat *req_stat) {
|
||||||
req_stat->request_time = std::chrono::steady_clock::now();
|
req_stat->request_time = std::chrono::steady_clock::now();
|
||||||
req_stat->request_wall_time = std::chrono::system_clock::now();
|
req_stat->request_wall_time = std::chrono::system_clock::now();
|
||||||
@@ -1344,7 +1517,8 @@ int get_ev_loop_flags() {
|
|||||||
|
|
||||||
Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
|
Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
|
||||||
size_t rate, size_t max_samples, Config *config)
|
size_t rate, size_t max_samples, Config *config)
|
||||||
: stats(req_todo, nclients),
|
: randgen(util::make_mt19937()),
|
||||||
|
stats(req_todo, nclients),
|
||||||
loop(ev_loop_new(get_ev_loop_flags())),
|
loop(ev_loop_new(get_ev_loop_flags())),
|
||||||
ssl_ctx(ssl_ctx),
|
ssl_ctx(ssl_ctx),
|
||||||
config(config),
|
config(config),
|
||||||
@@ -1403,7 +1577,7 @@ Worker::~Worker() {
|
|||||||
|
|
||||||
void Worker::stop_all_clients() {
|
void Worker::stop_all_clients() {
|
||||||
for (auto client : clients) {
|
for (auto client : clients) {
|
||||||
if (client && client->session) {
|
if (client) {
|
||||||
client->terminate_session();
|
client->terminate_session();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1936,8 +2110,14 @@ Options:
|
|||||||
http/1.1 is used, this specifies the number of HTTP
|
http/1.1 is used, this specifies the number of HTTP
|
||||||
pipelining requests in-flight.
|
pipelining requests in-flight.
|
||||||
Default: 1
|
Default: 1
|
||||||
|
-f, --max-frame-size=<SIZE>
|
||||||
|
Maximum frame size that the local endpoint is willing to
|
||||||
|
receive.
|
||||||
|
Default: )"
|
||||||
|
<< util::utos_unit(config.max_frame_size) << R"(
|
||||||
-w, --window-bits=<N>
|
-w, --window-bits=<N>
|
||||||
Sets the stream level initial window size to (2**<N>)-1.
|
Sets the stream level initial window size to (2**<N>)-1.
|
||||||
|
For QUIC, <N> is capped to 26 (roughly 64MiB).
|
||||||
Default: )"
|
Default: )"
|
||||||
<< config.window_bits << R"(
|
<< config.window_bits << R"(
|
||||||
-W, --connection-window-bits=<N>
|
-W, --connection-window-bits=<N>
|
||||||
@@ -1948,10 +2128,15 @@ Options:
|
|||||||
-H, --header=<HEADER>
|
-H, --header=<HEADER>
|
||||||
Add/Override a header to the requests.
|
Add/Override a header to the requests.
|
||||||
--ciphers=<SUITE>
|
--ciphers=<SUITE>
|
||||||
Set allowed cipher list. The format of the string is
|
Set allowed cipher list for TLSv1.2 or earlier. The
|
||||||
described in OpenSSL ciphers(1).
|
format of the string is described in OpenSSL ciphers(1).
|
||||||
Default: )"
|
Default: )"
|
||||||
<< config.ciphers << R"(
|
<< config.ciphers << R"(
|
||||||
|
--tls13-ciphers=<SUITE>
|
||||||
|
Set allowed cipher list for TLSv1.3. The format of the
|
||||||
|
string is described in OpenSSL ciphers(1).
|
||||||
|
Default: )"
|
||||||
|
<< config.tls13_ciphers << R"(
|
||||||
-p, --no-tls-proto=<PROTOID>
|
-p, --no-tls-proto=<PROTOID>
|
||||||
Specify ALPN identifier of the protocol to be used when
|
Specify ALPN identifier of the protocol to be used when
|
||||||
accessing http URI without SSL/TLS.
|
accessing http URI without SSL/TLS.
|
||||||
@@ -2065,11 +2250,25 @@ Options:
|
|||||||
response time when using one worker thread, but may
|
response time when using one worker thread, but may
|
||||||
appear slightly out of order with multiple threads due
|
appear slightly out of order with multiple threads due
|
||||||
to buffering. Status code is -1 for failed streams.
|
to buffering. Status code is -1 for failed streams.
|
||||||
|
--qlog-file-base=<PATH>
|
||||||
|
Enable qlog output and specify base file name for qlogs.
|
||||||
|
Qlog is emitted for each connection. For a given base
|
||||||
|
name "base", each output file name becomes
|
||||||
|
"base.M.N.sqlog" where M is worker ID and N is client ID
|
||||||
|
(e.g. "base.0.3.sqlog"). Only effective in QUIC runs.
|
||||||
--connect-to=<HOST>[:<PORT>]
|
--connect-to=<HOST>[:<PORT>]
|
||||||
Host and port to connect instead of using the authority
|
Host and port to connect instead of using the authority
|
||||||
in <URI>.
|
in <URI>.
|
||||||
--rps=<N> Specify request per second for each client. --rps and
|
--rps=<N> Specify request per second for each client. --rps and
|
||||||
--timing-script-file are mutually exclusive.
|
--timing-script-file are mutually exclusive.
|
||||||
|
--groups=<GROUPS>
|
||||||
|
Specify the supported groups.
|
||||||
|
Default: )"
|
||||||
|
<< config.groups << R"(
|
||||||
|
--no-udp-gso
|
||||||
|
Disable UDP GSO.
|
||||||
|
--max-udp-payload-size=<SIZE>
|
||||||
|
Specify the maximum outgoing UDP datagram payload size.
|
||||||
-v, --verbose
|
-v, --verbose
|
||||||
Output debug information.
|
Output debug information.
|
||||||
--version Display version information and exit.
|
--version Display version information and exit.
|
||||||
@@ -2097,6 +2296,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
std::string datafile;
|
std::string datafile;
|
||||||
std::string logfile;
|
std::string logfile;
|
||||||
|
std::string qlog_base;
|
||||||
bool nreqs_set_manually = false;
|
bool nreqs_set_manually = false;
|
||||||
while (1) {
|
while (1) {
|
||||||
static int flag = 0;
|
static int flag = 0;
|
||||||
@@ -2107,6 +2307,7 @@ int main(int argc, char **argv) {
|
|||||||
{"threads", required_argument, nullptr, 't'},
|
{"threads", required_argument, nullptr, 't'},
|
||||||
{"max-concurrent-streams", required_argument, nullptr, 'm'},
|
{"max-concurrent-streams", required_argument, nullptr, 'm'},
|
||||||
{"window-bits", required_argument, nullptr, 'w'},
|
{"window-bits", required_argument, nullptr, 'w'},
|
||||||
|
{"max-frame-size", required_argument, nullptr, 'f'},
|
||||||
{"connection-window-bits", required_argument, nullptr, 'W'},
|
{"connection-window-bits", required_argument, nullptr, 'W'},
|
||||||
{"input-file", required_argument, nullptr, 'i'},
|
{"input-file", required_argument, nullptr, 'i'},
|
||||||
{"header", required_argument, nullptr, 'H'},
|
{"header", required_argument, nullptr, 'H'},
|
||||||
@@ -2130,10 +2331,15 @@ int main(int argc, char **argv) {
|
|||||||
{"log-file", required_argument, &flag, 10},
|
{"log-file", required_argument, &flag, 10},
|
||||||
{"connect-to", required_argument, &flag, 11},
|
{"connect-to", required_argument, &flag, 11},
|
||||||
{"rps", required_argument, &flag, 12},
|
{"rps", required_argument, &flag, 12},
|
||||||
|
{"groups", required_argument, &flag, 13},
|
||||||
|
{"tls13-ciphers", required_argument, &flag, 14},
|
||||||
|
{"no-udp-gso", no_argument, &flag, 15},
|
||||||
|
{"qlog-file-base", required_argument, &flag, 16},
|
||||||
|
{"max-udp-payload-size", required_argument, &flag, 17},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
auto c = getopt_long(argc, argv,
|
auto c = getopt_long(argc, argv,
|
||||||
"hvW:c:d:m:n:p:t:w:H:i:r:T:N:D:B:", long_options,
|
"hvW:c:d:m:n:p:t:w:f:H:i:r:T:N:D:B:", long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
@@ -2179,6 +2385,24 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'f': {
|
||||||
|
auto n = util::parse_uint_with_unit(optarg);
|
||||||
|
if (n == -1) {
|
||||||
|
std::cerr << "--max-frame-size: bad option value: " << optarg
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (static_cast<uint64_t>(n) < 16_k) {
|
||||||
|
std::cerr << "--max-frame-size: minimum 16384" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (static_cast<uint64_t>(n) > 16_m - 1) {
|
||||||
|
std::cerr << "--max-frame-size: maximum 16777215" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
config.max_frame_size = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'H': {
|
case 'H': {
|
||||||
char *header = optarg;
|
char *header = optarg;
|
||||||
// Skip first possible ':' in the header name
|
// Skip first possible ':' in the header name
|
||||||
@@ -2380,6 +2604,38 @@ int main(int argc, char **argv) {
|
|||||||
config.rps = v;
|
config.rps = v;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 13:
|
||||||
|
// --groups
|
||||||
|
config.groups = optarg;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
// --tls13-ciphers
|
||||||
|
config.tls13_ciphers = optarg;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
// --no-udp-gso
|
||||||
|
config.no_udp_gso = true;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
// --qlog-file-base
|
||||||
|
qlog_base = optarg;
|
||||||
|
break;
|
||||||
|
case 17: {
|
||||||
|
// --max-udp-payload-size
|
||||||
|
auto n = util::parse_uint_with_unit(optarg);
|
||||||
|
if (n == -1) {
|
||||||
|
std::cerr << "--max-udp-payload-size: bad option value: " << optarg
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (static_cast<uint64_t>(n) > 64_k) {
|
||||||
|
std::cerr << "--max-udp-payload-size: must not exceed 65536"
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
config.max_udp_payload_size = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -2546,6 +2802,13 @@ int main(int argc, char **argv) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
config.data_length = data_stat.st_size;
|
config.data_length = data_stat.st_size;
|
||||||
|
auto addr = mmap(nullptr, config.data_length, PROT_READ, MAP_SHARED,
|
||||||
|
config.data_fd, 0);
|
||||||
|
if (addr == MAP_FAILED) {
|
||||||
|
std::cerr << "-d: Could not mmap file " << datafile << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
config.data = static_cast<uint8_t *>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!logfile.empty()) {
|
if (!logfile.empty()) {
|
||||||
@@ -2557,11 +2820,23 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!qlog_base.empty()) {
|
||||||
|
if (!config.is_quic()) {
|
||||||
|
std::cerr
|
||||||
|
<< "Warning: --qlog-file-base: only effective in quic, ignoring."
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config.qlog_file_base = qlog_base;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct sigaction act {};
|
struct sigaction act {};
|
||||||
act.sa_handler = SIG_IGN;
|
act.sa_handler = SIG_IGN;
|
||||||
sigaction(SIGPIPE, &act, nullptr);
|
sigaction(SIGPIPE, &act, nullptr);
|
||||||
|
|
||||||
auto ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
auto ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||||
if (!ssl_ctx) {
|
if (!ssl_ctx) {
|
||||||
std::cerr << "Failed to create SSL_CTX: "
|
std::cerr << "Failed to create SSL_CTX: "
|
||||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
@@ -2576,7 +2851,12 @@ int main(int argc, char **argv) {
|
|||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
if (nghttp2::tls::ssl_ctx_set_proto_versions(
|
if (config.is_quic()) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
|
||||||
|
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
} else if (nghttp2::tls::ssl_ctx_set_proto_versions(
|
||||||
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
|
ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
|
||||||
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
|
||||||
std::cerr << "Could not set TLS versions" << std::endl;
|
std::cerr << "Could not set TLS versions" << std::endl;
|
||||||
@@ -2590,6 +2870,27 @@ int main(int argc, char **argv) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
if (SSL_CTX_set_ciphersuites(ssl_ctx, config.tls13_ciphers.c_str()) == 0) {
|
||||||
|
std::cerr << "SSL_CTX_set_ciphersuites with " << config.tls13_ciphers
|
||||||
|
<< " failed: " << ERR_error_string(ERR_get_error(), nullptr)
|
||||||
|
<< std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif // OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
if (SSL_CTX_set1_groups_list(ssl_ctx, config.groups.c_str()) != 1) {
|
||||||
|
std::cerr << "SSL_CTX_set1_groups_list failed" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#else // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
|
if (SSL_CTX_set1_curves_list(ssl_ctx, config.groups.c_str()) != 1) {
|
||||||
|
std::cerr << "SSL_CTX_set1_curves_list failed" << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
SSL_CTX_set_next_proto_select_cb(ssl_ctx, client_select_next_proto_cb,
|
||||||
nullptr);
|
nullptr);
|
||||||
@@ -2604,6 +2905,16 @@ int main(int argc, char **argv) {
|
|||||||
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
|
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
|
||||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_1_API
|
||||||
|
auto keylog_filename = getenv("SSLKEYLOGFILE");
|
||||||
|
if (keylog_filename) {
|
||||||
|
keylog_file.open(keylog_filename, std::ios_base::app);
|
||||||
|
if (keylog_file) {
|
||||||
|
SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // OPENSSL_1_1_1_API
|
||||||
|
|
||||||
std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
|
std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION;
|
||||||
Headers shared_nva;
|
Headers shared_nva;
|
||||||
shared_nva.emplace_back(":scheme", config.scheme);
|
shared_nva.emplace_back(":scheme", config.scheme);
|
||||||
@@ -2822,6 +3133,8 @@ int main(int argc, char **argv) {
|
|||||||
stats.bytes_head += s.bytes_head;
|
stats.bytes_head += s.bytes_head;
|
||||||
stats.bytes_head_decomp += s.bytes_head_decomp;
|
stats.bytes_head_decomp += s.bytes_head_decomp;
|
||||||
stats.bytes_body += s.bytes_body;
|
stats.bytes_body += s.bytes_body;
|
||||||
|
stats.udp_dgram_recv += s.udp_dgram_recv;
|
||||||
|
stats.udp_dgram_sent += s.udp_dgram_sent;
|
||||||
|
|
||||||
for (size_t i = 0; i < stats.status.size(); ++i) {
|
for (size_t i = 0; i < stats.status.size(); ++i) {
|
||||||
stats.status[i] += s.status[i];
|
stats.status[i] += s.status[i];
|
||||||
@@ -2880,14 +3193,21 @@ traffic: )" << util::utos_funit(stats.bytes_total)
|
|||||||
<< util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head
|
<< util::utos_funit(stats.bytes_head) << "B (" << stats.bytes_head
|
||||||
<< ") headers (space savings " << header_space_savings * 100
|
<< ") headers (space savings " << header_space_savings * 100
|
||||||
<< "%), " << util::utos_funit(stats.bytes_body) << "B ("
|
<< "%), " << util::utos_funit(stats.bytes_body) << "B ("
|
||||||
<< stats.bytes_body << R"() data
|
<< stats.bytes_body << R"() data)" << std::endl;
|
||||||
min max mean sd +/- sd
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (config.is_quic()) {
|
||||||
|
std::cout << "UDP datagram: " << stats.udp_dgram_sent << " sent, "
|
||||||
|
<< stats.udp_dgram_recv << " received" << std::endl;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
std::cout
|
||||||
|
<< R"( min max mean sd +/- sd
|
||||||
time for request: )"
|
time for request: )"
|
||||||
<< std::setw(10) << util::format_duration(ts.request.min) << " "
|
<< std::setw(10) << util::format_duration(ts.request.min) << " "
|
||||||
<< std::setw(10) << util::format_duration(ts.request.max) << " "
|
<< std::setw(10) << util::format_duration(ts.request.max) << " "
|
||||||
<< std::setw(10) << util::format_duration(ts.request.mean) << " "
|
<< std::setw(10) << util::format_duration(ts.request.mean) << " "
|
||||||
<< std::setw(10) << util::format_duration(ts.request.sd)
|
<< std::setw(10) << util::format_duration(ts.request.sd) << std::setw(9)
|
||||||
<< std::setw(9) << util::dtos(ts.request.within_sd) << "%"
|
<< util::dtos(ts.request.within_sd) << "%"
|
||||||
<< "\ntime for connect: " << std::setw(10)
|
<< "\ntime for connect: " << std::setw(10)
|
||||||
<< util::format_duration(ts.connect.min) << " " << std::setw(10)
|
<< util::format_duration(ts.connect.min) << " " << std::setw(10)
|
||||||
<< util::format_duration(ts.connect.max) << " " << std::setw(10)
|
<< util::format_duration(ts.connect.max) << " " << std::setw(10)
|
||||||
@@ -2901,8 +3221,8 @@ time for request: )"
|
|||||||
<< util::format_duration(ts.ttfb.sd) << std::setw(9)
|
<< util::format_duration(ts.ttfb.sd) << std::setw(9)
|
||||||
<< util::dtos(ts.ttfb.within_sd) << "%"
|
<< util::dtos(ts.ttfb.within_sd) << "%"
|
||||||
<< "\nreq/s : " << std::setw(10) << ts.rps.min << " "
|
<< "\nreq/s : " << std::setw(10) << ts.rps.min << " "
|
||||||
<< std::setw(10) << ts.rps.max << " " << std::setw(10)
|
<< std::setw(10) << ts.rps.max << " " << std::setw(10) << ts.rps.mean
|
||||||
<< ts.rps.mean << " " << std::setw(10) << ts.rps.sd << std::setw(9)
|
<< " " << std::setw(10) << ts.rps.sd << std::setw(9)
|
||||||
<< util::dtos(ts.rps.within_sd) << "%" << std::endl;
|
<< util::dtos(ts.rps.within_sd) << "%" << std::endl;
|
||||||
|
|
||||||
SSL_CTX_free(ssl_ctx);
|
SSL_CTX_free(ssl_ctx);
|
||||||
|
|||||||
69
src/h2load.h
69
src/h2load.h
@@ -45,11 +45,19 @@
|
|||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include <ngtcp2/ngtcp2.h>
|
||||||
|
# include <ngtcp2/ngtcp2_crypto.h>
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include "quic.h"
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
#include "memchunk.h"
|
#include "memchunk.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
@@ -72,8 +80,13 @@ struct Config {
|
|||||||
std::string connect_to_host;
|
std::string connect_to_host;
|
||||||
std::string ifile;
|
std::string ifile;
|
||||||
std::string ciphers;
|
std::string ciphers;
|
||||||
|
std::string tls13_ciphers;
|
||||||
|
// supported groups (or curves).
|
||||||
|
std::string groups;
|
||||||
// length of upload data
|
// length of upload data
|
||||||
int64_t data_length;
|
int64_t data_length;
|
||||||
|
// memory mapped upload data
|
||||||
|
uint8_t *data;
|
||||||
addrinfo *addrs;
|
addrinfo *addrs;
|
||||||
size_t nreqs;
|
size_t nreqs;
|
||||||
size_t nclients;
|
size_t nclients;
|
||||||
@@ -82,6 +95,7 @@ struct Config {
|
|||||||
ssize_t max_concurrent_streams;
|
ssize_t max_concurrent_streams;
|
||||||
size_t window_bits;
|
size_t window_bits;
|
||||||
size_t connection_window_bits;
|
size_t connection_window_bits;
|
||||||
|
size_t max_frame_size;
|
||||||
// rate at which connections should be made
|
// rate at which connections should be made
|
||||||
size_t rate;
|
size_t rate;
|
||||||
ev_tstamp rate_period;
|
ev_tstamp rate_period;
|
||||||
@@ -100,6 +114,8 @@ struct Config {
|
|||||||
int data_fd;
|
int data_fd;
|
||||||
// file descriptor to write per-request stats to.
|
// file descriptor to write per-request stats to.
|
||||||
int log_fd;
|
int log_fd;
|
||||||
|
// base file name of qlog output files
|
||||||
|
std::string qlog_file_base;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
uint16_t default_port;
|
uint16_t default_port;
|
||||||
uint16_t connect_to_port;
|
uint16_t connect_to_port;
|
||||||
@@ -116,6 +132,10 @@ struct Config {
|
|||||||
std::vector<std::string> npn_list;
|
std::vector<std::string> npn_list;
|
||||||
// The number of request per second for each client.
|
// The number of request per second for each client.
|
||||||
double rps;
|
double rps;
|
||||||
|
// Disables GSO for UDP connections.
|
||||||
|
bool no_udp_gso;
|
||||||
|
// The maximum UDP datagram payload size to send.
|
||||||
|
size_t max_udp_payload_size;
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
~Config();
|
~Config();
|
||||||
@@ -124,6 +144,7 @@ struct Config {
|
|||||||
bool is_timing_based_mode() const;
|
bool is_timing_based_mode() const;
|
||||||
bool has_base_uri() const;
|
bool has_base_uri() const;
|
||||||
bool rps_enabled() const;
|
bool rps_enabled() const;
|
||||||
|
bool is_quic() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RequestStat {
|
struct RequestStat {
|
||||||
@@ -220,6 +241,10 @@ struct Stats {
|
|||||||
std::vector<RequestStat> req_stats;
|
std::vector<RequestStat> req_stats;
|
||||||
// The statistics per client
|
// The statistics per client
|
||||||
std::vector<ClientStat> client_stats;
|
std::vector<ClientStat> client_stats;
|
||||||
|
// The number of UDP datagrams received.
|
||||||
|
size_t udp_dgram_recv;
|
||||||
|
// The number of UDP datagrams sent.
|
||||||
|
size_t udp_dgram_sent;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
||||||
@@ -245,6 +270,7 @@ struct Sampling {
|
|||||||
|
|
||||||
struct Worker {
|
struct Worker {
|
||||||
MemchunkPool mcpool;
|
MemchunkPool mcpool;
|
||||||
|
std::mt19937 randgen;
|
||||||
Stats stats;
|
Stats stats;
|
||||||
Sampling request_times_smp;
|
Sampling request_times_smp;
|
||||||
Sampling client_smp;
|
Sampling client_smp;
|
||||||
@@ -309,6 +335,15 @@ struct Client {
|
|||||||
std::function<int(Client &)> readfn, writefn;
|
std::function<int(Client &)> readfn, writefn;
|
||||||
Worker *worker;
|
Worker *worker;
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
struct {
|
||||||
|
ev_timer pkt_timer;
|
||||||
|
ngtcp2_conn *conn;
|
||||||
|
quic::Error last_error;
|
||||||
|
bool close_requested;
|
||||||
|
FILE *qlog_file;
|
||||||
|
} quic;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
ev_timer request_timeout_watcher;
|
ev_timer request_timeout_watcher;
|
||||||
addrinfo *next_addr;
|
addrinfo *next_addr;
|
||||||
// Address for the current address. When try_new_connection() is
|
// Address for the current address. When try_new_connection() is
|
||||||
@@ -332,6 +367,7 @@ struct Client {
|
|||||||
// The client id per worker
|
// The client id per worker
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
int fd;
|
int fd;
|
||||||
|
Address local_addr;
|
||||||
ev_timer conn_active_watcher;
|
ev_timer conn_active_watcher;
|
||||||
ev_timer conn_inactivity_watcher;
|
ev_timer conn_inactivity_watcher;
|
||||||
std::string selected_proto;
|
std::string selected_proto;
|
||||||
@@ -419,6 +455,39 @@ struct Client {
|
|||||||
void record_client_end_time();
|
void record_client_end_time();
|
||||||
|
|
||||||
void signal_write();
|
void signal_write();
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
// QUIC
|
||||||
|
int quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
|
||||||
|
const sockaddr *remote_addr, socklen_t remote_addrlen);
|
||||||
|
void quic_free();
|
||||||
|
int read_quic();
|
||||||
|
int write_quic();
|
||||||
|
int write_udp(const sockaddr *addr, socklen_t addrlen, const uint8_t *data,
|
||||||
|
size_t datalen, size_t gso_size);
|
||||||
|
void quic_close_connection();
|
||||||
|
|
||||||
|
int quic_handshake_completed();
|
||||||
|
int quic_recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||||
|
const uint8_t *data, size_t datalen);
|
||||||
|
int quic_acked_stream_data_offset(int64_t stream_id, size_t datalen);
|
||||||
|
int quic_stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
int quic_stream_reset(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
int quic_stream_stop_sending(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
int quic_extend_max_local_streams();
|
||||||
|
|
||||||
|
int quic_on_rx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
|
||||||
|
size_t secretlen);
|
||||||
|
int quic_on_tx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
|
||||||
|
size_t secretlen);
|
||||||
|
void quic_set_tls_alert(uint8_t alert);
|
||||||
|
|
||||||
|
void quic_write_client_handshake(ngtcp2_crypto_level level,
|
||||||
|
const uint8_t *data, size_t datalen);
|
||||||
|
int quic_pkt_timeout();
|
||||||
|
void quic_restart_pkt_timer();
|
||||||
|
void quic_write_qlog(const void *data, size_t datalen);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace h2load
|
} // namespace h2load
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ void Http2Session::on_connect() {
|
|||||||
|
|
||||||
nghttp2_option_del(opt);
|
nghttp2_option_del(opt);
|
||||||
|
|
||||||
std::array<nghttp2_settings_entry, 3> iv;
|
std::array<nghttp2_settings_entry, 4> iv;
|
||||||
size_t niv = 2;
|
size_t niv = 2;
|
||||||
iv[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
|
iv[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
|
||||||
iv[0].value = 0;
|
iv[0].value = 0;
|
||||||
@@ -227,6 +227,11 @@ void Http2Session::on_connect() {
|
|||||||
iv[niv].value = config->header_table_size;
|
iv[niv].value = config->header_table_size;
|
||||||
++niv;
|
++niv;
|
||||||
}
|
}
|
||||||
|
if (config->max_frame_size != 16_k) {
|
||||||
|
iv[niv].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[niv].value = config->max_frame_size;
|
||||||
|
++niv;
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, iv.data(), niv);
|
rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, iv.data(), niv);
|
||||||
|
|
||||||
|
|||||||
425
src/h2load_http3_session.cc
Normal file
425
src/h2load_http3_session.cc
Normal file
@@ -0,0 +1,425 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "h2load_http3_session.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <ngtcp2/ngtcp2.h>
|
||||||
|
|
||||||
|
#include "h2load.h"
|
||||||
|
|
||||||
|
namespace h2load {
|
||||||
|
|
||||||
|
Http3Session::Http3Session(Client *client)
|
||||||
|
: client_(client), conn_(nullptr), npending_request_(0), reqidx_(0) {}
|
||||||
|
|
||||||
|
Http3Session::~Http3Session() { nghttp3_conn_del(conn_); }
|
||||||
|
|
||||||
|
void Http3Session::on_connect() {}
|
||||||
|
|
||||||
|
int Http3Session::submit_request() {
|
||||||
|
if (npending_request_) {
|
||||||
|
++npending_request_;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto config = client_->worker->config;
|
||||||
|
reqidx_ = client_->reqidx;
|
||||||
|
|
||||||
|
if (++client_->reqidx == config->nva.size()) {
|
||||||
|
client_->reqidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto stream_id = submit_request_internal();
|
||||||
|
if (stream_id < 0) {
|
||||||
|
if (stream_id == NGTCP2_ERR_STREAM_ID_BLOCKED) {
|
||||||
|
++npending_request_;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
nghttp3_ssize read_data(nghttp3_conn *conn, int64_t stream_id, nghttp3_vec *vec,
|
||||||
|
size_t veccnt, uint32_t *pflags, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
|
||||||
|
s->read_data(vec, veccnt, pflags);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http3Session::read_data(nghttp3_vec *vec, size_t veccnt,
|
||||||
|
uint32_t *pflags) {
|
||||||
|
assert(veccnt > 0);
|
||||||
|
|
||||||
|
auto config = client_->worker->config;
|
||||||
|
|
||||||
|
vec[0].base = config->data;
|
||||||
|
vec[0].len = config->data_length;
|
||||||
|
*pflags |= NGHTTP3_DATA_FLAG_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t Http3Session::submit_request_internal() {
|
||||||
|
int rv;
|
||||||
|
int64_t stream_id;
|
||||||
|
|
||||||
|
auto config = client_->worker->config;
|
||||||
|
auto &nva = config->nva[reqidx_];
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_open_bidi_stream(client_->quic.conn, &stream_id, nullptr);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp3_data_reader dr{};
|
||||||
|
dr.read_data = h2load::read_data;
|
||||||
|
|
||||||
|
rv = nghttp3_conn_submit_request(
|
||||||
|
conn_, stream_id, reinterpret_cast<nghttp3_nv *>(nva.data()), nva.size(),
|
||||||
|
config->data_fd == -1 ? nullptr : &dr, nullptr);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_->on_request(stream_id);
|
||||||
|
auto req_stat = client_->get_req_stat(stream_id);
|
||||||
|
assert(req_stat);
|
||||||
|
client_->record_request_time(req_stat);
|
||||||
|
|
||||||
|
return stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::on_read(const uint8_t *data, size_t len) { return -1; }
|
||||||
|
|
||||||
|
int Http3Session::on_write() { return -1; }
|
||||||
|
|
||||||
|
void Http3Session::terminate() {}
|
||||||
|
|
||||||
|
size_t Http3Session::max_concurrent_streams() {
|
||||||
|
return (size_t)client_->worker->config->max_concurrent_streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int stream_close(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code,
|
||||||
|
void *user_data, void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
if (s->stream_close(stream_id, app_error_code) != 0) {
|
||||||
|
return NGHTTP3_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Http3Session::stream_close(int64_t stream_id, uint64_t app_error_code) {
|
||||||
|
if (!ngtcp2_is_bidi_stream(stream_id)) {
|
||||||
|
assert(!ngtcp2_conn_is_local_stream(client_->quic.conn, stream_id));
|
||||||
|
ngtcp2_conn_extend_max_streams_uni(client_->quic.conn, 1);
|
||||||
|
}
|
||||||
|
client_->on_stream_close(stream_id, app_error_code == NGHTTP3_H3_NO_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
|
||||||
|
size_t datalen, void *user_data, void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
s->recv_data(stream_id, data, datalen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http3Session::recv_data(int64_t stream_id, const uint8_t *data,
|
||||||
|
size_t datalen) {
|
||||||
|
client_->record_ttfb();
|
||||||
|
client_->worker->stats.bytes_body += datalen;
|
||||||
|
consume(stream_id, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int deferred_consume(nghttp3_conn *conn, int64_t stream_id, size_t nconsumed,
|
||||||
|
void *user_data, void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
s->consume(stream_id, nconsumed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http3Session::consume(int64_t stream_id, size_t nconsumed) {
|
||||||
|
ngtcp2_conn_extend_max_stream_offset(client_->quic.conn, stream_id,
|
||||||
|
nconsumed);
|
||||||
|
ngtcp2_conn_extend_max_offset(client_->quic.conn, nconsumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int begin_headers(nghttp3_conn *conn, int64_t stream_id, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
s->begin_headers(stream_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http3Session::begin_headers(int64_t stream_id) {
|
||||||
|
auto payloadlen = nghttp3_conn_get_frame_payload_left(conn_, stream_id);
|
||||||
|
assert(payloadlen > 0);
|
||||||
|
|
||||||
|
client_->worker->stats.bytes_head += payloadlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int recv_header(nghttp3_conn *conn, int64_t stream_id, int32_t token,
|
||||||
|
nghttp3_rcbuf *name, nghttp3_rcbuf *value, uint8_t flags,
|
||||||
|
void *user_data, void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
auto k = nghttp3_rcbuf_get_buf(name);
|
||||||
|
auto v = nghttp3_rcbuf_get_buf(value);
|
||||||
|
s->recv_header(stream_id, &k, &v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http3Session::recv_header(int64_t stream_id, const nghttp3_vec *name,
|
||||||
|
const nghttp3_vec *value) {
|
||||||
|
client_->on_header(stream_id, name->base, name->len, value->base, value->len);
|
||||||
|
client_->worker->stats.bytes_head_decomp += name->len + value->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int stop_sending(nghttp3_conn *conn, int64_t stream_id, uint64_t app_error_code,
|
||||||
|
void *user_data, void *stream_user_data) {
|
||||||
|
auto s = static_cast<Http3Session *>(user_data);
|
||||||
|
if (s->stop_sending(stream_id, app_error_code) != 0) {
|
||||||
|
return NGHTTP3_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Http3Session::stop_sending(int64_t stream_id, uint64_t app_error_code) {
|
||||||
|
auto rv = ngtcp2_conn_shutdown_stream_read(client_->quic.conn, stream_id,
|
||||||
|
app_error_code);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "ngtcp2_conn_shutdown_stream_read: " << ngtcp2_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::close_stream(int64_t stream_id, uint64_t app_error_code) {
|
||||||
|
auto rv = nghttp3_conn_close_stream(conn_, stream_id, app_error_code);
|
||||||
|
switch (rv) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case NGHTTP3_ERR_STREAM_NOT_FOUND:
|
||||||
|
if (!ngtcp2_is_bidi_stream(stream_id)) {
|
||||||
|
assert(!ngtcp2_conn_is_local_stream(client_->quic.conn, stream_id));
|
||||||
|
ngtcp2_conn_extend_max_streams_uni(client_->quic.conn, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::shutdown_stream_read(int64_t stream_id) {
|
||||||
|
auto rv = nghttp3_conn_shutdown_stream_read(conn_, stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::extend_max_local_streams() {
|
||||||
|
auto config = client_->worker->config;
|
||||||
|
|
||||||
|
for (; npending_request_; --npending_request_) {
|
||||||
|
auto stream_id = submit_request_internal();
|
||||||
|
if (stream_id < 0) {
|
||||||
|
if (stream_id == NGTCP2_ERR_STREAM_ID_BLOCKED) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++reqidx_ == config->nva.size()) {
|
||||||
|
reqidx_ = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::init_conn() {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
assert(conn_ == nullptr);
|
||||||
|
|
||||||
|
if (ngtcp2_conn_get_max_local_streams_uni(client_->quic.conn) < 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp3_callbacks callbacks{
|
||||||
|
nullptr, // acked_stream_data
|
||||||
|
h2load::stream_close,
|
||||||
|
h2load::recv_data,
|
||||||
|
h2load::deferred_consume,
|
||||||
|
h2load::begin_headers,
|
||||||
|
h2load::recv_header,
|
||||||
|
nullptr, // end_headers
|
||||||
|
nullptr, // begin_trailers
|
||||||
|
h2load::recv_header,
|
||||||
|
nullptr, // end_trailers
|
||||||
|
h2load::stop_sending,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto config = client_->worker->config;
|
||||||
|
|
||||||
|
nghttp3_settings settings;
|
||||||
|
nghttp3_settings_default(&settings);
|
||||||
|
settings.qpack_max_dtable_capacity = config->header_table_size;
|
||||||
|
settings.qpack_blocked_streams = 100;
|
||||||
|
|
||||||
|
auto mem = nghttp3_mem_default();
|
||||||
|
|
||||||
|
rv = nghttp3_conn_client_new(&conn_, &callbacks, &settings, mem, this);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "nghttp3_conn_client_new: " << nghttp3_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ctrl_stream_id;
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &ctrl_stream_id, NULL);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp3_conn_bind_control_stream(conn_, ctrl_stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "nghttp3_conn_bind_control_stream: " << nghttp3_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t qpack_enc_stream_id, qpack_dec_stream_id;
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &qpack_enc_stream_id,
|
||||||
|
NULL);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_open_uni_stream(client_->quic.conn, &qpack_dec_stream_id,
|
||||||
|
NULL);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "ngtcp2_conn_open_uni_stream: " << ngtcp2_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = nghttp3_conn_bind_qpack_streams(conn_, qpack_enc_stream_id,
|
||||||
|
qpack_dec_stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "nghttp3_conn_bind_qpack_streams: " << nghttp3_strerror(rv)
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Http3Session::read_stream(uint32_t flags, int64_t stream_id,
|
||||||
|
const uint8_t *data, size_t datalen) {
|
||||||
|
auto nconsumed = nghttp3_conn_read_stream(
|
||||||
|
conn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN);
|
||||||
|
if (nconsumed < 0) {
|
||||||
|
std::cerr << "nghttp3_conn_read_stream: " << nghttp3_strerror(nconsumed)
|
||||||
|
<< std::endl;
|
||||||
|
client_->quic.last_error = quic::err_application(nconsumed);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return nconsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t Http3Session::write_stream(int64_t &stream_id, int &fin,
|
||||||
|
nghttp3_vec *vec, size_t veccnt) {
|
||||||
|
auto sveccnt =
|
||||||
|
nghttp3_conn_writev_stream(conn_, &stream_id, &fin, vec, veccnt);
|
||||||
|
if (sveccnt < 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(sveccnt);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return sveccnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::block_stream(int64_t stream_id) {
|
||||||
|
auto rv = nghttp3_conn_block_stream(conn_, stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(rv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::shutdown_stream_write(int64_t stream_id) {
|
||||||
|
auto rv = nghttp3_conn_shutdown_stream_write(conn_, stream_id);
|
||||||
|
if (rv != 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(rv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::add_write_offset(int64_t stream_id, size_t ndatalen) {
|
||||||
|
auto rv = nghttp3_conn_add_write_offset(conn_, stream_id, ndatalen);
|
||||||
|
if (rv != 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(rv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Http3Session::add_ack_offset(int64_t stream_id, size_t datalen) {
|
||||||
|
auto rv = nghttp3_conn_add_ack_offset(conn_, stream_id, datalen);
|
||||||
|
if (rv != 0) {
|
||||||
|
client_->quic.last_error = quic::err_application(rv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace h2load
|
||||||
81
src/h2load_http3_session.h
Normal file
81
src/h2load_http3_session.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef H2LOAD_HTTP3_SESSION_H
|
||||||
|
#define H2LOAD_HTTP3_SESSION_H
|
||||||
|
|
||||||
|
#include "h2load_session.h"
|
||||||
|
|
||||||
|
#include <nghttp3/nghttp3.h>
|
||||||
|
|
||||||
|
namespace h2load {
|
||||||
|
|
||||||
|
struct Client;
|
||||||
|
|
||||||
|
class Http3Session : public Session {
|
||||||
|
public:
|
||||||
|
Http3Session(Client *client);
|
||||||
|
virtual ~Http3Session();
|
||||||
|
virtual void on_connect();
|
||||||
|
virtual int submit_request();
|
||||||
|
virtual int on_read(const uint8_t *data, size_t len);
|
||||||
|
virtual int on_write();
|
||||||
|
virtual void terminate();
|
||||||
|
virtual size_t max_concurrent_streams();
|
||||||
|
|
||||||
|
int init_conn();
|
||||||
|
int stream_close(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
void recv_data(int64_t stream_id, const uint8_t *data, size_t datalen);
|
||||||
|
void consume(int64_t stream_id, size_t nconsumed);
|
||||||
|
void begin_headers(int64_t stream_id);
|
||||||
|
void recv_header(int64_t stream_id, const nghttp3_vec *name,
|
||||||
|
const nghttp3_vec *value);
|
||||||
|
int stop_sending(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
|
||||||
|
int close_stream(int64_t stream_id, uint64_t app_error_code);
|
||||||
|
int shutdown_stream_read(int64_t stream_id);
|
||||||
|
int extend_max_local_streams();
|
||||||
|
int64_t submit_request_internal();
|
||||||
|
|
||||||
|
ssize_t read_stream(uint32_t flags, int64_t stream_id, const uint8_t *data,
|
||||||
|
size_t datalen);
|
||||||
|
ssize_t write_stream(int64_t &stream_id, int &fin, nghttp3_vec *vec,
|
||||||
|
size_t veccnt);
|
||||||
|
int block_stream(int64_t stream_id);
|
||||||
|
int shutdown_stream_write(int64_t stream_id);
|
||||||
|
int add_write_offset(int64_t stream_id, size_t ndatalen);
|
||||||
|
int add_ack_offset(int64_t stream_id, size_t datalen);
|
||||||
|
|
||||||
|
void read_data(nghttp3_vec *vec, size_t veccnt, uint32_t *pflags);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Client *client_;
|
||||||
|
nghttp3_conn *conn_;
|
||||||
|
size_t npending_request_;
|
||||||
|
size_t reqidx_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace h2load
|
||||||
|
|
||||||
|
#endif // H2LOAD_HTTP3_SESSION_H
|
||||||
790
src/h2load_quic.cc
Normal file
790
src/h2load_quic.cc
Normal file
@@ -0,0 +1,790 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "h2load_quic.h"
|
||||||
|
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
|
||||||
|
# include <ngtcp2/ngtcp2_crypto_openssl.h>
|
||||||
|
#endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
|
||||||
|
#ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
|
||||||
|
# include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||||
|
#endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
|
||||||
|
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
#include "h2load_http3_session.h"
|
||||||
|
|
||||||
|
namespace h2load {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int handshake_completed(ngtcp2_conn *conn, void *user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
|
||||||
|
if (c->quic_handshake_completed() != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_handshake_completed() { return connection_made(); }
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
|
||||||
|
uint64_t offset, const uint8_t *data, size_t datalen,
|
||||||
|
void *user_data, void *stream_user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
if (c->quic_recv_stream_data(flags, stream_id, data, datalen) != 0) {
|
||||||
|
// TODO Better to do this gracefully rather than
|
||||||
|
// NGTCP2_ERR_CALLBACK_FAILURE. Perhaps, call
|
||||||
|
// ngtcp2_conn_write_application_close() ?
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_recv_stream_data(uint32_t flags, int64_t stream_id,
|
||||||
|
const uint8_t *data, size_t datalen) {
|
||||||
|
if (worker->current_phase == Phase::MAIN_DURATION) {
|
||||||
|
worker->stats.bytes_total += datalen;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
auto nconsumed = s->read_stream(flags, stream_id, data, datalen);
|
||||||
|
if (nconsumed == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngtcp2_conn_extend_max_stream_offset(quic.conn, stream_id, nconsumed);
|
||||||
|
ngtcp2_conn_extend_max_offset(quic.conn, nconsumed);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int acked_stream_data_offset(ngtcp2_conn *conn, int64_t stream_id,
|
||||||
|
uint64_t offset, uint64_t datalen, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
if (c->quic_acked_stream_data_offset(stream_id, datalen) != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_acked_stream_data_offset(int64_t stream_id, size_t datalen) {
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
if (s->add_ack_offset(stream_id, datalen) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int stream_close(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
|
||||||
|
uint64_t app_error_code, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
|
||||||
|
if (!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
|
||||||
|
app_error_code = NGHTTP3_H3_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->quic_stream_close(stream_id, app_error_code) != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_stream_close(int64_t stream_id, uint64_t app_error_code) {
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
if (s->close_stream(stream_id, app_error_code) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int stream_reset(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
|
||||||
|
uint64_t app_error_code, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
if (c->quic_stream_reset(stream_id, app_error_code) != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_stream_reset(int64_t stream_id, uint64_t app_error_code) {
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
if (s->shutdown_stream_read(stream_id) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int stream_stop_sending(ngtcp2_conn *conn, int64_t stream_id,
|
||||||
|
uint64_t app_error_code, void *user_data,
|
||||||
|
void *stream_user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
if (c->quic_stream_stop_sending(stream_id, app_error_code) != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_stream_stop_sending(int64_t stream_id,
|
||||||
|
uint64_t app_error_code) {
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
if (s->shutdown_stream_read(stream_id) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int extend_max_local_streams_bidi(ngtcp2_conn *conn, uint64_t max_streams,
|
||||||
|
void *user_data) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
|
||||||
|
if (c->quic_extend_max_local_streams() != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_extend_max_local_streams() {
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
if (s->extend_max_local_streams() != 0) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token,
|
||||||
|
size_t cidlen, void *user_data) {
|
||||||
|
if (RAND_bytes(cid->data, cidlen) != 1) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cid->datalen = cidlen;
|
||||||
|
|
||||||
|
if (RAND_bytes(token, NGTCP2_STATELESS_RESET_TOKENLEN) != 1) {
|
||||||
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void debug_log_printf(void *user_data, const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int generate_cid(ngtcp2_cid &dest) {
|
||||||
|
dest.datalen = 8;
|
||||||
|
|
||||||
|
if (RAND_bytes(dest.data, dest.datalen) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
ngtcp2_tstamp timestamp(struct ev_loop *loop) {
|
||||||
|
return ev_now(loop) * NGTCP2_SECONDS;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNGTCP2_CRYPTO_OPENSSL
|
||||||
|
namespace {
|
||||||
|
int set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
|
||||||
|
const uint8_t *rx_secret, const uint8_t *tx_secret,
|
||||||
|
size_t secret_len) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
auto level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
|
||||||
|
|
||||||
|
if (c->quic_on_rx_secret(level, rx_secret, secret_len) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->quic_on_tx_secret(level, tx_secret, secret_len) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
|
||||||
|
const uint8_t *data, size_t len) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
c->quic_write_client_handshake(
|
||||||
|
ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level), data, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int flush_flight(SSL *ssl) { return 1; }
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int send_alert(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
c->quic_set_tls_alert(alert);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
auto quic_method = SSL_QUIC_METHOD{
|
||||||
|
set_encryption_secrets,
|
||||||
|
add_handshake_data,
|
||||||
|
flush_flight,
|
||||||
|
send_alert,
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
#endif // HAVE_LIBNGTCP2_CRYPTO_OPENSSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
|
||||||
|
namespace {
|
||||||
|
int set_read_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
|
||||||
|
const SSL_CIPHER *cipher, const uint8_t *secret,
|
||||||
|
size_t secretlen) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
|
||||||
|
if (c->quic_on_rx_secret(
|
||||||
|
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), secret,
|
||||||
|
secretlen) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int set_write_secret(SSL *ssl, ssl_encryption_level_t ssl_level,
|
||||||
|
const SSL_CIPHER *cipher, const uint8_t *secret,
|
||||||
|
size_t secretlen) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
|
||||||
|
if (c->quic_on_tx_secret(
|
||||||
|
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), secret,
|
||||||
|
secretlen) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int add_handshake_data(SSL *ssl, ssl_encryption_level_t ssl_level,
|
||||||
|
const uint8_t *data, size_t len) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
c->quic_write_client_handshake(
|
||||||
|
ngtcp2_crypto_boringssl_from_ssl_encryption_level(ssl_level), data, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int flush_flight(SSL *ssl) { return 1; }
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int send_alert(SSL *ssl, ssl_encryption_level_t level, uint8_t alert) {
|
||||||
|
auto c = static_cast<Client *>(SSL_get_app_data(ssl));
|
||||||
|
c->quic_set_tls_alert(alert);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
auto quic_method = SSL_QUIC_METHOD{
|
||||||
|
set_read_secret, set_write_secret, add_handshake_data,
|
||||||
|
flush_flight, send_alert,
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
#endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL
|
||||||
|
|
||||||
|
// qlog write callback -- excerpted from ngtcp2/examples/client_base.cc
|
||||||
|
namespace {
|
||||||
|
void qlog_write_cb(void *user_data, uint32_t flags, const void *data,
|
||||||
|
size_t datalen) {
|
||||||
|
auto c = static_cast<Client *>(user_data);
|
||||||
|
c->quic_write_qlog(data, datalen);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Client::quic_write_qlog(const void *data, size_t datalen) {
|
||||||
|
assert(quic.qlog_file != nullptr);
|
||||||
|
fwrite(data, 1, datalen, quic.qlog_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void rand(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx) {
|
||||||
|
util::random_bytes(dest, dest + destlen,
|
||||||
|
*static_cast<std::mt19937 *>(rand_ctx->native_handle));
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int Client::quic_init(const sockaddr *local_addr, socklen_t local_addrlen,
|
||||||
|
const sockaddr *remote_addr, socklen_t remote_addrlen) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (!ssl) {
|
||||||
|
ssl = SSL_new(worker->ssl_ctx);
|
||||||
|
|
||||||
|
SSL_set_app_data(ssl, this);
|
||||||
|
SSL_set_connect_state(ssl);
|
||||||
|
SSL_set_quic_method(ssl, &quic_method);
|
||||||
|
SSL_set_quic_use_legacy_codepoint(ssl, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto callbacks = ngtcp2_callbacks{
|
||||||
|
ngtcp2_crypto_client_initial_cb,
|
||||||
|
nullptr, // recv_client_initial
|
||||||
|
ngtcp2_crypto_recv_crypto_data_cb,
|
||||||
|
h2load::handshake_completed,
|
||||||
|
nullptr, // recv_version_negotiation
|
||||||
|
ngtcp2_crypto_encrypt_cb,
|
||||||
|
ngtcp2_crypto_decrypt_cb,
|
||||||
|
ngtcp2_crypto_hp_mask_cb,
|
||||||
|
h2load::recv_stream_data,
|
||||||
|
h2load::acked_stream_data_offset,
|
||||||
|
nullptr, // stream_open
|
||||||
|
h2load::stream_close,
|
||||||
|
nullptr, // recv_stateless_reset
|
||||||
|
ngtcp2_crypto_recv_retry_cb,
|
||||||
|
h2load::extend_max_local_streams_bidi,
|
||||||
|
nullptr, // extend_max_local_streams_uni
|
||||||
|
h2load::rand,
|
||||||
|
get_new_connection_id,
|
||||||
|
nullptr, // remove_connection_id
|
||||||
|
ngtcp2_crypto_update_key_cb,
|
||||||
|
nullptr, // path_validation
|
||||||
|
nullptr, // select_preferred_addr
|
||||||
|
h2load::stream_reset,
|
||||||
|
nullptr, // extend_max_remote_streams_bidi
|
||||||
|
nullptr, // extend_max_remote_streams_uni
|
||||||
|
nullptr, // extend_max_stream_data
|
||||||
|
nullptr, // dcid_status
|
||||||
|
nullptr, // handshake_confirmed
|
||||||
|
nullptr, // recv_new_token
|
||||||
|
ngtcp2_crypto_delete_crypto_aead_ctx_cb,
|
||||||
|
ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
|
||||||
|
nullptr, // recv_datagram
|
||||||
|
nullptr, // ack_datagram
|
||||||
|
nullptr, // lost_datagram
|
||||||
|
ngtcp2_crypto_get_path_challenge_data_cb,
|
||||||
|
h2load::stream_stop_sending,
|
||||||
|
};
|
||||||
|
|
||||||
|
ngtcp2_cid scid, dcid;
|
||||||
|
if (generate_cid(scid) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (generate_cid(dcid) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto config = worker->config;
|
||||||
|
|
||||||
|
ngtcp2_settings settings;
|
||||||
|
ngtcp2_settings_default(&settings);
|
||||||
|
if (config->verbose) {
|
||||||
|
settings.log_printf = debug_log_printf;
|
||||||
|
}
|
||||||
|
settings.initial_ts = timestamp(worker->loop);
|
||||||
|
settings.rand_ctx.native_handle = &worker->randgen;
|
||||||
|
if (!config->qlog_file_base.empty()) {
|
||||||
|
assert(quic.qlog_file == nullptr);
|
||||||
|
auto path = config->qlog_file_base;
|
||||||
|
path += '.';
|
||||||
|
path += util::utos(worker->id);
|
||||||
|
path += '.';
|
||||||
|
path += util::utos(id);
|
||||||
|
path += ".sqlog";
|
||||||
|
quic.qlog_file = fopen(path.c_str(), "w");
|
||||||
|
if (quic.qlog_file == nullptr) {
|
||||||
|
std::cerr << "Failed to open a qlog file: " << path << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
settings.qlog.write = qlog_write_cb;
|
||||||
|
}
|
||||||
|
if (config->max_udp_payload_size) {
|
||||||
|
settings.max_udp_payload_size = config->max_udp_payload_size;
|
||||||
|
settings.no_udp_payload_size_shaping = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngtcp2_transport_params params;
|
||||||
|
ngtcp2_transport_params_default(¶ms);
|
||||||
|
auto max_stream_data =
|
||||||
|
std::min((1 << 26) - 1, (1 << config->window_bits) - 1);
|
||||||
|
params.initial_max_stream_data_bidi_local = max_stream_data;
|
||||||
|
params.initial_max_stream_data_uni = max_stream_data;
|
||||||
|
params.initial_max_data = (1 << config->connection_window_bits) - 1;
|
||||||
|
params.initial_max_streams_bidi = 0;
|
||||||
|
params.initial_max_streams_uni = 100;
|
||||||
|
params.max_idle_timeout = 30 * NGTCP2_SECONDS;
|
||||||
|
|
||||||
|
auto path = ngtcp2_path{
|
||||||
|
{
|
||||||
|
const_cast<sockaddr *>(local_addr),
|
||||||
|
local_addrlen,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
const_cast<sockaddr *>(remote_addr),
|
||||||
|
remote_addrlen,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(config->npn_list.size());
|
||||||
|
|
||||||
|
uint32_t quic_version;
|
||||||
|
|
||||||
|
if (config->npn_list[0] == NGHTTP3_ALPN_H3) {
|
||||||
|
quic_version = NGTCP2_PROTO_VER_V1;
|
||||||
|
} else {
|
||||||
|
quic_version = NGTCP2_PROTO_VER_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_client_new(&quic.conn, &dcid, &scid, &path, quic_version,
|
||||||
|
&callbacks, &settings, ¶ms, nullptr, this);
|
||||||
|
if (rv != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngtcp2_conn_set_tls_native_handle(quic.conn, ssl);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::quic_free() {
|
||||||
|
ngtcp2_conn_del(quic.conn);
|
||||||
|
if (quic.qlog_file != nullptr) {
|
||||||
|
fclose(quic.qlog_file);
|
||||||
|
quic.qlog_file = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::quic_close_connection() {
|
||||||
|
if (!quic.conn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<uint8_t, NGTCP2_MAX_UDP_PAYLOAD_SIZE> buf;
|
||||||
|
ngtcp2_ssize nwrite;
|
||||||
|
ngtcp2_path_storage ps;
|
||||||
|
ngtcp2_path_storage_zero(&ps);
|
||||||
|
|
||||||
|
switch (quic.last_error.type) {
|
||||||
|
case quic::ErrorType::TransportVersionNegotiation:
|
||||||
|
return;
|
||||||
|
case quic::ErrorType::Transport:
|
||||||
|
nwrite = ngtcp2_conn_write_connection_close(
|
||||||
|
quic.conn, &ps.path, nullptr, buf.data(), buf.size(),
|
||||||
|
quic.last_error.code, nullptr, 0, timestamp(worker->loop));
|
||||||
|
break;
|
||||||
|
case quic::ErrorType::Application:
|
||||||
|
nwrite = ngtcp2_conn_write_application_close(
|
||||||
|
quic.conn, &ps.path, nullptr, buf.data(), buf.size(),
|
||||||
|
quic.last_error.code, nullptr, 0, timestamp(worker->loop));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nwrite < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_udp(reinterpret_cast<sockaddr *>(ps.path.remote.addr),
|
||||||
|
ps.path.remote.addrlen, buf.data(), nwrite, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Client::quic_on_rx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
|
||||||
|
size_t secretlen) {
|
||||||
|
if (ngtcp2_crypto_derive_and_install_rx_key(quic.conn, nullptr, nullptr,
|
||||||
|
nullptr, level, secret,
|
||||||
|
secretlen) != 0) {
|
||||||
|
std::cerr << "ngtcp2_crypto_derive_and_install_rx_key() failed"
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
|
||||||
|
auto s = std::make_unique<Http3Session>(this);
|
||||||
|
if (s->init_conn() == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
session = std::move(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Client::quic_on_tx_secret(ngtcp2_crypto_level level, const uint8_t *secret,
|
||||||
|
size_t secretlen) {
|
||||||
|
if (ngtcp2_crypto_derive_and_install_tx_key(quic.conn, nullptr, nullptr,
|
||||||
|
nullptr, level, secret,
|
||||||
|
secretlen) != 0) {
|
||||||
|
std::cerr << "ngtcp2_crypto_derive_and_install_tx_key() failed"
|
||||||
|
<< std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::quic_set_tls_alert(uint8_t alert) {
|
||||||
|
quic.last_error = quic::err_transport_tls(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::quic_write_client_handshake(ngtcp2_crypto_level level,
|
||||||
|
const uint8_t *data, size_t datalen) {
|
||||||
|
assert(level < 2);
|
||||||
|
|
||||||
|
ngtcp2_conn_submit_crypto_data(quic.conn, level, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void quic_pkt_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
|
auto c = static_cast<Client *>(w->data);
|
||||||
|
|
||||||
|
if (c->quic_pkt_timeout() != 0) {
|
||||||
|
c->fail();
|
||||||
|
c->worker->free_client(c);
|
||||||
|
delete c;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Client::quic_pkt_timeout() {
|
||||||
|
int rv;
|
||||||
|
auto now = timestamp(worker->loop);
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_handle_expiry(quic.conn, now);
|
||||||
|
if (rv != 0) {
|
||||||
|
quic.last_error = quic::err_transport(NGTCP2_ERR_INTERNAL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return write_quic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::quic_restart_pkt_timer() {
|
||||||
|
auto expiry = ngtcp2_conn_get_expiry(quic.conn);
|
||||||
|
auto now = timestamp(worker->loop);
|
||||||
|
auto t = expiry > now ? static_cast<ev_tstamp>(expiry - now) / NGTCP2_SECONDS
|
||||||
|
: 1e-9;
|
||||||
|
quic.pkt_timer.repeat = t;
|
||||||
|
ev_timer_again(worker->loop, &quic.pkt_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Client::read_quic() {
|
||||||
|
std::array<uint8_t, 65536> buf;
|
||||||
|
sockaddr_union su;
|
||||||
|
socklen_t addrlen = sizeof(su);
|
||||||
|
int rv;
|
||||||
|
size_t pktcnt = 0;
|
||||||
|
ngtcp2_pkt_info pi{};
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
auto nread =
|
||||||
|
recvfrom(fd, buf.data(), buf.size(), MSG_DONTWAIT, &su.sa, &addrlen);
|
||||||
|
if (nread == -1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(quic.conn);
|
||||||
|
|
||||||
|
++worker->stats.udp_dgram_recv;
|
||||||
|
|
||||||
|
auto path = ngtcp2_path{
|
||||||
|
{
|
||||||
|
&local_addr.su.sa,
|
||||||
|
static_cast<socklen_t>(local_addr.len),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&su.sa,
|
||||||
|
addrlen,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rv = ngtcp2_conn_read_pkt(quic.conn, &path, &pi, buf.data(), nread,
|
||||||
|
timestamp(worker->loop));
|
||||||
|
if (rv != 0) {
|
||||||
|
std::cerr << "ngtcp2_conn_read_pkt: " << ngtcp2_strerror(rv) << std::endl;
|
||||||
|
|
||||||
|
if (!quic.last_error.code) {
|
||||||
|
quic.last_error = quic::err_transport(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++pktcnt == 100) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Client::write_quic() {
|
||||||
|
ev_io_stop(worker->loop, &wev);
|
||||||
|
|
||||||
|
if (quic.close_requested) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<nghttp3_vec, 16> vec;
|
||||||
|
size_t pktcnt = 0;
|
||||||
|
auto max_udp_payload_size =
|
||||||
|
ngtcp2_conn_get_path_max_udp_payload_size(quic.conn);
|
||||||
|
size_t max_pktcnt =
|
||||||
|
#ifdef UDP_SEGMENT
|
||||||
|
worker->config->no_udp_gso
|
||||||
|
? 1
|
||||||
|
: std::min(static_cast<size_t>(10),
|
||||||
|
static_cast<size_t>(64_k / max_udp_payload_size));
|
||||||
|
#else // !UDP_SEGMENT
|
||||||
|
1;
|
||||||
|
#endif // !UDP_SEGMENT
|
||||||
|
std::array<uint8_t, 64_k> buf;
|
||||||
|
uint8_t *bufpos = buf.data();
|
||||||
|
ngtcp2_path_storage ps;
|
||||||
|
|
||||||
|
ngtcp2_path_storage_zero(&ps);
|
||||||
|
|
||||||
|
auto s = static_cast<Http3Session *>(session.get());
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int64_t stream_id = -1;
|
||||||
|
int fin = 0;
|
||||||
|
ssize_t sveccnt = 0;
|
||||||
|
|
||||||
|
if (session && ngtcp2_conn_get_max_data_left(quic.conn)) {
|
||||||
|
sveccnt = s->write_stream(stream_id, fin, vec.data(), vec.size());
|
||||||
|
if (sveccnt == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngtcp2_ssize ndatalen;
|
||||||
|
auto v = vec.data();
|
||||||
|
auto vcnt = static_cast<size_t>(sveccnt);
|
||||||
|
|
||||||
|
uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE;
|
||||||
|
if (fin) {
|
||||||
|
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nwrite = ngtcp2_conn_writev_stream(
|
||||||
|
quic.conn, &ps.path, nullptr, bufpos, max_udp_payload_size, &ndatalen,
|
||||||
|
flags, stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt,
|
||||||
|
timestamp(worker->loop));
|
||||||
|
if (nwrite < 0) {
|
||||||
|
switch (nwrite) {
|
||||||
|
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
|
||||||
|
assert(ndatalen == -1);
|
||||||
|
if (s->block_stream(stream_id) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case NGTCP2_ERR_STREAM_SHUT_WR:
|
||||||
|
assert(ndatalen == -1);
|
||||||
|
if (s->shutdown_stream_write(stream_id) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case NGTCP2_ERR_WRITE_MORE:
|
||||||
|
assert(ndatalen >= 0);
|
||||||
|
if (s->add_write_offset(stream_id, ndatalen) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
quic.last_error = quic::err_transport(nwrite);
|
||||||
|
return -1;
|
||||||
|
} else if (ndatalen >= 0 && s->add_write_offset(stream_id, ndatalen) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
quic_restart_pkt_timer();
|
||||||
|
|
||||||
|
if (nwrite == 0) {
|
||||||
|
if (bufpos - buf.data()) {
|
||||||
|
write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(),
|
||||||
|
bufpos - buf.data(), max_udp_payload_size);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufpos += nwrite;
|
||||||
|
|
||||||
|
// Assume that the path does not change.
|
||||||
|
if (++pktcnt == max_pktcnt ||
|
||||||
|
static_cast<size_t>(nwrite) < max_udp_payload_size) {
|
||||||
|
write_udp(ps.path.remote.addr, ps.path.remote.addrlen, buf.data(),
|
||||||
|
bufpos - buf.data(), max_udp_payload_size);
|
||||||
|
signal_write();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace h2load
|
||||||
38
src/h2load_quic.h
Normal file
38
src/h2load_quic.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef H2LOAD_QUIC_H
|
||||||
|
#define H2LOAD_QUIC_H
|
||||||
|
|
||||||
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#include <ev.h>
|
||||||
|
|
||||||
|
#include "h2load.h"
|
||||||
|
|
||||||
|
namespace h2load {
|
||||||
|
void quic_pkt_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents);
|
||||||
|
} // namespace h2load
|
||||||
|
|
||||||
|
#endif // H2LOAD_QUIC_H
|
||||||
@@ -916,7 +916,7 @@ void test_http2_rewrite_clean_path(void) {
|
|||||||
CU_ASSERT("/delta%3A" == http2::rewrite_clean_path(
|
CU_ASSERT("/delta%3A" == http2::rewrite_clean_path(
|
||||||
balloc, StringRef::from_lit("/delta%3a")));
|
balloc, StringRef::from_lit("/delta%3a")));
|
||||||
|
|
||||||
// path component is normalized before mathcing
|
// path component is normalized before matching
|
||||||
CU_ASSERT(
|
CU_ASSERT(
|
||||||
"/alpha/bravo/" ==
|
"/alpha/bravo/" ==
|
||||||
http2::rewrite_clean_path(
|
http2::rewrite_clean_path(
|
||||||
|
|||||||
206
src/http3.cc
Normal file
206
src/http3.cc
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "http3.h"
|
||||||
|
|
||||||
|
namespace nghttp2 {
|
||||||
|
|
||||||
|
namespace http3 {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
nghttp3_nv make_nv_internal(const std::string &name, const std::string &value,
|
||||||
|
bool never_index, uint8_t nv_flags) {
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
flags = nv_flags |
|
||||||
|
(never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
|
||||||
|
|
||||||
|
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
|
||||||
|
value.size(), flags};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
nghttp3_nv make_nv_internal(const StringRef &name, const StringRef &value,
|
||||||
|
bool never_index, uint8_t nv_flags) {
|
||||||
|
uint8_t flags;
|
||||||
|
|
||||||
|
flags = nv_flags |
|
||||||
|
(never_index ? NGHTTP3_NV_FLAG_NEVER_INDEX : NGHTTP3_NV_FLAG_NONE);
|
||||||
|
|
||||||
|
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
|
||||||
|
value.size(), flags};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
nghttp3_nv make_nv(const std::string &name, const std::string &value,
|
||||||
|
bool never_index) {
|
||||||
|
return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp3_nv make_nv(const StringRef &name, const StringRef &value,
|
||||||
|
bool never_index) {
|
||||||
|
return make_nv_internal(name, value, never_index, NGHTTP3_NV_FLAG_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp3_nv make_nv_nocopy(const std::string &name, const std::string &value,
|
||||||
|
bool never_index) {
|
||||||
|
return make_nv_internal(name, value, never_index,
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME |
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp3_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
|
||||||
|
bool never_index) {
|
||||||
|
return make_nv_internal(name, value, never_index,
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME |
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void copy_headers_to_nva_internal(std::vector<nghttp3_nv> &nva,
|
||||||
|
const HeaderRefs &headers, uint8_t nv_flags,
|
||||||
|
uint32_t flags) {
|
||||||
|
auto it_forwarded = std::end(headers);
|
||||||
|
auto it_xff = std::end(headers);
|
||||||
|
auto it_xfp = std::end(headers);
|
||||||
|
auto it_via = std::end(headers);
|
||||||
|
|
||||||
|
for (auto it = std::begin(headers); it != std::end(headers); ++it) {
|
||||||
|
auto kv = &(*it);
|
||||||
|
if (kv->name.empty() || kv->name[0] == ':') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (kv->token) {
|
||||||
|
case http2::HD_COOKIE:
|
||||||
|
case http2::HD_CONNECTION:
|
||||||
|
case http2::HD_HOST:
|
||||||
|
case http2::HD_HTTP2_SETTINGS:
|
||||||
|
case http2::HD_KEEP_ALIVE:
|
||||||
|
case http2::HD_PROXY_CONNECTION:
|
||||||
|
case http2::HD_SERVER:
|
||||||
|
case http2::HD_TE:
|
||||||
|
case http2::HD_TRANSFER_ENCODING:
|
||||||
|
case http2::HD_UPGRADE:
|
||||||
|
continue;
|
||||||
|
case http2::HD_EARLY_DATA:
|
||||||
|
if (flags & http2::HDOP_STRIP_EARLY_DATA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case http2::HD_SEC_WEBSOCKET_ACCEPT:
|
||||||
|
if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_ACCEPT) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case http2::HD_SEC_WEBSOCKET_KEY:
|
||||||
|
if (flags & http2::HDOP_STRIP_SEC_WEBSOCKET_KEY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case http2::HD_FORWARDED:
|
||||||
|
if (flags & http2::HDOP_STRIP_FORWARDED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_forwarded == std::end(headers)) {
|
||||||
|
it_forwarded = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_forwarded);
|
||||||
|
it_forwarded = it;
|
||||||
|
break;
|
||||||
|
case http2::HD_X_FORWARDED_FOR:
|
||||||
|
if (flags & http2::HDOP_STRIP_X_FORWARDED_FOR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xff == std::end(headers)) {
|
||||||
|
it_xff = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xff);
|
||||||
|
it_xff = it;
|
||||||
|
break;
|
||||||
|
case http2::HD_X_FORWARDED_PROTO:
|
||||||
|
if (flags & http2::HDOP_STRIP_X_FORWARDED_PROTO) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_xfp == std::end(headers)) {
|
||||||
|
it_xfp = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_xfp);
|
||||||
|
it_xfp = it;
|
||||||
|
break;
|
||||||
|
case http2::HD_VIA:
|
||||||
|
if (flags & http2::HDOP_STRIP_VIA) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it_via == std::end(headers)) {
|
||||||
|
it_via = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kv = &(*it_via);
|
||||||
|
it_via = it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nva.push_back(
|
||||||
|
make_nv_internal(kv->name, kv->value, kv->no_index, nv_flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void copy_headers_to_nva(std::vector<nghttp3_nv> &nva,
|
||||||
|
const HeaderRefs &headers, uint32_t flags) {
|
||||||
|
copy_headers_to_nva_internal(nva, headers, NGHTTP3_NV_FLAG_NONE, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_headers_to_nva_nocopy(std::vector<nghttp3_nv> &nva,
|
||||||
|
const HeaderRefs &headers, uint32_t flags) {
|
||||||
|
copy_headers_to_nva_internal(
|
||||||
|
nva, headers,
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||||
|
size_t valuelen) {
|
||||||
|
if (!nghttp3_check_header_name(name, namelen)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!nghttp3_check_header_value(value, valuelen)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace http3
|
||||||
|
|
||||||
|
} // namespace nghttp2
|
||||||
123
src/http3.h
Normal file
123
src/http3.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef HTTP3_H
|
||||||
|
#define HTTP3_H
|
||||||
|
|
||||||
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nghttp3/nghttp3.h>
|
||||||
|
|
||||||
|
#include "http2.h"
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
namespace nghttp2 {
|
||||||
|
|
||||||
|
namespace http3 {
|
||||||
|
|
||||||
|
// Creates nghttp3_nv using |name| and |value| and returns it. The
|
||||||
|
// returned value only references the data pointer to name.c_str() and
|
||||||
|
// value.c_str(). If |no_index| is true, nghttp3_nv flags member has
|
||||||
|
// NGHTTP3_NV_FLAG_NEVER_INDEX flag set.
|
||||||
|
nghttp3_nv make_nv(const std::string &name, const std::string &value,
|
||||||
|
bool never_index = false);
|
||||||
|
|
||||||
|
nghttp3_nv make_nv(const StringRef &name, const StringRef &value,
|
||||||
|
bool never_index = false);
|
||||||
|
|
||||||
|
nghttp3_nv make_nv_nocopy(const std::string &name, const std::string &value,
|
||||||
|
bool never_index = false);
|
||||||
|
|
||||||
|
nghttp3_nv make_nv_nocopy(const StringRef &name, const StringRef &value,
|
||||||
|
bool never_index = false);
|
||||||
|
|
||||||
|
// Create nghttp3_nv from string literal |name| and |value|.
|
||||||
|
template <size_t N, size_t M>
|
||||||
|
constexpr nghttp3_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create nghttp3_nv from string literal |name| and c-string |value|.
|
||||||
|
template <size_t N>
|
||||||
|
nghttp3_nv make_nv_lc(const char (&name)[N], const char *value) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
nghttp3_nv make_nv_lc_nocopy(const char (&name)[N], const char *value) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create nghttp3_nv from string literal |name| and std::string
|
||||||
|
// |value|.
|
||||||
|
template <size_t N>
|
||||||
|
nghttp3_nv make_nv_ls(const char (&name)[N], const std::string &value) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
nghttp3_nv make_nv_ls_nocopy(const char (&name)[N], const std::string &value) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
nghttp3_nv make_nv_ls_nocopy(const char (&name)[N], const StringRef &value) {
|
||||||
|
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||||
|
NGHTTP3_NV_FLAG_NO_COPY_NAME | NGHTTP3_NV_FLAG_NO_COPY_VALUE};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends headers in |headers| to |nv|. |headers| must be indexed
|
||||||
|
// before this call (its element's token field is assigned). Certain
|
||||||
|
// headers, including disallowed headers in HTTP/3 spec and headers
|
||||||
|
// which require special handling (i.e. via), are not copied. |flags|
|
||||||
|
// is one or more of HeaderBuildOp flags. They tell function that
|
||||||
|
// certain header fields should not be added.
|
||||||
|
void copy_headers_to_nva(std::vector<nghttp3_nv> &nva,
|
||||||
|
const HeaderRefs &headers, uint32_t flags);
|
||||||
|
|
||||||
|
// Just like copy_headers_to_nva(), but this adds
|
||||||
|
// NGHTTP3_NV_FLAG_NO_COPY_NAME and NGHTTP3_NV_FLAG_NO_COPY_VALUE.
|
||||||
|
void copy_headers_to_nva_nocopy(std::vector<nghttp3_nv> &nva,
|
||||||
|
const HeaderRefs &headers, uint32_t flags);
|
||||||
|
|
||||||
|
// Checks the header name/value pair using nghttp3_check_header_name()
|
||||||
|
// and nghttp3_check_header_value(). If both function returns nonzero,
|
||||||
|
// this function returns nonzero.
|
||||||
|
int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||||
|
size_t valuelen);
|
||||||
|
|
||||||
|
} // namespace http3
|
||||||
|
|
||||||
|
} // namespace nghttp2
|
||||||
|
|
||||||
|
#endif // HTTP3_H
|
||||||
@@ -113,13 +113,22 @@ template <typename T> struct Pool {
|
|||||||
|
|
||||||
template <typename Memchunk> struct Memchunks {
|
template <typename Memchunk> struct Memchunks {
|
||||||
Memchunks(Pool<Memchunk> *pool)
|
Memchunks(Pool<Memchunk> *pool)
|
||||||
: pool(pool), head(nullptr), tail(nullptr), len(0) {}
|
: pool(pool),
|
||||||
|
head(nullptr),
|
||||||
|
tail(nullptr),
|
||||||
|
len(0),
|
||||||
|
mark(nullptr),
|
||||||
|
mark_pos(nullptr),
|
||||||
|
mark_offset(0) {}
|
||||||
Memchunks(const Memchunks &) = delete;
|
Memchunks(const Memchunks &) = delete;
|
||||||
Memchunks(Memchunks &&other) noexcept
|
Memchunks(Memchunks &&other) noexcept
|
||||||
: pool{other.pool}, // keep other.pool
|
: pool{other.pool}, // keep other.pool
|
||||||
head{std::exchange(other.head, nullptr)},
|
head{std::exchange(other.head, nullptr)},
|
||||||
tail{std::exchange(other.tail, nullptr)},
|
tail{std::exchange(other.tail, nullptr)},
|
||||||
len{std::exchange(other.len, 0)} {}
|
len{std::exchange(other.len, 0)},
|
||||||
|
mark{std::exchange(other.mark, nullptr)},
|
||||||
|
mark_pos{std::exchange(other.mark_pos, nullptr)},
|
||||||
|
mark_offset{std::exchange(other.mark_offset, 0)} {}
|
||||||
Memchunks &operator=(const Memchunks &) = delete;
|
Memchunks &operator=(const Memchunks &) = delete;
|
||||||
Memchunks &operator=(Memchunks &&other) noexcept {
|
Memchunks &operator=(Memchunks &&other) noexcept {
|
||||||
if (this == &other) {
|
if (this == &other) {
|
||||||
@@ -132,6 +141,9 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
head = std::exchange(other.head, nullptr);
|
head = std::exchange(other.head, nullptr);
|
||||||
tail = std::exchange(other.tail, nullptr);
|
tail = std::exchange(other.tail, nullptr);
|
||||||
len = std::exchange(other.len, 0);
|
len = std::exchange(other.len, 0);
|
||||||
|
mark = std::exchange(other.mark, nullptr);
|
||||||
|
mark_pos = std::exchange(other.mark_pos, nullptr);
|
||||||
|
mark_offset = std::exchange(other.mark_offset, 0);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -200,6 +212,8 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
size_t remove(void *dest, size_t count) {
|
size_t remove(void *dest, size_t count) {
|
||||||
|
assert(mark == nullptr);
|
||||||
|
|
||||||
if (!tail || count == 0) {
|
if (!tail || count == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -231,6 +245,8 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
return first - static_cast<uint8_t *>(dest);
|
return first - static_cast<uint8_t *>(dest);
|
||||||
}
|
}
|
||||||
size_t remove(Memchunks &dest, size_t count) {
|
size_t remove(Memchunks &dest, size_t count) {
|
||||||
|
assert(mark == nullptr);
|
||||||
|
|
||||||
if (!tail || count == 0) {
|
if (!tail || count == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -262,6 +278,7 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
}
|
}
|
||||||
size_t remove(Memchunks &dest) {
|
size_t remove(Memchunks &dest) {
|
||||||
assert(pool == dest.pool);
|
assert(pool == dest.pool);
|
||||||
|
assert(mark == nullptr);
|
||||||
|
|
||||||
if (head == nullptr) {
|
if (head == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -284,6 +301,8 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
size_t drain(size_t count) {
|
size_t drain(size_t count) {
|
||||||
|
assert(mark == nullptr);
|
||||||
|
|
||||||
auto ndata = count;
|
auto ndata = count;
|
||||||
auto m = head;
|
auto m = head;
|
||||||
while (m) {
|
while (m) {
|
||||||
@@ -305,6 +324,38 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
}
|
}
|
||||||
return ndata - count;
|
return ndata - count;
|
||||||
}
|
}
|
||||||
|
size_t drain_mark(size_t count) {
|
||||||
|
auto ndata = count;
|
||||||
|
auto m = head;
|
||||||
|
while (m) {
|
||||||
|
auto next = m->next;
|
||||||
|
auto n = std::min(count, m->len());
|
||||||
|
m->pos += n;
|
||||||
|
count -= n;
|
||||||
|
len -= n;
|
||||||
|
mark_offset -= n;
|
||||||
|
|
||||||
|
if (m->len() > 0) {
|
||||||
|
assert(mark != m || m->pos <= mark_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mark == m) {
|
||||||
|
assert(m->pos <= mark_pos);
|
||||||
|
|
||||||
|
mark = nullptr;
|
||||||
|
mark_pos = nullptr;
|
||||||
|
mark_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->recycle(m);
|
||||||
|
m = next;
|
||||||
|
}
|
||||||
|
head = m;
|
||||||
|
if (head == nullptr) {
|
||||||
|
tail = nullptr;
|
||||||
|
}
|
||||||
|
return ndata - count;
|
||||||
|
}
|
||||||
int riovec(struct iovec *iov, int iovcnt) const {
|
int riovec(struct iovec *iov, int iovcnt) const {
|
||||||
if (!head) {
|
if (!head) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -317,7 +368,41 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
int riovec_mark(struct iovec *iov, int iovcnt) {
|
||||||
|
if (!head || iovcnt == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
Memchunk *m;
|
||||||
|
if (mark) {
|
||||||
|
if (mark_pos != mark->last) {
|
||||||
|
iov[0].iov_base = mark_pos;
|
||||||
|
iov[0].iov_len = mark->len() - (mark_pos - mark->pos);
|
||||||
|
|
||||||
|
mark_pos = mark->last;
|
||||||
|
mark_offset += iov[0].iov_len;
|
||||||
|
i = 1;
|
||||||
|
}
|
||||||
|
m = mark->next;
|
||||||
|
} else {
|
||||||
|
i = 0;
|
||||||
|
m = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < iovcnt && m; ++i, m = m->next) {
|
||||||
|
iov[i].iov_base = m->pos;
|
||||||
|
iov[i].iov_len = m->len();
|
||||||
|
|
||||||
|
mark = m;
|
||||||
|
mark_pos = m->last;
|
||||||
|
mark_offset += m->len();
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
size_t rleft() const { return len; }
|
size_t rleft() const { return len; }
|
||||||
|
size_t rleft_mark() const { return len - mark_offset; }
|
||||||
void reset() {
|
void reset() {
|
||||||
for (auto m = head; m;) {
|
for (auto m = head; m;) {
|
||||||
auto next = m->next;
|
auto next = m->next;
|
||||||
@@ -325,12 +410,17 @@ template <typename Memchunk> struct Memchunks {
|
|||||||
m = next;
|
m = next;
|
||||||
}
|
}
|
||||||
len = 0;
|
len = 0;
|
||||||
head = tail = nullptr;
|
head = tail = mark = nullptr;
|
||||||
|
mark_pos = nullptr;
|
||||||
|
mark_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pool<Memchunk> *pool;
|
Pool<Memchunk> *pool;
|
||||||
Memchunk *head, *tail;
|
Memchunk *head, *tail;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
Memchunk *mark;
|
||||||
|
uint8_t *mark_pos;
|
||||||
|
size_t mark_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrapper around Memchunks to offer "peeking" functionality.
|
// Wrapper around Memchunks to offer "peeking" functionality.
|
||||||
|
|||||||
@@ -2268,7 +2268,7 @@ int communicate(
|
|||||||
auto loop = EV_DEFAULT;
|
auto loop = EV_DEFAULT;
|
||||||
SSL_CTX *ssl_ctx = nullptr;
|
SSL_CTX *ssl_ctx = nullptr;
|
||||||
if (scheme == "https") {
|
if (scheme == "https") {
|
||||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||||
if (!ssl_ctx) {
|
if (!ssl_ctx) {
|
||||||
std::cerr << "[ERROR] Failed to create SSL_CTX: "
|
std::cerr << "[ERROR] Failed to create SSL_CTX: "
|
||||||
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
<< ERR_error_string(ERR_get_error(), nullptr) << std::endl;
|
||||||
|
|||||||
60
src/quic.cc
Normal file
60
src/quic.cc
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "quic.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <ngtcp2/ngtcp2.h>
|
||||||
|
#include <nghttp3/nghttp3.h>
|
||||||
|
|
||||||
|
#include "template.h"
|
||||||
|
|
||||||
|
using namespace nghttp2;
|
||||||
|
|
||||||
|
namespace quic {
|
||||||
|
|
||||||
|
Error err_transport(int liberr) {
|
||||||
|
if (liberr == NGTCP2_ERR_RECV_VERSION_NEGOTIATION) {
|
||||||
|
return {ErrorType::TransportVersionNegotiation, 0};
|
||||||
|
}
|
||||||
|
return {ErrorType::Transport,
|
||||||
|
ngtcp2_err_infer_quic_transport_error_code(liberr)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Error err_transport_idle_timeout() {
|
||||||
|
return {ErrorType::TransportIdleTimeout, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
Error err_transport_tls(int alert) {
|
||||||
|
return {ErrorType::Transport, ngtcp2_err_infer_quic_transport_error_code(
|
||||||
|
NGTCP2_CRYPTO_ERROR | alert)};
|
||||||
|
}
|
||||||
|
|
||||||
|
Error err_application(int liberr) {
|
||||||
|
return {ErrorType::Application,
|
||||||
|
nghttp3_err_infer_quic_app_error_code(liberr)};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace quic
|
||||||
56
src/quic.h
Normal file
56
src/quic.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef QUIC_H
|
||||||
|
#define QUIC_H
|
||||||
|
|
||||||
|
#include "nghttp2_config.h"
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
namespace quic {
|
||||||
|
|
||||||
|
enum class ErrorType {
|
||||||
|
Transport,
|
||||||
|
TransportVersionNegotiation,
|
||||||
|
TransportIdleTimeout,
|
||||||
|
Application,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Error {
|
||||||
|
Error(ErrorType type, uint64_t code) : type(type), code(code) {}
|
||||||
|
Error() : type(ErrorType::Transport), code(0) {}
|
||||||
|
|
||||||
|
ErrorType type;
|
||||||
|
uint64_t code;
|
||||||
|
};
|
||||||
|
|
||||||
|
Error err_transport(int liberr);
|
||||||
|
Error err_transport_idle_timeout();
|
||||||
|
Error err_transport_tls(int alert);
|
||||||
|
Error err_application(int liberr);
|
||||||
|
|
||||||
|
} // namespace quic
|
||||||
|
|
||||||
|
#endif // QUIC_H
|
||||||
@@ -135,6 +135,8 @@ int main(int argc, char *argv[]) {
|
|||||||
shrpx::test_shrpx_http_create_via_header_value) ||
|
shrpx::test_shrpx_http_create_via_header_value) ||
|
||||||
!CU_add_test(pSuite, "http_create_affinity_cookie",
|
!CU_add_test(pSuite, "http_create_affinity_cookie",
|
||||||
shrpx::test_shrpx_http_create_affinity_cookie) ||
|
shrpx::test_shrpx_http_create_affinity_cookie) ||
|
||||||
|
!CU_add_test(pSuite, "http_create_atlsvc_header_field_value",
|
||||||
|
shrpx::test_shrpx_http_create_altsvc_header_value) ||
|
||||||
!CU_add_test(pSuite, "router_match", shrpx::test_shrpx_router_match) ||
|
!CU_add_test(pSuite, "router_match", shrpx::test_shrpx_router_match) ||
|
||||||
!CU_add_test(pSuite, "router_match_wildcard",
|
!CU_add_test(pSuite, "router_match_wildcard",
|
||||||
shrpx::test_shrpx_router_match_wildcard) ||
|
shrpx::test_shrpx_router_match_wildcard) ||
|
||||||
@@ -197,6 +199,7 @@ int main(int argc, char *argv[]) {
|
|||||||
shrpx::test_util_extract_host) ||
|
shrpx::test_util_extract_host) ||
|
||||||
!CU_add_test(pSuite, "util_split_hostport",
|
!CU_add_test(pSuite, "util_split_hostport",
|
||||||
shrpx::test_util_split_hostport) ||
|
shrpx::test_util_split_hostport) ||
|
||||||
|
!CU_add_test(pSuite, "util_split_str", shrpx::test_util_split_str) ||
|
||||||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
|
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
|
||||||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
|
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
|
||||||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
|
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
|
||||||
|
|||||||
886
src/shrpx.cc
886
src/shrpx.cc
File diff suppressed because it is too large
Load Diff
@@ -48,4 +48,11 @@
|
|||||||
inline int initgroups(const char *user, gid_t group) { return 0; }
|
inline int initgroups(const char *user, gid_t group) { return 0; }
|
||||||
#endif // defined(HAVE_DECL_INITGROUPS) && !HAVE_DECL_INITGROUPS
|
#endif // defined(HAVE_DECL_INITGROUPS) && !HAVE_DECL_INITGROUPS
|
||||||
|
|
||||||
|
#ifndef HAVE_BPF_STATS_TYPE
|
||||||
|
/* Newer kernel should have this defined in linux/bpf.h */
|
||||||
|
enum bpf_stats_type {
|
||||||
|
BPF_STATS_RUN_TIME = 0,
|
||||||
|
};
|
||||||
|
#endif // !HAVE_BPF_STATS_TYPE
|
||||||
|
|
||||||
#endif // SHRPX_H
|
#endif // SHRPX_H
|
||||||
|
|||||||
@@ -463,7 +463,7 @@ int APIDownstreamConnection::on_read() { return 0; }
|
|||||||
|
|
||||||
int APIDownstreamConnection::on_write() { return 0; }
|
int APIDownstreamConnection::on_write() { return 0; }
|
||||||
|
|
||||||
void APIDownstreamConnection::on_upstream_change(Upstream *uptream) {}
|
void APIDownstreamConnection::on_upstream_change(Upstream *upstream) {}
|
||||||
|
|
||||||
bool APIDownstreamConnection::poolable() const { return false; }
|
bool APIDownstreamConnection::poolable() const { return false; }
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public:
|
|||||||
virtual int on_read();
|
virtual int on_read();
|
||||||
virtual int on_write();
|
virtual int on_write();
|
||||||
|
|
||||||
virtual void on_upstream_change(Upstream *uptream);
|
virtual void on_upstream_change(Upstream *upstream);
|
||||||
|
|
||||||
// true if this object is poolable.
|
// true if this object is poolable.
|
||||||
virtual bool poolable() const;
|
virtual bool poolable() const;
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
#include "shrpx_connect_blocker.h"
|
#include "shrpx_connect_blocker.h"
|
||||||
#include "shrpx_api_downstream_connection.h"
|
#include "shrpx_api_downstream_connection.h"
|
||||||
#include "shrpx_health_monitor_downstream_connection.h"
|
#include "shrpx_health_monitor_downstream_connection.h"
|
||||||
|
#include "shrpx_null_downstream_connection.h"
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include "shrpx_http3_upstream.h"
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
#include "shrpx_log.h"
|
#include "shrpx_log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
@@ -285,6 +289,20 @@ int ClientHandler::write_tls() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
int ClientHandler::read_quic(const UpstreamAddr *faddr,
|
||||||
|
const Address &remote_addr,
|
||||||
|
const Address &local_addr,
|
||||||
|
const ngtcp2_pkt_info &pi, const uint8_t *data,
|
||||||
|
size_t datalen) {
|
||||||
|
auto upstream = static_cast<Http3Upstream *>(upstream_.get());
|
||||||
|
|
||||||
|
return upstream->on_read(faddr, remote_addr, local_addr, pi, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClientHandler::write_quic() { return upstream_->on_write(); }
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
int ClientHandler::upstream_noop() { return 0; }
|
int ClientHandler::upstream_noop() { return 0; }
|
||||||
|
|
||||||
int ClientHandler::upstream_read() {
|
int ClientHandler::upstream_read() {
|
||||||
@@ -401,7 +419,8 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|||||||
get_config()->conn.upstream.ratelimit.write,
|
get_config()->conn.upstream.ratelimit.write,
|
||||||
get_config()->conn.upstream.ratelimit.read, writecb, readcb,
|
get_config()->conn.upstream.ratelimit.read, writecb, readcb,
|
||||||
timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
|
timeoutcb, this, get_config()->tls.dyn_rec.warmup_threshold,
|
||||||
get_config()->tls.dyn_rec.idle_timeout, Proto::NONE),
|
get_config()->tls.dyn_rec.idle_timeout,
|
||||||
|
faddr->quic ? Proto::HTTP3 : Proto::NONE),
|
||||||
ipaddr_(make_string_ref(balloc_, ipaddr)),
|
ipaddr_(make_string_ref(balloc_, ipaddr)),
|
||||||
port_(make_string_ref(balloc_, port)),
|
port_(make_string_ref(balloc_, port)),
|
||||||
faddr_(faddr),
|
faddr_(faddr),
|
||||||
@@ -417,11 +436,14 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|||||||
|
|
||||||
reneg_shutdown_timer_.data = this;
|
reneg_shutdown_timer_.data = this;
|
||||||
|
|
||||||
|
if (!faddr->quic) {
|
||||||
conn_.rlimit.startw();
|
conn_.rlimit.startw();
|
||||||
|
}
|
||||||
ev_timer_again(conn_.loop, &conn_.rt);
|
ev_timer_again(conn_.loop, &conn_.rt);
|
||||||
|
|
||||||
auto config = get_config();
|
auto config = get_config();
|
||||||
|
|
||||||
|
if (!faddr->quic) {
|
||||||
if (faddr_->accept_proxy_protocol ||
|
if (faddr_->accept_proxy_protocol ||
|
||||||
config->conn.upstream.accept_proxy_protocol) {
|
config->conn.upstream.accept_proxy_protocol) {
|
||||||
read_ = &ClientHandler::read_clear;
|
read_ = &ClientHandler::read_clear;
|
||||||
@@ -431,6 +453,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|||||||
} else {
|
} else {
|
||||||
setup_upstream_io_callback();
|
setup_upstream_io_callback();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto &fwdconf = config->http.forwarded;
|
auto &fwdconf = config->http.forwarded;
|
||||||
|
|
||||||
@@ -491,6 +514,18 @@ void ClientHandler::setup_upstream_io_callback() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
void ClientHandler::setup_http3_upstream(
|
||||||
|
std::unique_ptr<Http3Upstream> &&upstream) {
|
||||||
|
upstream_ = std::move(upstream);
|
||||||
|
write_ = &ClientHandler::write_quic;
|
||||||
|
|
||||||
|
auto config = get_config();
|
||||||
|
|
||||||
|
reset_upstream_read_timeout(config->conn.upstream.timeout.http3_read);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
ClientHandler::~ClientHandler() {
|
ClientHandler::~ClientHandler() {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
CLOG(INFO, this) << "Deleting";
|
CLOG(INFO, this) << "Deleting";
|
||||||
@@ -511,7 +546,8 @@ ClientHandler::~ClientHandler() {
|
|||||||
|
|
||||||
// TODO If backend is http/2, and it is in CONNECTED state, signal
|
// TODO If backend is http/2, and it is in CONNECTED state, signal
|
||||||
// it and make it loopbreak when output is zero.
|
// it and make it loopbreak when output is zero.
|
||||||
if (worker_->get_graceful_shutdown() && worker_stat->num_connections == 0) {
|
if (worker_->get_graceful_shutdown() && worker_stat->num_connections == 0 &&
|
||||||
|
worker_stat->num_close_waits == 0) {
|
||||||
ev_break(conn_.loop);
|
ev_break(conn_.loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +884,6 @@ DownstreamAddr *ClientHandler::get_downstream_addr(int &err,
|
|||||||
err = -1;
|
err = -1;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
aff_idx = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
@@ -973,6 +1008,13 @@ ClientHandler::get_downstream_connection(int &err, Downstream *downstream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto &group = groups[group_idx];
|
auto &group = groups[group_idx];
|
||||||
|
|
||||||
|
if (group->shared_addr->dnf) {
|
||||||
|
auto dconn = std::make_unique<NullDownstreamConnection>(group);
|
||||||
|
dconn->set_client_handler(this);
|
||||||
|
return dconn;
|
||||||
|
}
|
||||||
|
|
||||||
auto addr = get_downstream_addr(err, group.get(), downstream);
|
auto addr = get_downstream_addr(err, group.get(), downstream);
|
||||||
if (addr == nullptr) {
|
if (addr == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -1556,4 +1598,13 @@ StringRef ClientHandler::get_alpn() const { return alpn_; }
|
|||||||
|
|
||||||
BlockAllocator &ClientHandler::get_block_allocator() { return balloc_; }
|
BlockAllocator &ClientHandler::get_block_allocator() { return balloc_; }
|
||||||
|
|
||||||
|
void ClientHandler::set_alpn_from_conn() {
|
||||||
|
const unsigned char *alpn;
|
||||||
|
unsigned int alpnlen;
|
||||||
|
|
||||||
|
SSL_get0_alpn_selected(conn_.tls.ssl, &alpn, &alpnlen);
|
||||||
|
|
||||||
|
alpn_ = make_string_ref(balloc_, StringRef{alpn, alpnlen});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ class Downstream;
|
|||||||
struct WorkerStat;
|
struct WorkerStat;
|
||||||
struct DownstreamAddrGroup;
|
struct DownstreamAddrGroup;
|
||||||
struct DownstreamAddr;
|
struct DownstreamAddr;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
class Http3Upstream;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
class ClientHandler {
|
class ClientHandler {
|
||||||
public:
|
public:
|
||||||
@@ -143,6 +146,14 @@ public:
|
|||||||
|
|
||||||
void setup_upstream_io_callback();
|
void setup_upstream_io_callback();
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
void setup_http3_upstream(std::unique_ptr<Http3Upstream> &&upstream);
|
||||||
|
int read_quic(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||||
|
const Address &local_addr, const ngtcp2_pkt_info &pi,
|
||||||
|
const uint8_t *data, size_t datalen);
|
||||||
|
int write_quic();
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
// Returns string suitable for use in "by" parameter of Forwarded
|
// Returns string suitable for use in "by" parameter of Forwarded
|
||||||
// header field.
|
// header field.
|
||||||
StringRef get_forwarded_by() const;
|
StringRef get_forwarded_by() const;
|
||||||
@@ -177,6 +188,8 @@ public:
|
|||||||
|
|
||||||
BlockAllocator &get_block_allocator();
|
BlockAllocator &get_block_allocator();
|
||||||
|
|
||||||
|
void set_alpn_from_conn();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Allocator to allocate memory for connection-wide objects. Make
|
// Allocator to allocate memory for connection-wide objects. Make
|
||||||
// sure that the allocations must be bounded, and not proportional
|
// sure that the allocations must be bounded, and not proportional
|
||||||
|
|||||||
@@ -230,10 +230,81 @@ read_tls_ticket_key_file(const std::vector<StringRef> &files,
|
|||||||
return ticket_keys;
|
return ticket_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
std::shared_ptr<QUICKeyingMaterials>
|
||||||
|
read_quic_secret_file(const StringRef &path) {
|
||||||
|
constexpr size_t expectedlen =
|
||||||
|
SHRPX_QUIC_SECRET_RESERVEDLEN + SHRPX_QUIC_SECRETLEN + SHRPX_QUIC_SALTLEN;
|
||||||
|
|
||||||
|
auto qkms = std::make_shared<QUICKeyingMaterials>();
|
||||||
|
auto &kms = qkms->keying_materials;
|
||||||
|
|
||||||
|
std::ifstream f(path.c_str());
|
||||||
|
if (!f) {
|
||||||
|
LOG(ERROR) << "frontend-quic-secret-file: could not open file " << path;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<char, 4096> buf;
|
||||||
|
|
||||||
|
while (f.getline(buf.data(), buf.size())) {
|
||||||
|
auto len = strlen(buf.data());
|
||||||
|
if (len == 0 || buf[0] == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = StringRef{std::begin(buf), std::begin(buf) + len};
|
||||||
|
if (s.size() != expectedlen * 2 || !util::is_hex_string(s)) {
|
||||||
|
LOG(ERROR) << "frontend-quic-secret-file: each line must be a "
|
||||||
|
<< expectedlen * 2 << " bytes hex encoded string";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
kms.emplace_back();
|
||||||
|
auto &qkm = kms.back();
|
||||||
|
|
||||||
|
auto p = std::begin(s);
|
||||||
|
|
||||||
|
util::decode_hex(std::begin(qkm.reserved),
|
||||||
|
StringRef{p, p + qkm.reserved.size()});
|
||||||
|
p += qkm.reserved.size() * 2;
|
||||||
|
util::decode_hex(std::begin(qkm.secret),
|
||||||
|
StringRef{p, p + qkm.secret.size()});
|
||||||
|
p += qkm.secret.size() * 2;
|
||||||
|
util::decode_hex(std::begin(qkm.salt), StringRef{p, p + qkm.salt.size()});
|
||||||
|
p += qkm.salt.size() * 2;
|
||||||
|
|
||||||
|
assert(static_cast<size_t>(p - std::begin(s)) == expectedlen * 2);
|
||||||
|
|
||||||
|
qkm.id = qkm.reserved[0] & 0xc0;
|
||||||
|
|
||||||
|
if (kms.size() == 4) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f.bad() || (!f.eof() && f.fail())) {
|
||||||
|
LOG(ERROR)
|
||||||
|
<< "frontend-quic-secret-file: error occurred while reading file "
|
||||||
|
<< path;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kms.empty()) {
|
||||||
|
LOG(WARN)
|
||||||
|
<< "frontend-quic-secret-file: no keying materials are present in file "
|
||||||
|
<< path;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return qkms;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
FILE *open_file_for_write(const char *filename) {
|
FILE *open_file_for_write(const char *filename) {
|
||||||
std::array<char, STRERROR_BUFSIZE> errbuf;
|
std::array<char, STRERROR_BUFSIZE> errbuf;
|
||||||
|
|
||||||
#if defined O_CLOEXEC
|
#ifdef O_CLOEXEC
|
||||||
auto fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC,
|
auto fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC,
|
||||||
S_IRUSR | S_IWUSR);
|
S_IRUSR | S_IWUSR);
|
||||||
#else
|
#else
|
||||||
@@ -372,6 +443,57 @@ int parse_int(T *dest, const StringRef &opt, const char *optarg) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int parse_altsvc(AltSvc &altsvc, const StringRef &opt,
|
||||||
|
const StringRef &optarg) {
|
||||||
|
// PROTOID, PORT, HOST, ORIGIN, PARAMS.
|
||||||
|
auto tokens = util::split_str(optarg, ',', 5);
|
||||||
|
|
||||||
|
if (tokens.size() < 2) {
|
||||||
|
// Requires at least protocol_id and port
|
||||||
|
LOG(ERROR) << opt << ": too few parameters: " << optarg;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int port;
|
||||||
|
|
||||||
|
if (parse_uint(&port, opt, tokens[1]) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port < 1 ||
|
||||||
|
port > static_cast<int>(std::numeric_limits<uint16_t>::max())) {
|
||||||
|
LOG(ERROR) << opt << ": port is invalid: " << tokens[1];
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
altsvc.protocol_id = make_string_ref(config->balloc, tokens[0]);
|
||||||
|
|
||||||
|
altsvc.port = port;
|
||||||
|
altsvc.service = make_string_ref(config->balloc, tokens[1]);
|
||||||
|
|
||||||
|
if (tokens.size() > 2) {
|
||||||
|
if (!tokens[2].empty()) {
|
||||||
|
altsvc.host = make_string_ref(config->balloc, tokens[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens.size() > 3) {
|
||||||
|
if (!tokens[3].empty()) {
|
||||||
|
altsvc.origin = make_string_ref(config->balloc, tokens[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokens.size() > 4) {
|
||||||
|
if (!tokens[4].empty()) {
|
||||||
|
altsvc.params = make_string_ref(config->balloc, tokens[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// generated by gennghttpxfun.py
|
// generated by gennghttpxfun.py
|
||||||
LogFragmentType log_var_lookup_token(const char *name, size_t namelen) {
|
LogFragmentType log_var_lookup_token(const char *name, size_t namelen) {
|
||||||
@@ -785,6 +907,7 @@ struct UpstreamParams {
|
|||||||
bool tls;
|
bool tls;
|
||||||
bool sni_fwd;
|
bool sni_fwd;
|
||||||
bool proxyproto;
|
bool proxyproto;
|
||||||
|
bool quic;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -819,6 +942,13 @@ int parse_upstream_params(UpstreamParams &out, const StringRef &src_params) {
|
|||||||
out.alt_mode = UpstreamAltMode::HEALTHMON;
|
out.alt_mode = UpstreamAltMode::HEALTHMON;
|
||||||
} else if (util::strieq_l("proxyproto", param)) {
|
} else if (util::strieq_l("proxyproto", param)) {
|
||||||
out.proxyproto = true;
|
out.proxyproto = true;
|
||||||
|
} else if (util::strieq_l("quic", param)) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
out.quic = true;
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
LOG(ERROR) << "quic: QUIC is disabled at compile time";
|
||||||
|
return -1;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
} else if (!param.empty()) {
|
} else if (!param.empty()) {
|
||||||
LOG(ERROR) << "frontend: " << param << ": unknown keyword";
|
LOG(ERROR) << "frontend: " << param << ": unknown keyword";
|
||||||
return -1;
|
return -1;
|
||||||
@@ -851,6 +981,7 @@ struct DownstreamParams {
|
|||||||
bool dns;
|
bool dns;
|
||||||
bool redirect_if_not_tls;
|
bool redirect_if_not_tls;
|
||||||
bool upgrade_scheme;
|
bool upgrade_scheme;
|
||||||
|
bool dnf;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1025,6 +1156,8 @@ int parse_downstream_params(DownstreamParams &out,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
out.group_weight = n;
|
out.group_weight = n;
|
||||||
|
} else if (util::strieq_l("dnf", param)) {
|
||||||
|
out.dnf = true;
|
||||||
} else if (!param.empty()) {
|
} else if (!param.empty()) {
|
||||||
LOG(ERROR) << "backend: " << param << ": unknown keyword";
|
LOG(ERROR) << "backend: " << param << ": unknown keyword";
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1089,6 +1222,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
|
|||||||
addr.sni = make_string_ref(downstreamconf.balloc, params.sni);
|
addr.sni = make_string_ref(downstreamconf.balloc, params.sni);
|
||||||
addr.dns = params.dns;
|
addr.dns = params.dns;
|
||||||
addr.upgrade_scheme = params.upgrade_scheme;
|
addr.upgrade_scheme = params.upgrade_scheme;
|
||||||
|
addr.dnf = params.dnf;
|
||||||
|
|
||||||
auto &routerconf = downstreamconf.router;
|
auto &routerconf = downstreamconf.router;
|
||||||
auto &router = routerconf.router;
|
auto &router = routerconf.router;
|
||||||
@@ -1189,6 +1323,14 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// All backends in the same group must have the same dnf
|
||||||
|
// setting. If some backends do not specify dnf, and there is
|
||||||
|
// at least one backend with dnf, it is used for all backends in
|
||||||
|
// the group. In general, multiple backends are not necessary
|
||||||
|
// for dnf because there is no need for load balancing.
|
||||||
|
if (params.dnf) {
|
||||||
|
g.dnf = true;
|
||||||
|
}
|
||||||
|
|
||||||
g.addrs.push_back(addr);
|
g.addrs.push_back(addr);
|
||||||
continue;
|
continue;
|
||||||
@@ -1213,6 +1355,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
|
|||||||
g.mruby_file = make_string_ref(downstreamconf.balloc, params.mruby);
|
g.mruby_file = make_string_ref(downstreamconf.balloc, params.mruby);
|
||||||
g.timeout.read = params.read_timeout;
|
g.timeout.read = params.read_timeout;
|
||||||
g.timeout.write = params.write_timeout;
|
g.timeout.write = params.write_timeout;
|
||||||
|
g.dnf = params.dnf;
|
||||||
|
|
||||||
if (pattern[0] == '*') {
|
if (pattern[0] == '*') {
|
||||||
// wildcard pattern
|
// wildcard pattern
|
||||||
@@ -1795,6 +1938,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_SERVER_NAME;
|
return SHRPX_OPTID_SERVER_NAME;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (util::strieq_l("no-quic-bp", name, 10)) {
|
||||||
|
return SHRPX_OPTID_NO_QUIC_BPF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("tls-sct-di", name, 10)) {
|
if (util::strieq_l("tls-sct-di", name, 10)) {
|
||||||
return SHRPX_OPTID_TLS_SCT_DIR;
|
return SHRPX_OPTID_TLS_SCT_DIR;
|
||||||
@@ -1838,6 +1986,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_BACKEND_IPV6;
|
return SHRPX_OPTID_BACKEND_IPV6;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'c':
|
||||||
|
if (util::strieq_l("http2-altsv", name, 11)) {
|
||||||
|
return SHRPX_OPTID_HTTP2_ALTSVC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (util::strieq_l("host-rewrit", name, 11)) {
|
if (util::strieq_l("host-rewrit", name, 11)) {
|
||||||
return SHRPX_OPTID_HOST_REWRITE;
|
return SHRPX_OPTID_HOST_REWRITE;
|
||||||
@@ -1901,6 +2054,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
switch (name[13]) {
|
switch (name[13]) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq_l("quic-server-i", name, 13)) {
|
||||||
|
return SHRPX_OPTID_QUIC_SERVER_ID;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (util::strieq_l("accesslog-fil", name, 13)) {
|
if (util::strieq_l("accesslog-fil", name, 13)) {
|
||||||
return SHRPX_OPTID_ACCESSLOG_FILE;
|
return SHRPX_OPTID_ACCESSLOG_FILE;
|
||||||
@@ -1911,6 +2069,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_NO_SERVER_PUSH;
|
return SHRPX_OPTID_NO_SERVER_PUSH;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
if (util::strieq_l("rlimit-memloc", name, 13)) {
|
||||||
|
return SHRPX_OPTID_RLIMIT_MEMLOCK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if (util::strieq_l("no-verify-ocs", name, 13)) {
|
if (util::strieq_l("no-verify-ocs", name, 13)) {
|
||||||
return SHRPX_OPTID_NO_VERIFY_OCSP;
|
return SHRPX_OPTID_NO_VERIFY_OCSP;
|
||||||
@@ -2090,6 +2253,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
|
if (util::strieq_l("max-worker-processe", name, 19)) {
|
||||||
|
return SHRPX_OPTID_MAX_WORKER_PROCESSES;
|
||||||
|
}
|
||||||
if (util::strieq_l("tls13-client-cipher", name, 19)) {
|
if (util::strieq_l("tls13-client-cipher", name, 19)) {
|
||||||
return SHRPX_OPTID_TLS13_CLIENT_CIPHERS;
|
return SHRPX_OPTID_TLS13_CLIENT_CIPHERS;
|
||||||
}
|
}
|
||||||
@@ -2119,6 +2285,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_BACKEND_TLS_SNI_FIELD;
|
return SHRPX_OPTID_BACKEND_TLS_SNI_FIELD;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq_l("quic-bpf-program-fil", name, 20)) {
|
||||||
|
return SHRPX_OPTID_QUIC_BPF_PROGRAM_FILE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
if (util::strieq_l("accept-proxy-protoco", name, 20)) {
|
if (util::strieq_l("accept-proxy-protoco", name, 20)) {
|
||||||
return SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL;
|
return SHRPX_OPTID_ACCEPT_PROXY_PROTOCOL;
|
||||||
@@ -2168,6 +2339,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("backend-request-buffe", name, 21)) {
|
if (util::strieq_l("backend-request-buffe", name, 21)) {
|
||||||
return SHRPX_OPTID_BACKEND_REQUEST_BUFFER;
|
return SHRPX_OPTID_BACKEND_REQUEST_BUFFER;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-quic-qlog-di", name, 21)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_QLOG_DIR;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (util::strieq_l("frontend-write-timeou", name, 21)) {
|
if (util::strieq_l("frontend-write-timeou", name, 21)) {
|
||||||
@@ -2191,6 +2365,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE;
|
return SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'g':
|
||||||
|
if (util::strieq_l("frontend-quic-debug-lo", name, 22)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_DEBUG_LOG;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("backend-response-buffe", name, 22)) {
|
if (util::strieq_l("backend-response-buffe", name, 22)) {
|
||||||
return SHRPX_OPTID_BACKEND_RESPONSE_BUFFER;
|
return SHRPX_OPTID_BACKEND_RESPONSE_BUFFER;
|
||||||
@@ -2205,6 +2384,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
switch (name[23]) {
|
switch (name[23]) {
|
||||||
|
case 'a':
|
||||||
|
if (util::strieq_l("frontend-quic-early-dat", name, 23)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (util::strieq_l("strip-incoming-forwarde", name, 23)) {
|
if (util::strieq_l("strip-incoming-forwarde", name, 23)) {
|
||||||
return SHRPX_OPTID_STRIP_INCOMING_FORWARDED;
|
return SHRPX_OPTID_STRIP_INCOMING_FORWARDED;
|
||||||
@@ -2239,6 +2423,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("backend-http2-window-siz", name, 24)) {
|
if (util::strieq_l("backend-http2-window-siz", name, 24)) {
|
||||||
return SHRPX_OPTID_BACKEND_HTTP2_WINDOW_SIZE;
|
return SHRPX_OPTID_BACKEND_HTTP2_WINDOW_SIZE;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-quic-secret-fil", name, 24)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_SECRET_FILE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
if (util::strieq_l("http2-no-cookie-crumblin", name, 24)) {
|
if (util::strieq_l("http2-no-cookie-crumblin", name, 24)) {
|
||||||
@@ -2253,6 +2440,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS;
|
return SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (util::strieq_l("frontend-quic-initial-rt", name, 24)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_INITIAL_RTT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 26:
|
case 26:
|
||||||
@@ -2266,6 +2458,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("frontend-http2-window-siz", name, 25)) {
|
if (util::strieq_l("frontend-http2-window-siz", name, 25)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE;
|
return SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-http3-window-siz", name, 25)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (util::strieq_l("frontend-http2-window-bit", name, 25)) {
|
if (util::strieq_l("frontend-http2-window-bit", name, 25)) {
|
||||||
@@ -2279,6 +2474,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("backend-keep-alive-timeou", name, 25)) {
|
if (util::strieq_l("backend-keep-alive-timeou", name, 25)) {
|
||||||
return SHRPX_OPTID_BACKEND_KEEP_ALIVE_TIMEOUT;
|
return SHRPX_OPTID_BACKEND_KEEP_ALIVE_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-quic-idle-timeou", name, 25)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT;
|
||||||
|
}
|
||||||
if (util::strieq_l("no-http2-cipher-black-lis", name, 25)) {
|
if (util::strieq_l("no-http2-cipher-black-lis", name, 25)) {
|
||||||
return SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST;
|
return SHRPX_OPTID_NO_HTTP2_CIPHER_BLACK_LIST;
|
||||||
}
|
}
|
||||||
@@ -2295,6 +2493,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
|
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (util::strieq_l("frontend-quic-require-toke", name, 26)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_REQUIRE_TOKEN;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("request-header-field-buffe", name, 26)) {
|
if (util::strieq_l("request-header-field-buffe", name, 26)) {
|
||||||
return SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER;
|
return SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER;
|
||||||
@@ -2309,6 +2512,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("frontend-http2-read-timeou", name, 26)) {
|
if (util::strieq_l("frontend-http2-read-timeou", name, 26)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_READ_TIMEOUT;
|
return SHRPX_OPTID_FRONTEND_HTTP2_READ_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-http3-read-timeou", name, 26)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_READ_TIMEOUT;
|
||||||
|
}
|
||||||
if (util::strieq_l("frontend-keep-alive-timeou", name, 26)) {
|
if (util::strieq_l("frontend-keep-alive-timeou", name, 26)) {
|
||||||
return SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT;
|
return SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT;
|
||||||
}
|
}
|
||||||
@@ -2354,6 +2560,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
return SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED;
|
return SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
if (util::strieq_l("frontend-http3-max-window-siz", name, 29)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
if (util::strieq_l("ignore-per-pattern-mruby-erro", name, 29)) {
|
if (util::strieq_l("ignore-per-pattern-mruby-erro", name, 29)) {
|
||||||
return SHRPX_OPTID_IGNORE_PER_PATTERN_MRUBY_ERROR;
|
return SHRPX_OPTID_IGNORE_PER_PATTERN_MRUBY_ERROR;
|
||||||
@@ -2452,11 +2663,19 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
if (util::strieq_l("frontend-http2-dump-response-heade", name, 34)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-quic-congestion-controlle", name, 34)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_QUIC_CONGESTION_CONTROLLER;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 36:
|
case 36:
|
||||||
switch (name[35]) {
|
switch (name[35]) {
|
||||||
|
case 'd':
|
||||||
|
if (util::strieq_l("worker-process-grace-shutdown-perio", name, 35)) {
|
||||||
|
return SHRPX_OPTID_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (util::strieq_l("backend-http2-connection-window-siz", name, 35)) {
|
if (util::strieq_l("backend-http2-connection-window-siz", name, 35)) {
|
||||||
return SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE;
|
return SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE;
|
||||||
@@ -2483,6 +2702,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("frontend-http2-connection-window-siz", name, 36)) {
|
if (util::strieq_l("frontend-http2-connection-window-siz", name, 36)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE;
|
return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-http3-connection-window-siz", name, 36)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE;
|
||||||
|
}
|
||||||
if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) {
|
if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) {
|
||||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE;
|
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE;
|
||||||
}
|
}
|
||||||
@@ -2494,6 +2716,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
if (util::strieq_l("frontend-http2-max-concurrent-stream", name, 36)) {
|
if (util::strieq_l("frontend-http2-max-concurrent-stream", name, 36)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS;
|
return SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-http3-max-concurrent-stream", name, 36)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2542,6 +2767,10 @@ int option_lookup_token(const char *name, size_t namelen) {
|
|||||||
40)) {
|
40)) {
|
||||||
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE;
|
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("frontend-http3-max-connection-window-siz", name,
|
||||||
|
40)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE;
|
||||||
|
}
|
||||||
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
|
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
|
||||||
40)) {
|
40)) {
|
||||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
|
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
|
||||||
@@ -2624,7 +2853,6 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SHRPX_OPTID_FRONTEND: {
|
case SHRPX_OPTID_FRONTEND: {
|
||||||
auto &listenerconf = config->conn.listener;
|
|
||||||
auto &apiconf = config->api;
|
auto &apiconf = config->api;
|
||||||
|
|
||||||
auto addr_end = std::find(std::begin(optarg), std::end(optarg), ';');
|
auto addr_end = std::find(std::begin(optarg), std::end(optarg), ';');
|
||||||
@@ -2642,23 +2870,49 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.quic) {
|
||||||
|
if (params.alt_mode != UpstreamAltMode::NONE) {
|
||||||
|
LOG(ERROR) << "frontend: api or healthmon cannot be used with quic";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.tls) {
|
||||||
|
LOG(ERROR) << "frontend: quic requires TLS";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpstreamAddr addr{};
|
UpstreamAddr addr{};
|
||||||
addr.fd = -1;
|
addr.fd = -1;
|
||||||
addr.tls = params.tls;
|
addr.tls = params.tls;
|
||||||
addr.sni_fwd = params.sni_fwd;
|
addr.sni_fwd = params.sni_fwd;
|
||||||
addr.alt_mode = params.alt_mode;
|
addr.alt_mode = params.alt_mode;
|
||||||
addr.accept_proxy_protocol = params.proxyproto;
|
addr.accept_proxy_protocol = params.proxyproto;
|
||||||
|
addr.quic = params.quic;
|
||||||
|
|
||||||
if (addr.alt_mode == UpstreamAltMode::API) {
|
if (addr.alt_mode == UpstreamAltMode::API) {
|
||||||
apiconf.enabled = true;
|
apiconf.enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
auto &addrs = params.quic ? config->conn.quic_listener.addrs
|
||||||
|
: config->conn.listener.addrs;
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
auto &addrs = config->conn.listener.addrs;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
|
|
||||||
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
||||||
|
if (addr.quic) {
|
||||||
|
LOG(ERROR) << "frontend: quic cannot be used on UNIX domain socket";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size();
|
auto path = std::begin(optarg) + SHRPX_UNIX_PATH_PREFIX.size();
|
||||||
addr.host = make_string_ref(config->balloc, StringRef{path, addr_end});
|
addr.host = make_string_ref(config->balloc, StringRef{path, addr_end});
|
||||||
addr.host_unix = true;
|
addr.host_unix = true;
|
||||||
|
addr.index = addrs.size();
|
||||||
|
|
||||||
listenerconf.addrs.push_back(std::move(addr));
|
addrs.push_back(std::move(addr));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2673,21 +2927,25 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
|
|
||||||
if (util::numeric_host(host, AF_INET)) {
|
if (util::numeric_host(host, AF_INET)) {
|
||||||
addr.family = AF_INET;
|
addr.family = AF_INET;
|
||||||
listenerconf.addrs.push_back(std::move(addr));
|
addr.index = addrs.size();
|
||||||
|
addrs.push_back(std::move(addr));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util::numeric_host(host, AF_INET6)) {
|
if (util::numeric_host(host, AF_INET6)) {
|
||||||
addr.family = AF_INET6;
|
addr.family = AF_INET6;
|
||||||
listenerconf.addrs.push_back(std::move(addr));
|
addr.index = addrs.size();
|
||||||
|
addrs.push_back(std::move(addr));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.family = AF_INET;
|
addr.family = AF_INET;
|
||||||
listenerconf.addrs.push_back(addr);
|
addr.index = addrs.size();
|
||||||
|
addrs.push_back(addr);
|
||||||
|
|
||||||
addr.family = AF_INET6;
|
addr.family = AF_INET6;
|
||||||
listenerconf.addrs.push_back(std::move(addr));
|
addr.index = addrs.size();
|
||||||
|
addrs.push_back(std::move(addr));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3136,45 +3394,10 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
case SHRPX_OPTID_PADDING:
|
case SHRPX_OPTID_PADDING:
|
||||||
return parse_uint(&config->padding, opt, optarg);
|
return parse_uint(&config->padding, opt, optarg);
|
||||||
case SHRPX_OPTID_ALTSVC: {
|
case SHRPX_OPTID_ALTSVC: {
|
||||||
auto tokens = util::split_str(optarg, ',');
|
|
||||||
|
|
||||||
if (tokens.size() < 2) {
|
|
||||||
// Requires at least protocol_id and port
|
|
||||||
LOG(ERROR) << opt << ": too few parameters: " << optarg;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens.size() > 4) {
|
|
||||||
// We only need protocol_id, port, host and origin
|
|
||||||
LOG(ERROR) << opt << ": too many parameters: " << optarg;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int port;
|
|
||||||
|
|
||||||
if (parse_uint(&port, opt, tokens[1]) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port < 1 ||
|
|
||||||
port > static_cast<int>(std::numeric_limits<uint16_t>::max())) {
|
|
||||||
LOG(ERROR) << opt << ": port is invalid: " << tokens[1];
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AltSvc altsvc{};
|
AltSvc altsvc{};
|
||||||
|
|
||||||
altsvc.protocol_id = make_string_ref(config->balloc, tokens[0]);
|
if (parse_altsvc(altsvc, opt, optarg) != 0) {
|
||||||
|
return -1;
|
||||||
altsvc.port = port;
|
|
||||||
altsvc.service = make_string_ref(config->balloc, tokens[1]);
|
|
||||||
|
|
||||||
if (tokens.size() > 2) {
|
|
||||||
altsvc.host = make_string_ref(config->balloc, tokens[2]);
|
|
||||||
|
|
||||||
if (tokens.size() > 3) {
|
|
||||||
altsvc.origin = make_string_ref(config->balloc, tokens[3]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config->http.altsvcs.push_back(std::move(altsvc));
|
config->http.altsvcs.push_back(std::move(altsvc));
|
||||||
@@ -3731,7 +3954,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
"65535], inclusive";
|
"65535], inclusive";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
config->http.redirect_https_port = optarg;
|
config->http.redirect_https_port = make_string_ref(config->balloc, optarg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SHRPX_OPTID_FRONTEND_MAX_REQUESTS:
|
case SHRPX_OPTID_FRONTEND_MAX_REQUESTS:
|
||||||
@@ -3779,6 +4002,168 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
|||||||
config->http.early_data.strip_incoming = !util::strieq_l("yes", optarg);
|
config->http.early_data.strip_incoming = !util::strieq_l("yes", optarg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
case SHRPX_OPTID_QUIC_BPF_PROGRAM_FILE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.bpf.prog_file = make_string_ref(config->balloc, optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_NO_QUIC_BPF:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.bpf.disabled = util::strieq_l("yes", optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_HTTP2_ALTSVC: {
|
||||||
|
AltSvc altsvc{};
|
||||||
|
|
||||||
|
if (parse_altsvc(altsvc, opt, optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->http.http2_altsvcs.push_back(std::move(altsvc));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_READ_TIMEOUT:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
return parse_duration(&config->conn.upstream.timeout.http3_read, opt,
|
||||||
|
optarg);
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
return 0;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
return parse_duration(&config->quic.upstream.timeout.idle, opt, optarg);
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
return 0;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_DEBUG_LOG:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.upstream.debug.log = util::strieq_l("yes", optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (parse_uint_with_unit(&config->http3.upstream.window_size, opt,
|
||||||
|
optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (parse_uint_with_unit(&config->http3.upstream.connection_window_size,
|
||||||
|
opt, optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (parse_uint_with_unit(&config->http3.upstream.max_window_size, opt,
|
||||||
|
optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (parse_uint_with_unit(&config->http3.upstream.max_connection_window_size,
|
||||||
|
opt, optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
return parse_uint(&config->http3.upstream.max_concurrent_streams, opt,
|
||||||
|
optarg);
|
||||||
|
#else // !ENABLE_HTTP3
|
||||||
|
return 0;
|
||||||
|
#endif // !ENABLE_HTTP3
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.upstream.early_data = util::strieq_l("yes", optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_QLOG_DIR:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.upstream.qlog.dir = make_string_ref(config->balloc, optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_REQUIRE_TOKEN:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.upstream.require_token = util::strieq_l("yes", optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_CONGESTION_CONTROLLER:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (util::strieq_l("cubic", optarg)) {
|
||||||
|
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 {
|
||||||
|
LOG(ERROR) << opt << ": must be either cubic or bbr";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_QUIC_SERVER_ID:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (optarg.size() != config->quic.server_id.size() * 2 ||
|
||||||
|
!util::is_hex_string(optarg)) {
|
||||||
|
LOG(ERROR) << opt << ": must be a hex-string";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
util::decode_hex(std::begin(config->quic.server_id), optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_SECRET_FILE:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
config->quic.upstream.secret_file = make_string_ref(config->balloc, optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case SHRPX_OPTID_RLIMIT_MEMLOCK: {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (parse_uint(&n, opt, optarg) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
LOG(ERROR) << opt << ": specify the integer more than or equal to 0";
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->rlimit_memlock = n;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case SHRPX_OPTID_MAX_WORKER_PROCESSES:
|
||||||
|
return parse_uint(&config->max_worker_processes, opt, optarg);
|
||||||
|
case SHRPX_OPTID_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD:
|
||||||
|
return parse_duration(&config->worker_process_grace_shutdown_period, opt,
|
||||||
|
optarg);
|
||||||
|
case SHRPX_OPTID_FRONTEND_QUIC_INITIAL_RTT: {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
return parse_duration(&config->quic.upstream.initial_rtt, opt, optarg);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
||||||
@@ -3967,6 +4352,8 @@ StringRef strproto(Proto proto) {
|
|||||||
return StringRef::from_lit("http/1.1");
|
return StringRef::from_lit("http/1.1");
|
||||||
case Proto::HTTP2:
|
case Proto::HTTP2:
|
||||||
return StringRef::from_lit("h2");
|
return StringRef::from_lit("h2");
|
||||||
|
case Proto::HTTP3:
|
||||||
|
return StringRef::from_lit("h3");
|
||||||
case Proto::MEMCACHED:
|
case Proto::MEMCACHED:
|
||||||
return StringRef::from_lit("memcached");
|
return StringRef::from_lit("memcached");
|
||||||
}
|
}
|
||||||
@@ -4076,7 +4463,7 @@ int configure_downstream_group(Config *config, bool http2_proxy,
|
|||||||
if (!g.mruby_file.empty()) {
|
if (!g.mruby_file.empty()) {
|
||||||
if (mruby::create_mruby_context(g.mruby_file) == nullptr) {
|
if (mruby::create_mruby_context(g.mruby_file) == nullptr) {
|
||||||
LOG(config->ignore_per_pattern_mruby_error ? ERROR : FATAL)
|
LOG(config->ignore_per_pattern_mruby_error ? ERROR : FATAL)
|
||||||
<< "backend: Could not compile mruby flie for pattern "
|
<< "backend: Could not compile mruby file for pattern "
|
||||||
<< g.pattern;
|
<< g.pattern;
|
||||||
if (!config->ignore_per_pattern_mruby_error) {
|
if (!config->ignore_per_pattern_mruby_error) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -4111,6 +4498,8 @@ int configure_downstream_group(Config *config, bool http2_proxy,
|
|||||||
|
|
||||||
auto resolve_flags = numeric_addr_only ? AI_NUMERICHOST | AI_NUMERICSERV : 0;
|
auto resolve_flags = numeric_addr_only ? AI_NUMERICHOST | AI_NUMERICSERV : 0;
|
||||||
|
|
||||||
|
std::array<char, util::max_hostport> hostport_buf;
|
||||||
|
|
||||||
for (auto &g : addr_groups) {
|
for (auto &g : addr_groups) {
|
||||||
std::unordered_map<StringRef, uint32_t> wgchk;
|
std::unordered_map<StringRef, uint32_t> wgchk;
|
||||||
for (auto &addr : g.addrs) {
|
for (auto &addr : g.addrs) {
|
||||||
@@ -4156,7 +4545,7 @@ int configure_downstream_group(Config *config, bool http2_proxy,
|
|||||||
util::make_http_hostport(downstreamconf.balloc, addr.host, addr.port);
|
util::make_http_hostport(downstreamconf.balloc, addr.host, addr.port);
|
||||||
|
|
||||||
auto hostport =
|
auto hostport =
|
||||||
util::make_hostport(downstreamconf.balloc, addr.host, addr.port);
|
util::make_hostport(std::begin(hostport_buf), addr.host, addr.port);
|
||||||
|
|
||||||
if (!addr.dns) {
|
if (!addr.dns) {
|
||||||
if (resolve_hostname(&addr.addr, addr.host.c_str(), addr.port,
|
if (resolve_hostname(&addr.addr, addr.host.c_str(), addr.port,
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
#include "shrpx_router.h"
|
#include "shrpx_router.h"
|
||||||
|
#if ENABLE_HTTP3
|
||||||
|
# include "shrpx_quic.h"
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
#include "http2.h"
|
#include "http2.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
@@ -360,6 +363,44 @@ constexpr auto SHRPX_OPT_TLS13_CLIENT_CIPHERS =
|
|||||||
StringRef::from_lit("tls13-client-ciphers");
|
StringRef::from_lit("tls13-client-ciphers");
|
||||||
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA =
|
constexpr auto SHRPX_OPT_NO_STRIP_INCOMING_EARLY_DATA =
|
||||||
StringRef::from_lit("no-strip-incoming-early-data");
|
StringRef::from_lit("no-strip-incoming-early-data");
|
||||||
|
constexpr auto SHRPX_OPT_QUIC_BPF_PROGRAM_FILE =
|
||||||
|
StringRef::from_lit("quic-bpf-program-file");
|
||||||
|
constexpr auto SHRPX_OPT_NO_QUIC_BPF = StringRef::from_lit("no-quic-bpf");
|
||||||
|
constexpr auto SHRPX_OPT_HTTP2_ALTSVC = StringRef::from_lit("http2-altsvc");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_READ_TIMEOUT =
|
||||||
|
StringRef::from_lit("frontend-http3-read-timeout");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_IDLE_TIMEOUT =
|
||||||
|
StringRef::from_lit("frontend-quic-idle-timeout");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_DEBUG_LOG =
|
||||||
|
StringRef::from_lit("frontend-quic-debug-log");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_WINDOW_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http3-window-size");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http3-connection-window-size");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_WINDOW_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http3-max-window-size");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE =
|
||||||
|
StringRef::from_lit("frontend-http3-max-connection-window-size");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS =
|
||||||
|
StringRef::from_lit("frontend-http3-max-concurrent-streams");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_EARLY_DATA =
|
||||||
|
StringRef::from_lit("frontend-quic-early-data");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_QLOG_DIR =
|
||||||
|
StringRef::from_lit("frontend-quic-qlog-dir");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_REQUIRE_TOKEN =
|
||||||
|
StringRef::from_lit("frontend-quic-require-token");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_CONGESTION_CONTROLLER =
|
||||||
|
StringRef::from_lit("frontend-quic-congestion-controller");
|
||||||
|
constexpr auto SHRPX_OPT_QUIC_SERVER_ID = StringRef::from_lit("quic-server-id");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_SECRET_FILE =
|
||||||
|
StringRef::from_lit("frontend-quic-secret-file");
|
||||||
|
constexpr auto SHRPX_OPT_RLIMIT_MEMLOCK = StringRef::from_lit("rlimit-memlock");
|
||||||
|
constexpr auto SHRPX_OPT_MAX_WORKER_PROCESSES =
|
||||||
|
StringRef::from_lit("max-worker-processes");
|
||||||
|
constexpr auto SHRPX_OPT_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD =
|
||||||
|
StringRef::from_lit("worker-process-grace-shutdown-period");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_QUIC_INITIAL_RTT =
|
||||||
|
StringRef::from_lit("frontend-quic-initial-rtt");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
@@ -370,6 +411,7 @@ enum class Proto {
|
|||||||
NONE,
|
NONE,
|
||||||
HTTP1,
|
HTTP1,
|
||||||
HTTP2,
|
HTTP2,
|
||||||
|
HTTP3,
|
||||||
MEMCACHED,
|
MEMCACHED,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -419,7 +461,7 @@ enum class ForwardedNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AltSvc {
|
struct AltSvc {
|
||||||
StringRef protocol_id, host, origin, service;
|
StringRef protocol_id, host, origin, service, params;
|
||||||
|
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
};
|
};
|
||||||
@@ -434,6 +476,8 @@ enum class UpstreamAltMode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct UpstreamAddr {
|
struct UpstreamAddr {
|
||||||
|
// The unique index of this address.
|
||||||
|
size_t index;
|
||||||
// The frontend address (e.g., FQDN, hostname, IP address). If
|
// The frontend address (e.g., FQDN, hostname, IP address). If
|
||||||
// |host_unix| is true, this is UNIX domain socket path. This must
|
// |host_unix| is true, this is UNIX domain socket path. This must
|
||||||
// be NULL terminated string.
|
// be NULL terminated string.
|
||||||
@@ -458,6 +502,7 @@ struct UpstreamAddr {
|
|||||||
bool sni_fwd;
|
bool sni_fwd;
|
||||||
// true if client is supposed to send PROXY protocol v1 header.
|
// true if client is supposed to send PROXY protocol v1 header.
|
||||||
bool accept_proxy_protocol;
|
bool accept_proxy_protocol;
|
||||||
|
bool quic;
|
||||||
int fd;
|
int fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -494,6 +539,8 @@ struct DownstreamAddrConfig {
|
|||||||
// variant (e.g., "https") when forwarding request to a backend
|
// variant (e.g., "https") when forwarding request to a backend
|
||||||
// connected by TLS connection.
|
// connected by TLS connection.
|
||||||
bool upgrade_scheme;
|
bool upgrade_scheme;
|
||||||
|
// true if a request should not be forwarded to a backend.
|
||||||
|
bool dnf;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mapping hash to idx which is an index into
|
// Mapping hash to idx which is an index into
|
||||||
@@ -510,6 +557,7 @@ struct DownstreamAddrGroupConfig {
|
|||||||
: pattern(pattern),
|
: pattern(pattern),
|
||||||
affinity{SessionAffinity::NONE},
|
affinity{SessionAffinity::NONE},
|
||||||
redirect_if_not_tls(false),
|
redirect_if_not_tls(false),
|
||||||
|
dnf{false},
|
||||||
timeout{} {}
|
timeout{} {}
|
||||||
|
|
||||||
StringRef pattern;
|
StringRef pattern;
|
||||||
@@ -523,6 +571,8 @@ struct DownstreamAddrGroupConfig {
|
|||||||
// true if this group requires that client connection must be TLS,
|
// true if this group requires that client connection must be TLS,
|
||||||
// and the request must be redirected to https URI.
|
// and the request must be redirected to https URI.
|
||||||
bool redirect_if_not_tls;
|
bool redirect_if_not_tls;
|
||||||
|
// true if a request should not be forwarded to a backend.
|
||||||
|
bool dnf;
|
||||||
// Timeouts for backend connection.
|
// Timeouts for backend connection.
|
||||||
struct {
|
struct {
|
||||||
ev_tstamp read;
|
ev_tstamp read;
|
||||||
@@ -561,6 +611,22 @@ struct TLSCertificate {
|
|||||||
std::vector<uint8_t> sct_data;
|
std::vector<uint8_t> sct_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
struct QUICKeyingMaterial {
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_SECRET_RESERVEDLEN> reserved;
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_SECRETLEN> secret;
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_SALTLEN> salt;
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_CID_ENCRYPTION_KEYLEN> cid_encryption_key;
|
||||||
|
// Identifier of this keying material. Only the first 2 bits are
|
||||||
|
// used.
|
||||||
|
uint8_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QUICKeyingMaterials {
|
||||||
|
std::vector<QUICKeyingMaterial> keying_materials;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
struct HttpProxy {
|
struct HttpProxy {
|
||||||
Address addr;
|
Address addr;
|
||||||
// host in http proxy URI
|
// host in http proxy URI
|
||||||
@@ -625,7 +691,7 @@ struct TLSConfig {
|
|||||||
ev_tstamp idle_timeout;
|
ev_tstamp idle_timeout;
|
||||||
} dyn_rec;
|
} dyn_rec;
|
||||||
|
|
||||||
// OCSP realted configurations
|
// OCSP related configurations
|
||||||
struct {
|
struct {
|
||||||
ev_tstamp update_interval;
|
ev_tstamp update_interval;
|
||||||
StringRef fetch_ocsp_response_file;
|
StringRef fetch_ocsp_response_file;
|
||||||
@@ -698,6 +764,42 @@ struct TLSConfig {
|
|||||||
bool no_postpone_early_data;
|
bool no_postpone_early_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
struct QUICConfig {
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
ev_tstamp idle;
|
||||||
|
} timeout;
|
||||||
|
struct {
|
||||||
|
bool log;
|
||||||
|
} debug;
|
||||||
|
struct {
|
||||||
|
StringRef dir;
|
||||||
|
} qlog;
|
||||||
|
ngtcp2_cc_algo congestion_controller;
|
||||||
|
bool early_data;
|
||||||
|
bool require_token;
|
||||||
|
StringRef secret_file;
|
||||||
|
ev_tstamp initial_rtt;
|
||||||
|
} upstream;
|
||||||
|
struct {
|
||||||
|
StringRef prog_file;
|
||||||
|
bool disabled;
|
||||||
|
} bpf;
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_SERVER_IDLEN> server_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Http3Config {
|
||||||
|
struct {
|
||||||
|
size_t max_concurrent_streams;
|
||||||
|
int32_t window_size;
|
||||||
|
int32_t connection_window_size;
|
||||||
|
int32_t max_window_size;
|
||||||
|
int32_t max_connection_window_size;
|
||||||
|
} upstream;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
// custom error page
|
// custom error page
|
||||||
struct ErrorPage {
|
struct ErrorPage {
|
||||||
// not NULL-terminated
|
// not NULL-terminated
|
||||||
@@ -734,6 +836,11 @@ struct HttpConfig {
|
|||||||
bool strip_incoming;
|
bool strip_incoming;
|
||||||
} early_data;
|
} early_data;
|
||||||
std::vector<AltSvc> altsvcs;
|
std::vector<AltSvc> altsvcs;
|
||||||
|
// altsvcs serialized in a wire format.
|
||||||
|
StringRef altsvc_header_value;
|
||||||
|
std::vector<AltSvc> http2_altsvcs;
|
||||||
|
// http2_altsvcs serialized in a wire format.
|
||||||
|
StringRef http2_altsvc_header_value;
|
||||||
std::vector<ErrorPage> error_pages;
|
std::vector<ErrorPage> error_pages;
|
||||||
HeaderRefs add_request_headers;
|
HeaderRefs add_request_headers;
|
||||||
HeaderRefs add_response_headers;
|
HeaderRefs add_response_headers;
|
||||||
@@ -903,9 +1010,16 @@ struct ConnectionConfig {
|
|||||||
int fastopen;
|
int fastopen;
|
||||||
} listener;
|
} listener;
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
struct {
|
||||||
|
std::vector<UpstreamAddr> addrs;
|
||||||
|
} quic_listener;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct {
|
struct {
|
||||||
ev_tstamp http2_read;
|
ev_tstamp http2_read;
|
||||||
|
ev_tstamp http3_read;
|
||||||
ev_tstamp read;
|
ev_tstamp read;
|
||||||
ev_tstamp write;
|
ev_tstamp write;
|
||||||
ev_tstamp idle_read;
|
ev_tstamp idle_read;
|
||||||
@@ -946,6 +1060,9 @@ struct Config {
|
|||||||
http{},
|
http{},
|
||||||
http2{},
|
http2{},
|
||||||
tls{},
|
tls{},
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic{},
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
logging{},
|
logging{},
|
||||||
conn{},
|
conn{},
|
||||||
api{},
|
api{},
|
||||||
@@ -954,6 +1071,7 @@ struct Config {
|
|||||||
num_worker{0},
|
num_worker{0},
|
||||||
padding{0},
|
padding{0},
|
||||||
rlimit_nofile{0},
|
rlimit_nofile{0},
|
||||||
|
rlimit_memlock{0},
|
||||||
uid{0},
|
uid{0},
|
||||||
gid{0},
|
gid{0},
|
||||||
pid{0},
|
pid{0},
|
||||||
@@ -963,7 +1081,10 @@ struct Config {
|
|||||||
single_process{false},
|
single_process{false},
|
||||||
single_thread{false},
|
single_thread{false},
|
||||||
ignore_per_pattern_mruby_error{false},
|
ignore_per_pattern_mruby_error{false},
|
||||||
ev_loop_flags{0} {}
|
ev_loop_flags{0},
|
||||||
|
max_worker_processes{0},
|
||||||
|
worker_process_grace_shutdown_period{0.} {
|
||||||
|
}
|
||||||
~Config();
|
~Config();
|
||||||
|
|
||||||
Config(Config &&) = delete;
|
Config(Config &&) = delete;
|
||||||
@@ -979,6 +1100,10 @@ struct Config {
|
|||||||
HttpConfig http;
|
HttpConfig http;
|
||||||
Http2Config http2;
|
Http2Config http2;
|
||||||
TLSConfig tls;
|
TLSConfig tls;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
QUICConfig quic;
|
||||||
|
Http3Config http3;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
LoggingConfig logging;
|
LoggingConfig logging;
|
||||||
ConnectionConfig conn;
|
ConnectionConfig conn;
|
||||||
APIConfig api;
|
APIConfig api;
|
||||||
@@ -997,6 +1122,7 @@ struct Config {
|
|||||||
size_t num_worker;
|
size_t num_worker;
|
||||||
size_t padding;
|
size_t padding;
|
||||||
size_t rlimit_nofile;
|
size_t rlimit_nofile;
|
||||||
|
size_t rlimit_memlock;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@@ -1011,6 +1137,8 @@ struct Config {
|
|||||||
bool ignore_per_pattern_mruby_error;
|
bool ignore_per_pattern_mruby_error;
|
||||||
// flags passed to ev_default_loop() and ev_loop_new()
|
// flags passed to ev_default_loop() and ev_loop_new()
|
||||||
int ev_loop_flags;
|
int ev_loop_flags;
|
||||||
|
size_t max_worker_processes;
|
||||||
|
ev_tstamp worker_process_grace_shutdown_period;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Config *get_config();
|
const Config *get_config();
|
||||||
@@ -1103,13 +1231,28 @@ enum {
|
|||||||
SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE,
|
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_CONNECTION_WINDOW_SIZE,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONCURRENT_STREAMS,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_MAX_CONNECTION_WINDOW_SIZE,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_MAX_WINDOW_SIZE,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_READ_TIMEOUT,
|
||||||
|
SHRPX_OPTID_FRONTEND_HTTP3_WINDOW_SIZE,
|
||||||
SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_MAX_REQUESTS,
|
SHRPX_OPTID_FRONTEND_MAX_REQUESTS,
|
||||||
SHRPX_OPTID_FRONTEND_NO_TLS,
|
SHRPX_OPTID_FRONTEND_NO_TLS,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_CONGESTION_CONTROLLER,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_DEBUG_LOG,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_EARLY_DATA,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_IDLE_TIMEOUT,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_INITIAL_RTT,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_QLOG_DIR,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_REQUIRE_TOKEN,
|
||||||
|
SHRPX_OPTID_FRONTEND_QUIC_SECRET_FILE,
|
||||||
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
||||||
SHRPX_OPTID_HEADER_FIELD_BUFFER,
|
SHRPX_OPTID_HEADER_FIELD_BUFFER,
|
||||||
SHRPX_OPTID_HOST_REWRITE,
|
SHRPX_OPTID_HOST_REWRITE,
|
||||||
|
SHRPX_OPTID_HTTP2_ALTSVC,
|
||||||
SHRPX_OPTID_HTTP2_BRIDGE,
|
SHRPX_OPTID_HTTP2_BRIDGE,
|
||||||
SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS,
|
SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS,
|
||||||
SHRPX_OPTID_HTTP2_NO_COOKIE_CRUMBLING,
|
SHRPX_OPTID_HTTP2_NO_COOKIE_CRUMBLING,
|
||||||
@@ -1122,6 +1265,7 @@ enum {
|
|||||||
SHRPX_OPTID_MAX_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
||||||
|
SHRPX_OPTID_MAX_WORKER_PROCESSES,
|
||||||
SHRPX_OPTID_MRUBY_FILE,
|
SHRPX_OPTID_MRUBY_FILE,
|
||||||
SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO,
|
SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO,
|
||||||
SHRPX_OPTID_NO_HOST_REWRITE,
|
SHRPX_OPTID_NO_HOST_REWRITE,
|
||||||
@@ -1130,6 +1274,7 @@ enum {
|
|||||||
SHRPX_OPTID_NO_KQUEUE,
|
SHRPX_OPTID_NO_KQUEUE,
|
||||||
SHRPX_OPTID_NO_LOCATION_REWRITE,
|
SHRPX_OPTID_NO_LOCATION_REWRITE,
|
||||||
SHRPX_OPTID_NO_OCSP,
|
SHRPX_OPTID_NO_OCSP,
|
||||||
|
SHRPX_OPTID_NO_QUIC_BPF,
|
||||||
SHRPX_OPTID_NO_SERVER_PUSH,
|
SHRPX_OPTID_NO_SERVER_PUSH,
|
||||||
SHRPX_OPTID_NO_SERVER_REWRITE,
|
SHRPX_OPTID_NO_SERVER_REWRITE,
|
||||||
SHRPX_OPTID_NO_STRIP_INCOMING_EARLY_DATA,
|
SHRPX_OPTID_NO_STRIP_INCOMING_EARLY_DATA,
|
||||||
@@ -1144,11 +1289,14 @@ enum {
|
|||||||
SHRPX_OPTID_PRIVATE_KEY_FILE,
|
SHRPX_OPTID_PRIVATE_KEY_FILE,
|
||||||
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
|
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
|
||||||
SHRPX_OPTID_PSK_SECRETS,
|
SHRPX_OPTID_PSK_SECRETS,
|
||||||
|
SHRPX_OPTID_QUIC_BPF_PROGRAM_FILE,
|
||||||
|
SHRPX_OPTID_QUIC_SERVER_ID,
|
||||||
SHRPX_OPTID_READ_BURST,
|
SHRPX_OPTID_READ_BURST,
|
||||||
SHRPX_OPTID_READ_RATE,
|
SHRPX_OPTID_READ_RATE,
|
||||||
SHRPX_OPTID_REDIRECT_HTTPS_PORT,
|
SHRPX_OPTID_REDIRECT_HTTPS_PORT,
|
||||||
SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER,
|
SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER,
|
||||||
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
|
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
|
||||||
|
SHRPX_OPTID_RLIMIT_MEMLOCK,
|
||||||
SHRPX_OPTID_RLIMIT_NOFILE,
|
SHRPX_OPTID_RLIMIT_NOFILE,
|
||||||
SHRPX_OPTID_SERVER_NAME,
|
SHRPX_OPTID_SERVER_NAME,
|
||||||
SHRPX_OPTID_SINGLE_PROCESS,
|
SHRPX_OPTID_SINGLE_PROCESS,
|
||||||
@@ -1189,6 +1337,7 @@ enum {
|
|||||||
SHRPX_OPTID_VERIFY_CLIENT_CACERT,
|
SHRPX_OPTID_VERIFY_CLIENT_CACERT,
|
||||||
SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED,
|
SHRPX_OPTID_VERIFY_CLIENT_TOLERATE_EXPIRED,
|
||||||
SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS,
|
SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS,
|
||||||
|
SHRPX_OPTID_WORKER_PROCESS_GRACE_SHUTDOWN_PERIOD,
|
||||||
SHRPX_OPTID_WORKER_READ_BURST,
|
SHRPX_OPTID_WORKER_READ_BURST,
|
||||||
SHRPX_OPTID_WORKER_READ_RATE,
|
SHRPX_OPTID_WORKER_READ_RATE,
|
||||||
SHRPX_OPTID_WORKER_WRITE_BURST,
|
SHRPX_OPTID_WORKER_WRITE_BURST,
|
||||||
@@ -1253,6 +1402,11 @@ std::unique_ptr<TicketKeys>
|
|||||||
read_tls_ticket_key_file(const std::vector<StringRef> &files,
|
read_tls_ticket_key_file(const std::vector<StringRef> &files,
|
||||||
const EVP_CIPHER *cipher, const EVP_MD *hmac);
|
const EVP_CIPHER *cipher, const EVP_MD *hmac);
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
std::shared_ptr<QUICKeyingMaterials>
|
||||||
|
read_quic_secret_file(const StringRef &path);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
// Returns string representation of |proto|.
|
// Returns string representation of |proto|.
|
||||||
StringRef strproto(Proto proto);
|
StringRef strproto(Proto proto);
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ Connection::Connection(struct ev_loop *loop, int fd, SSL *ssl,
|
|||||||
read_timeout(read_timeout) {
|
read_timeout(read_timeout) {
|
||||||
|
|
||||||
ev_io_init(&wev, writecb, fd, EV_WRITE);
|
ev_io_init(&wev, writecb, fd, EV_WRITE);
|
||||||
ev_io_init(&rev, readcb, fd, EV_READ);
|
ev_io_init(&rev, readcb, proto == Proto::HTTP3 ? 0 : fd, EV_READ);
|
||||||
|
|
||||||
wev.data = this;
|
wev.data = this;
|
||||||
rev.data = this;
|
rev.data = this;
|
||||||
@@ -128,7 +128,7 @@ void Connection::disconnect() {
|
|||||||
tls.early_data_finish = false;
|
tls.early_data_finish = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd != -1) {
|
if (proto != Proto::HTTP3 && fd != -1) {
|
||||||
shutdown(fd, SHUT_WR);
|
shutdown(fd, SHUT_WR);
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
@@ -312,10 +312,13 @@ BIO_METHOD *create_bio_method() {
|
|||||||
void Connection::set_ssl(SSL *ssl) {
|
void Connection::set_ssl(SSL *ssl) {
|
||||||
tls.ssl = ssl;
|
tls.ssl = ssl;
|
||||||
|
|
||||||
|
if (proto != Proto::HTTP3) {
|
||||||
auto &tlsconf = get_config()->tls;
|
auto &tlsconf = get_config()->tls;
|
||||||
auto bio = BIO_new(tlsconf.bio_method);
|
auto bio = BIO_new(tlsconf.bio_method);
|
||||||
BIO_set_data(bio, this);
|
BIO_set_data(bio, this);
|
||||||
SSL_set_bio(tls.ssl, bio, bio);
|
SSL_set_bio(tls.ssl, bio, bio);
|
||||||
|
}
|
||||||
|
|
||||||
SSL_set_app_data(tls.ssl, this);
|
SSL_set_app_data(tls.ssl, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,11 +397,14 @@ int Connection::tls_handshake() {
|
|||||||
|
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
||||||
#if OPENSSL_1_1_1_API
|
#if OPENSSL_1_1_1_API || defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
auto &tlsconf = get_config()->tls;
|
||||||
|
#endif // OPENSSL_1_1_1_API || defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
|
||||||
|
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
if (!tls.server_handshake || tls.early_data_finish) {
|
if (!tls.server_handshake || tls.early_data_finish) {
|
||||||
rv = SSL_do_handshake(tls.ssl);
|
rv = SSL_do_handshake(tls.ssl);
|
||||||
} else {
|
} else {
|
||||||
auto &tlsconf = get_config()->tls;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t nread;
|
size_t nread;
|
||||||
|
|
||||||
@@ -446,9 +452,9 @@ int Connection::tls_handshake() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // !OPENSSL_1_1_1_API
|
#else // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
rv = SSL_do_handshake(tls.ssl);
|
rv = SSL_do_handshake(tls.ssl);
|
||||||
#endif // !OPENSSL_1_1_1_API
|
#endif // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
|
|
||||||
if (rv <= 0) {
|
if (rv <= 0) {
|
||||||
auto err = SSL_get_error(tls.ssl, rv);
|
auto err = SSL_get_error(tls.ssl, rv);
|
||||||
@@ -496,7 +502,12 @@ int Connection::tls_handshake() {
|
|||||||
// Don't send handshake data if handshake was completed in OpenSSL
|
// Don't send handshake data if handshake was completed in OpenSSL
|
||||||
// routine. We have to check HTTP/2 requirement if HTTP/2 was
|
// routine. We have to check HTTP/2 requirement if HTTP/2 was
|
||||||
// negotiated before sending finished message to the peer.
|
// negotiated before sending finished message to the peer.
|
||||||
if (rv != 1 && tls.wbuf.rleft()) {
|
if ((rv != 1
|
||||||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||||||
|
|| SSL_in_init(tls.ssl)
|
||||||
|
#endif // OPENSSL_IS_BORINGSSL
|
||||||
|
) &&
|
||||||
|
tls.wbuf.rleft()) {
|
||||||
// First write indicates that resumption stuff has done.
|
// First write indicates that resumption stuff has done.
|
||||||
if (tls.handshake_state != TLSHandshakeState::WRITE_STARTED) {
|
if (tls.handshake_state != TLSHandshakeState::WRITE_STARTED) {
|
||||||
tls.handshake_state = TLSHandshakeState::WRITE_STARTED;
|
tls.handshake_state = TLSHandshakeState::WRITE_STARTED;
|
||||||
@@ -532,6 +543,40 @@ int Connection::tls_handshake() {
|
|||||||
return SHRPX_ERR_INPROGRESS;
|
return SHRPX_ERR_INPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||||||
|
if (!tlsconf.no_postpone_early_data && SSL_in_early_data(tls.ssl) &&
|
||||||
|
SSL_in_init(tls.ssl)) {
|
||||||
|
auto nread = SSL_read(tls.ssl, buf.data(), buf.size());
|
||||||
|
if (nread <= 0) {
|
||||||
|
auto err = SSL_get_error(tls.ssl, nread);
|
||||||
|
switch (err) {
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
|
return SHRPX_ERR_EOF;
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "SSL_read: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
}
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
default:
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "SSL_read: SSL_get_error returned " << err;
|
||||||
|
}
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tls.earlybuf.append(buf.data(), nread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_in_init(tls.ssl)) {
|
||||||
|
return SHRPX_ERR_INPROGRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // OPENSSL_IS_BORINGSSL
|
||||||
|
|
||||||
// Handshake was done
|
// Handshake was done
|
||||||
|
|
||||||
rv = check_http2_requirement();
|
rv = check_http2_requirement();
|
||||||
@@ -568,6 +613,36 @@ int Connection::write_tls_pending_handshake() {
|
|||||||
tls.wbuf.drain(nwrite);
|
tls.wbuf.drain(nwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OPENSSL_IS_BORINGSSL
|
||||||
|
if (!SSL_in_init(tls.ssl)) {
|
||||||
|
// This will send a session ticket.
|
||||||
|
auto nwrite = SSL_write(tls.ssl, "", 0);
|
||||||
|
if (nwrite < 0) {
|
||||||
|
auto err = SSL_get_error(tls.ssl, nwrite);
|
||||||
|
switch (err) {
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "Close connection due to TLS renegotiation";
|
||||||
|
}
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "SSL_write: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
}
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
default:
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "SSL_write: SSL_get_error returned " << err;
|
||||||
|
}
|
||||||
|
return SHRPX_ERR_NETWORK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // OPENSSL_IS_BORINGSSL
|
||||||
|
|
||||||
// We have to start read watcher, since later stage of code expects
|
// We have to start read watcher, since later stage of code expects
|
||||||
// this.
|
// this.
|
||||||
rlimit.startw();
|
rlimit.startw();
|
||||||
@@ -678,7 +753,7 @@ ssize_t Connection::write_tls(const void *data, size_t len) {
|
|||||||
// length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
|
// length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
|
||||||
// get_write_limit() may return smaller length than previously
|
// get_write_limit() may return smaller length than previously
|
||||||
// passed to SSL_write, which violates OpenSSL assumption. To avoid
|
// passed to SSL_write, which violates OpenSSL assumption. To avoid
|
||||||
// this, we keep last legnth passed to SSL_write to
|
// this, we keep last length passed to SSL_write to
|
||||||
// tls.last_writelen if SSL_write indicated I/O blocking.
|
// tls.last_writelen if SSL_write indicated I/O blocking.
|
||||||
if (tls.last_writelen == 0) {
|
if (tls.last_writelen == 0) {
|
||||||
len = std::min(len, wlimit.avail());
|
len = std::min(len, wlimit.avail());
|
||||||
@@ -695,7 +770,7 @@ ssize_t Connection::write_tls(const void *data, size_t len) {
|
|||||||
|
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
||||||
#if OPENSSL_1_1_1_API
|
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
int rv;
|
int rv;
|
||||||
if (SSL_is_init_finished(tls.ssl)) {
|
if (SSL_is_init_finished(tls.ssl)) {
|
||||||
rv = SSL_write(tls.ssl, data, len);
|
rv = SSL_write(tls.ssl, data, len);
|
||||||
@@ -707,9 +782,9 @@ ssize_t Connection::write_tls(const void *data, size_t len) {
|
|||||||
rv = nwrite;
|
rv = nwrite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else // !OPENSSL_1_1_1_API
|
#else // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
auto rv = SSL_write(tls.ssl, data, len);
|
auto rv = SSL_write(tls.ssl, data, len);
|
||||||
#endif // !OPENSSL_1_1_1_API
|
#endif // !(OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL))
|
||||||
|
|
||||||
if (rv <= 0) {
|
if (rv <= 0) {
|
||||||
auto err = SSL_get_error(tls.ssl, rv);
|
auto err = SSL_get_error(tls.ssl, rv);
|
||||||
@@ -756,7 +831,7 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
|||||||
// length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
|
// length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE.
|
||||||
// rlimit_.avail() or rlimit_.avail() may return different length
|
// rlimit_.avail() or rlimit_.avail() may return different length
|
||||||
// than the length previously passed to SSL_read, which violates
|
// than the length previously passed to SSL_read, which violates
|
||||||
// OpenSSL assumption. To avoid this, we keep last legnth passed
|
// OpenSSL assumption. To avoid this, we keep last length passed
|
||||||
// to SSL_read to tls_last_readlen_ if SSL_read indicated I/O
|
// to SSL_read to tls_last_readlen_ if SSL_read indicated I/O
|
||||||
// blocking.
|
// blocking.
|
||||||
if (tls.last_readlen == 0) {
|
if (tls.last_readlen == 0) {
|
||||||
@@ -769,7 +844,7 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
|||||||
tls.last_readlen = 0;
|
tls.last_readlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPENSSL_1_1_1_API
|
#if OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
if (!tls.early_data_finish) {
|
if (!tls.early_data_finish) {
|
||||||
// TLSv1.3 handshake is still going on.
|
// TLSv1.3 handshake is still going on.
|
||||||
size_t nread;
|
size_t nread;
|
||||||
@@ -808,7 +883,7 @@ ssize_t Connection::read_tls(void *data, size_t len) {
|
|||||||
}
|
}
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
#endif // OPENSSL_1_1_1_API
|
#endif // OPENSSL_1_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
|
||||||
|
|
||||||
auto rv = SSL_read(tls.ssl, data, len);
|
auto rv = SSL_read(tls.ssl, data, len);
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
#include "shrpx_memcached_dispatcher.h"
|
#include "shrpx_memcached_dispatcher.h"
|
||||||
#include "shrpx_signal.h"
|
#include "shrpx_signal.h"
|
||||||
#include "shrpx_log.h"
|
#include "shrpx_log.h"
|
||||||
|
#include "xsi_strerror.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "template.h"
|
#include "template.h"
|
||||||
|
|
||||||
@@ -112,7 +113,11 @@ void serial_event_async_cb(struct ev_loop *loop, ev_async *w, int revent) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ConnectionHandler::ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen)
|
ConnectionHandler::ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen)
|
||||||
: gen_(gen),
|
:
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_ipc_fd_(-1),
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
gen_(gen),
|
||||||
single_worker_(nullptr),
|
single_worker_(nullptr),
|
||||||
loop_(loop),
|
loop_(loop),
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
@@ -156,6 +161,19 @@ ConnectionHandler::~ConnectionHandler() {
|
|||||||
ev_timer_stop(loop_, &ocsp_timer_);
|
ev_timer_stop(loop_, &ocsp_timer_);
|
||||||
ev_timer_stop(loop_, &disable_acceptor_timer_);
|
ev_timer_stop(loop_, &disable_acceptor_timer_);
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
for (auto ssl_ctx : quic_all_ssl_ctx_) {
|
||||||
|
if (ssl_ctx == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tls_ctx_data =
|
||||||
|
static_cast<tls::TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
|
||||||
|
delete tls_ctx_data;
|
||||||
|
SSL_CTX_free(ssl_ctx);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
for (auto ssl_ctx : all_ssl_ctx_) {
|
for (auto ssl_ctx : all_ssl_ctx_) {
|
||||||
auto tls_ctx_data =
|
auto tls_ctx_data =
|
||||||
static_cast<tls::TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
|
static_cast<tls::TLSContextData *>(SSL_CTX_get_app_data(ssl_ctx));
|
||||||
@@ -179,24 +197,24 @@ void ConnectionHandler::set_ticket_keys_to_worker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::worker_reopen_log_files() {
|
void ConnectionHandler::worker_reopen_log_files() {
|
||||||
|
for (auto &worker : workers_) {
|
||||||
WorkerEvent wev{};
|
WorkerEvent wev{};
|
||||||
|
|
||||||
wev.type = WorkerEventType::REOPEN_LOG;
|
wev.type = WorkerEventType::REOPEN_LOG;
|
||||||
|
|
||||||
for (auto &worker : workers_) {
|
worker->send(std::move(wev));
|
||||||
worker->send(wev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionHandler::worker_replace_downstream(
|
void ConnectionHandler::worker_replace_downstream(
|
||||||
std::shared_ptr<DownstreamConfig> downstreamconf) {
|
std::shared_ptr<DownstreamConfig> downstreamconf) {
|
||||||
|
for (auto &worker : workers_) {
|
||||||
WorkerEvent wev{};
|
WorkerEvent wev{};
|
||||||
|
|
||||||
wev.type = WorkerEventType::REPLACE_DOWNSTREAM;
|
wev.type = WorkerEventType::REPLACE_DOWNSTREAM;
|
||||||
wev.downstreamconf = std::move(downstreamconf);
|
wev.downstreamconf = downstreamconf;
|
||||||
|
|
||||||
for (auto &worker : workers_) {
|
worker->send(std::move(wev));
|
||||||
worker->send(wev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +227,18 @@ int ConnectionHandler::create_single_worker() {
|
|||||||
nb_
|
nb_
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_cert_tree_ = tls::create_cert_lookup_tree();
|
||||||
|
auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context(
|
||||||
|
quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get()
|
||||||
|
# ifdef HAVE_NEVERBLEED
|
||||||
|
,
|
||||||
|
nb_
|
||||||
|
# endif // HAVE_NEVERBLEED
|
||||||
|
);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
nb_
|
nb_
|
||||||
@@ -217,6 +247,9 @@ int ConnectionHandler::create_single_worker() {
|
|||||||
|
|
||||||
if (cl_ssl_ctx) {
|
if (cl_ssl_ctx) {
|
||||||
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_all_ssl_ctx_.push_back(nullptr);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
|
|
||||||
auto config = get_config();
|
auto config = get_config();
|
||||||
@@ -233,11 +266,30 @@ int ConnectionHandler::create_single_worker() {
|
|||||||
tlsconf.cacert, memcachedconf.cert_file,
|
tlsconf.cacert, memcachedconf.cert_file,
|
||||||
memcachedconf.private_key_file, nullptr);
|
memcachedconf.private_key_file, nullptr);
|
||||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_all_ssl_ctx_.push_back(nullptr);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF)
|
||||||
|
quic_bpf_refs_.resize(config->conn.quic_listener.addrs.size());
|
||||||
|
#endif // ENABLE_HTTP3 && HAVE_LIBBPF
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
assert(cid_prefixes_.size() == 1);
|
||||||
|
const auto &cid_prefix = cid_prefixes_[0];
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
single_worker_ = std::make_unique<Worker>(
|
single_worker_ = std::make_unique<Worker>(
|
||||||
loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(),
|
loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(),
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_sv_ssl_ctx, quic_cert_tree_.get(), cid_prefix.data(),
|
||||||
|
cid_prefix.size(),
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
/* index = */ 0,
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
ticket_keys_, this, config->conn.downstream);
|
ticket_keys_, this, config->conn.downstream);
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
if (single_worker_->create_mruby_context() != 0) {
|
if (single_worker_->create_mruby_context() != 0) {
|
||||||
@@ -245,6 +297,12 @@ int ConnectionHandler::create_single_worker() {
|
|||||||
}
|
}
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
if (single_worker_->setup_quic_server_socket() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,6 +318,18 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
|||||||
nb_
|
nb_
|
||||||
# endif // HAVE_NEVERBLEED
|
# endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
quic_cert_tree_ = tls::create_cert_lookup_tree();
|
||||||
|
auto quic_sv_ssl_ctx = tls::setup_quic_server_ssl_context(
|
||||||
|
quic_all_ssl_ctx_, quic_indexed_ssl_ctx_, quic_cert_tree_.get()
|
||||||
|
# ifdef HAVE_NEVERBLEED
|
||||||
|
,
|
||||||
|
nb_
|
||||||
|
# endif // HAVE_NEVERBLEED
|
||||||
|
);
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
|
|
||||||
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
||||||
# ifdef HAVE_NEVERBLEED
|
# ifdef HAVE_NEVERBLEED
|
||||||
nb_
|
nb_
|
||||||
@@ -268,12 +338,19 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
|||||||
|
|
||||||
if (cl_ssl_ctx) {
|
if (cl_ssl_ctx) {
|
||||||
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
quic_all_ssl_ctx_.push_back(nullptr);
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
|
|
||||||
auto config = get_config();
|
auto config = get_config();
|
||||||
auto &tlsconf = config->tls;
|
auto &tlsconf = config->tls;
|
||||||
auto &apiconf = config->api;
|
auto &apiconf = config->api;
|
||||||
|
|
||||||
|
# if defined(ENABLE_HTTP3) && defined(HAVE_LIBBPF)
|
||||||
|
quic_bpf_refs_.resize(config->conn.quic_listener.addrs.size());
|
||||||
|
# endif // ENABLE_HTTP3 && HAVE_LIBBPF
|
||||||
|
|
||||||
// We have dedicated worker for API request processing.
|
// We have dedicated worker for API request processing.
|
||||||
if (apiconf.enabled) {
|
if (apiconf.enabled) {
|
||||||
++num;
|
++num;
|
||||||
@@ -291,14 +368,32 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
|||||||
tlsconf.cacert, memcachedconf.cert_file,
|
tlsconf.cacert, memcachedconf.cert_file,
|
||||||
memcachedconf.private_key_file, nullptr);
|
memcachedconf.private_key_file, nullptr);
|
||||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
quic_all_ssl_ctx_.push_back(nullptr);
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
assert(cid_prefixes_.size() == num);
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
|
|
||||||
for (size_t i = 0; i < num; ++i) {
|
for (size_t i = 0; i < num; ++i) {
|
||||||
auto loop = ev_loop_new(config->ev_loop_flags);
|
auto loop = ev_loop_new(config->ev_loop_flags);
|
||||||
|
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
const auto &cid_prefix = cid_prefixes_[i];
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
|
|
||||||
auto worker = std::make_unique<Worker>(
|
auto worker = std::make_unique<Worker>(
|
||||||
loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(),
|
loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx, cert_tree_.get(),
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
quic_sv_ssl_ctx, quic_cert_tree_.get(), cid_prefix.data(),
|
||||||
|
cid_prefix.size(),
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
i,
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
ticket_keys_, this, config->conn.downstream);
|
ticket_keys_, this, config->conn.downstream);
|
||||||
# ifdef HAVE_MRUBY
|
# ifdef HAVE_MRUBY
|
||||||
if (worker->create_mruby_context() != 0) {
|
if (worker->create_mruby_context() != 0) {
|
||||||
@@ -306,6 +401,13 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
|||||||
}
|
}
|
||||||
# endif // HAVE_MRUBY
|
# endif // HAVE_MRUBY
|
||||||
|
|
||||||
|
# ifdef ENABLE_HTTP3
|
||||||
|
if ((!apiconf.enabled || i != 0) &&
|
||||||
|
worker->setup_quic_server_socket() != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
# endif // ENABLE_HTTP3
|
||||||
|
|
||||||
workers_.push_back(std::move(worker));
|
workers_.push_back(std::move(worker));
|
||||||
worker_loops_.push_back(loop);
|
worker_loops_.push_back(loop);
|
||||||
|
|
||||||
@@ -345,15 +447,15 @@ void ConnectionHandler::graceful_shutdown_worker() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkerEvent wev{};
|
|
||||||
wev.type = WorkerEventType::GRACEFUL_SHUTDOWN;
|
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
LLOG(INFO, this) << "Sending graceful shutdown signal to worker";
|
LLOG(INFO, this) << "Sending graceful shutdown signal to worker";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &worker : workers_) {
|
for (auto &worker : workers_) {
|
||||||
worker->send(wev);
|
WorkerEvent wev{};
|
||||||
|
wev.type = WorkerEventType::GRACEFUL_SHUTDOWN;
|
||||||
|
|
||||||
|
worker->send(std::move(wev));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NOTHREADS
|
#ifndef NOTHREADS
|
||||||
@@ -436,7 +538,7 @@ int ConnectionHandler::handle_connection(int fd, sockaddr *addr, int addrlen,
|
|||||||
wev.client_addrlen = addrlen;
|
wev.client_addrlen = addrlen;
|
||||||
wev.faddr = faddr;
|
wev.faddr = faddr;
|
||||||
|
|
||||||
worker->send(wev);
|
worker->send(std::move(wev));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -602,6 +704,9 @@ void ConnectionHandler::handle_ocsp_complete() {
|
|||||||
ev_child_stop(loop_, &ocsp_.chldev);
|
ev_child_stop(loop_, &ocsp_.chldev);
|
||||||
|
|
||||||
assert(ocsp_.next < all_ssl_ctx_.size());
|
assert(ocsp_.next < all_ssl_ctx_.size());
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
assert(all_ssl_ctx_.size() == quic_all_ssl_ctx_.size());
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
auto ssl_ctx = all_ssl_ctx_[ocsp_.next];
|
auto ssl_ctx = all_ssl_ctx_[ocsp_.next];
|
||||||
auto tls_ctx_data =
|
auto tls_ctx_data =
|
||||||
@@ -629,6 +734,32 @@ void ConnectionHandler::handle_ocsp_complete() {
|
|||||||
if (tlsconf.ocsp.no_verify ||
|
if (tlsconf.ocsp.no_verify ||
|
||||||
tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
|
tls::verify_ocsp_response(ssl_ctx, ocsp_.resp.data(),
|
||||||
ocsp_.resp.size()) == 0) {
|
ocsp_.resp.size()) == 0) {
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
// We have list of SSL_CTX with the same certificate in
|
||||||
|
// quic_all_ssl_ctx_ as well. Some SSL_CTXs are missing there in
|
||||||
|
// that case we get nullptr.
|
||||||
|
auto quic_ssl_ctx = quic_all_ssl_ctx_[ocsp_.next];
|
||||||
|
if (quic_ssl_ctx) {
|
||||||
|
# ifndef OPENSSL_IS_BORINGSSL
|
||||||
|
auto quic_tls_ctx_data = static_cast<tls::TLSContextData *>(
|
||||||
|
SSL_CTX_get_app_data(quic_ssl_ctx));
|
||||||
|
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
|
std::atomic_store_explicit(
|
||||||
|
&quic_tls_ctx_data->ocsp_data,
|
||||||
|
std::make_shared<std::vector<uint8_t>>(ocsp_.resp),
|
||||||
|
std::memory_order_release);
|
||||||
|
# else // !HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
|
std::lock_guard<std::mutex> g(quic_tls_ctx_data->mu);
|
||||||
|
quic_tls_ctx_data->ocsp_data =
|
||||||
|
std::make_shared<std::vector<uint8_t>>(ocsp_.resp);
|
||||||
|
# endif // !HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
|
# else // OPENSSL_IS_BORINGSSL
|
||||||
|
SSL_CTX_set_ocsp_response(quic_ssl_ctx, ocsp_.resp.data(),
|
||||||
|
ocsp_.resp.size());
|
||||||
|
# endif // OPENSSL_IS_BORINGSSL
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
#ifndef OPENSSL_IS_BORINGSSL
|
#ifndef OPENSSL_IS_BORINGSSL
|
||||||
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
# ifdef HAVE_ATOMIC_STD_SHARED_PTR
|
||||||
std::atomic_store_explicit(
|
std::atomic_store_explicit(
|
||||||
@@ -809,6 +940,9 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
|||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
all_ssl_ctx_.push_back(ssl_ctx);
|
all_ssl_ctx_.push_back(ssl_ctx);
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
quic_all_ssl_ctx_.push_back(nullptr);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
return ssl_ctx;
|
return ssl_ctx;
|
||||||
}
|
}
|
||||||
@@ -871,8 +1005,329 @@ ConnectionHandler::get_indexed_ssl_ctx(size_t idx) const {
|
|||||||
return indexed_ssl_ctx_[idx];
|
return indexed_ssl_ctx_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
const std::vector<SSL_CTX *> &
|
||||||
|
ConnectionHandler::get_quic_indexed_ssl_ctx(size_t idx) const {
|
||||||
|
return quic_indexed_ssl_ctx_[idx];
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) {
|
void ConnectionHandler::set_enable_acceptor_on_ocsp_completion(bool f) {
|
||||||
enable_acceptor_on_ocsp_completion_ = f;
|
enable_acceptor_on_ocsp_completion_ = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
int ConnectionHandler::forward_quic_packet(
|
||||||
|
const UpstreamAddr *faddr, const Address &remote_addr,
|
||||||
|
const Address &local_addr, const ngtcp2_pkt_info &pi,
|
||||||
|
const uint8_t *cid_prefix, const uint8_t *data, size_t datalen) {
|
||||||
|
assert(!get_config()->single_thread);
|
||||||
|
|
||||||
|
for (auto &worker : workers_) {
|
||||||
|
if (!std::equal(cid_prefix, cid_prefix + SHRPX_QUIC_CID_PREFIXLEN,
|
||||||
|
worker->get_cid_prefix())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerEvent wev{};
|
||||||
|
wev.type = WorkerEventType::QUIC_PKT_FORWARD;
|
||||||
|
wev.quic_pkt = std::make_unique<QUICPacket>(faddr->index, remote_addr,
|
||||||
|
local_addr, pi, data, datalen);
|
||||||
|
|
||||||
|
worker->send(std::move(wev));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionHandler::set_quic_keying_materials(
|
||||||
|
std::shared_ptr<QUICKeyingMaterials> qkms) {
|
||||||
|
quic_keying_materials_ = std::move(qkms);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<QUICKeyingMaterials> &
|
||||||
|
ConnectionHandler::get_quic_keying_materials() const {
|
||||||
|
return quic_keying_materials_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionHandler::set_cid_prefixes(
|
||||||
|
const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
|
||||||
|
&cid_prefixes) {
|
||||||
|
cid_prefixes_ = cid_prefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUICLingeringWorkerProcess *
|
||||||
|
ConnectionHandler::match_quic_lingering_worker_process_cid_prefix(
|
||||||
|
const uint8_t *dcid, size_t dcidlen) {
|
||||||
|
assert(dcidlen >= SHRPX_QUIC_CID_PREFIXLEN);
|
||||||
|
|
||||||
|
for (auto &lwps : quic_lingering_worker_processes_) {
|
||||||
|
for (auto &cid_prefix : lwps.cid_prefixes) {
|
||||||
|
if (std::equal(std::begin(cid_prefix), std::end(cid_prefix), dcid)) {
|
||||||
|
return &lwps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
std::vector<BPFRef> &ConnectionHandler::get_quic_bpf_refs() {
|
||||||
|
return quic_bpf_refs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionHandler::unload_bpf_objects() {
|
||||||
|
std::array<char, STRERROR_BUFSIZE> errbuf;
|
||||||
|
|
||||||
|
LOG(NOTICE) << "Unloading BPF objects";
|
||||||
|
|
||||||
|
for (auto &ref : quic_bpf_refs_) {
|
||||||
|
if (ref.obj == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bpf_object__unload(ref.obj) != 0) {
|
||||||
|
LOG(WARN) << "Failed to unload bpf object: "
|
||||||
|
<< xsi_strerror(errno, errbuf.data(), errbuf.size());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref.obj = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
|
||||||
|
void ConnectionHandler::set_quic_ipc_fd(int fd) { quic_ipc_fd_ = fd; }
|
||||||
|
|
||||||
|
void ConnectionHandler::set_quic_lingering_worker_processes(
|
||||||
|
const std::vector<QUICLingeringWorkerProcess> &quic_lwps) {
|
||||||
|
quic_lingering_worker_processes_ = quic_lwps;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectionHandler::forward_quic_packet_to_lingering_worker_process(
|
||||||
|
QUICLingeringWorkerProcess *quic_lwp, const Address &remote_addr,
|
||||||
|
const Address &local_addr, const ngtcp2_pkt_info &pi, const uint8_t *data,
|
||||||
|
size_t datalen) {
|
||||||
|
std::array<uint8_t, 512> header;
|
||||||
|
|
||||||
|
assert(header.size() >= 1 + 1 + 1 + 1 + sizeof(sockaddr_storage) * 2);
|
||||||
|
assert(remote_addr.len > 0);
|
||||||
|
assert(local_addr.len > 0);
|
||||||
|
|
||||||
|
auto p = header.data();
|
||||||
|
|
||||||
|
*p++ = static_cast<uint8_t>(QUICIPCType::DGRAM_FORWARD);
|
||||||
|
*p++ = static_cast<uint8_t>(remote_addr.len - 1);
|
||||||
|
p = std::copy_n(reinterpret_cast<const uint8_t *>(&remote_addr.su),
|
||||||
|
remote_addr.len, p);
|
||||||
|
*p++ = static_cast<uint8_t>(local_addr.len - 1);
|
||||||
|
p = std::copy_n(reinterpret_cast<const uint8_t *>(&local_addr.su),
|
||||||
|
local_addr.len, p);
|
||||||
|
*p++ = pi.ecn;
|
||||||
|
|
||||||
|
iovec msg_iov[] = {
|
||||||
|
{
|
||||||
|
.iov_base = header.data(),
|
||||||
|
.iov_len = static_cast<size_t>(p - header.data()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.iov_base = const_cast<uint8_t *>(data),
|
||||||
|
.iov_len = datalen,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
msghdr msg{};
|
||||||
|
msg.msg_iov = msg_iov;
|
||||||
|
msg.msg_iovlen = array_size(msg_iov);
|
||||||
|
|
||||||
|
ssize_t nwrite;
|
||||||
|
|
||||||
|
while ((nwrite = sendmsg(quic_lwp->quic_ipc_fd, &msg, 0)) == -1 &&
|
||||||
|
errno == EINTR)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (nwrite == -1) {
|
||||||
|
std::array<char, STRERROR_BUFSIZE> errbuf;
|
||||||
|
|
||||||
|
auto error = errno;
|
||||||
|
LOG(ERROR) << "Failed to send QUIC IPC message: "
|
||||||
|
<< xsi_strerror(error, errbuf.data(), errbuf.size());
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConnectionHandler::quic_ipc_read() {
|
||||||
|
std::array<uint8_t, 65536> buf;
|
||||||
|
|
||||||
|
ssize_t nread;
|
||||||
|
|
||||||
|
while ((nread = recv(quic_ipc_fd_, buf.data(), buf.size(), 0)) == -1 &&
|
||||||
|
errno == EINTR)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (nread == -1) {
|
||||||
|
std::array<char, STRERROR_BUFSIZE> errbuf;
|
||||||
|
|
||||||
|
auto error = errno;
|
||||||
|
LOG(ERROR) << "Failed to read data from QUIC IPC channel: "
|
||||||
|
<< xsi_strerror(error, errbuf.data(), errbuf.size());
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nread == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = 1 + 1 + 1 + 1;
|
||||||
|
|
||||||
|
// Wire format:
|
||||||
|
// TYPE(1) REMOTE_ADDRLEN(1) REMOTE_ADDR(N) LOCAL_ADDRLEN(1) LOCAL_ADDR(N)
|
||||||
|
// ECN(1) DGRAM_PAYLOAD(N)
|
||||||
|
//
|
||||||
|
// When encoding, REMOTE_ADDRLEN and LOCAL_ADDRLEN are decremented
|
||||||
|
// by 1.
|
||||||
|
if (static_cast<size_t>(nread) < len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p = buf.data();
|
||||||
|
if (*p != static_cast<uint8_t>(QUICIPCType::DGRAM_FORWARD)) {
|
||||||
|
LOG(ERROR) << "Unknown QUICIPCType: " << static_cast<uint32_t>(*p);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
auto pkt = std::make_unique<QUICPacket>();
|
||||||
|
|
||||||
|
auto remote_addrlen = static_cast<size_t>(*p++) + 1;
|
||||||
|
if (remote_addrlen > sizeof(sockaddr_storage)) {
|
||||||
|
LOG(ERROR) << "The length of remote address is too large: "
|
||||||
|
<< remote_addrlen;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len += remote_addrlen;
|
||||||
|
|
||||||
|
if (static_cast<size_t>(nread) < len) {
|
||||||
|
LOG(ERROR) << "Insufficient QUIC IPC message length";
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt->remote_addr.len = remote_addrlen;
|
||||||
|
memcpy(&pkt->remote_addr.su, p, remote_addrlen);
|
||||||
|
|
||||||
|
p += remote_addrlen;
|
||||||
|
|
||||||
|
auto local_addrlen = static_cast<size_t>(*p++) + 1;
|
||||||
|
if (local_addrlen > sizeof(sockaddr_storage)) {
|
||||||
|
LOG(ERROR) << "The length of local address is too large: " << local_addrlen;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len += local_addrlen;
|
||||||
|
|
||||||
|
if (static_cast<size_t>(nread) < len) {
|
||||||
|
LOG(ERROR) << "Insufficient QUIC IPC message length";
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkt->local_addr.len = local_addrlen;
|
||||||
|
memcpy(&pkt->local_addr.su, p, local_addrlen);
|
||||||
|
|
||||||
|
p += local_addrlen;
|
||||||
|
|
||||||
|
pkt->pi.ecn = *p++;
|
||||||
|
|
||||||
|
auto datalen = nread - (p - buf.data());
|
||||||
|
|
||||||
|
pkt->data.assign(p, p + datalen);
|
||||||
|
|
||||||
|
// At the moment, UpstreamAddr index is unknown.
|
||||||
|
pkt->upstream_addr_index = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
uint32_t version;
|
||||||
|
const uint8_t *dcid;
|
||||||
|
size_t dcidlen;
|
||||||
|
const uint8_t *scid;
|
||||||
|
size_t scidlen;
|
||||||
|
|
||||||
|
auto rv =
|
||||||
|
ngtcp2_pkt_decode_version_cid(&version, &dcid, &dcidlen, &scid, &scidlen,
|
||||||
|
p, datalen, SHRPX_QUIC_SCIDLEN);
|
||||||
|
if (rv < 0) {
|
||||||
|
LOG(ERROR) << "ngtcp2_pkt_decode_version_cid: " << ngtcp2_strerror(rv);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dcidlen != SHRPX_QUIC_SCIDLEN) {
|
||||||
|
LOG(ERROR) << "DCID length is invalid";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (single_worker_) {
|
||||||
|
auto faddr = single_worker_->find_quic_upstream_addr(pkt->local_addr);
|
||||||
|
if (faddr == nullptr) {
|
||||||
|
LOG(ERROR) << "No suitable upstream address found";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto quic_conn_handler = single_worker_->get_quic_connection_handler();
|
||||||
|
|
||||||
|
// Ignore return value
|
||||||
|
quic_conn_handler->handle_packet(faddr, pkt->remote_addr, pkt->local_addr,
|
||||||
|
pkt->pi, pkt->data.data(),
|
||||||
|
pkt->data.size());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &qkm = quic_keying_materials_->keying_materials.front();
|
||||||
|
|
||||||
|
std::array<uint8_t, SHRPX_QUIC_DECRYPTED_DCIDLEN> decrypted_dcid;
|
||||||
|
|
||||||
|
if (decrypt_quic_connection_id(decrypted_dcid.data(),
|
||||||
|
dcid + SHRPX_QUIC_CID_PREFIX_OFFSET,
|
||||||
|
qkm.cid_encryption_key.data()) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &worker : workers_) {
|
||||||
|
if (!std::equal(std::begin(decrypted_dcid),
|
||||||
|
std::begin(decrypted_dcid) + SHRPX_QUIC_CID_PREFIXLEN,
|
||||||
|
worker->get_cid_prefix())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkerEvent wev{
|
||||||
|
.type = WorkerEventType::QUIC_PKT_FORWARD,
|
||||||
|
.quic_pkt = std::move(pkt),
|
||||||
|
};
|
||||||
|
worker->send(std::move(wev));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
LOG(INFO) << "No worker to match CID prefix";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
# include <future>
|
# include <future>
|
||||||
#endif // NOTHREADS
|
#endif // NOTHREADS
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBBPF
|
||||||
|
# include <bpf/libbpf.h>
|
||||||
|
#endif // HAVE_LIBBPF
|
||||||
|
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
#include <ev.h>
|
#include <ev.h>
|
||||||
@@ -99,6 +103,35 @@ struct SerialEvent {
|
|||||||
std::shared_ptr<DownstreamConfig> downstreamconf;
|
std::shared_ptr<DownstreamConfig> downstreamconf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
struct BPFRef {
|
||||||
|
bpf_object *obj;
|
||||||
|
int reuseport_array;
|
||||||
|
int cid_prefix_map;
|
||||||
|
};
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
|
||||||
|
// QUIC IPC message type.
|
||||||
|
enum class QUICIPCType {
|
||||||
|
NONE,
|
||||||
|
// Send forwarded QUIC UDP datagram and its metadata.
|
||||||
|
DGRAM_FORWARD,
|
||||||
|
};
|
||||||
|
|
||||||
|
// WorkerProcesses which are in graceful shutdown period.
|
||||||
|
struct QUICLingeringWorkerProcess {
|
||||||
|
QUICLingeringWorkerProcess(
|
||||||
|
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes,
|
||||||
|
int quic_ipc_fd)
|
||||||
|
: cid_prefixes{std::move(cid_prefixes)}, quic_ipc_fd{quic_ipc_fd} {}
|
||||||
|
|
||||||
|
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes;
|
||||||
|
// Socket to send QUIC IPC message to this worker process.
|
||||||
|
int quic_ipc_fd;
|
||||||
|
};
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
class ConnectionHandler {
|
class ConnectionHandler {
|
||||||
public:
|
public:
|
||||||
ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen);
|
ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen);
|
||||||
@@ -130,7 +163,7 @@ public:
|
|||||||
|
|
||||||
// Cancels ocsp update process
|
// Cancels ocsp update process
|
||||||
void cancel_ocsp_update();
|
void cancel_ocsp_update();
|
||||||
// Starts ocsp update for certficate |cert_file|.
|
// Starts ocsp update for certificate |cert_file|.
|
||||||
int start_ocsp_update(const char *cert_file);
|
int start_ocsp_update(const char *cert_file);
|
||||||
// Reads incoming data from ocsp update process
|
// Reads incoming data from ocsp update process
|
||||||
void read_ocsp_chunk();
|
void read_ocsp_chunk();
|
||||||
@@ -159,6 +192,45 @@ public:
|
|||||||
SSL_CTX *get_ssl_ctx(size_t idx) const;
|
SSL_CTX *get_ssl_ctx(size_t idx) const;
|
||||||
|
|
||||||
const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const;
|
const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
const std::vector<SSL_CTX *> &get_quic_indexed_ssl_ctx(size_t idx) const;
|
||||||
|
|
||||||
|
int forward_quic_packet(const UpstreamAddr *faddr, const Address &remote_addr,
|
||||||
|
const Address &local_addr, const ngtcp2_pkt_info &pi,
|
||||||
|
const uint8_t *cid_prefix, const uint8_t *data,
|
||||||
|
size_t datalen);
|
||||||
|
|
||||||
|
void set_quic_keying_materials(std::shared_ptr<QUICKeyingMaterials> qkms);
|
||||||
|
const std::shared_ptr<QUICKeyingMaterials> &get_quic_keying_materials() const;
|
||||||
|
|
||||||
|
void set_cid_prefixes(
|
||||||
|
const std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
|
||||||
|
&cid_prefixes);
|
||||||
|
|
||||||
|
void set_quic_lingering_worker_processes(
|
||||||
|
const std::vector<QUICLingeringWorkerProcess> &quic_lwps);
|
||||||
|
|
||||||
|
// Return matching QUICLingeringWorkerProcess which has a CID prefix
|
||||||
|
// such that |dcid| starts with it. If no such
|
||||||
|
// QUICLingeringWorkerProcess, it returns nullptr.
|
||||||
|
QUICLingeringWorkerProcess *
|
||||||
|
match_quic_lingering_worker_process_cid_prefix(const uint8_t *dcid,
|
||||||
|
size_t dcidlen);
|
||||||
|
|
||||||
|
int forward_quic_packet_to_lingering_worker_process(
|
||||||
|
QUICLingeringWorkerProcess *quic_lwp, const Address &remote_addr,
|
||||||
|
const Address &local_addr, const ngtcp2_pkt_info &pi, const uint8_t *data,
|
||||||
|
size_t datalen);
|
||||||
|
|
||||||
|
void set_quic_ipc_fd(int fd);
|
||||||
|
|
||||||
|
int quic_ipc_read();
|
||||||
|
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
std::vector<BPFRef> &get_quic_bpf_refs();
|
||||||
|
void unload_bpf_objects();
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
void set_neverbleed(neverbleed_t *nb);
|
void set_neverbleed(neverbleed_t *nb);
|
||||||
@@ -187,6 +259,19 @@ private:
|
|||||||
// selection among them are performed by hostname presented by SNI,
|
// selection among them are performed by hostname presented by SNI,
|
||||||
// and signature algorithm presented by client.
|
// and signature algorithm presented by client.
|
||||||
std::vector<std::vector<SSL_CTX *>> indexed_ssl_ctx_;
|
std::vector<std::vector<SSL_CTX *>> indexed_ssl_ctx_;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>> cid_prefixes_;
|
||||||
|
std::vector<std::array<uint8_t, SHRPX_QUIC_CID_PREFIXLEN>>
|
||||||
|
lingering_cid_prefixes_;
|
||||||
|
int quic_ipc_fd_;
|
||||||
|
std::vector<QUICLingeringWorkerProcess> quic_lingering_worker_processes_;
|
||||||
|
# ifdef HAVE_LIBBPF
|
||||||
|
std::vector<BPFRef> quic_bpf_refs_;
|
||||||
|
# endif // HAVE_LIBBPF
|
||||||
|
std::shared_ptr<QUICKeyingMaterials> quic_keying_materials_;
|
||||||
|
std::vector<SSL_CTX *> quic_all_ssl_ctx_;
|
||||||
|
std::vector<std::vector<SSL_CTX *>> quic_indexed_ssl_ctx_;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
OCSPUpdateContext ocsp_;
|
OCSPUpdateContext ocsp_;
|
||||||
std::mt19937 &gen_;
|
std::mt19937 &gen_;
|
||||||
// ev_loop for each worker
|
// ev_loop for each worker
|
||||||
@@ -203,6 +288,9 @@ private:
|
|||||||
// Otherwise, nullptr and workers_ has instances of Worker instead.
|
// Otherwise, nullptr and workers_ has instances of Worker instead.
|
||||||
std::unique_ptr<Worker> single_worker_;
|
std::unique_ptr<Worker> single_worker_;
|
||||||
std::unique_ptr<tls::CertLookupTree> cert_tree_;
|
std::unique_ptr<tls::CertLookupTree> cert_tree_;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
std::unique_ptr<tls::CertLookupTree> quic_cert_tree_;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
std::unique_ptr<MemcachedDispatcher> tls_ticket_key_memcached_dispatcher_;
|
std::unique_ptr<MemcachedDispatcher> tls_ticket_key_memcached_dispatcher_;
|
||||||
// Current TLS session ticket keys. Note that TLS connection does
|
// Current TLS session ticket keys. Note that TLS connection does
|
||||||
// not refer to this field directly. They use TicketKeys object in
|
// not refer to this field directly. They use TicketKeys object in
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public:
|
|||||||
int on_write(int fd);
|
int on_write(int fd);
|
||||||
int on_timeout();
|
int on_timeout();
|
||||||
// Calls this function when DNS query finished.
|
// Calls this function when DNS query finished.
|
||||||
void on_result(int staus, hostent *hostent);
|
void on_result(int status, hostent *hostent);
|
||||||
void reset_timeout();
|
void reset_timeout();
|
||||||
|
|
||||||
void start_rev(int fd);
|
void start_rev(int fd);
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ void downstream_wtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|||||||
|
|
||||||
// upstream could be nullptr for unittests
|
// upstream could be nullptr for unittests
|
||||||
Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
||||||
int32_t stream_id)
|
int64_t stream_id)
|
||||||
: dlnext(nullptr),
|
: dlnext(nullptr),
|
||||||
dlprev(nullptr),
|
dlprev(nullptr),
|
||||||
response_sent_body_length(0),
|
response_sent_body_length(0),
|
||||||
@@ -145,7 +145,8 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
|||||||
accesslog_written_(false),
|
accesslog_written_(false),
|
||||||
new_affinity_cookie_(false),
|
new_affinity_cookie_(false),
|
||||||
blocked_request_data_eof_(false),
|
blocked_request_data_eof_(false),
|
||||||
expect_100_continue_(false) {
|
expect_100_continue_(false),
|
||||||
|
stop_reading_(false) {
|
||||||
|
|
||||||
auto &timeoutconf = get_config()->http2.timeout;
|
auto &timeoutconf = get_config()->http2.timeout;
|
||||||
|
|
||||||
@@ -164,6 +165,9 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
|||||||
downstream_wtimer_.data = this;
|
downstream_wtimer_.data = this;
|
||||||
|
|
||||||
rcbufs_.reserve(32);
|
rcbufs_.reserve(32);
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
rcbufs3_.reserve(32);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
}
|
}
|
||||||
|
|
||||||
Downstream::~Downstream() {
|
Downstream::~Downstream() {
|
||||||
@@ -203,6 +207,12 @@ Downstream::~Downstream() {
|
|||||||
// explicitly.
|
// explicitly.
|
||||||
dconn_.reset();
|
dconn_.reset();
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
for (auto rcbuf : rcbufs3_) {
|
||||||
|
nghttp3_rcbuf_decref(rcbuf);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
for (auto rcbuf : rcbufs_) {
|
for (auto rcbuf : rcbufs_) {
|
||||||
nghttp2_rcbuf_decref(rcbuf);
|
nghttp2_rcbuf_decref(rcbuf);
|
||||||
}
|
}
|
||||||
@@ -605,9 +615,9 @@ void Downstream::reset_upstream(Upstream *upstream) {
|
|||||||
|
|
||||||
Upstream *Downstream::get_upstream() const { return upstream_; }
|
Upstream *Downstream::get_upstream() const { return upstream_; }
|
||||||
|
|
||||||
void Downstream::set_stream_id(int32_t stream_id) { stream_id_ = stream_id; }
|
void Downstream::set_stream_id(int64_t stream_id) { stream_id_ = stream_id; }
|
||||||
|
|
||||||
int32_t Downstream::get_stream_id() const { return stream_id_; }
|
int64_t Downstream::get_stream_id() const { return stream_id_; }
|
||||||
|
|
||||||
void Downstream::set_request_state(DownstreamState state) {
|
void Downstream::set_request_state(DownstreamState state) {
|
||||||
request_state_ = state;
|
request_state_ = state;
|
||||||
@@ -886,7 +896,8 @@ bool Downstream::get_non_final_response() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::supports_non_final_response() const {
|
bool Downstream::supports_non_final_response() const {
|
||||||
return req_.http_major == 2 || (req_.http_major == 1 && req_.http_minor == 1);
|
return req_.http_major == 3 || req_.http_major == 2 ||
|
||||||
|
(req_.http_major == 1 && req_.http_minor == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::get_upgraded() const { return upgraded_; }
|
bool Downstream::get_upgraded() const { return upgraded_; }
|
||||||
@@ -904,11 +915,11 @@ StringRef Downstream::get_http2_settings() const {
|
|||||||
return http2_settings->value;
|
return http2_settings->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::set_downstream_stream_id(int32_t stream_id) {
|
void Downstream::set_downstream_stream_id(int64_t stream_id) {
|
||||||
downstream_stream_id_ = stream_id;
|
downstream_stream_id_ = stream_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Downstream::get_downstream_stream_id() const {
|
int64_t Downstream::get_downstream_stream_id() const {
|
||||||
return downstream_stream_id_;
|
return downstream_stream_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -937,7 +948,8 @@ bool Downstream::expect_response_trailer() const {
|
|||||||
// In HTTP/2, if final response HEADERS does not bear END_STREAM it
|
// In HTTP/2, if final response HEADERS does not bear END_STREAM it
|
||||||
// is possible trailer fields might come, regardless of request
|
// is possible trailer fields might come, regardless of request
|
||||||
// method or status code.
|
// method or status code.
|
||||||
return !resp_.headers_only && resp_.http_major == 2;
|
return !resp_.headers_only &&
|
||||||
|
(resp_.http_major == 3 || resp_.http_major == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1115,11 +1127,11 @@ DefaultMemchunks Downstream::pop_response_buf() {
|
|||||||
return std::move(response_buf_);
|
return std::move(response_buf_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::set_assoc_stream_id(int32_t stream_id) {
|
void Downstream::set_assoc_stream_id(int64_t stream_id) {
|
||||||
assoc_stream_id_ = stream_id;
|
assoc_stream_id_ = stream_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Downstream::get_assoc_stream_id() const { return assoc_stream_id_; }
|
int64_t Downstream::get_assoc_stream_id() const { return assoc_stream_id_; }
|
||||||
|
|
||||||
BlockAllocator &Downstream::get_block_allocator() { return balloc_; }
|
BlockAllocator &Downstream::get_block_allocator() { return balloc_; }
|
||||||
|
|
||||||
@@ -1128,6 +1140,13 @@ void Downstream::add_rcbuf(nghttp2_rcbuf *rcbuf) {
|
|||||||
rcbufs_.push_back(rcbuf);
|
rcbufs_.push_back(rcbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
void Downstream::add_rcbuf(nghttp3_rcbuf *rcbuf) {
|
||||||
|
nghttp3_rcbuf_incref(rcbuf);
|
||||||
|
rcbufs3_.push_back(rcbuf);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
void Downstream::set_downstream_addr_group(
|
void Downstream::set_downstream_addr_group(
|
||||||
const std::shared_ptr<DownstreamAddrGroup> &group) {
|
const std::shared_ptr<DownstreamAddrGroup> &group) {
|
||||||
group_ = group;
|
group_ = group;
|
||||||
@@ -1169,4 +1188,8 @@ bool Downstream::get_expect_100_continue() const {
|
|||||||
return expect_100_continue_;
|
return expect_100_continue_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Downstream::get_stop_reading() const { return stop_reading_; }
|
||||||
|
|
||||||
|
void Downstream::set_stop_reading(bool f) { stop_reading_ = f; }
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|||||||
@@ -38,6 +38,10 @@
|
|||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
# include <nghttp3/nghttp3.h>
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
#include "llhttp.h"
|
#include "llhttp.h"
|
||||||
|
|
||||||
#include "shrpx_io_control.h"
|
#include "shrpx_io_control.h"
|
||||||
@@ -319,20 +323,20 @@ enum class DispatchState {
|
|||||||
|
|
||||||
class Downstream {
|
class Downstream {
|
||||||
public:
|
public:
|
||||||
Downstream(Upstream *upstream, MemchunkPool *mcpool, int32_t stream_id);
|
Downstream(Upstream *upstream, MemchunkPool *mcpool, int64_t stream_id);
|
||||||
~Downstream();
|
~Downstream();
|
||||||
void reset_upstream(Upstream *upstream);
|
void reset_upstream(Upstream *upstream);
|
||||||
Upstream *get_upstream() const;
|
Upstream *get_upstream() const;
|
||||||
void set_stream_id(int32_t stream_id);
|
void set_stream_id(int64_t stream_id);
|
||||||
int32_t get_stream_id() const;
|
int64_t get_stream_id() const;
|
||||||
void set_assoc_stream_id(int32_t stream_id);
|
void set_assoc_stream_id(int64_t stream_id);
|
||||||
int32_t get_assoc_stream_id() const;
|
int64_t get_assoc_stream_id() const;
|
||||||
void pause_read(IOCtrlReason reason);
|
void pause_read(IOCtrlReason reason);
|
||||||
int resume_read(IOCtrlReason reason, size_t consumed);
|
int resume_read(IOCtrlReason reason, size_t consumed);
|
||||||
void force_resume_read();
|
void force_resume_read();
|
||||||
// Set stream ID for downstream HTTP2 connection.
|
// Set stream ID for downstream HTTP2 connection.
|
||||||
void set_downstream_stream_id(int32_t stream_id);
|
void set_downstream_stream_id(int64_t stream_id);
|
||||||
int32_t get_downstream_stream_id() const;
|
int64_t get_downstream_stream_id() const;
|
||||||
|
|
||||||
int attach_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
|
int attach_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
|
||||||
void detach_downstream_connection();
|
void detach_downstream_connection();
|
||||||
@@ -488,6 +492,9 @@ public:
|
|||||||
BlockAllocator &get_block_allocator();
|
BlockAllocator &get_block_allocator();
|
||||||
|
|
||||||
void add_rcbuf(nghttp2_rcbuf *rcbuf);
|
void add_rcbuf(nghttp2_rcbuf *rcbuf);
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
void add_rcbuf(nghttp3_rcbuf *rcbuf);
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
void
|
void
|
||||||
set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group);
|
set_downstream_addr_group(const std::shared_ptr<DownstreamAddrGroup> &group);
|
||||||
@@ -513,6 +520,9 @@ public:
|
|||||||
|
|
||||||
bool get_expect_100_continue() const;
|
bool get_expect_100_continue() const;
|
||||||
|
|
||||||
|
bool get_stop_reading() const;
|
||||||
|
void set_stop_reading(bool f);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EVENT_ERROR = 0x1,
|
EVENT_ERROR = 0x1,
|
||||||
EVENT_TIMEOUT = 0x2,
|
EVENT_TIMEOUT = 0x2,
|
||||||
@@ -527,6 +537,9 @@ private:
|
|||||||
BlockAllocator balloc_;
|
BlockAllocator balloc_;
|
||||||
|
|
||||||
std::vector<nghttp2_rcbuf *> rcbufs_;
|
std::vector<nghttp2_rcbuf *> rcbufs_;
|
||||||
|
#ifdef ENABLE_HTTP3
|
||||||
|
std::vector<nghttp3_rcbuf *> rcbufs3_;
|
||||||
|
#endif // ENABLE_HTTP3
|
||||||
|
|
||||||
Request req_;
|
Request req_;
|
||||||
Response resp_;
|
Response resp_;
|
||||||
@@ -566,12 +579,12 @@ private:
|
|||||||
// How many times we tried in backend connection
|
// How many times we tried in backend connection
|
||||||
size_t num_retry_;
|
size_t num_retry_;
|
||||||
// The stream ID in frontend connection
|
// The stream ID in frontend connection
|
||||||
int32_t stream_id_;
|
int64_t stream_id_;
|
||||||
// The associated stream ID in frontend connection if this is pushed
|
// The associated stream ID in frontend connection if this is pushed
|
||||||
// stream.
|
// stream.
|
||||||
int32_t assoc_stream_id_;
|
int64_t assoc_stream_id_;
|
||||||
// stream ID in backend connection
|
// stream ID in backend connection
|
||||||
int32_t downstream_stream_id_;
|
int64_t downstream_stream_id_;
|
||||||
// RST_STREAM error_code from downstream HTTP2 connection
|
// RST_STREAM error_code from downstream HTTP2 connection
|
||||||
uint32_t response_rst_stream_error_code_;
|
uint32_t response_rst_stream_error_code_;
|
||||||
// An affinity cookie value.
|
// An affinity cookie value.
|
||||||
@@ -606,6 +619,7 @@ private:
|
|||||||
bool blocked_request_data_eof_;
|
bool blocked_request_data_eof_;
|
||||||
// true if request contains "expect: 100-continue" header field.
|
// true if request contains "expect: 100-continue" header field.
|
||||||
bool expect_100_continue_;
|
bool expect_100_continue_;
|
||||||
|
bool stop_reading_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
virtual int on_write() = 0;
|
virtual int on_write() = 0;
|
||||||
virtual int on_timeout() { return 0; }
|
virtual int on_timeout() { return 0; }
|
||||||
|
|
||||||
virtual void on_upstream_change(Upstream *uptream) = 0;
|
virtual void on_upstream_change(Upstream *upstream) = 0;
|
||||||
|
|
||||||
// true if this object is poolable.
|
// true if this object is poolable.
|
||||||
virtual bool poolable() const = 0;
|
virtual bool poolable() const = 0;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user