mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 18:48:54 +08:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2324bdda1 | ||
|
|
6f0ae9d49a | ||
|
|
0389af5724 | ||
|
|
1766e25f45 | ||
|
|
323001238a | ||
|
|
91f062f873 | ||
|
|
650a0cfbff | ||
|
|
e6b8b3d1d3 | ||
|
|
a170023f23 | ||
|
|
4be4c0cddc | ||
|
|
0de9d374df | ||
|
|
0df199198a | ||
|
|
7646e376e0 | ||
|
|
5996798a34 | ||
|
|
6fec532012 | ||
|
|
15713e0b7c | ||
|
|
a6a561af47 | ||
|
|
09c468a4b4 | ||
|
|
bcda1c2409 | ||
|
|
afcd8d9ab1 | ||
|
|
c9b1c91944 | ||
|
|
5d9434eb09 | ||
|
|
1a44b5d52a | ||
|
|
6635ca5e26 | ||
|
|
9c6c78833b | ||
|
|
9a9ab0813c | ||
|
|
0ccaaa48ce | ||
|
|
3f2fe98dd1 | ||
|
|
0d91e9c255 | ||
|
|
af926fbe1f | ||
|
|
83039ae2d4 | ||
|
|
4c53da6961 | ||
|
|
eb306f463e | ||
|
|
788835c5fd | ||
|
|
4d76606fa2 | ||
|
|
1baf7d34b3 | ||
|
|
c78159469a | ||
|
|
b72ca0289c | ||
|
|
46f670f8a2 | ||
|
|
4b44362b9f | ||
|
|
d068a29798 | ||
|
|
0836a51408 | ||
|
|
566cee8fe7 | ||
|
|
e85698e131 | ||
|
|
5f3c541c4c | ||
|
|
3c43e00d8a | ||
|
|
92d686d356 | ||
|
|
0f69e9c825 | ||
|
|
217d979458 | ||
|
|
cc289972fc | ||
|
|
c601e603c2 | ||
|
|
1002c6da1c | ||
|
|
0911337689 | ||
|
|
3bcc416e13 | ||
|
|
65837806f5 | ||
|
|
b0772dcc66 | ||
|
|
c6d65aad3b | ||
|
|
18dd20ce55 | ||
|
|
0f6d76a501 | ||
|
|
0f1320109f | ||
|
|
defa28c618 | ||
|
|
b7c95be47c | ||
|
|
a18d154e0e | ||
|
|
52195a12ee | ||
|
|
59c78d5809 | ||
|
|
be164fc8f9 | ||
|
|
5833ef1efc | ||
|
|
28f88d46f3 | ||
|
|
6ec7683991 | ||
|
|
fb2d8f79d6 | ||
|
|
8f7fa1b1bf | ||
|
|
e5889ce622 |
10
AUTHORS
10
AUTHORS
@@ -22,10 +22,10 @@ Anders Bakken
|
|||||||
Andreas Pohl
|
Andreas Pohl
|
||||||
Andy Davies
|
Andy Davies
|
||||||
Angus Gratton
|
Angus Gratton
|
||||||
|
Anna Henningsen
|
||||||
Ant Bryan
|
Ant Bryan
|
||||||
Benedikt Christoph Wolters
|
Benedikt Christoph Wolters
|
||||||
Benedikt Christoph Wolters
|
Benjamin Peterson
|
||||||
Bernard Spil
|
|
||||||
Bernard Spil
|
Bernard Spil
|
||||||
Brian Card
|
Brian Card
|
||||||
Brian Suh
|
Brian Suh
|
||||||
@@ -33,10 +33,12 @@ Daniel Stenberg
|
|||||||
Dave Reisner
|
Dave Reisner
|
||||||
David Beitey
|
David Beitey
|
||||||
David Weekly
|
David Weekly
|
||||||
|
Dmitriy Vetutnev
|
||||||
Etienne Cimon
|
Etienne Cimon
|
||||||
Fabian Möller
|
Fabian Möller
|
||||||
Fabian Wiesel
|
Fabian Wiesel
|
||||||
Gabi Davar
|
Gabi Davar
|
||||||
|
Gitai
|
||||||
Google Inc.
|
Google Inc.
|
||||||
Jacob Champion
|
Jacob Champion
|
||||||
Jan-E
|
Jan-E
|
||||||
@@ -53,6 +55,7 @@ Kit Chan
|
|||||||
Kyle Schomp
|
Kyle Schomp
|
||||||
Lucas Pardue
|
Lucas Pardue
|
||||||
MATSUMOTO Ryosuke
|
MATSUMOTO Ryosuke
|
||||||
|
Marc Bachmann
|
||||||
Matt Rudary
|
Matt Rudary
|
||||||
Matt Way
|
Matt Way
|
||||||
Mike Conlen
|
Mike Conlen
|
||||||
@@ -65,8 +68,11 @@ Piotr Sikora
|
|||||||
Raul Gutierrez Segales
|
Raul Gutierrez Segales
|
||||||
Remo E
|
Remo E
|
||||||
Reza Tavakoli
|
Reza Tavakoli
|
||||||
|
Rick Lei
|
||||||
Ross Smith II
|
Ross Smith II
|
||||||
Scott Mitchell
|
Scott Mitchell
|
||||||
|
Sebastiaan Deckers
|
||||||
|
Simone Basso
|
||||||
Soham Sinha
|
Soham Sinha
|
||||||
Stefan Eissing
|
Stefan Eissing
|
||||||
Stephen Ludin
|
Stephen Ludin
|
||||||
|
|||||||
@@ -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.23.1)
|
project(nghttp2 VERSION 1.26.0)
|
||||||
|
|
||||||
# See versioning rule:
|
# See versioning rule:
|
||||||
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
set(LT_CURRENT 27)
|
set(LT_CURRENT 28)
|
||||||
set(LT_REVISION 3)
|
set(LT_REVISION 0)
|
||||||
set(LT_AGE 13)
|
set(LT_AGE 14)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
include(Version)
|
include(Version)
|
||||||
|
|||||||
@@ -10,39 +10,47 @@
|
|||||||
#
|
#
|
||||||
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
# $ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out
|
||||||
|
|
||||||
FROM ubuntu:vivid
|
|
||||||
|
|
||||||
|
# Only use standalone-toolchain for reduce size
|
||||||
|
FROM ubuntu:xenial
|
||||||
MAINTAINER Tatsuhiro Tsujikawa
|
MAINTAINER Tatsuhiro Tsujikawa
|
||||||
|
ENV ANDROID_HOME /root
|
||||||
ENV ANDROID_HOME /root/android
|
|
||||||
ENV PREFIX $ANDROID_HOME/usr/local
|
|
||||||
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
ENV TOOLCHAIN $ANDROID_HOME/toolchain
|
||||||
ENV PATH $TOOLCHAIN/bin:$PATH
|
ENV PATH $TOOLCHAIN/bin:$PATH
|
||||||
|
|
||||||
# It would be better to use nearest ubuntu archive mirror for faster
|
ENV NDK_VERSION r14b
|
||||||
# downloads.
|
|
||||||
# RUN sed -ie 's/archive\.ubuntu/jp.archive.ubuntu/g' /etc/apt/sources.list
|
|
||||||
|
|
||||||
RUN apt-get update
|
WORKDIR /root
|
||||||
# genisoimage, libc6-i386 and lib32stdc++6 are required to decompress ndk.
|
RUN apt-get update && \
|
||||||
RUN apt-get install -y make binutils autoconf automake autotools-dev libtool \
|
apt-get install -y unzip make binutils autoconf \
|
||||||
pkg-config git curl dpkg-dev libxml2-dev \
|
automake autotools-dev libtool pkg-config git \
|
||||||
genisoimage libc6-i386 lib32stdc++6
|
curl dpkg-dev libxml2-dev genisoimage libc6-i386 \
|
||||||
|
lib32stdc++6 python&& \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
# Install toolchain
|
||||||
|
RUN curl -L -O https://dl.google.com/android/repository/android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
unzip -q android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
rm android-ndk-$NDK_VERSION-linux-x86_64.zip && \
|
||||||
|
mkdir -p $ANDROID_HOME/toolchain && \
|
||||||
|
$ANDROID_HOME/android-ndk-$NDK_VERSION/build/tools/make-standalone-toolchain.sh \
|
||||||
|
--install-dir=$ANDROID_HOME/toolchain \
|
||||||
|
--toolchain=arm-linux-androideabi-4.9 \
|
||||||
|
--force && \
|
||||||
|
rm -r android-ndk-$NDK_VERSION
|
||||||
|
|
||||||
|
ENV PREFIX /root/usr/local
|
||||||
|
|
||||||
|
# Setup version of libraries
|
||||||
|
ENV OPENSSL_VERSION 1.0.2d
|
||||||
|
ENV SPDYLAY_VERSION v1.4.0
|
||||||
|
ENV LIBEV_VERSION 4.19
|
||||||
|
ENV ZLIB_VERSION 1.2.8
|
||||||
|
ENV CARES_VERSION 1.13.0
|
||||||
|
ENV NGHTTP2_VERSION v1.24.0
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin && \
|
RUN git clone https://github.com/tatsuhiro-t/spdylay -b $SPDYLAY_VERSION --depth 1
|
||||||
chmod a+x android-ndk-r10d-linux-x86_64.bin && \
|
|
||||||
./android-ndk-r10d-linux-x86_64.bin && \
|
|
||||||
rm android-ndk-r10d-linux-x86_64.bin
|
|
||||||
|
|
||||||
WORKDIR /root/build/android-ndk-r10d
|
|
||||||
RUN /bin/bash build/tools/make-standalone-toolchain.sh \
|
|
||||||
--install-dir=$ANDROID_HOME/toolchain \
|
|
||||||
--toolchain=arm-linux-androideabi-4.9 --llvm-version=3.5 \
|
|
||||||
--system=linux-x86_64
|
|
||||||
|
|
||||||
WORKDIR /root/build
|
|
||||||
RUN git clone https://github.com/tatsuhiro-t/spdylay
|
|
||||||
WORKDIR /root/build/spdylay
|
WORKDIR /root/build/spdylay
|
||||||
RUN autoreconf -i && \
|
RUN autoreconf -i && \
|
||||||
./configure \
|
./configure \
|
||||||
@@ -59,22 +67,22 @@ RUN autoreconf -i && \
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O https://www.openssl.org/source/openssl-1.0.2d.tar.gz && \
|
RUN curl -L -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz && \
|
||||||
tar xf openssl-1.0.2d.tar.gz && \
|
tar xf openssl-$OPENSSL_VERSION.tar.gz && \
|
||||||
rm openssl-1.0.2d.tar.gz
|
rm openssl-$OPENSSL_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/openssl-1.0.2d
|
WORKDIR /root/build/openssl-$OPENSSL_VERSION
|
||||||
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
RUN export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi- && \
|
||||||
./Configure --prefix=$PREFIX android && \
|
./Configure --prefix=$PREFIX android && \
|
||||||
make && make install_sw
|
make && make install_sw
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://dist.schmorp.de/libev/libev-4.19.tar.gz && \
|
RUN curl -L -O http://dist.schmorp.de/libev/Attic/libev-$LIBEV_VERSION.tar.gz && \
|
||||||
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
curl -L -O https://gist.github.com/tatsuhiro-t/48c45f08950f587180ed/raw/80a8f003b5d1091eae497c5995bbaa68096e739b/libev-4.19-android.patch && \
|
||||||
tar xf libev-4.19.tar.gz && \
|
tar xf libev-$LIBEV_VERSION.tar.gz && \
|
||||||
rm libev-4.19.tar.gz
|
rm libev-$LIBEV_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/libev-4.19
|
WORKDIR /root/build/libev-$LIBEV_VERSION
|
||||||
RUN patch -p1 < ../libev-4.19-android.patch && \
|
RUN patch -p1 < ../libev-4.19-android.patch && \
|
||||||
./configure \
|
./configure \
|
||||||
--host=arm-linux-androideabi \
|
--host=arm-linux-androideabi \
|
||||||
@@ -87,11 +95,11 @@ RUN patch -p1 < ../libev-4.19-android.patch && \
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN curl -L -O http://zlib.net/zlib-1.2.8.tar.gz && \
|
RUN curl -L -O https://downloads.sourceforge.net/project/libpng/zlib/$ZLIB_VERSION/zlib-$ZLIB_VERSION.tar.gz && \
|
||||||
tar xf zlib-1.2.8.tar.gz && \
|
tar xf zlib-$ZLIB_VERSION.tar.gz && \
|
||||||
rm zlib-1.2.8.tar.gz
|
rm zlib-$ZLIB_VERSION.tar.gz
|
||||||
|
|
||||||
WORKDIR /root/build/zlib-1.2.8
|
WORKDIR /root/build/zlib-$ZLIB_VERSION
|
||||||
RUN HOST=arm-linux-androideabi \
|
RUN HOST=arm-linux-androideabi \
|
||||||
CC=$HOST-gcc \
|
CC=$HOST-gcc \
|
||||||
AR=$HOST-ar \
|
AR=$HOST-ar \
|
||||||
@@ -105,11 +113,26 @@ RUN HOST=arm-linux-androideabi \
|
|||||||
--static && \
|
--static && \
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /root/build
|
WORKDIR /root/build
|
||||||
RUN git clone https://github.com/nghttp2/nghttp2
|
RUN curl -L -O https://c-ares.haxx.se/download/c-ares-$CARES_VERSION.tar.gz && \
|
||||||
|
tar xf c-ares-$CARES_VERSION.tar.gz && \
|
||||||
|
rm c-ares-$CARES_VERSION.tar.gz
|
||||||
|
|
||||||
|
WORKDIR /root/build/c-ares-$CARES_VERSION
|
||||||
|
RUN ./configure \
|
||||||
|
--host=arm-linux-androideabi \
|
||||||
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
|
--prefix=$PREFIX \
|
||||||
|
--disable-shared && \
|
||||||
|
make install
|
||||||
|
|
||||||
|
WORKDIR /root/build
|
||||||
|
RUN git clone https://github.com/nghttp2/nghttp2 -b $NGHTTP2_VERSION --depth 1
|
||||||
WORKDIR /root/build/nghttp2
|
WORKDIR /root/build/nghttp2
|
||||||
RUN autoreconf -i && \
|
RUN autoreconf -i && \
|
||||||
./configure \
|
./configure \
|
||||||
|
--enable-app \
|
||||||
--disable-shared \
|
--disable-shared \
|
||||||
--host=arm-linux-androideabi \
|
--host=arm-linux-androideabi \
|
||||||
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
--build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \
|
||||||
@@ -118,11 +141,10 @@ RUN autoreconf -i && \
|
|||||||
--disable-python-bindings \
|
--disable-python-bindings \
|
||||||
--disable-examples \
|
--disable-examples \
|
||||||
--disable-threads \
|
--disable-threads \
|
||||||
LIBSPDYLAY_CFLAGS=-I$PREFIX/usr/local/include \
|
CC="$TOOLCHAIN"/bin/arm-linux-androideabi-clang \
|
||||||
LIBSPDYLAY_LIBS="-L$PREFIX/usr/local/lib -lspdylay" \
|
CXX="$TOOLCHAIN"/bin/arm-linux-androideabi-clang++ \
|
||||||
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
CPPFLAGS="-fPIE -I$PREFIX/include" \
|
||||||
CXXFLAGS="-fno-strict-aliasing" \
|
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
||||||
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \
|
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
||||||
LDFLAGS="-fPIE -pie -L$PREFIX/lib" && \
|
|
||||||
make && \
|
make && \
|
||||||
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
arm-linux-androideabi-strip src/nghttpx src/nghttpd src/nghttp
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ 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.
|
||||||
|
|
||||||
In ordre to compile the source code, gcc >= 4.8.3 or clang >= 3.4 is
|
In order to compile the source code, gcc >= 4.8.3 or clang >= 3.4 is
|
||||||
required.
|
required.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ dnl Do not change user variables!
|
|||||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||||
|
|
||||||
AC_PREREQ(2.61)
|
AC_PREREQ(2.61)
|
||||||
AC_INIT([nghttp2], [1.23.1], [t-tujikawa@users.sourceforge.net])
|
AC_INIT([nghttp2], [1.26.0], [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])
|
||||||
@@ -44,9 +44,9 @@ 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 http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||||
AC_SUBST(LT_CURRENT, 27)
|
AC_SUBST(LT_CURRENT, 28)
|
||||||
AC_SUBST(LT_REVISION, 3)
|
AC_SUBST(LT_REVISION, 0)
|
||||||
AC_SUBST(LT_AGE, 13)
|
AC_SUBST(LT_AGE, 14)
|
||||||
|
|
||||||
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"`
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ set(APIDOCS
|
|||||||
nghttp2_rcbuf_decref.rst
|
nghttp2_rcbuf_decref.rst
|
||||||
nghttp2_rcbuf_get_buf.rst
|
nghttp2_rcbuf_get_buf.rst
|
||||||
nghttp2_rcbuf_incref.rst
|
nghttp2_rcbuf_incref.rst
|
||||||
|
nghttp2_rcbuf_is_static.rst
|
||||||
nghttp2_select_next_protocol.rst
|
nghttp2_select_next_protocol.rst
|
||||||
nghttp2_session_callbacks_del.rst
|
nghttp2_session_callbacks_del.rst
|
||||||
nghttp2_session_callbacks_new.rst
|
nghttp2_session_callbacks_new.rst
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ APIDOCS= \
|
|||||||
nghttp2_rcbuf_decref.rst \
|
nghttp2_rcbuf_decref.rst \
|
||||||
nghttp2_rcbuf_get_buf.rst \
|
nghttp2_rcbuf_get_buf.rst \
|
||||||
nghttp2_rcbuf_incref.rst \
|
nghttp2_rcbuf_incref.rst \
|
||||||
|
nghttp2_rcbuf_is_static.rst \
|
||||||
nghttp2_select_next_protocol.rst \
|
nghttp2_select_next_protocol.rst \
|
||||||
nghttp2_session_callbacks_del.rst \
|
nghttp2_session_callbacks_del.rst \
|
||||||
nghttp2_session_callbacks_new.rst \
|
nghttp2_session_callbacks_new.rst \
|
||||||
@@ -267,7 +268,7 @@ apiref.rst: \
|
|||||||
$(APIDOCS): apiref.rst
|
$(APIDOCS): apiref.rst
|
||||||
|
|
||||||
clean-local:
|
clean-local:
|
||||||
[ $(srcdir) = $(builddir) ] || for i in $(RST_FILES); do [ -e $(builddir)/$$i ] && rm -f $(builddir)/$$i; done
|
if [ $(srcdir) != $(builddir) ]; then for i in $(RST_FILES); do rm -f $(builddir)/$$i; done fi
|
||||||
-rm -f apiref.rst
|
-rm -f apiref.rst
|
||||||
-rm -f $(APIDOCS)
|
-rm -f $(APIDOCS)
|
||||||
-rm -rf $(BUILDDIR)/*
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|||||||
@@ -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 --header-table-size --requests --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --header ' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '--connection-window-bits --clients --verbose --ciphers --rate --no-tls-proto --header-table-size --requests --base-uri --h1 --threads --npn-list --rate-period --data --version --connection-inactivity-timeout --timing-script-file --encoder-header-table-size --max-concurrent-streams --connection-active-timeout --input-file --help --window-bits --warm-up-time --duration --header ' -- "$cur" ) )
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
_filedir
|
_filedir
|
||||||
|
|||||||
19
doc/h2load.1
19
doc/h2load.1
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "H2LOAD" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
.TH "H2LOAD" "1" "Sep 20, 2017" "1.26.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
h2load \- HTTP/2 benchmarking tool
|
h2load \- HTTP/2 benchmarking tool
|
||||||
.
|
.
|
||||||
@@ -54,7 +54,9 @@ scheme, host or port values.
|
|||||||
Number of requests across all clients. If it is used
|
Number of requests across all clients. If it is used
|
||||||
with \fI\%\-\-timing\-script\-file\fP option, this option specifies
|
with \fI\%\-\-timing\-script\-file\fP option, this option specifies
|
||||||
the number of requests each client performs rather than
|
the number of requests each client performs rather than
|
||||||
the number of requests across all clients.
|
the number of requests across all clients. This option
|
||||||
|
is ignored if timing\-based benchmarking is enabled (see
|
||||||
|
\fI\%\-\-duration\fP option).
|
||||||
.sp
|
.sp
|
||||||
Default: \fB1\fP
|
Default: \fB1\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
@@ -170,6 +172,19 @@ option is 1s.
|
|||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-D, \-\-duration=<N>
|
||||||
|
Specifies the main duration for the measurements in case
|
||||||
|
of timing\-based benchmarking.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
|
.B \-\-warm\-up\-time=<DURATION>
|
||||||
|
Specifies the time period before starting the actual
|
||||||
|
measurements, in case of timing\-based benchmarking.
|
||||||
|
Needs to provided along with \fI\%\-D\fP option.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-T, \-\-connection\-active\-timeout=<DURATION>
|
.B \-T, \-\-connection\-active\-timeout=<DURATION>
|
||||||
Specifies the maximum time that h2load is willing to
|
Specifies the maximum time that h2load is willing to
|
||||||
keep a connection open, regardless of the activity on
|
keep a connection open, regardless of the activity on
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ OPTIONS
|
|||||||
Number of requests across all clients. If it is used
|
Number of requests across all clients. If it is used
|
||||||
with :option:`--timing-script-file` option, this option specifies
|
with :option:`--timing-script-file` option, this option specifies
|
||||||
the number of requests each client performs rather than
|
the number of requests each client performs rather than
|
||||||
the number of requests across all clients.
|
the number of requests across all clients. This option
|
||||||
|
is ignored if timing-based benchmarking is enabled (see
|
||||||
|
:option:`--duration` option).
|
||||||
|
|
||||||
Default: ``1``
|
Default: ``1``
|
||||||
|
|
||||||
@@ -136,6 +138,17 @@ OPTIONS
|
|||||||
the rate option is not used. The default value for this
|
the rate option is not used. The default value for this
|
||||||
option is 1s.
|
option is 1s.
|
||||||
|
|
||||||
|
.. option:: -D, --duration=<N>
|
||||||
|
|
||||||
|
Specifies the main duration for the measurements in case
|
||||||
|
of timing-based benchmarking.
|
||||||
|
|
||||||
|
.. option:: --warm-up-time=<DURATION>
|
||||||
|
|
||||||
|
Specifies the time period before starting the actual
|
||||||
|
measurements, in case of timing-based benchmarking.
|
||||||
|
Needs to provided along with :option:`-D` option.
|
||||||
|
|
||||||
.. option:: -T, --connection-active-timeout=<DURATION>
|
.. option:: -T, --connection-active-timeout=<DURATION>
|
||||||
|
|
||||||
Specifies the maximum time that h2load is willing to
|
Specifies the maximum time that h2load is willing to
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTP" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
.TH "NGHTTP" "1" "Sep 20, 2017" "1.26.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" "May 30, 2017" "1.23.1" "nghttp2"
|
.TH "NGHTTPD" "1" "Sep 20, 2017" "1.26.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpd \- HTTP/2 server
|
nghttpd \- HTTP/2 server
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPX" "1" "May 30, 2017" "1.23.1" "nghttp2"
|
.TH "NGHTTPX" "1" "Sep 20, 2017" "1.26.0" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpx \- HTTP/2 proxy
|
nghttpx \- HTTP/2 proxy
|
||||||
.
|
.
|
||||||
@@ -604,11 +604,14 @@ enabled for backend connections.
|
|||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-cacert=<PATH>
|
.B \-\-cacert=<PATH>
|
||||||
Set path to trusted CA certificate file used in backend
|
Set path to trusted CA certificate file. It is used in
|
||||||
TLS connections. The file must be in PEM format. It
|
backend TLS connections to verify peer\(aqs certificate.
|
||||||
can contain multiple certificates. If the linked
|
It is also used to verify OCSP response from the script
|
||||||
OpenSSL is configured to load system wide certificates,
|
set by \fI\%\-\-fetch\-ocsp\-response\-file\fP\&. The file must be in
|
||||||
they are loaded at startup regardless of this option.
|
PEM format. It can contain multiple certificates. If
|
||||||
|
the linked OpenSSL is configured to load system wide
|
||||||
|
certificates, they are loaded at startup regardless of
|
||||||
|
this option.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
@@ -691,10 +694,14 @@ done in case\-insensitive manner. The versions between
|
|||||||
\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
|
\fI\%\-\-tls\-min\-proto\-version\fP and \fI\%\-\-tls\-max\-proto\-version\fP are
|
||||||
enabled. If the protocol list advertised by client does
|
enabled. If the protocol list advertised by client does
|
||||||
not overlap this range, you will receive the error
|
not overlap this range, you will receive the error
|
||||||
message "unknown protocol". The available versions are:
|
message "unknown protocol". If a protocol version lower
|
||||||
|
than TLSv1.2 is specified, make sure that the compatible
|
||||||
|
ciphers are included in \fI\%\-\-ciphers\fP option. The default
|
||||||
|
cipher list only includes ciphers compatible with
|
||||||
|
TLSv1.2 or above. The available versions are:
|
||||||
TLSv1.2, TLSv1.1, and TLSv1.0
|
TLSv1.2, TLSv1.1, and TLSv1.0
|
||||||
.sp
|
.sp
|
||||||
Default: \fBTLSv1.1\fP
|
Default: \fBTLSv1.2\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -558,11 +558,14 @@ SSL/TLS
|
|||||||
|
|
||||||
.. option:: --cacert=<PATH>
|
.. option:: --cacert=<PATH>
|
||||||
|
|
||||||
Set path to trusted CA certificate file used in backend
|
Set path to trusted CA certificate file. It is used in
|
||||||
TLS connections. The file must be in PEM format. It
|
backend TLS connections to verify peer's certificate.
|
||||||
can contain multiple certificates. If the linked
|
It is also used to verify OCSP response from the script
|
||||||
OpenSSL is configured to load system wide certificates,
|
set by :option:`--fetch-ocsp-response-file`\. The file must be in
|
||||||
they are loaded at startup regardless of this option.
|
PEM format. It can contain multiple certificates. If
|
||||||
|
the linked OpenSSL is configured to load system wide
|
||||||
|
certificates, they are loaded at startup regardless of
|
||||||
|
this option.
|
||||||
|
|
||||||
.. option:: --private-key-passwd-file=<PATH>
|
.. option:: --private-key-passwd-file=<PATH>
|
||||||
|
|
||||||
@@ -636,10 +639,14 @@ SSL/TLS
|
|||||||
:option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
|
:option:`--tls-min-proto-version` and :option:`\--tls-max-proto-version` are
|
||||||
enabled. If the protocol list advertised by client does
|
enabled. If the protocol list advertised by client does
|
||||||
not overlap this range, you will receive the error
|
not overlap this range, you will receive the error
|
||||||
message "unknown protocol". The available versions are:
|
message "unknown protocol". If a protocol version lower
|
||||||
|
than TLSv1.2 is specified, make sure that the compatible
|
||||||
|
ciphers are included in :option:`--ciphers` option. The default
|
||||||
|
cipher list only includes ciphers compatible with
|
||||||
|
TLSv1.2 or above. The available versions are:
|
||||||
TLSv1.2, TLSv1.1, and TLSv1.0
|
TLSv1.2, TLSv1.1, and TLSv1.0
|
||||||
|
|
||||||
Default: ``TLSv1.1``
|
Default: ``TLSv1.2``
|
||||||
|
|
||||||
.. option:: --tls-max-proto-version=<VER>
|
.. option:: --tls-max-proto-version=<VER>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ protocol selection will be done via ALPN or NPN.
|
|||||||
|
|
||||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
||||||
in :option:`--frontend` option. In this case, SPDY protocol is not
|
in :option:`--frontend` option. In this case, SPDY protocol is not
|
||||||
available even if spdylay library is liked to nghttpx. HTTP/2 and
|
available even if spdylay library is linked to nghttpx. HTTP/2 and
|
||||||
HTTP/1 are available on the frontend, and an HTTP/1 connection can be
|
HTTP/1 are available on the frontend, and an HTTP/1 connection can be
|
||||||
upgraded to HTTP/2 using HTTP Upgrade. Starting HTTP/2 connection by
|
upgraded to HTTP/2 using HTTP Upgrade. Starting HTTP/2 connection by
|
||||||
sending HTTP/2 connection preface is also supported.
|
sending HTTP/2 connection preface is also supported.
|
||||||
@@ -45,17 +45,17 @@ that default backend protocol is HTTP/1.1. To use HTTP/2 in backend,
|
|||||||
you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
|
you have to specify ``h2`` in ``proto`` keyword in :option:`--backend`
|
||||||
explicitly.
|
explicitly.
|
||||||
|
|
||||||
The backend is supposed to be Web server. For example, to make
|
The backend is supposed to be a Web server. For example, to make
|
||||||
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
||||||
backend Web server is configured to listen to HTTP request at port
|
backend Web server is configured to listen to HTTP requests at port
|
||||||
8080 in the same host, run nghttpx command-line like this:
|
8080 on the same host, run nghttpx command-line like this:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
$ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
$ nghttpx -f0.0.0.0,8443 -b127.0.0.1,8080 /path/to/server.key /path/to/server.crt
|
||||||
|
|
||||||
Then HTTP/2 enabled client can access to the nghttpx in HTTP/2. For
|
Then an HTTP/2 enabled client can access the nghttpx server using HTTP/2. For
|
||||||
example, you can send GET request to the server using nghttp:
|
example, you can send a GET request using nghttp:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
@@ -66,19 +66,19 @@ HTTP/2 proxy mode
|
|||||||
|
|
||||||
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
||||||
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
||||||
protocols in frontend and backend connections are the same in `default
|
protocols in frontend and backend connections are the same as in `default
|
||||||
mode`_. The difference is that this mode acts like forward proxy and
|
mode`_. The difference is that this mode acts like a forward proxy and
|
||||||
assumes the backend is HTTP proxy server (e.g., Squid, Apache Traffic
|
assumes the backend is an HTTP proxy server (e.g., Squid, Apache Traffic
|
||||||
Server). HTTP/1 request must include absolute URI in request line.
|
Server). HTTP/1 requests must include an absolute URI in request line.
|
||||||
|
|
||||||
By default, frontend connection is encrypted. So this mode is also
|
By default, the frontend connection is encrypted. So this mode is also
|
||||||
called secure proxy. If nghttpx is linked with spdylay, it supports
|
called secure proxy. If nghttpx is linked with spdylay, it supports
|
||||||
SPDY protocols and it works as so called SPDY proxy.
|
SPDY protocols and it works as so called SPDY proxy.
|
||||||
|
|
||||||
To turn off encryption on frontend connection, use ``no-tls`` keyword
|
To turn off encryption on the frontend connection, use ``no-tls`` keyword
|
||||||
in :option:`--frontend` option.
|
in :option:`--frontend` option.
|
||||||
|
|
||||||
The backend must be HTTP proxy server. nghttpx supports multiple
|
The backend must be an HTTP proxy server. nghttpx supports multiple
|
||||||
backend server addresses. It translates incoming requests to HTTP
|
backend server addresses. It translates incoming requests to HTTP
|
||||||
request to backend server. The backend server performs real proxy
|
request to backend server. The backend server performs real proxy
|
||||||
work for each request, for example, dispatching requests to the origin
|
work for each request, for example, dispatching requests to the origin
|
||||||
@@ -92,7 +92,7 @@ connection, use :option:`--backend` option, and specify ``h2`` in
|
|||||||
|
|
||||||
For example, to make nghttpx listen to encrypted HTTP/2 requests at
|
For example, to make nghttpx listen to encrypted HTTP/2 requests at
|
||||||
port 8443, and a backend HTTP proxy server is configured to listen to
|
port 8443, and a backend HTTP proxy server is configured to listen to
|
||||||
HTTP/1 request at port 8080 in the same host, run nghttpx command-line
|
HTTP/1 requests at port 8080 on the same host, run nghttpx command-line
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
@@ -297,13 +297,31 @@ When you write this option in command-line, you should enclose
|
|||||||
argument with single or double quotes, since the character ``;`` has a
|
argument with single or double quotes, since the character ``;`` has a
|
||||||
special meaning in shell.
|
special meaning in shell.
|
||||||
|
|
||||||
To route, request to request path whose prefix is ``/foo`` to backend
|
To route, request to request path ``/foo`` to backend server
|
||||||
server ``[::1]:8080``, you can write like so:
|
``[::1]:8080``, you can write like so:
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
backend=::1,8080;/foo
|
backend=::1,8080;/foo
|
||||||
|
|
||||||
|
If the last character of path pattern is ``/``, all request paths
|
||||||
|
which start with that pattern match:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
backend=::1,8080;/bar/
|
||||||
|
|
||||||
|
The request path ``/bar/buzz`` matches the ``/bar/``.
|
||||||
|
|
||||||
|
You can use ``*`` at the end of the path pattern to make it wildcard
|
||||||
|
pattern. ``*`` must match at least one character:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
backend=::1,8080;/sample*
|
||||||
|
|
||||||
|
The request path ``/sample1/foo`` matches the ``/sample*`` pattern.
|
||||||
|
|
||||||
Of course, you can specify both host and request path at the same
|
Of course, you can specify both host and request path at the same
|
||||||
time:
|
time:
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,8 @@ if(ENABLE_EXAMPLES)
|
|||||||
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/lib/includes
|
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
|
||||||
${CMAKE_BINARY_DIR}/lib/includes
|
|
||||||
${CMAKE_SOURCE_DIR}/src/includes
|
|
||||||
${CMAKE_SOURCE_DIR}/third-party
|
|
||||||
|
|
||||||
${LIBEVENT_INCLUDE_DIRS}
|
${LIBEVENT_INCLUDE_DIRS}
|
||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
|
|||||||
@@ -1113,14 +1113,45 @@ func TestH2H1Upgrade(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded
|
||||||
|
// header field includes obfuscated address even if PROXY protocol
|
||||||
|
// version 1 containing TCP4 entry is accepted.
|
||||||
|
func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) {
|
||||||
|
pattern := fmt.Sprintf(`^for=_[^;]+$`)
|
||||||
|
validFwd := regexp.MustCompile(pattern)
|
||||||
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=obfuscated"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
|
||||||
|
t.Errorf("Forwarded: %v; want pattern %v", got, pattern)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
defer st.Close()
|
||||||
|
|
||||||
|
st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
|
||||||
|
|
||||||
|
res, err := st.http2(requestParam{
|
||||||
|
name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated",
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error st.http2() = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := res.status, 200; got != want {
|
||||||
|
t.Errorf("res.status: %v; want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
|
// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
|
||||||
// containing TCP4 entry is accepted and X-Forwarded-For contains
|
// containing TCP4 entry is accepted and X-Forwarded-For contains
|
||||||
// advertised src address.
|
// advertised src address.
|
||||||
func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
|
if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
|
||||||
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
|
if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
|
||||||
|
t.Errorf("Forwarded: %v; want %v", got, want)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
@@ -1143,10 +1174,13 @@ func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
|
|||||||
// containing TCP6 entry is accepted and X-Forwarded-For contains
|
// containing TCP6 entry is accepted and X-Forwarded-For contains
|
||||||
// advertised src address.
|
// advertised src address.
|
||||||
func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
|
if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
|
||||||
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
t.Errorf("X-Forwarded-For: %v; want %v", got, want)
|
||||||
}
|
}
|
||||||
|
if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want {
|
||||||
|
t.Errorf("Forwarded: %v; want %v", got, want)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
@@ -1168,10 +1202,13 @@ func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
|
|||||||
// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
|
// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
|
||||||
// containing UNKNOWN entry is accepted.
|
// containing UNKNOWN entry is accepted.
|
||||||
func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
|
func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
|
||||||
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
|
st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
|
if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
|
||||||
t.Errorf("X-Forwarded-For: %v")
|
t.Errorf("X-Forwarded-For: %v")
|
||||||
}
|
}
|
||||||
|
if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant {
|
||||||
|
t.Errorf("Forwarded: %v")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
defer st.Close()
|
defer st.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ set_target_properties(nghttp2 PROPERTIES
|
|||||||
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
||||||
C_VISIBILITY_PRESET hidden
|
C_VISIBILITY_PRESET hidden
|
||||||
)
|
)
|
||||||
|
target_include_directories(nghttp2 INTERFACE
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
|
)
|
||||||
|
|
||||||
if(HAVE_CUNIT)
|
if(HAVE_CUNIT)
|
||||||
# Static library (for unittests because of symbol visibility)
|
# Static library (for unittests because of symbol visibility)
|
||||||
|
|||||||
@@ -469,6 +469,15 @@ NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf);
|
|||||||
*/
|
*/
|
||||||
NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
|
NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* Returns nonzero if the underlying buffer is statically allocated,
|
||||||
|
* and 0 otherwise. This can be useful for language bindings that wish
|
||||||
|
* to avoid creating duplicate strings for these buffers.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum
|
* @enum
|
||||||
*
|
*
|
||||||
@@ -3809,9 +3818,8 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
|||||||
* Submits trailer fields HEADERS against the stream |stream_id|.
|
* Submits trailer fields HEADERS against the stream |stream_id|.
|
||||||
*
|
*
|
||||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||||
* |nvlen| elements. The application is responsible not to include
|
* |nvlen| elements. The application must not include pseudo-header
|
||||||
* pseudo-header fields (header field whose name starts with ":") in
|
* fields (headers whose names starts with ":") in |nva|.
|
||||||
* |nva|.
|
|
||||||
*
|
*
|
||||||
* This function creates copies of all name/value pairs in |nva|. It
|
* This function creates copies of all name/value pairs in |nva|. It
|
||||||
* also lower-cases all names in |nva|. The order of elements in
|
* also lower-cases all names in |nva|. The order of elements in
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ typedef struct {
|
|||||||
nghttp2_pq_entry **q;
|
nghttp2_pq_entry **q;
|
||||||
/* Memory allocator */
|
/* Memory allocator */
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
/* The number of items sotred */
|
/* The number of items stored */
|
||||||
size_t length;
|
size_t length;
|
||||||
/* The maximum number of items this pq can store. This is
|
/* The maximum number of items this pq can store. This is
|
||||||
automatically extended when length is reached to this value. */
|
automatically extended when length is reached to this value. */
|
||||||
|
|||||||
@@ -96,3 +96,7 @@ nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) {
|
|||||||
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) {
|
||||||
|
return rcbuf->ref == -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ struct nghttp2_session {
|
|||||||
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
||||||
to refuse the incoming stream if it exceeds this value. */
|
to refuse the incoming stream if it exceeds this value. */
|
||||||
uint32_t pending_local_max_concurrent_stream;
|
uint32_t pending_local_max_concurrent_stream;
|
||||||
/* The bitwose OR of zero or more of nghttp2_typemask to indicate
|
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
|
||||||
that the default handling of extension frame is enabled. */
|
that the default handling of extension frame is enabled. */
|
||||||
uint32_t builtin_recv_ext_types;
|
uint32_t builtin_recv_ext_types;
|
||||||
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
||||||
|
|||||||
@@ -8,11 +8,8 @@ set_source_files_properties(${cxx_sources} PROPERTIES
|
|||||||
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
COMPILE_FLAGS "${WARNCXXFLAGS} ${CXX1XCXXFLAGS}")
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
"${CMAKE_SOURCE_DIR}/lib/includes"
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
"${CMAKE_BINARY_DIR}/lib/includes"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../third-party"
|
||||||
"${CMAKE_SOURCE_DIR}/lib"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/includes"
|
|
||||||
"${CMAKE_SOURCE_DIR}/third-party"
|
|
||||||
|
|
||||||
${JEMALLOC_INCLUDE_DIRS}
|
${JEMALLOC_INCLUDE_DIRS}
|
||||||
${SPDYLAY_INCLUDE_DIRS}
|
${SPDYLAY_INCLUDE_DIRS}
|
||||||
@@ -252,6 +249,11 @@ if(ENABLE_ASIO_LIB)
|
|||||||
${OPENSSL_INCLUDE_DIRS}
|
${OPENSSL_INCLUDE_DIRS}
|
||||||
${Boost_INCLUDE_DIRS}
|
${Boost_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
target_include_directories(nghttp2_asio INTERFACE
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/../lib/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/../lib/includes"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||||
|
)
|
||||||
target_link_libraries(nghttp2_asio
|
target_link_libraries(nghttp2_asio
|
||||||
nghttp2
|
nghttp2
|
||||||
${OPENSSL_LIBRARIES}
|
${OPENSSL_LIBRARIES}
|
||||||
|
|||||||
431
src/h2load.cc
431
src/h2load.cc
@@ -90,6 +90,8 @@ Config::Config()
|
|||||||
connection_window_bits(30),
|
connection_window_bits(30),
|
||||||
rate(0),
|
rate(0),
|
||||||
rate_period(1.0),
|
rate_period(1.0),
|
||||||
|
duration(0.0),
|
||||||
|
warm_up_time(0.0),
|
||||||
conn_active_timeout(0.),
|
conn_active_timeout(0.),
|
||||||
conn_inactivity_timeout(0.),
|
conn_inactivity_timeout(0.),
|
||||||
no_tls_proto(PROTO_HTTP2),
|
no_tls_proto(PROTO_HTTP2),
|
||||||
@@ -118,6 +120,7 @@ Config::~Config() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Config::is_rate_mode() const { return (this->rate != 0); }
|
bool Config::is_rate_mode() const { return (this->rate != 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()); }
|
||||||
Config config;
|
Config config;
|
||||||
|
|
||||||
@@ -151,33 +154,12 @@ std::mt19937 gen(rd());
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void sampling_init(Sampling &smp, size_t total, size_t max_samples) {
|
void sampling_init(Sampling &smp, size_t max_samples) {
|
||||||
smp.n = 0;
|
smp.n = 0;
|
||||||
|
smp.max_samples = max_samples;
|
||||||
if (total <= max_samples) {
|
|
||||||
smp.interval = 0.;
|
|
||||||
smp.point = 0.;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
smp.interval = static_cast<double>(total) / max_samples;
|
|
||||||
|
|
||||||
std::uniform_real_distribution<> dis(0., smp.interval);
|
|
||||||
|
|
||||||
smp.point = dis(gen);
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool sampling_should_pick(Sampling &smp) {
|
|
||||||
return smp.interval == 0. || smp.n == ceil(smp.point);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void sampling_advance_point(Sampling &smp) { smp.point += smp.interval; }
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||||
auto client = static_cast<Client *>(w->data);
|
auto client = static_cast<Client *>(w->data);
|
||||||
@@ -190,6 +172,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||||||
rv = client->connect();
|
rv = client->connect();
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
client->fail();
|
client->fail();
|
||||||
|
client->worker->free_client(client);
|
||||||
delete client;
|
delete client;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -197,6 +180,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||||||
}
|
}
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
client->fail();
|
client->fail();
|
||||||
|
client->worker->free_client(client);
|
||||||
delete client;
|
delete client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,6 +194,7 @@ void readcb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||||||
if (client->try_again_or_fail() == 0) {
|
if (client->try_again_or_fail() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
client->worker->free_client(client);
|
||||||
delete client;
|
delete client;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,16 +226,71 @@ void rate_period_timeout_w_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
|||||||
std::cerr << "client could not connect to host" << std::endl;
|
std::cerr << "client could not connect to host" << std::endl;
|
||||||
client->fail();
|
client->fail();
|
||||||
} else {
|
} else {
|
||||||
client.release();
|
if (worker->config->is_timing_based_mode()) {
|
||||||
|
worker->clients.push_back(client.release());
|
||||||
|
} else {
|
||||||
|
client.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
worker->report_rate_progress();
|
worker->report_rate_progress();
|
||||||
}
|
}
|
||||||
if (worker->nconns_made >= worker->nclients) {
|
if (!worker->config->is_timing_based_mode()) {
|
||||||
ev_timer_stop(worker->loop, w);
|
if (worker->nconns_made >= worker->nclients) {
|
||||||
|
ev_timer_stop(worker->loop, w);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// To check whether all created clients are pushed correctly
|
||||||
|
assert(worker->nclients == worker->clients.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Called when the duration for infinite number of requests are over
|
||||||
|
void duration_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
|
auto worker = static_cast<Worker *>(w->data);
|
||||||
|
|
||||||
|
worker->current_phase = Phase::DURATION_OVER;
|
||||||
|
|
||||||
|
std::cout << "Main benchmark duration is over for thread #" << worker->id
|
||||||
|
<< ". Stopping all clients." << std::endl;
|
||||||
|
worker->stop_all_clients();
|
||||||
|
std::cout << "Stopped all clients for thread #" << worker->id << std::endl;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Called when the warmup duration for infinite number of requests are over
|
||||||
|
void warmup_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
|
auto worker = static_cast<Worker *>(w->data);
|
||||||
|
|
||||||
|
std::cout << "Warm-up phase is over for thread #" << worker->id << "."
|
||||||
|
<< std::endl;
|
||||||
|
std::cout << "Main benchmark duration is started for thread #" << worker->id
|
||||||
|
<< "." << std::endl;
|
||||||
|
assert(worker->stats.req_started == 0);
|
||||||
|
assert(worker->stats.req_done == 0);
|
||||||
|
|
||||||
|
for (auto client : worker->clients) {
|
||||||
|
if (client) {
|
||||||
|
assert(client->req_todo == 0);
|
||||||
|
assert(client->req_left == 1);
|
||||||
|
assert(client->req_inflight == 0);
|
||||||
|
assert(client->req_started == 0);
|
||||||
|
assert(client->req_done == 0);
|
||||||
|
|
||||||
|
client->record_client_start_time();
|
||||||
|
client->clear_connect_times();
|
||||||
|
client->record_connect_start_time();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worker->current_phase = Phase::MAIN_DURATION;
|
||||||
|
|
||||||
|
ev_timer_start(worker->loop, &worker->duration_watcher);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Called when an a connection has been inactive for a set period of time
|
// Called when an a connection has been inactive for a set period of time
|
||||||
// or a fixed amount of time after all requests have been made on a
|
// or a fixed amount of time after all requests have been made on a
|
||||||
@@ -269,8 +309,7 @@ void conn_timeout_cb(EV_P_ ev_timer *w, int revents) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool check_stop_client_request_timeout(Client *client, ev_timer *w) {
|
bool check_stop_client_request_timeout(Client *client, ev_timer *w) {
|
||||||
if (client->req_left == 0 ||
|
if (client->req_left == 0) {
|
||||||
client->streams.size() >= client->session->max_concurrent_streams()) {
|
|
||||||
// no more requests to make, stop timer
|
// no more requests to make, stop timer
|
||||||
ev_timer_stop(client->worker->loop, w);
|
ev_timer_stop(client->worker->loop, w);
|
||||||
return true;
|
return true;
|
||||||
@@ -284,6 +323,11 @@ namespace {
|
|||||||
void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
auto client = static_cast<Client *>(w->data);
|
auto client = static_cast<Client *>(w->data);
|
||||||
|
|
||||||
|
if (client->streams.size() >= (size_t)config.max_concurrent_streams) {
|
||||||
|
ev_timer_stop(client->worker->loop, w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->submit_request() != 0) {
|
if (client->submit_request() != 0) {
|
||||||
ev_timer_stop(client->worker->loop, w);
|
ev_timer_stop(client->worker->loop, w);
|
||||||
client->process_request_failure();
|
client->process_request_failure();
|
||||||
@@ -336,6 +380,11 @@ Client::Client(uint32_t id, Worker *worker, size_t req_todo)
|
|||||||
fd(-1),
|
fd(-1),
|
||||||
new_connection_requested(false),
|
new_connection_requested(false),
|
||||||
final(false) {
|
final(false) {
|
||||||
|
if (req_todo == 0) { // this means infinite number of requests are to be made
|
||||||
|
// This ensures that number of requests are unbounded
|
||||||
|
// Just a positive number is fine, we chose the first positive number
|
||||||
|
req_left = 1;
|
||||||
|
}
|
||||||
ev_io_init(&wev, writecb, 0, EV_WRITE);
|
ev_io_init(&wev, writecb, 0, EV_WRITE);
|
||||||
ev_io_init(&rev, readcb, 0, EV_READ);
|
ev_io_init(&rev, readcb, 0, EV_READ);
|
||||||
|
|
||||||
@@ -361,10 +410,7 @@ Client::~Client() {
|
|||||||
SSL_free(ssl);
|
SSL_free(ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sampling_should_pick(worker->client_smp)) {
|
worker->sample_client_stat(&cstat);
|
||||||
sampling_advance_point(worker->client_smp);
|
|
||||||
worker->sample_client_stat(&cstat);
|
|
||||||
}
|
|
||||||
++worker->client_smp.n;
|
++worker->client_smp.n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,9 +453,17 @@ int Client::make_socket(addrinfo *addr) {
|
|||||||
int Client::connect() {
|
int Client::connect() {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
record_client_start_time();
|
if (!worker->config->is_timing_based_mode() ||
|
||||||
clear_connect_times();
|
worker->current_phase == Phase::MAIN_DURATION) {
|
||||||
record_connect_start_time();
|
record_client_start_time();
|
||||||
|
clear_connect_times();
|
||||||
|
record_connect_start_time();
|
||||||
|
} else if (worker->current_phase == Phase::INITIAL_IDLE) {
|
||||||
|
worker->current_phase = Phase::WARM_UP;
|
||||||
|
std::cout << "Warm-up started for thread #" << worker->id << "."
|
||||||
|
<< std::endl;
|
||||||
|
ev_timer_start(worker->loop, &worker->warmup_watcher);
|
||||||
|
}
|
||||||
|
|
||||||
if (worker->config->conn_inactivity_timeout > 0.) {
|
if (worker->config->conn_inactivity_timeout > 0.) {
|
||||||
ev_timer_again(worker->loop, &conn_inactivity_watcher);
|
ev_timer_again(worker->loop, &conn_inactivity_watcher);
|
||||||
@@ -467,13 +521,17 @@ int Client::try_again_or_fail() {
|
|||||||
|
|
||||||
if (new_connection_requested) {
|
if (new_connection_requested) {
|
||||||
new_connection_requested = false;
|
new_connection_requested = false;
|
||||||
if (req_left) {
|
|
||||||
// At the moment, we don't have a facility to re-start request
|
|
||||||
// already in in-flight. Make them fail.
|
|
||||||
worker->stats.req_failed += req_inflight;
|
|
||||||
worker->stats.req_error += req_inflight;
|
|
||||||
|
|
||||||
req_inflight = 0;
|
if (req_left) {
|
||||||
|
|
||||||
|
if (worker->current_phase == Phase::MAIN_DURATION) {
|
||||||
|
// At the moment, we don't have a facility to re-start request
|
||||||
|
// already in in-flight. Make them fail.
|
||||||
|
worker->stats.req_failed += req_inflight;
|
||||||
|
worker->stats.req_error += req_inflight;
|
||||||
|
|
||||||
|
req_inflight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep using current address
|
// Keep using current address
|
||||||
if (connect() == 0) {
|
if (connect() == 0) {
|
||||||
@@ -529,11 +587,16 @@ int Client::submit_request() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
++worker->stats.req_started;
|
++worker->stats.req_started;
|
||||||
--req_left;
|
|
||||||
++req_started;
|
++req_started;
|
||||||
++req_inflight;
|
++req_inflight;
|
||||||
|
if (!worker->config->is_timing_based_mode()) {
|
||||||
|
--req_left;
|
||||||
|
}
|
||||||
// if an active timeout is set and this is the last request to be submitted
|
// if an active timeout is set and this is the last request to be submitted
|
||||||
// on this connection, start the active timeout.
|
// on this connection, start the active timeout.
|
||||||
if (worker->config->conn_active_timeout > 0. && req_left == 0) {
|
if (worker->config->conn_active_timeout > 0. && req_left == 0) {
|
||||||
@@ -544,6 +607,10 @@ int Client::submit_request() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::process_timedout_streams() {
|
void Client::process_timedout_streams() {
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &p : streams) {
|
for (auto &p : streams) {
|
||||||
auto &req_stat = p.second.req_stat;
|
auto &req_stat = p.second.req_stat;
|
||||||
if (!req_stat.completed) {
|
if (!req_stat.completed) {
|
||||||
@@ -557,6 +624,10 @@ void Client::process_timedout_streams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::process_abandoned_streams() {
|
void Client::process_abandoned_streams() {
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto req_abandoned = req_inflight + req_left;
|
auto req_abandoned = req_inflight + req_left;
|
||||||
|
|
||||||
worker->stats.req_failed += req_abandoned;
|
worker->stats.req_failed += req_abandoned;
|
||||||
@@ -567,6 +638,10 @@ void Client::process_abandoned_streams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::process_request_failure() {
|
void Client::process_request_failure() {
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
worker->stats.req_failed += req_left;
|
worker->stats.req_failed += req_left;
|
||||||
worker->stats.req_error += req_left;
|
worker->stats.req_error += req_left;
|
||||||
|
|
||||||
@@ -575,6 +650,8 @@ void Client::process_request_failure() {
|
|||||||
if (req_inflight == 0) {
|
if (req_inflight == 0) {
|
||||||
terminate_session();
|
terminate_session();
|
||||||
}
|
}
|
||||||
|
std::cout << "Process Request Failure:" << worker->stats.req_failed
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -653,6 +730,15 @@ void Client::on_header(int32_t stream_id, const uint8_t *name, size_t namelen,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto &stream = (*itr).second;
|
auto &stream = (*itr).second;
|
||||||
|
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
// If the stream is for warm-up phase, then mark as a success
|
||||||
|
// But we do not update the count for 2xx, 3xx, etc status codes
|
||||||
|
// Same has been done in on_status_code function
|
||||||
|
stream.status_success = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream.status_success == -1 && namelen == 7 &&
|
if (stream.status_success == -1 && namelen == 7 &&
|
||||||
util::streq_l(":status", name, namelen)) {
|
util::streq_l(":status", name, namelen)) {
|
||||||
int status = 0;
|
int status = 0;
|
||||||
@@ -691,6 +777,11 @@ void Client::on_status_code(int32_t stream_id, uint16_t status) {
|
|||||||
}
|
}
|
||||||
auto &stream = (*itr).second;
|
auto &stream = (*itr).second;
|
||||||
|
|
||||||
|
if (worker->current_phase != Phase::MAIN_DURATION) {
|
||||||
|
stream.status_success = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (status >= 200 && status < 300) {
|
if (status >= 200 && status < 300) {
|
||||||
++worker->stats.status[2];
|
++worker->stats.status[2];
|
||||||
stream.status_success = 1;
|
stream.status_success = 1;
|
||||||
@@ -706,40 +797,39 @@ void Client::on_status_code(int32_t stream_id, uint16_t status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::on_stream_close(int32_t stream_id, bool success, bool final) {
|
void Client::on_stream_close(int32_t stream_id, bool success, bool final) {
|
||||||
++req_done;
|
if (worker->current_phase == Phase::MAIN_DURATION) {
|
||||||
--req_inflight;
|
if (req_inflight > 0) {
|
||||||
|
--req_inflight;
|
||||||
|
}
|
||||||
|
auto req_stat = get_req_stat(stream_id);
|
||||||
|
if (!req_stat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto req_stat = get_req_stat(stream_id);
|
req_stat->stream_close_time = std::chrono::steady_clock::now();
|
||||||
if (!req_stat) {
|
if (success) {
|
||||||
return;
|
req_stat->completed = true;
|
||||||
}
|
++worker->stats.req_success;
|
||||||
|
++cstat.req_success;
|
||||||
|
|
||||||
req_stat->stream_close_time = std::chrono::steady_clock::now();
|
if (streams[stream_id].status_success == 1) {
|
||||||
if (success) {
|
++worker->stats.req_status_success;
|
||||||
req_stat->completed = true;
|
} else {
|
||||||
++worker->stats.req_success;
|
++worker->stats.req_failed;
|
||||||
++cstat.req_success;
|
}
|
||||||
|
|
||||||
if (streams[stream_id].status_success == 1) {
|
worker->sample_req_stat(req_stat);
|
||||||
++worker->stats.req_status_success;
|
|
||||||
|
// Count up in successful cases only
|
||||||
|
++worker->request_times_smp.n;
|
||||||
} else {
|
} else {
|
||||||
++worker->stats.req_failed;
|
++worker->stats.req_failed;
|
||||||
|
++worker->stats.req_error;
|
||||||
}
|
}
|
||||||
|
++worker->stats.req_done;
|
||||||
if (sampling_should_pick(worker->request_times_smp)) {
|
++req_done;
|
||||||
sampling_advance_point(worker->request_times_smp);
|
|
||||||
worker->sample_req_stat(req_stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count up in successful cases only
|
|
||||||
++worker->request_times_smp.n;
|
|
||||||
} else {
|
|
||||||
++worker->stats.req_failed;
|
|
||||||
++worker->stats.req_error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++worker->stats.req_done;
|
|
||||||
|
|
||||||
worker->report_progress();
|
worker->report_progress();
|
||||||
streams.erase(stream_id);
|
streams.erase(stream_id);
|
||||||
if (req_left == 0 && req_inflight == 0) {
|
if (req_left == 0 && req_inflight == 0) {
|
||||||
@@ -747,10 +837,14 @@ void Client::on_stream_close(int32_t stream_id, bool success, bool final) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.timing_script && !final && req_left > 0 &&
|
if (!final && req_left > 0) {
|
||||||
submit_request() != 0) {
|
if (config.timing_script) {
|
||||||
process_request_failure();
|
if (!ev_is_active(&request_timeout_watcher)) {
|
||||||
return;
|
ev_feed_event(worker->loop, &request_timeout_watcher, EV_TIMER);
|
||||||
|
}
|
||||||
|
} else if (submit_request() != 0) {
|
||||||
|
process_request_failure();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,7 +959,9 @@ int Client::connection_made() {
|
|||||||
record_connect_time();
|
record_connect_time();
|
||||||
|
|
||||||
if (!config.timing_script) {
|
if (!config.timing_script) {
|
||||||
auto nreq = std::min(req_left, session->max_concurrent_streams());
|
auto nreq = config.is_timing_based_mode()
|
||||||
|
? std::max(req_left, session->max_concurrent_streams())
|
||||||
|
: std::min(req_left, session->max_concurrent_streams());
|
||||||
for (; nreq > 0; --nreq) {
|
for (; nreq > 0; --nreq) {
|
||||||
if (submit_request() != 0) {
|
if (submit_request() != 0) {
|
||||||
process_request_failure();
|
process_request_failure();
|
||||||
@@ -906,7 +1002,9 @@ int Client::on_read(const uint8_t *data, size_t len) {
|
|||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
worker->stats.bytes_total += len;
|
if (worker->current_phase == Phase::MAIN_DURATION) {
|
||||||
|
worker->stats.bytes_total += len;
|
||||||
|
}
|
||||||
signal_write();
|
signal_write();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1176,37 +1274,78 @@ Worker::Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t req_todo, size_t nclients,
|
|||||||
rate(rate),
|
rate(rate),
|
||||||
max_samples(max_samples),
|
max_samples(max_samples),
|
||||||
next_client_id(0) {
|
next_client_id(0) {
|
||||||
if (!config->is_rate_mode()) {
|
if (!config->is_rate_mode() && !config->is_timing_based_mode()) {
|
||||||
progress_interval = std::max(static_cast<size_t>(1), req_todo / 10);
|
progress_interval = std::max(static_cast<size_t>(1), req_todo / 10);
|
||||||
} else {
|
} else {
|
||||||
progress_interval = std::max(static_cast<size_t>(1), nclients / 10);
|
progress_interval = std::max(static_cast<size_t>(1), nclients / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Below timeout is not needed in case of timing-based benchmarking
|
||||||
// create timer that will go off every rate_period
|
// create timer that will go off every rate_period
|
||||||
ev_timer_init(&timeout_watcher, rate_period_timeout_w_cb, 0.,
|
ev_timer_init(&timeout_watcher, rate_period_timeout_w_cb, 0.,
|
||||||
config->rate_period);
|
config->rate_period);
|
||||||
timeout_watcher.data = this;
|
timeout_watcher.data = this;
|
||||||
|
|
||||||
stats.req_stats.reserve(std::min(req_todo, max_samples));
|
if (config->is_timing_based_mode()) {
|
||||||
stats.client_stats.reserve(std::min(nclients, max_samples));
|
stats.req_stats.reserve(std::max(req_todo, max_samples));
|
||||||
|
stats.client_stats.reserve(std::max(nclients, max_samples));
|
||||||
|
} else {
|
||||||
|
stats.req_stats.reserve(std::min(req_todo, max_samples));
|
||||||
|
stats.client_stats.reserve(std::min(nclients, max_samples));
|
||||||
|
}
|
||||||
|
|
||||||
sampling_init(request_times_smp, req_todo, max_samples);
|
sampling_init(request_times_smp, max_samples);
|
||||||
sampling_init(client_smp, nclients, max_samples);
|
sampling_init(client_smp, max_samples);
|
||||||
|
|
||||||
|
ev_timer_init(&duration_watcher, duration_timeout_cb, config->duration, 0.);
|
||||||
|
duration_watcher.data = this;
|
||||||
|
|
||||||
|
ev_timer_init(&warmup_watcher, warmup_timeout_cb, config->warm_up_time, 0.);
|
||||||
|
warmup_watcher.data = this;
|
||||||
|
|
||||||
|
if (config->is_timing_based_mode()) {
|
||||||
|
current_phase = Phase::INITIAL_IDLE;
|
||||||
|
} else {
|
||||||
|
current_phase = Phase::MAIN_DURATION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Worker::~Worker() {
|
Worker::~Worker() {
|
||||||
ev_timer_stop(loop, &timeout_watcher);
|
ev_timer_stop(loop, &timeout_watcher);
|
||||||
|
ev_timer_stop(loop, &duration_watcher);
|
||||||
|
ev_timer_stop(loop, &warmup_watcher);
|
||||||
ev_loop_destroy(loop);
|
ev_loop_destroy(loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Worker::stop_all_clients() {
|
||||||
|
for (auto client : clients) {
|
||||||
|
if (client && client->session) {
|
||||||
|
client->terminate_session();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Worker::free_client(Client *deleted_client) {
|
||||||
|
for (auto &client : clients) {
|
||||||
|
if (client == deleted_client) {
|
||||||
|
client->req_todo = client->req_done;
|
||||||
|
stats.req_todo += client->req_todo;
|
||||||
|
auto index = &client - &clients[0];
|
||||||
|
clients[index] = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Worker::run() {
|
void Worker::run() {
|
||||||
if (!config->is_rate_mode()) {
|
if (!config->is_rate_mode() && !config->is_timing_based_mode()) {
|
||||||
for (size_t i = 0; i < nclients; ++i) {
|
for (size_t i = 0; i < nclients; ++i) {
|
||||||
auto req_todo = nreqs_per_client;
|
auto req_todo = nreqs_per_client;
|
||||||
if (nreqs_rem > 0) {
|
if (nreqs_rem > 0) {
|
||||||
++req_todo;
|
++req_todo;
|
||||||
--nreqs_rem;
|
--nreqs_rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto client = make_unique<Client>(next_client_id++, this, req_todo);
|
auto client = make_unique<Client>(next_client_id++, this, req_todo);
|
||||||
if (client->connect() != 0) {
|
if (client->connect() != 0) {
|
||||||
std::cerr << "client could not connect to host" << std::endl;
|
std::cerr << "client could not connect to host" << std::endl;
|
||||||
@@ -1215,27 +1354,45 @@ void Worker::run() {
|
|||||||
client.release();
|
client.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (config->is_rate_mode()) {
|
||||||
ev_timer_again(loop, &timeout_watcher);
|
ev_timer_again(loop, &timeout_watcher);
|
||||||
|
|
||||||
// call callback so that we don't waste the first rate_period
|
// call callback so that we don't waste the first rate_period
|
||||||
rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
|
rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
|
||||||
|
} else {
|
||||||
|
// call the callback to start for one single time
|
||||||
|
rate_period_timeout_w_cb(loop, &timeout_watcher, 0);
|
||||||
}
|
}
|
||||||
ev_run(loop, 0);
|
ev_run(loop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename Stats, typename Stat>
|
||||||
|
void sample(Sampling &smp, Stats &stats, Stat *s) {
|
||||||
|
++smp.n;
|
||||||
|
if (stats.size() < smp.max_samples) {
|
||||||
|
stats.push_back(*s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto d = std::uniform_int_distribution<unsigned long>(0, smp.n - 1);
|
||||||
|
auto i = d(gen);
|
||||||
|
if (i < smp.max_samples) {
|
||||||
|
stats[i] = *s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void Worker::sample_req_stat(RequestStat *req_stat) {
|
void Worker::sample_req_stat(RequestStat *req_stat) {
|
||||||
stats.req_stats.push_back(*req_stat);
|
sample(request_times_smp, stats.req_stats, req_stat);
|
||||||
assert(stats.req_stats.size() <= max_samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::sample_client_stat(ClientStat *cstat) {
|
void Worker::sample_client_stat(ClientStat *cstat) {
|
||||||
stats.client_stats.push_back(*cstat);
|
sample(client_smp, stats.client_stats, cstat);
|
||||||
assert(stats.client_stats.size() <= max_samples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Worker::report_progress() {
|
void Worker::report_progress() {
|
||||||
if (id != 0 || config->is_rate_mode() || stats.req_done % progress_interval) {
|
if (id != 0 || config->is_rate_mode() || stats.req_done % progress_interval ||
|
||||||
|
config->is_timing_based_mode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1313,14 +1470,10 @@ process_time_stats(const std::vector<std::unique_ptr<Worker>> &workers) {
|
|||||||
size_t nclient_times = 0;
|
size_t nclient_times = 0;
|
||||||
for (const auto &w : workers) {
|
for (const auto &w : workers) {
|
||||||
nrequest_times += w->stats.req_stats.size();
|
nrequest_times += w->stats.req_stats.size();
|
||||||
if (w->request_times_smp.interval != 0.) {
|
request_times_sampling = w->request_times_smp.n > w->stats.req_stats.size();
|
||||||
request_times_sampling = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
nclient_times += w->stats.client_stats.size();
|
nclient_times += w->stats.client_stats.size();
|
||||||
if (w->client_smp.interval != 0.) {
|
client_times_sampling = w->client_smp.n > w->stats.client_stats.size();
|
||||||
client_times_sampling = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<double> request_times;
|
std::vector<double> request_times;
|
||||||
@@ -1581,12 +1734,27 @@ std::unique_ptr<Worker> create_worker(uint32_t id, SSL_CTX *ssl_ctx,
|
|||||||
<< util::duration_str(config.rate_period) << " ";
|
<< util::duration_str(config.rate_period) << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "spawning thread #" << id << ": " << nclients
|
if (config.is_timing_based_mode()) {
|
||||||
<< " total client(s). " << rate_report.str() << nreqs
|
std::cout << "spawning thread #" << id << ": " << nclients
|
||||||
<< " total requests" << std::endl;
|
<< " total client(s). Timing-based test with "
|
||||||
|
<< config.warm_up_time << "s of warm-up time and "
|
||||||
|
<< config.duration << "s of main duration for measurements."
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "spawning thread #" << id << ": " << nclients
|
||||||
|
<< " total client(s). " << rate_report.str() << nreqs
|
||||||
|
<< " total requests" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
return make_unique<Worker>(id, ssl_ctx, nreqs, nclients, rate, max_samples,
|
if (config.is_rate_mode()) {
|
||||||
&config);
|
return make_unique<Worker>(id, ssl_ctx, nreqs, nclients, rate, max_samples,
|
||||||
|
&config);
|
||||||
|
} else {
|
||||||
|
// Here rate is same as client because the rate_timeout callback
|
||||||
|
// will be called only once
|
||||||
|
return make_unique<Worker>(id, ssl_ctx, nreqs, nclients, nclients,
|
||||||
|
max_samples, &config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -1652,7 +1820,9 @@ Options:
|
|||||||
Number of requests across all clients. If it is used
|
Number of requests across all clients. If it is used
|
||||||
with --timing-script-file option, this option specifies
|
with --timing-script-file option, this option specifies
|
||||||
the number of requests each client performs rather than
|
the number of requests each client performs rather than
|
||||||
the number of requests across all clients.
|
the number of requests across all clients. This option
|
||||||
|
is ignored if timing-based benchmarking is enabled (see
|
||||||
|
--duration option).
|
||||||
Default: )"
|
Default: )"
|
||||||
<< config.nreqs << R"(
|
<< config.nreqs << R"(
|
||||||
-c, --clients=<N>
|
-c, --clients=<N>
|
||||||
@@ -1737,6 +1907,13 @@ Options:
|
|||||||
length of the period in time. This option is ignored if
|
length of the period in time. This option is ignored if
|
||||||
the rate option is not used. The default value for this
|
the rate option is not used. The default value for this
|
||||||
option is 1s.
|
option is 1s.
|
||||||
|
-D, --duration=<N>
|
||||||
|
Specifies the main duration for the measurements in case
|
||||||
|
of timing-based benchmarking.
|
||||||
|
--warm-up-time=<DURATION>
|
||||||
|
Specifies the time period before starting the actual
|
||||||
|
measurements, in case of timing-based benchmarking.
|
||||||
|
Needs to provided along with -D option.
|
||||||
-T, --connection-active-timeout=<DURATION>
|
-T, --connection-active-timeout=<DURATION>
|
||||||
Specifies the maximum time that h2load is willing to
|
Specifies the maximum time that h2load is willing to
|
||||||
keep a connection open, regardless of the activity on
|
keep a connection open, regardless of the activity on
|
||||||
@@ -1850,6 +2027,7 @@ int main(int argc, char **argv) {
|
|||||||
{"rate", required_argument, nullptr, 'r'},
|
{"rate", required_argument, nullptr, 'r'},
|
||||||
{"connection-active-timeout", required_argument, nullptr, 'T'},
|
{"connection-active-timeout", required_argument, nullptr, 'T'},
|
||||||
{"connection-inactivity-timeout", required_argument, nullptr, 'N'},
|
{"connection-inactivity-timeout", required_argument, nullptr, 'N'},
|
||||||
|
{"duration", required_argument, nullptr, 'D'},
|
||||||
{"timing-script-file", required_argument, &flag, 3},
|
{"timing-script-file", required_argument, &flag, 3},
|
||||||
{"base-uri", required_argument, nullptr, 'B'},
|
{"base-uri", required_argument, nullptr, 'B'},
|
||||||
{"npn-list", required_argument, &flag, 4},
|
{"npn-list", required_argument, &flag, 4},
|
||||||
@@ -1857,11 +2035,12 @@ int main(int argc, char **argv) {
|
|||||||
{"h1", no_argument, &flag, 6},
|
{"h1", no_argument, &flag, 6},
|
||||||
{"header-table-size", required_argument, &flag, 7},
|
{"header-table-size", required_argument, &flag, 7},
|
||||||
{"encoder-header-table-size", required_argument, &flag, 8},
|
{"encoder-header-table-size", required_argument, &flag, 8},
|
||||||
|
{"warm-up-time", required_argument, &flag, 9},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
auto c =
|
auto c = getopt_long(argc, argv,
|
||||||
getopt_long(argc, argv, "hvW:c:d:m:n:p:t:w:H:i:r:T:N:B:", long_options,
|
"hvW:c:d:m:n:p:t:w:H:i:r:T:N:D:B:", long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2016,6 +2195,14 @@ int main(int argc, char **argv) {
|
|||||||
config.base_uri = arg.str();
|
config.base_uri = arg.str();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'D':
|
||||||
|
config.duration = strtoul(optarg, nullptr, 10);
|
||||||
|
if (config.duration == 0) {
|
||||||
|
std::cerr << "-D: the main duration for timing-based benchmarking "
|
||||||
|
<< "must be positive." << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
config.verbose = true;
|
config.verbose = true;
|
||||||
break;
|
break;
|
||||||
@@ -2072,6 +2259,14 @@ int main(int argc, char **argv) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 9:
|
||||||
|
// --warm-up-time
|
||||||
|
config.warm_up_time = util::parse_duration_with_unit(optarg);
|
||||||
|
if (!std::isfinite(config.warm_up_time)) {
|
||||||
|
std::cerr << "--warm-up-time: value error " << optarg << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -2157,8 +2352,9 @@ int main(int argc, char **argv) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.nreqs == 0) {
|
if (config.nreqs == 0 && !config.is_timing_based_mode()) {
|
||||||
std::cerr << "-n: the number of requests must be strictly greater than 0."
|
std::cerr << "-n: the number of requests must be strictly greater than 0 "
|
||||||
|
"if timing-based test is not being run."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -2182,7 +2378,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// With timing script, we don't distribute config.nreqs to each
|
// With timing script, we don't distribute config.nreqs to each
|
||||||
// client or thread.
|
// client or thread.
|
||||||
if (!config.timing_script && config.nreqs < config.nclients) {
|
if (!config.timing_script && config.nreqs < config.nclients &&
|
||||||
|
!config.is_timing_based_mode()) {
|
||||||
std::cerr << "-n, -c: the number of requests must be greater than or "
|
std::cerr << "-n, -c: the number of requests must be greater than or "
|
||||||
<< "equal to the clients." << std::endl;
|
<< "equal to the clients." << std::endl;
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -2190,11 +2387,14 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (config.nclients < config.nthreads) {
|
if (config.nclients < config.nthreads) {
|
||||||
std::cerr << "-c, -t: the number of clients must be greater than or equal "
|
std::cerr << "-c, -t: the number of clients must be greater than or equal "
|
||||||
"to the number of threads."
|
<< "to the number of threads." << std::endl;
|
||||||
<< std::endl;
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.is_timing_based_mode()) {
|
||||||
|
config.nreqs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (config.is_rate_mode()) {
|
if (config.is_rate_mode()) {
|
||||||
if (config.rate < config.nthreads) {
|
if (config.rate < config.nthreads) {
|
||||||
std::cerr << "-r, -t: the connection rate must be greater than or equal "
|
std::cerr << "-r, -t: the connection rate must be greater than or equal "
|
||||||
@@ -2528,7 +2728,7 @@ int main(int argc, char **argv) {
|
|||||||
// Requests which have not been issued due to connection errors, are
|
// Requests which have not been issued due to connection errors, are
|
||||||
// counted towards req_failed and req_error.
|
// counted towards req_failed and req_error.
|
||||||
auto req_not_issued =
|
auto req_not_issued =
|
||||||
stats.req_todo - stats.req_status_success - stats.req_failed;
|
(stats.req_todo - stats.req_status_success - stats.req_failed);
|
||||||
stats.req_failed += req_not_issued;
|
stats.req_failed += req_not_issued;
|
||||||
stats.req_error += req_not_issued;
|
stats.req_error += req_not_issued;
|
||||||
|
|
||||||
@@ -2539,10 +2739,17 @@ int main(int argc, char **argv) {
|
|||||||
double rps = 0;
|
double rps = 0;
|
||||||
int64_t bps = 0;
|
int64_t bps = 0;
|
||||||
if (duration.count() > 0) {
|
if (duration.count() > 0) {
|
||||||
auto secd = std::chrono::duration_cast<
|
if (config.is_timing_based_mode()) {
|
||||||
std::chrono::duration<double, std::chrono::seconds::period>>(duration);
|
// we only want to consider the main duration if warm-up is given
|
||||||
rps = stats.req_success / secd.count();
|
rps = stats.req_success / config.duration;
|
||||||
bps = stats.bytes_total / secd.count();
|
bps = stats.bytes_total / config.duration;
|
||||||
|
} else {
|
||||||
|
auto secd = std::chrono::duration_cast<
|
||||||
|
std::chrono::duration<double, std::chrono::seconds::period>>(
|
||||||
|
duration);
|
||||||
|
rps = stats.req_success / secd.count();
|
||||||
|
bps = stats.bytes_total / secd.count();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double header_space_savings = 0.;
|
double header_space_savings = 0.;
|
||||||
|
|||||||
36
src/h2load.h
36
src/h2load.h
@@ -85,6 +85,10 @@ struct Config {
|
|||||||
// 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;
|
||||||
|
// amount of time for main measurements in timing-based test
|
||||||
|
ev_tstamp duration;
|
||||||
|
// amount of time to wait before starting measurements in timing-based test
|
||||||
|
ev_tstamp warm_up_time;
|
||||||
// amount of time to wait for activity on a given connection
|
// amount of time to wait for activity on a given connection
|
||||||
ev_tstamp conn_active_timeout;
|
ev_tstamp conn_active_timeout;
|
||||||
// amount of time to wait after the last request is made on a connection
|
// amount of time to wait after the last request is made on a connection
|
||||||
@@ -118,6 +122,7 @@ struct Config {
|
|||||||
~Config();
|
~Config();
|
||||||
|
|
||||||
bool is_rate_mode() const;
|
bool is_rate_mode() const;
|
||||||
|
bool is_timing_based_mode() const;
|
||||||
bool has_base_uri() const;
|
bool has_base_uri() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -215,15 +220,21 @@ struct Stats {
|
|||||||
|
|
||||||
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
||||||
|
|
||||||
|
// This type tells whether the client is in warmup phase or not or is over
|
||||||
|
enum class Phase {
|
||||||
|
INITIAL_IDLE, // Initial idle state before warm-up phase
|
||||||
|
WARM_UP, // Warm up phase when no measurements are done
|
||||||
|
MAIN_DURATION, // Main measurement phase; if timing-based
|
||||||
|
// test is not run, this is the default phase
|
||||||
|
DURATION_OVER // This phase occurs after the measurements are over
|
||||||
|
};
|
||||||
|
|
||||||
struct Client;
|
struct Client;
|
||||||
|
|
||||||
// We use systematic sampling method
|
// We use reservoir sampling method
|
||||||
struct Sampling {
|
struct Sampling {
|
||||||
// sampling interval
|
// maximum number of samples
|
||||||
double interval;
|
size_t max_samples;
|
||||||
// cumulative value of interval, and the next point is the integer
|
|
||||||
// rounded up from this value.
|
|
||||||
double point;
|
|
||||||
// number of samples seen, including discarded samples.
|
// number of samples seen, including discarded samples.
|
||||||
size_t n;
|
size_t n;
|
||||||
};
|
};
|
||||||
@@ -253,6 +264,15 @@ struct Worker {
|
|||||||
ev_timer timeout_watcher;
|
ev_timer timeout_watcher;
|
||||||
// The next client ID this worker assigns
|
// The next client ID this worker assigns
|
||||||
uint32_t next_client_id;
|
uint32_t next_client_id;
|
||||||
|
// Keeps track of the current phase (for timing-based experiment) for the
|
||||||
|
// worker
|
||||||
|
Phase current_phase;
|
||||||
|
// We need to keep track of the clients in order to stop them when needed
|
||||||
|
std::vector<Client *> clients;
|
||||||
|
// This is only active when there is not a bounded number of requests
|
||||||
|
// specified
|
||||||
|
ev_timer duration_watcher;
|
||||||
|
ev_timer warmup_watcher;
|
||||||
|
|
||||||
Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
|
Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients,
|
||||||
size_t rate, size_t max_samples, Config *config);
|
size_t rate, size_t max_samples, Config *config);
|
||||||
@@ -263,6 +283,10 @@ struct Worker {
|
|||||||
void sample_client_stat(ClientStat *cstat);
|
void sample_client_stat(ClientStat *cstat);
|
||||||
void report_progress();
|
void report_progress();
|
||||||
void report_rate_progress();
|
void report_rate_progress();
|
||||||
|
// This function calls the destructors of all the clients.
|
||||||
|
void stop_all_clients();
|
||||||
|
// This function frees a client from the list of clients for this Worker.
|
||||||
|
void free_client(Client *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stream {
|
struct Stream {
|
||||||
|
|||||||
@@ -404,17 +404,10 @@ int htp_msg_begincb(http_parser *htp) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
|
||||||
int htp_statuscb(http_parser *htp, const char *at, size_t length) {
|
|
||||||
auto client = static_cast<HttpClient *>(htp->data);
|
|
||||||
client->upgrade_response_status_code = htp->status_code;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int htp_msg_completecb(http_parser *htp) {
|
int htp_msg_completecb(http_parser *htp) {
|
||||||
auto client = static_cast<HttpClient *>(htp->data);
|
auto client = static_cast<HttpClient *>(htp->data);
|
||||||
|
client->upgrade_response_status_code = htp->status_code;
|
||||||
client->upgrade_response_complete = true;
|
client->upgrade_response_complete = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -424,7 +417,7 @@ namespace {
|
|||||||
constexpr http_parser_settings htp_hooks = {
|
constexpr http_parser_settings htp_hooks = {
|
||||||
htp_msg_begincb, // http_cb on_message_begin;
|
htp_msg_begincb, // http_cb on_message_begin;
|
||||||
nullptr, // http_data_cb on_url;
|
nullptr, // http_data_cb on_url;
|
||||||
htp_statuscb, // http_data_cb on_status;
|
nullptr, // http_data_cb on_status;
|
||||||
nullptr, // http_data_cb on_header_field;
|
nullptr, // http_data_cb on_header_field;
|
||||||
nullptr, // http_data_cb on_header_value;
|
nullptr, // http_data_cb on_header_value;
|
||||||
nullptr, // http_cb on_headers_complete;
|
nullptr, // http_cb on_headers_complete;
|
||||||
|
|||||||
21
src/shrpx.cc
21
src/shrpx.cc
@@ -1392,7 +1392,7 @@ constexpr auto DEFAULT_NPN_LIST = StringRef::from_lit("h2,h2-16,h2-14,"
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.1");
|
constexpr auto DEFAULT_TLS_MIN_PROTO_VERSION = StringRef::from_lit("TLSv1.2");
|
||||||
#ifdef TLS1_3_VERSION
|
#ifdef TLS1_3_VERSION
|
||||||
constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
|
constexpr auto DEFAULT_TLS_MAX_PROTO_VERSION = StringRef::from_lit("TLSv1.3");
|
||||||
#else // !TLS1_3_VERSION
|
#else // !TLS1_3_VERSION
|
||||||
@@ -2071,11 +2071,14 @@ SSL/TLS:
|
|||||||
Don't verify backend server's certificate if TLS is
|
Don't verify backend server's certificate if TLS is
|
||||||
enabled for backend connections.
|
enabled for backend connections.
|
||||||
--cacert=<PATH>
|
--cacert=<PATH>
|
||||||
Set path to trusted CA certificate file used in backend
|
Set path to trusted CA certificate file. It is used in
|
||||||
TLS connections. The file must be in PEM format. It
|
backend TLS connections to verify peer's certificate.
|
||||||
can contain multiple certificates. If the linked
|
It is also used to verify OCSP response from the script
|
||||||
OpenSSL is configured to load system wide certificates,
|
set by --fetch-ocsp-response-file. The file must be in
|
||||||
they are loaded at startup regardless of this option.
|
PEM format. It can contain multiple certificates. If
|
||||||
|
the linked OpenSSL is configured to load system wide
|
||||||
|
certificates, they are loaded at startup regardless of
|
||||||
|
this option.
|
||||||
--private-key-passwd-file=<PATH>
|
--private-key-passwd-file=<PATH>
|
||||||
Path to file that contains password for the server's
|
Path to file that contains password for the server's
|
||||||
private key. If none is given and the private key is
|
private key. If none is given and the private key is
|
||||||
@@ -2131,7 +2134,11 @@ SSL/TLS:
|
|||||||
--tls-min-proto-version and --tls-max-proto-version are
|
--tls-min-proto-version and --tls-max-proto-version are
|
||||||
enabled. If the protocol list advertised by client does
|
enabled. If the protocol list advertised by client does
|
||||||
not overlap this range, you will receive the error
|
not overlap this range, you will receive the error
|
||||||
message "unknown protocol". The available versions are:
|
message "unknown protocol". If a protocol version lower
|
||||||
|
than TLSv1.2 is specified, make sure that the compatible
|
||||||
|
ciphers are included in --ciphers option. The default
|
||||||
|
cipher list only includes ciphers compatible with
|
||||||
|
TLSv1.2 or above. The available versions are:
|
||||||
)"
|
)"
|
||||||
#ifdef TLS1_3_VERSION
|
#ifdef TLS1_3_VERSION
|
||||||
"TLSv1.3, "
|
"TLSv1.3, "
|
||||||
|
|||||||
@@ -445,25 +445,32 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
forwarded_for_ = StringRef{buf.base, p};
|
forwarded_for_ = StringRef{buf.base, p};
|
||||||
} else if (family == AF_INET6) {
|
} else if (!faddr_->accept_proxy_protocol &&
|
||||||
// 2 for '[' and ']'
|
!config->conn.upstream.accept_proxy_protocol) {
|
||||||
auto len = 2 + ipaddr_.size();
|
init_forwarded_for(family, ipaddr_);
|
||||||
// 1 for terminating NUL.
|
|
||||||
auto buf = make_byte_ref(balloc_, len + 1);
|
|
||||||
auto p = buf.base;
|
|
||||||
*p++ = '[';
|
|
||||||
p = std::copy(std::begin(ipaddr_), std::end(ipaddr_), p);
|
|
||||||
*p++ = ']';
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
forwarded_for_ = StringRef{buf.base, p};
|
|
||||||
} else {
|
|
||||||
// family == AF_INET or family == AF_UNIX
|
|
||||||
forwarded_for_ = ipaddr_;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientHandler::init_forwarded_for(int family, const StringRef &ipaddr) {
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
// 2 for '[' and ']'
|
||||||
|
auto len = 2 + ipaddr.size();
|
||||||
|
// 1 for terminating NUL.
|
||||||
|
auto buf = make_byte_ref(balloc_, len + 1);
|
||||||
|
auto p = buf.base;
|
||||||
|
*p++ = '[';
|
||||||
|
p = std::copy(std::begin(ipaddr), std::end(ipaddr), p);
|
||||||
|
*p++ = ']';
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
forwarded_for_ = StringRef{buf.base, p};
|
||||||
|
} else {
|
||||||
|
// family == AF_INET or family == AF_UNIX
|
||||||
|
forwarded_for_ = ipaddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientHandler::setup_upstream_io_callback() {
|
void ClientHandler::setup_upstream_io_callback() {
|
||||||
if (conn_.tls.ssl) {
|
if (conn_.tls.ssl) {
|
||||||
conn_.prepare_server_handshake();
|
conn_.prepare_server_handshake();
|
||||||
@@ -1459,6 +1466,14 @@ int ClientHandler::proxy_protocol_read() {
|
|||||||
<< " bytes read";
|
<< " bytes read";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto config = get_config();
|
||||||
|
auto &fwdconf = config->http.forwarded;
|
||||||
|
|
||||||
|
if ((fwdconf.params & FORWARDED_FOR) &&
|
||||||
|
fwdconf.for_node_type == FORWARDED_NODE_IP) {
|
||||||
|
init_forwarded_for(family, ipaddr_);
|
||||||
|
}
|
||||||
|
|
||||||
return on_proxy_protocol_finish();
|
return on_proxy_protocol_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ public:
|
|||||||
|
|
||||||
Worker *get_worker() const;
|
Worker *get_worker() const;
|
||||||
|
|
||||||
|
// Initializes forwarded_for_.
|
||||||
|
void init_forwarded_for(int family, const StringRef &ipaddr);
|
||||||
|
|
||||||
using ReadBuf = DefaultMemchunkBuffer;
|
using ReadBuf = DefaultMemchunkBuffer;
|
||||||
|
|
||||||
ReadBuf *get_rb();
|
ReadBuf *get_rb();
|
||||||
|
|||||||
@@ -201,9 +201,7 @@ ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||||||
if (!trailers.empty()) {
|
if (!trailers.empty()) {
|
||||||
std::vector<nghttp2_nv> nva;
|
std::vector<nghttp2_nv> nva;
|
||||||
nva.reserve(trailers.size());
|
nva.reserve(trailers.size());
|
||||||
// We cannot use nocopy version, since nva may be touched after
|
http2::copy_headers_to_nva_nocopy(nva, trailers, http2::HDOP_STRIP_ALL);
|
||||||
// Downstream object is deleted.
|
|
||||||
http2::copy_headers_to_nva(nva, trailers, http2::HDOP_STRIP_ALL);
|
|
||||||
if (!nva.empty()) {
|
if (!nva.empty()) {
|
||||||
rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
|
rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
|||||||
@@ -45,7 +45,9 @@
|
|||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/dh.h>
|
#include <openssl/dh.h>
|
||||||
|
#ifndef OPENSSL_NO_OCSP
|
||||||
#include <openssl/ocsp.h>
|
#include <openssl/ocsp.h>
|
||||||
|
#endif // OPENSSL_NO_OCSP
|
||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
@@ -829,6 +831,22 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||||
|
|
||||||
|
if (SSL_CTX_set_default_verify_paths(ssl_ctx) != 1) {
|
||||||
|
LOG(WARN) << "Could not load system trusted ca certificates: "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tlsconf.cacert.empty()) {
|
||||||
|
if (SSL_CTX_load_verify_locations(ssl_ctx, tlsconf.cacert.c_str(),
|
||||||
|
nullptr) != 1) {
|
||||||
|
LOG(FATAL) << "Could not load trusted ca certificates from "
|
||||||
|
<< tlsconf.cacert << ": "
|
||||||
|
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||||
|
DIE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!tlsconf.private_key_passwd.empty()) {
|
if (!tlsconf.private_key_passwd.empty()) {
|
||||||
SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb);
|
SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb);
|
||||||
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, config);
|
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, config);
|
||||||
@@ -1821,7 +1839,9 @@ int proto_version_from_string(const StringRef &v) {
|
|||||||
|
|
||||||
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||||
size_t ocsp_resplen) {
|
size_t ocsp_resplen) {
|
||||||
#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
||||||
|
#if !defined(OPENSSL_NO_OCSP) && !defined(LIBRESSL_VERSION_NUMBER) && \
|
||||||
|
OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
STACK_OF(X509) * chain_certs;
|
STACK_OF(X509) * chain_certs;
|
||||||
@@ -1844,12 +1864,11 @@ int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
|||||||
}
|
}
|
||||||
auto bs_deleter = defer(OCSP_BASICRESP_free, bs);
|
auto bs_deleter = defer(OCSP_BASICRESP_free, bs);
|
||||||
|
|
||||||
auto store = X509_STORE_new();
|
auto store = SSL_CTX_get_cert_store(ssl_ctx);
|
||||||
auto store_deleter = defer(X509_STORE_free, store);
|
|
||||||
|
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
|
||||||
rv = OCSP_basic_verify(bs, chain_certs, store, OCSP_TRUSTOTHER);
|
rv = OCSP_basic_verify(bs, chain_certs, store, 0);
|
||||||
|
|
||||||
if (rv != 1) {
|
if (rv != 1) {
|
||||||
LOG(ERROR) << "OCSP_basic_verify failed: "
|
LOG(ERROR) << "OCSP_basic_verify failed: "
|
||||||
@@ -1894,8 +1913,8 @@ int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
|||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
LOG(INFO) << "OCSP verification succeeded";
|
LOG(INFO) << "OCSP verification succeeded";
|
||||||
}
|
}
|
||||||
#endif // !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >=
|
#endif // !defined(OPENSSL_NO_OCSP) && !defined(LIBRESSL_VERSION_NUMBER)
|
||||||
// 0x10002000L
|
// && OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1103,8 +1103,9 @@ std::string format_duration(double t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string dtos(double n) {
|
std::string dtos(double n) {
|
||||||
auto f = utos(static_cast<int64_t>(round(100. * n)) % 100);
|
auto m = llround(100. * n);
|
||||||
return utos(static_cast<int64_t>(n)) + "." + (f.size() == 1 ? "0" : "") + f;
|
auto f = utos(m % 100);
|
||||||
|
return utos(m / 100) + "." + (f.size() == 1 ? "0" : "") + f;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
|
StringRef make_http_hostport(BlockAllocator &balloc, const StringRef &host,
|
||||||
|
|||||||
2
third-party/build_config.rb
vendored
2
third-party/build_config.rb
vendored
@@ -4,7 +4,7 @@ MRuby::Build.new do |conf|
|
|||||||
|
|
||||||
# C++ project needs this. Without this, mruby exception does not
|
# C++ project needs this. Without this, mruby exception does not
|
||||||
# properly destory C++ object allocated on stack.
|
# properly destory C++ object allocated on stack.
|
||||||
conf.enable_cxx_abi
|
conf.enable_cxx_exception
|
||||||
|
|
||||||
conf.build_dir = ENV['BUILD_DIR']
|
conf.build_dir = ENV['BUILD_DIR']
|
||||||
|
|
||||||
|
|||||||
2
third-party/mruby
vendored
2
third-party/mruby
vendored
Submodule third-party/mruby updated: 22464fe5a0...4696093673
Reference in New Issue
Block a user