tests: add HTTP/3 test case, custom location for proper nghttpx

- adding support for HTTP/3 test cases via a nghttpx server that is
  build with ngtcp2 and nghttp3.
- test2500 is the first test case, performing a simple GET.
- nghttpx is checked for support and the 'feature' nghttpx-h3
  is set accordingly. test2500 will only run, when supported.
- a specific nghttpx location can be given in the environment
  variable NGHTTPX or via the configure option
    --with-test-nghttpx=<path>

Extend NGHTTPX config to H2 tests as well

* use $ENV{NGHTTPX} and the configured default also in http2 server starts
* always provide the empty test/nghttpx.conf to nghttpx. as it defaults to
  reading /etc/nghttpx/nghttpx.conf otherwise.

Added nghttpx to CI ngtcp2 jobs to run h3 tests.

Closes #9031
This commit is contained in:
Stefan Eissing 2022-11-29 16:41:15 +01:00 committed by Daniel Stenberg
parent 0186ec41b1
commit ca15b7512e
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
16 changed files with 582 additions and 24 deletions

View File

@ -28,9 +28,21 @@ jobs:
matrix: matrix:
build: build:
- name: gnutls - name: gnutls
install: nettle-dev libp11-kit-dev libtspi-dev libunistring-dev guile-2.2-dev libtasn1-bin libtasn1-6-dev libidn2-0-dev gawk gperf libtss2-dev dns-root-data bison gtk-doc-tools texinfo texlive texlive-extra-utils autopoint libev-dev install: >-
configure: LDFLAGS="-Wl,-rpath,$HOME/all/lib" --with-gnutls=$HOME/all --enable-debug libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libev-dev libc-ares-dev
gnutls-configure: --with-included-libtasn1 --with-included-unistring --disable-guile --disable-doc --disable-tests nettle-dev libp11-kit-dev libtspi-dev libunistring-dev guile-2.2-dev libtasn1-bin
libtasn1-6-dev libidn2-0-dev gawk gperf libtss2-dev dns-root-data bison gtk-doc-tools
texinfo texlive texlive-extra-utils autopoint libev-dev
configure: >-
PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" LDFLAGS="-Wl,-rpath,$HOME/all/lib"
--with-ngtcp2=$HOME/all --enable-warnings --enable-werror --enable-debug
--with-test-nghttpx="$HOME/all/bin/nghttpx"
ngtcp2-configure: >-
--prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
gnutls-configure: >-
PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" LDFLAGS="-Wl,-rpath,$HOME/all/lib -L$HOME/all/lib"
--with-included-libtasn1 --with-included-unistring
--disable-guile --disable-doc --disable-tests --disable-tools
steps: steps:
- run: | - run: |
@ -39,6 +51,13 @@ jobs:
sudo python3 -m pip install impacket sudo python3 -m pip install impacket
name: 'install prereqs and impacket' name: 'install prereqs and impacket'
- run: |
git clone --depth=1 -b openssl-3.0.7+quic https://github.com/quictls/openssl
cd openssl
./config --prefix=$HOME/all --libdir=$HOME/all/lib
make install_sw
name: 'install quictls'
- run: | - run: |
git clone --depth=1 https://gitlab.com/gnutls/nettle.git git clone --depth=1 https://gitlab.com/gnutls/nettle.git
cd nettle cd nettle
@ -51,7 +70,7 @@ jobs:
git clone --depth=1 -b 3.7.7 https://github.com/gnutls/gnutls.git git clone --depth=1 -b 3.7.7 https://github.com/gnutls/gnutls.git
cd gnutls cd gnutls
./bootstrap ./bootstrap
./configure PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" LDFLAGS="-Wl,-rpath,$HOME/all/lib -L$HOME/all/lib" --prefix=$HOME/all ${{ matrix.build.gnutls-configure }} --disable-tools ./configure ${{ matrix.build.gnutls-configure }} --prefix=$HOME/all
make install make install
name: 'install gnutls' name: 'install gnutls'
@ -59,7 +78,7 @@ jobs:
git clone --depth=1 https://github.com/ngtcp2/nghttp3 git clone --depth=1 https://github.com/ngtcp2/nghttp3
cd nghttp3 cd nghttp3
autoreconf -fi autoreconf -fi
./configure --prefix=$HOME/all --enable-lib-only ./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
make install make install
name: 'install nghttp3' name: 'install nghttp3'
@ -67,16 +86,24 @@ jobs:
git clone --depth=1 https://github.com/ngtcp2/ngtcp2 git clone --depth=1 https://github.com/ngtcp2/ngtcp2
cd ngtcp2 cd ngtcp2
autoreconf -fi autoreconf -fi
./configure PKG_CONFIG_PATH=$HOME/all/lib/pkgconfig LDFLAGS="-Wl,-rpath,$HOME/all/lib" --prefix=$HOME/all --enable-lib-only --with-gnutls=$HOME/all ./configure ${{ matrix.build.ngtcp2-configure }} --with-openssl --with-gnutls
make install make install
name: 'install ngtcp2' name: 'install ngtcp2'
- run: |
git clone --depth=1 https://github.com/nghttp2/nghttp2
cd nghttp2
autoreconf -fi
./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-http3
make install
name: 'install nghttp2'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: autoreconf -fi - run: autoreconf -fi
name: 'autoreconf' name: 'autoreconf'
- run: ./configure --enable-warnings --enable-werror ${{ matrix.build.configure }} - run: ./configure --with-gnutls=$HOME/all ${{ matrix.build.configure }}
name: 'configure' name: 'configure'
- run: make V=1 - run: make V=1

98
.github/workflows/ngtcp2-quictls.yml vendored Normal file
View File

@ -0,0 +1,98 @@
# Copyright (C) 2000 - 2022 Daniel Stenberg, <daniel@haxx.se>, et al.
#
# SPDX-License-Identifier: curl
name: ngtcp2
on:
push:
branches:
- master
- '*/ci'
pull_request:
branches:
- master
concurrency:
# Hardcoded workflow filename as workflow name above is just Linux again
group: ngtcp2-openssl-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
jobs:
autotools:
name: ${{ matrix.build.name }}
runs-on: 'ubuntu-latest'
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
build:
- name: quictls
install: >-
libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libev-dev libc-ares-dev
configure: >-
PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" LDFLAGS="-Wl,-rpath,$HOME/all/lib"
--with-ngtcp2=$HOME/all --enable-warnings --enable-werror --enable-debug
--with-test-nghttpx="$HOME/all/bin/nghttpx"
ngtcp2-configure: >-
--prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
steps:
- run: |
sudo apt-get update
sudo apt-get install libtool autoconf automake pkg-config stunnel4 ${{ matrix.build.install }}
sudo python3 -m pip install impacket
name: 'install prereqs and impacket'
- run: |
git clone --depth=1 -b openssl-3.0.7+quic https://github.com/quictls/openssl
cd openssl
./config --prefix=$HOME/all --libdir=$HOME/all/lib
make install_sw
name: 'install quictls'
- run: |
git clone --depth=1 https://github.com/ngtcp2/nghttp3
cd nghttp3
autoreconf -fi
./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
make install
name: 'install nghttp3'
- run: |
git clone --depth=1 https://github.com/ngtcp2/ngtcp2
cd ngtcp2
autoreconf -fi
./configure ${{ matrix.build.ngtcp2-configure }} --with-openssl
make install
name: 'install ngtcp2'
- run: |
git clone --depth=1 https://github.com/nghttp2/nghttp2
cd nghttp2
autoreconf -fi
./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-http3
make install
name: 'install nghttp2'
- uses: actions/checkout@v3
- run: autoreconf -fi
name: 'autoreconf'
- run: ./configure --with-openssl=$HOME/all ${{ matrix.build.configure }}
name: 'configure'
- run: make V=1
name: 'make'
- run: make V=1 examples
name: 'make examples'
- run: make V=1 -C tests
name: 'make tests'
- run: make V=1 test-ci
name: 'run tests'
env:
TFLAGS: "${{ matrix.build.tflags }}"

View File

@ -28,9 +28,17 @@ jobs:
matrix: matrix:
build: build:
- name: wolfssl - name: wolfssl
install: install: >-
configure: LDFLAGS="-Wl,-rpath,$HOME/all/lib" --with-wolfssl=$HOME/all --enable-debug libpsl-dev libbrotli-dev libzstd-dev zlib1g-dev libev-dev libc-ares-dev
wolfssl-configure: --enable-quic --enable-session-ticket --enable-earlydata --enable-psk --enable-harden --enable-altcertchains configure: >-
PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" LDFLAGS="-Wl,-rpath,$HOME/all/lib"
--with-ngtcp2=$HOME/all --enable-warnings --enable-werror --enable-debug
--with-test-nghttpx="$HOME/all/bin/nghttpx"
ngtcp2-configure: >-
--prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
wolfssl-configure: >-
--enable-quic --enable-session-ticket --enable-earlydata --enable-psk
--enable-harden --enable-altcertchains
steps: steps:
- run: | - run: |
@ -48,27 +56,42 @@ jobs:
name: 'install wolfssl' name: 'install wolfssl'
- run: | - run: |
git clone https://github.com/ngtcp2/nghttp3 git clone --depth=1 -b openssl-3.0.7+quic https://github.com/quictls/openssl
cd openssl
./config --prefix=$HOME/all --libdir=$HOME/all/lib
make install_sw
name: 'install quictls'
- run: |
git clone --depth=1 https://github.com/ngtcp2/nghttp3
cd nghttp3 cd nghttp3
autoreconf -fi autoreconf -fi
./configure --prefix=$HOME/all --enable-lib-only ./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-lib-only
make install make install
name: 'install nghttp3' name: 'install nghttp3'
- run: | - run: |
git clone https://github.com/ngtcp2/ngtcp2 git clone --depth=1 https://github.com/ngtcp2/ngtcp2
cd ngtcp2 cd ngtcp2
autoreconf -fi autoreconf -fi
./configure PKG_CONFIG_PATH=$HOME/all/lib/pkgconfig LDFLAGS="-Wl,-rpath,$HOME/all/lib" --prefix=$HOME/all --enable-lib-only --with-wolfssl=$HOME/all ./configure ${{ matrix.build.ngtcp2-configure }} --with-openssl --with-wolfssl
make install make install
name: 'install ngtcp2' name: 'install ngtcp2'
- run: |
git clone --depth=1 https://github.com/nghttp2/nghttp2
cd nghttp2
autoreconf -fi
./configure --prefix=$HOME/all PKG_CONFIG_PATH="$HOME/all/lib/pkgconfig" --enable-http3
make install
name: 'install nghttp2'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- run: autoreconf -fi - run: autoreconf -fi
name: 'autoreconf' name: 'autoreconf'
- run: ./configure --enable-warnings --enable-werror ${{ matrix.build.configure }} - run: ./configure --with-wolfssl=$HOME/all ${{ matrix.build.configure }}
name: 'configure' name: 'configure'
- run: make V=1 - run: make V=1

2
.gitignore vendored
View File

@ -64,3 +64,5 @@ curl_fuzzer
curl_fuzzer_seed_corpus.zip curl_fuzzer_seed_corpus.zip
libstandaloneengine.a libstandaloneengine.a
tests/string tests/string
tests/config

View File

@ -301,6 +301,16 @@ AS_HELP_STRING([--with-nss=PATH],[where to look for NSS, PATH points to the inst
fi fi
) )
TEST_NGHTTPX=nghttpx
AC_ARG_WITH(test-nghttpx,dnl
AS_HELP_STRING([--with-test-nghttpx=PATH],[where to find nghttpx for testing]),
TEST_NGHTTPX=$withval
if test X"$OPT_TEST_NGHTTPX" = "Xno" ; then
TEST_NGHTTPX=""
fi
)
AC_SUBST(TEST_NGHTTPX)
dnl If no TLS choice has been made, check if it was explicitly disabled or dnl If no TLS choice has been made, check if it was explicitly disabled or
dnl error out to force the user to decide. dnl error out to force the user to decide.
if test -z "$TLSCHOICE"; then if test -z "$TLSCHOICE"; then
@ -4568,6 +4578,7 @@ AC_CONFIG_FILES([Makefile \
lib/libcurl.vers \ lib/libcurl.vers \
lib/libcurl.plist \ lib/libcurl.plist \
tests/Makefile \ tests/Makefile \
tests/config \
tests/certs/Makefile \ tests/certs/Makefile \
tests/certs/scripts/Makefile \ tests/certs/scripts/Makefile \
tests/data/Makefile \ tests/data/Makefile \

1
tests/.gitignore vendored
View File

@ -24,3 +24,4 @@ runtests.pdf
testcurl.html testcurl.html
testcurl.pdf testcurl.pdf
*.port *.port
config

View File

@ -16,7 +16,7 @@ SPDX-License-Identifier: curl
- diff (when a test fails, a diff is shown) - diff (when a test fails, a diff is shown)
- stunnel (for HTTPS and FTPS tests) - stunnel (for HTTPS and FTPS tests)
- OpenSSH or SunSSH (for SCP, SFTP and SOCKS4/5 tests) - OpenSSH or SunSSH (for SCP, SFTP and SOCKS4/5 tests)
- nghttpx (for HTTP/2 tests) - nghttpx (for HTTP/2 and HTTP/3 tests)
- nroff (for --manual tests) - nroff (for --manual tests)
- An available `en_US.UTF-8` locale - An available `en_US.UTF-8` locale
@ -70,6 +70,11 @@ SPDX-License-Identifier: curl
The HTTP server supports listening on a Unix domain socket, the default The HTTP server supports listening on a Unix domain socket, the default
location is 'http.sock'. location is 'http.sock'.
For HTTP/2 and HTTP/3 testing an installed `nghttpx` is used. HTTP/3
tests check if nghttpx supports the protocol. To override the nghttpx
used, set the environment variable `NGHTTPX`. The default can also be
changed by specifying `--with-test-nghttpx=<path>` as argument to `configure`.
### Run ### Run
`./configure && make && make test`. This builds the test suite support code `./configure && make && make test`. This builds the test suite support code

24
tests/config.in Normal file
View File

@ -0,0 +1,24 @@
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
NGHTTPX: @TEST_NGHTTPX@

View File

@ -243,6 +243,8 @@ test2200 test2201 test2202 test2203 test2204 test2205 \
\ \
test2300 test2301 test2302 test2303 \ test2300 test2301 test2302 test2303 \
\ \
test2500 \
\
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \ test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \ test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \
test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \ test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \

78
tests/data/test2500 Normal file
View File

@ -0,0 +1,78 @@
<testcase http-crlf="yes">
<info>
<keywords>
HTTP
HTTP GET
HTTP/3
</keywords>
</info>
#
# Server-side
<reply>
<data nocheck="yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</data>
</reply>
#
# Client-side
<client>
<features>
http/3
nghttpx-h3
</features>
<server>
http
http/3
</server>
<name>
HTTP/3 GET:
</name>
<command>
--cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --http3 --resolve localhost:%HTTP3PORT:%HOSTIP https://localhost:%HTTP3PORT/%TESTNUMBER
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<strip>
^X-Forwarded-Proto:.*
^Via:.*
</strip>
<protocol>
GET https://localhost:%HTTP3PORT/%TESTNUMBER HTTP/1.1
Host: localhost:%HTTP3PORT
User-Agent: curl/%VERSION
Accept: */*
</protocol>
<stdout crlf="yes">
HTTP/3 200
date: Tue, 09 Nov 2010 14:49:00 GMT
last-modified: Tue, 13 Jun 2000 12:10:00 GMT
etag: "21025-dc7-39462498"
accept-ranges: bytes
content-length: 6
content-type: text/html
funny-head: yesyes
via: 1.1 nghttpx
-foo-
</stdout>
<stripfile>
s/^server: nghttpx.*\r?\n//
</stripfile>
</verify>
</testcase>

View File

@ -41,6 +41,21 @@ sub decode_hex {
return $s; return $s;
} }
sub testcaseattr {
my %hash;
for(@xml) {
if(($_ =~ /^ *\<testcase ([^>]*)/)) {
my $attr=$1;
while($attr =~ s/ *([^=]*)= *(\"([^\"]*)\"|([^\> ]*))//) {
my ($var, $cont)=($1, $2);
$cont =~ s/^\"(.*)\"$/$1/;
$hash{$var}=$cont;
}
}
}
return %hash;
}
sub getpartattr { sub getpartattr {
# if $part is undefined (ie only one argument) then # if $part is undefined (ie only one argument) then
# return the attributes of the section # return the attributes of the section

View File

@ -31,6 +31,7 @@ my $logfile = "log/http2.log";
my $nghttpx = "nghttpx"; my $nghttpx = "nghttpx";
my $listenport = 9015; my $listenport = 9015;
my $connect = "127.0.0.1,8990"; my $connect = "127.0.0.1,8990";
my $conf = "nghttpx.conf";
#*************************************************************************** #***************************************************************************
# Process command line options # Process command line options
@ -70,6 +71,12 @@ while(@ARGV) {
shift @ARGV; shift @ARGV;
} }
} }
elsif($ARGV[0] eq '--conf') {
if($ARGV[1]) {
$conf = $ARGV[1];
shift @ARGV;
}
}
else { else {
print STDERR "\nWarning: http2-server.pl unknown parameter: $ARGV[0]\n"; print STDERR "\nWarning: http2-server.pl unknown parameter: $ARGV[0]\n";
} }
@ -80,6 +87,7 @@ my $cmdline="$nghttpx --backend=$connect ".
"--frontend=\"*,$listenport;no-tls\" ". "--frontend=\"*,$listenport;no-tls\" ".
"--log-level=INFO ". "--log-level=INFO ".
"--pid-file=$pidfile ". "--pid-file=$pidfile ".
"--conf=$conf ".
"--errorlog-file=$logfile"; "--errorlog-file=$logfile";
print "RUN: $cmdline\n" if($verbose); print "RUN: $cmdline\n" if($verbose);
system("$cmdline 2>/dev/null"); system("$cmdline 2>/dev/null");

111
tests/http3-server.pl Normal file
View File

@ -0,0 +1,111 @@
#!/usr/bin/env perl
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 2016 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
#***************************************************************************
# This script invokes nghttpx properly to have it serve HTTP/3 for us.
# nghttpx runs as a proxy in front of our "actual" HTTP/1 server.
use Cwd;
use Cwd 'abs_path';
my $pidfile = "log/nghttpx.pid";
my $logfile = "log/http3.log";
my $nghttpx = "nghttpx";
my $listenport = 9015;
my $connect = "127.0.0.1,8990";
my $cert = "Server-localhost-sv";
my $conf = "nghttpx.conf";
#***************************************************************************
# Process command line options
#
while(@ARGV) {
if($ARGV[0] eq '--verbose') {
$verbose = 1;
}
elsif($ARGV[0] eq '--pidfile') {
if($ARGV[1]) {
$pidfile = $ARGV[1];
shift @ARGV;
}
}
elsif($ARGV[0] eq '--nghttpx') {
if($ARGV[1]) {
$nghttpx = $ARGV[1];
shift @ARGV;
}
}
elsif($ARGV[0] eq '--port') {
if($ARGV[1]) {
$listenport = $ARGV[1];
shift @ARGV;
}
}
elsif($ARGV[0] eq '--connect') {
if($ARGV[1]) {
$connect = $ARGV[1];
$connect =~ s/:/,/;
shift @ARGV;
}
}
elsif($ARGV[0] eq '--cert') {
if($ARGV[1]) {
$cert = $ARGV[1];
shift @ARGV;
}
}
elsif($ARGV[0] eq '--logfile') {
if($ARGV[1]) {
$logfile = $ARGV[1];
shift @ARGV;
}
}
elsif($ARGV[0] eq '--conf') {
if($ARGV[1]) {
$conf = $ARGV[1];
shift @ARGV;
}
}
else {
print STDERR "\nWarning: http3-server.pl unknown parameter: $ARGV[0]\n";
}
shift @ARGV;
}
my $path = getcwd();
my $srcdir = $path;
$certfile = "$srcdir/certs/$cert.pem";
$keyfile = "$srcdir/certs/$cert.key";
$certfile = abs_path($certfile);
$keyfile = abs_path($keyfile);
my $cmdline="$nghttpx --http2-proxy --backend=$connect ".
"--frontend=\"*,$listenport;quic\" ".
"--log-level=INFO ".
"--pid-file=$pidfile ".
"--errorlog-file=$logfile ".
"--conf=$conf ".
"$keyfile $certfile";
print "RUN: $cmdline\n" if($verbose);
system("$cmdline 2>/dev/null");

26
tests/nghttpx.conf Normal file
View File

@ -0,0 +1,26 @@
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
# nghttpx reads /etc/nghttpx/nghttpx.conf if we do not give it another one.
# This is what this otherwise empty file is for.

View File

@ -159,6 +159,7 @@ my $HTTPTLSPORT=$noport; # HTTP TLS (non-stunnel) server port
my $HTTPTLS6PORT=$noport; # HTTP TLS (non-stunnel) IPv6 server port my $HTTPTLS6PORT=$noport; # HTTP TLS (non-stunnel) IPv6 server port
my $HTTPPROXYPORT=$noport; # HTTP proxy port, when using CONNECT my $HTTPPROXYPORT=$noport; # HTTP proxy port, when using CONNECT
my $HTTP2PORT=$noport; # HTTP/2 server port my $HTTP2PORT=$noport; # HTTP/2 server port
my $HTTP3PORT=$noport; # HTTP/3 server port
my $DICTPORT=$noport; # DICT server port my $DICTPORT=$noport; # DICT server port
my $SMBPORT=$noport; # SMB server port my $SMBPORT=$noport; # SMB server port
my $SMBSPORT=$noport; # SMBS server port my $SMBSPORT=$noport; # SMBS server port
@ -262,6 +263,7 @@ my $has_charconv; # set if libcurl is built with CharConv support
my $has_tls_srp; # set if libcurl is built with TLS-SRP support my $has_tls_srp; # set if libcurl is built with TLS-SRP support
my $has_http2; # set if libcurl is built with HTTP2 support my $has_http2; # set if libcurl is built with HTTP2 support
my $has_h2c; # set if libcurl is built with h2c support my $has_h2c; # set if libcurl is built with h2c support
my $has_http3; # set if libcurl is built with HTTP3 support
my $has_httpsproxy; # set if libcurl is built with HTTPS-proxy support my $has_httpsproxy; # set if libcurl is built with HTTPS-proxy support
my $has_crypto; # set if libcurl is built with cryptographic support my $has_crypto; # set if libcurl is built with cryptographic support
my $has_cares; # set if built with c-ares my $has_cares; # set if built with c-ares
@ -315,7 +317,7 @@ my %ignored_keywords; # key words of tests to ignore results
my %enabled_keywords; # key words of tests to run my %enabled_keywords; # key words of tests to run
my %disabled; # disabled test cases my %disabled; # disabled test cases
my %ignored; # ignored results of test cases my %ignored; # ignored results of test cases
my $crlf_http = 0; # always convert HTTP heaaders to cr+lf
my $sshdid; # for socks server, ssh daemon version id my $sshdid; # for socks server, ssh daemon version id
my $sshdvernum; # for socks server, ssh daemon version number my $sshdvernum; # for socks server, ssh daemon version number
my $sshdverstr; # for socks server, ssh daemon version string my $sshdverstr; # for socks server, ssh daemon version string
@ -438,12 +440,36 @@ delete $ENV{'SSL_CERT_DIR'} if($ENV{'SSL_CERT_DIR'});
delete $ENV{'SSL_CERT_PATH'} if($ENV{'SSL_CERT_PATH'}); delete $ENV{'SSL_CERT_PATH'} if($ENV{'SSL_CERT_PATH'});
delete $ENV{'CURL_CA_BUNDLE'} if($ENV{'CURL_CA_BUNDLE'}); delete $ENV{'CURL_CA_BUNDLE'} if($ENV{'CURL_CA_BUNDLE'});
# provide defaults from our config file for ENV vars not explicitly
# set by the caller
if (open(my $fd, "< config")) {
while(my $line = <$fd>) {
next if ($line =~ /^#/);
chomp $line;
my ($name, $val) = split(/\s*:\s*/, $line, 2);
$ENV{$name} = $val if(!$ENV{$name});
}
close($fd);
}
# Check if we have nghttpx available and if it talks http/3
my $nghttpx_h3 = 0;
if (!$ENV{"NGHTTPX"}) {
$ENV{"NGHTTPX"} = checktestcmd("nghttpx");
}
if ($ENV{"NGHTTPX"}) {
my $nghttpx_version=join(' ', runclientoutput("$ENV{'NGHTTPX'} -v"));
$nghttpx_h3 = $nghttpx_version =~ /nghttp3\//;
logmsg "nghttpx_h3=$nghttpx_h3, output=$nghttpx_version\n";
}
####################################################################### #######################################################################
# Load serverpidfile and serverportfile hashes with file names for all # Load serverpidfile and serverportfile hashes with file names for all
# possible servers. # possible servers.
# #
sub init_serverpidfile_hash { sub init_serverpidfile_hash {
for my $proto (('ftp', 'gopher', 'http', 'imap', 'pop3', 'smtp', 'http/2')) { for my $proto (('ftp', 'gopher', 'http', 'imap', 'pop3', 'smtp', 'http/2', 'http/3')) {
for my $ssl (('', 's')) { for my $ssl (('', 's')) {
for my $ipvnum ((4, 6)) { for my $ipvnum ((4, 6)) {
for my $idnum ((1, 2, 3)) { for my $idnum ((1, 2, 3)) {
@ -468,7 +494,7 @@ sub init_serverpidfile_hash {
} }
} }
} }
for my $proto (('http', 'imap', 'pop3', 'smtp', 'http/2')) { for my $proto (('http', 'imap', 'pop3', 'smtp', 'http/2', 'http/3')) {
for my $ssl (('', 's')) { for my $ssl (('', 's')) {
my $serv = servername_id("$proto$ssl", "unix", 1); my $serv = servername_id("$proto$ssl", "unix", 1);
my $pidf = server_pidfilename("$proto$ssl", "unix", 1); my $pidf = server_pidfilename("$proto$ssl", "unix", 1);
@ -840,10 +866,11 @@ sub stopserver {
push @killservers, "socks${2}"; push @killservers, "socks${2}";
} }
if($server eq "http") { if($server eq "http") {
# since the http2 server is a proxy that needs to know about the # since the http2+3 server is a proxy that needs to know about the
# dynamic http port it too needs to get restarted when the http server # dynamic http port it too needs to get restarted when the http server
# is killed # is killed
push @killservers, "http/2"; push @killservers, "http/2";
push @killservers, "http/3";
} }
push @killservers, $server; push @killservers, $server;
# #
@ -1528,6 +1555,7 @@ sub runhttp2server {
$logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
$flags .= "--nghttpx \"$ENV{'NGHTTPX'}\" ";
$flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
$flags .= "--connect $HOSTIP:$HTTPPORT "; $flags .= "--connect $HOSTIP:$HTTPPORT ";
$flags .= $verbose_flag if($debugprotocol); $flags .= $verbose_flag if($debugprotocol);
@ -1561,6 +1589,76 @@ sub runhttp2server {
return ($http2pid, $pid2, $port); return ($http2pid, $pid2, $port);
} }
#######################################################################
# start the http3 server
#
sub runhttp3server {
my ($verbose, $cert) = @_;
my $server;
my $srvrname;
my $pidfile;
my $logfile;
my $flags = "";
my $proto="http/3";
my $ipvnum = 4;
my $idnum = 0;
my $exe = "$perl $srcdir/http3-server.pl";
my $verbose_flag = "--verbose ";
$server = servername_id($proto, $ipvnum, $idnum);
$pidfile = $serverpidfile{$server};
# don't retry if the server doesn't work
if ($doesntrun{$pidfile}) {
return (0, 0, 0);
}
my $pid = processexists($pidfile);
if($pid > 0) {
stopserver($server, "$pid");
}
unlink($pidfile) if(-f $pidfile);
$srvrname = servername_str($proto, $ipvnum, $idnum);
$logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum);
$flags .= "--nghttpx \"$ENV{'NGHTTPX'}\" ";
$flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" ";
$flags .= "--connect $HOSTIP:$HTTPPORT ";
$flags .= "--cert \"$cert\" " if($cert);
$flags .= $verbose_flag if($debugprotocol);
my ($http3pid, $pid3);
my $port = 24113;
for(1 .. 10) {
$port += int(rand(900));
my $aflags = "--port $port $flags";
my $cmd = "$exe $aflags";
($http3pid, $pid3) = startnew($cmd, $pidfile, 15, 0);
if($http3pid <= 0 || !pidexists($http3pid)) {
# it is NOT alive
stopserver($server, "$pid3");
$doesntrun{$pidfile} = 1;
$http3pid = $pid3 = 0;
next;
}
$doesntrun{$pidfile} = 0;
if($verbose) {
logmsg "RUN: $srvrname server PID $http3pid port $port\n";
}
last;
}
logmsg "RUN: failed to start the $srvrname server\n" if(!$http3pid);
return ($http3pid, $pid3, $port);
}
####################################################################### #######################################################################
# start the http server # start the http server
# #
@ -2899,6 +2997,7 @@ sub setupfeatures {
$feature{"h2c"} = $has_h2c; $feature{"h2c"} = $has_h2c;
$feature{"HSTS"} = $has_hsts; $feature{"HSTS"} = $has_hsts;
$feature{"http/2"} = $has_http2; $feature{"http/2"} = $has_http2;
$feature{"http/3"} = $has_http3;
$feature{"https-proxy"} = $has_httpsproxy; $feature{"https-proxy"} = $has_httpsproxy;
$feature{"hyper"} = $has_hyper; $feature{"hyper"} = $has_hyper;
$feature{"idn"} = $has_idn; $feature{"idn"} = $has_idn;
@ -2959,6 +3058,8 @@ sub setupfeatures {
$feature{"wakeup"} = 1; $feature{"wakeup"} = 1;
$feature{"headers-api"} = 1; $feature{"headers-api"} = 1;
$feature{"xattr"} = 1; $feature{"xattr"} = 1;
$feature{"nghttpx"} = !!$ENV{'NGHTTPX'};
$feature{"nghttpx-h3"} = !!$nghttpx_h3;
} }
####################################################################### #######################################################################
@ -3213,6 +3314,12 @@ sub checksystem {
push @protocols, 'http/2'; push @protocols, 'http/2';
} }
if($feat =~ /HTTP3/) {
# http3 enabled
$has_http3=1;
push @protocols, 'http/3';
}
if($feat =~ /HTTPS-proxy/) { if($feat =~ /HTTPS-proxy/) {
$has_httpsproxy=1; $has_httpsproxy=1;
@ -3400,6 +3507,7 @@ sub subVariables {
$$thing =~ s/${prefix}HTTPSPORT/$HTTPSPORT/g; $$thing =~ s/${prefix}HTTPSPORT/$HTTPSPORT/g;
$$thing =~ s/${prefix}HTTPSPROXYPORT/$HTTPSPROXYPORT/g; $$thing =~ s/${prefix}HTTPSPROXYPORT/$HTTPSPROXYPORT/g;
$$thing =~ s/${prefix}HTTP2PORT/$HTTP2PORT/g; $$thing =~ s/${prefix}HTTP2PORT/$HTTP2PORT/g;
$$thing =~ s/${prefix}HTTP3PORT/$HTTP3PORT/g;
$$thing =~ s/${prefix}HTTPPORT/$HTTPPORT/g; $$thing =~ s/${prefix}HTTPPORT/$HTTPPORT/g;
$$thing =~ s/${prefix}PROXYPORT/$HTTPPROXYPORT/g; $$thing =~ s/${prefix}PROXYPORT/$HTTPPROXYPORT/g;
$$thing =~ s/${prefix}MQTTPORT/$MQTTPORT/g; $$thing =~ s/${prefix}MQTTPORT/$MQTTPORT/g;
@ -3510,7 +3618,8 @@ sub subNewlines {
# as well, all test comparisons will survive without knowing about this # as well, all test comparisons will survive without knowing about this
# little quirk. # little quirk.
if(($$thing =~ /^HTTP\/(1.1|1.0|2) [1-5][^\x0d]*\z/) || if(($$thing =~ /^HTTP\/(1.1|1.0|2|3) [1-5][^\x0d]*\z/) ||
($$thing =~ /^(GET|POST|PUT|DELETE) \S+ HTTP\/\d+(\.\d+)?/) ||
(($$thing =~ /^[a-z0-9_-]+: [^\x0d]*\z/i) && (($$thing =~ /^[a-z0-9_-]+: [^\x0d]*\z/i) &&
# skip curl error messages # skip curl error messages
($$thing !~ /^curl: \(\d+\) /))) { ($$thing !~ /^curl: \(\d+\) /))) {
@ -3587,6 +3696,8 @@ sub prepro {
my (@entiretest) = @_; my (@entiretest) = @_;
my $show = 1; my $show = 1;
my @out; my @out;
my $crlf_header = ($crlf_http || ($has_hyper && ($keywords{"HTTP"}
|| $keywords{"HTTPS"})));
for my $s (@entiretest) { for my $s (@entiretest) {
my $f = $s; my $f = $s;
if($s =~ /^ *%if (.*)/) { if($s =~ /^ *%if (.*)/) {
@ -3612,8 +3723,7 @@ sub prepro {
if($show) { if($show) {
subVariables(\$s, $testnum, "%"); subVariables(\$s, $testnum, "%");
subBase64(\$s); subBase64(\$s);
subNewlines(\$s) if($has_hyper && ($keywords{"HTTP"} || subNewlines(\$s) if($crlf_header);
$keywords{"HTTPS"}));
push @out, $s; push @out, $s;
} }
} }
@ -3807,6 +3917,12 @@ sub singletest {
$why = serverfortest($testnum); $why = serverfortest($testnum);
} }
$crlf_http = 0;
my %hash = testcaseattr();
if($hash{'http-crlf'}) {
$crlf_http = 1;
}
# Save a preprocessed version of the entire test file. This allows more # Save a preprocessed version of the entire test file. This allows more
# "basic" test case readers to enjoy variable replacements. # "basic" test case readers to enjoy variable replacements.
my @entiretest = fulltest(); my @entiretest = fulltest();
@ -4958,6 +5074,17 @@ sub startservers {
$run{'gopher-ipv6'}="$pid $pid2"; $run{'gopher-ipv6'}="$pid $pid2";
} }
} }
elsif($what eq "http/3") {
if(!$run{'http/3'}) {
($pid, $pid2, $HTTP3PORT) = runhttp3server($verbose);
if($pid <= 0) {
return "failed starting HTTP/3 server";
}
logmsg sprintf ("* pid http/3 => %d %d\n", $pid, $pid2)
if($verbose);
$run{'http/3'}="$pid $pid2";
}
}
elsif($what eq "http/2") { elsif($what eq "http/2") {
if(!$run{'http/2'}) { if(!$run{'http/2'}) {
($pid, $pid2, $HTTP2PORT) = runhttp2server($verbose); ($pid, $pid2, $HTTP2PORT) = runhttp2server($verbose);

View File

@ -108,7 +108,7 @@ sub servername_str {
$proto = uc($proto) if($proto); $proto = uc($proto) if($proto);
die "unsupported protocol: '$proto'" unless($proto && die "unsupported protocol: '$proto'" unless($proto &&
($proto =~ /^(((FTP|HTTP|HTTP\/2|IMAP|POP3|GOPHER|SMTP|HTTP-PIPE)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|HTTPTLS|DICT|SMB|SMBS|TELNET|MQTT))$/)); ($proto =~ /^(((FTP|HTTP|HTTP\/2|HTTP\/3|IMAP|POP3|GOPHER|SMTP|HTTP-PIPE)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|HTTPTLS|DICT|SMB|SMBS|TELNET|MQTT))$/));
$ipver = (not $ipver) ? 'ipv4' : lc($ipver); $ipver = (not $ipver) ? 'ipv4' : lc($ipver);
die "unsupported IP version: '$ipver'" unless($ipver && die "unsupported IP version: '$ipver'" unless($ipver &&