Compare commits

..

72 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
d2324bdda1 Update bash_completion 2017-09-20 22:42:14 +09:00
Tatsuhiro Tsujikawa
6f0ae9d49a Update manual pages 2017-09-20 22:41:56 +09:00
Tatsuhiro Tsujikawa
0389af5724 Bump up version number to 1.26.0 2017-09-20 22:29:38 +09:00
Tatsuhiro Tsujikawa
1766e25f45 Update AUTHORS 2017-09-20 22:28:43 +09:00
Tatsuhiro Tsujikawa
323001238a clang-format 2017-09-20 22:08:22 +09:00
Tatsuhiro Tsujikawa
91f062f873 src: Fix compile error 2017-09-20 22:08:08 +09:00
Tatsuhiro Tsujikawa
650a0cfbff Merge pull request #1013 from marcbachmann/patch-1
Fix some typos in the nghttpx how-to doc
2017-09-13 23:59:07 +09:00
Marc Bachmann
e6b8b3d1d3 docs: Fix some typos in the nghttpx how-to 2017-09-11 22:10:03 +02:00
Tatsuhiro Tsujikawa
a170023f23 nghttpx: Verify OCSP response using trusted CA certificates 2017-09-01 21:35:38 +09:00
Tatsuhiro Tsujikawa
4be4c0cddc Revert "nghttpx: Verify OCSP response using trusted CA certificates"
This reverts commit 59c78d5809.
2017-08-30 22:27:02 +09:00
Tatsuhiro Tsujikawa
0de9d374df Merge pull request #1002 from GitaiQAQ/master
Just fix unreachable links and remove ndk...
2017-08-26 22:39:24 +09:00
Tatsuhiro Tsujikawa
0df199198a Merge pull request #1001 from rlei/master
Fix OCSP related error when building with BoringSSL
2017-08-26 22:00:56 +09:00
Gitai
7646e376e0 Fix unreachable 2017-08-26 12:54:03 +08:00
Rick Lei
5996798a34 Fix OCSP related error when building with BoringSSL
BoringSSL has no "openssl/ocsp.h" nor most OCSP related APIs used in
shrpx_tls.cc. This commit add ifdefs to disable related code to allow
building nghttp2 with BoringSSL (again).

It's possible to use !defined(OPENSSL_IS_BORINGSSL), but since BoringSSL
defines OPENSSL_NO_OCSP which is more specific, I chose to go with the
latter one.
2017-08-24 11:56:46 -04:00
Tatsuhiro Tsujikawa
6fec532012 Merge pull request #998 from nghttp2/h2load-fix-timing-script-stall
Fix bug that timing script stalls with -m1
2017-08-24 21:17:43 +09:00
Tatsuhiro Tsujikawa
15713e0b7c h2load: Ignore -n for timing-based mode instead of requiring -n=0 2017-08-23 20:35:01 +09:00
Tatsuhiro Tsujikawa
a6a561af47 Fix bug that timing script stalls with -m1 2017-08-23 20:10:23 +09:00
Tatsuhiro Tsujikawa
09c468a4b4 Merge branch 'sohamm17-master' 2017-08-23 19:22:44 +09:00
Tatsuhiro Tsujikawa
bcda1c2409 Fix assertion failure 2017-08-23 19:22:23 +09:00
Tatsuhiro Tsujikawa
afcd8d9ab1 clang-format 2017-08-23 19:19:00 +09:00
Tatsuhiro Tsujikawa
c9b1c91944 Fix compile error 2017-08-23 19:18:27 +09:00
Tatsuhiro Tsujikawa
5d9434eb09 Merge branch 'master' of https://github.com/sohamm17/nghttp2 into sohamm17-master 2017-08-23 19:16:40 +09:00
Tatsuhiro Tsujikawa
1a44b5d52a Merge pull request #984 from nghttp2/h2load-reservoir-sampling
h2load: Reservoir sampling
2017-08-23 19:00:28 +09:00
Tatsuhiro Tsujikawa
6635ca5e26 Merge pull request #988 from dvetutnev/refactoring_include_directories
Refactoring include directories
2017-08-23 18:59:28 +09:00
Tatsuhiro Tsujikawa
9c6c78833b Bump up version number to 1.26.0-DEV 2017-08-18 23:19:36 +09:00
Tatsuhiro Tsujikawa
9a9ab0813c Update manual pages 2017-08-18 23:00:58 +09:00
Tatsuhiro Tsujikawa
0ccaaa48ce Bump up version number to 1.25.0, LT revision to 28:0:14 2017-08-18 22:38:10 +09:00
Tatsuhiro Tsujikawa
3f2fe98dd1 Update AUTHORS 2017-08-18 22:11:11 +09:00
Tatsuhiro Tsujikawa
0d91e9c255 Update doc 2017-08-18 22:06:43 +09:00
Dmitriy Vetutnev
af926fbe1f Refactoring include directories for build as CMake subdirectory (add_subdirectory(nghttp2)) 2017-08-16 21:28:12 +03:00
Tatsuhiro Tsujikawa
83039ae2d4 h2load: Reservoir sampling 2017-08-14 20:25:02 +09:00
Tatsuhiro Tsujikawa
4c53da6961 Merge pull request #983 from addaleax/static-rcbuf
lib: add nghttp2_rcbuf_is_static()
2017-08-13 09:10:41 +09:00
Anna Henningsen
eb306f463e lib: add nghttp2_rcbuf_is_static()
Add a `nghttp2_rcbuf_is_static()` method to tell whether a rcbuf
is statically allocated.

This can be useful for language bindings that wish to avoid
creating duplicate strings for these buffers; concretely, I am
planning to use this in the Node HTTP/2 module that is being
introduced.
2017-08-12 17:48:14 +02:00
Tatsuhiro Tsujikawa
788835c5fd Merge pull request #980 from nghttp2/fix-forwarded-for-with-proxyprotocol
Fix bug that forwarded for is not affected by proxy protocol
2017-08-09 23:34:43 +09:00
Tatsuhiro Tsujikawa
4d76606fa2 Fix bug that forwarded for is not affected by proxy protocol 2017-08-09 22:44:14 +09:00
Soham Sinha
1baf7d34b3 Duration watcher and warmup watcher is initialised in Worker constructor. Statistic calculation is removed from duration watcher call_back, it's done in free_client. 2017-08-08 17:26:37 -04:00
Soham Sinha
c78159469a Added a function to free a client from Worker's list of client, if the client is destroyed 2017-08-07 18:58:12 -04:00
Soham Sinha
b72ca0289c formatting issue 2017-08-04 14:20:00 -04:00
Soham Sinha
46f670f8a2 concurrent connections are created in timing-based mode. Some safety asserts added. 2017-08-03 16:15:14 -04:00
Soham Sinha
4b44362b9f minor style changes 2017-08-01 20:22:20 -04:00
Soham Sinha
d068a29798 removed unnecessary code 2017-08-01 19:51:47 -04:00
Soham Sinha
0836a51408 Handling requests starting in warm-up phase and ending in MAIN_DURATION 2017-08-01 18:29:00 -04:00
Soham Sinha
566cee8fe7 MAIN_DURATION is initiliazed in Worker constructor, MAIN_DURATION check is removed from two functions because those functions are needed in warm-up phase as well. 2017-08-01 17:45:52 -04:00
Soham Sinha
e85698e131 MAIN_DURATION is initiliazed in Worker constructor, MAIN_DURATION check is removed from two functions because those functions are needed in warm-up phase as well. 2017-08-01 17:45:18 -04:00
Soham Sinha
5f3c541c4c enabled --duration option. 2017-07-28 17:31:13 -04:00
Soham Sinha
3c43e00d8a Timing (#1)
* Adding timing-sensitive load test option in h2load.

* more checks added for parameters

* A worker thread can control its clients' warmup and main duration.

* Changed warmup to an enum variable.

* removed unnecessary call to ev_timer_stop

* assertion is done before starting main measurement phase

* phase variable is implemented only inside the Worker class

* enum to enum class

* else indentation corrected

* check added for timing-based test when duration CB is called explicitly

* New argument is introduced for timing-based benchmarking.

* styling corrections

* duration watcher initialization is pushed back into warmup timeout

* Warmup and Duration timer is moved to Worker instead of clients. Now both timers and phase belongs to the Workers.

* some client functions are modified to return if it's not main_duration phase. client is not destructed but sessions are terminated

* outputs are adjusted for thread.

* Needed to check if a session exist before terminating

* formatting

* more formatting

* formatting
2017-07-28 17:08:20 -04:00
Tatsuhiro Tsujikawa
92d686d356 Merge branch 'mruby-1.3.0' 2017-07-28 00:51:48 +09:00
Tatsuhiro Tsujikawa
0f69e9c825 Fix typo 2017-07-28 00:51:34 +09:00
Tatsuhiro Tsujikawa
217d979458 Update mruby to 1.3.0
Fix compile error with mruby 1.3.0
2017-07-28 00:23:25 +09:00
Tatsuhiro Tsujikawa
cc289972fc Merge pull request #958 from sebdeckers/patch-1
fix: typo
2017-07-15 11:44:14 +09:00
Sebastiaan Deckers
c601e603c2 fix: typo
Came up in downstream code review by @lucaslago https://github.com/nodejs/node/pull/14239#discussion_r127539852
2017-07-15 07:46:26 +08:00
Tatsuhiro Tsujikawa
1002c6da1c src: Use llround instead of round 2017-07-12 23:23:47 +09:00
Tatsuhiro Tsujikawa
0911337689 Bump up version number to 1.25.0-DEV 2017-07-02 17:51:24 +09:00
Tatsuhiro Tsujikawa
3bcc416e13 Update manual pages 2017-07-02 13:40:21 +09:00
Tatsuhiro Tsujikawa
65837806f5 Bump up version number to 1.24.0 2017-07-02 13:37:53 +09:00
Tatsuhiro Tsujikawa
b0772dcc66 Update AUTHORS 2017-07-02 13:31:47 +09:00
Tatsuhiro Tsujikawa
c6d65aad3b Merge branch 'nghttp-not-upgrade-without-reason-phrase' 2017-06-28 21:36:13 +09:00
Tatsuhiro Tsujikawa
18dd20ce55 nghttp: Fix bug that upgrade fails if reason-phrase is missing 2017-06-28 01:01:39 +09:00
Tatsuhiro Tsujikawa
0f6d76a501 Merge pull request #947 from bassosimone/patch-1
README.rst: fix typo
2017-06-23 00:33:00 +09:00
Simone Basso
0f1320109f README.rst: fix typo 2017-06-22 17:03:05 +02:00
Tatsuhiro Tsujikawa
defa28c618 Merge pull request #945 from benjaminp/trailer-grammar
fix up grammar in submit_trailer docs
2017-06-20 00:35:46 +09:00
Benjamin Peterson
b7c95be47c fix up grammar in submit_trailer docs 2017-06-18 23:55:53 -07:00
Tatsuhiro Tsujikawa
a18d154e0e Merge pull request #943 from nghttp2/nghttpx-verify-ocsp-resp-with-cacerts
nghttpx: Verify OCSP response using trusted CA certificates
2017-06-15 20:56:44 +09:00
Tatsuhiro Tsujikawa
52195a12ee Merge pull request #941 from nghttp2/nghttpx-tls-min-proto
nghttpx: Set default minimum TLS version to TLSv1.2
2017-06-13 23:01:54 +09:00
Tatsuhiro Tsujikawa
59c78d5809 nghttpx: Verify OCSP response using trusted CA certificates 2017-06-13 23:00:26 +09:00
Tatsuhiro Tsujikawa
be164fc8f9 nghttpx: Set default minimum TLS version to TLSv1.2
Previously, the default minimum TLS version was TLSv1.1, but the
default cipher list didn't include any compatible ciphers with it.
This made handshake fail if TLSv1.1 was negotiated because there was
no shared ciphers.  To make the default settings consistent, the
default minimum TLS version is now TLSv1.2.
2017-06-12 23:54:12 +09:00
Tatsuhiro Tsujikawa
5833ef1efc Merge pull request #938 from benjaminp/fix-clean
fix cleaning in out-of-tree builds
2017-06-12 00:21:10 +09:00
Benjamin Peterson
28f88d46f3 fix cleaning in out-of-tree builds
The altered previously failed if the rst sources hadn't been copied over.
2017-06-11 00:03:36 -07:00
Tatsuhiro Tsujikawa
6ec7683991 nghttpx: Use nocopy version to send trailer headers to backend
It looks like we can use nocopy version here.  We use nocopy version
in frontend in day 1.
2017-06-02 22:38:39 +09:00
Tatsuhiro Tsujikawa
fb2d8f79d6 Update doc 2017-06-02 22:22:44 +09:00
Tatsuhiro Tsujikawa
8f7fa1b1bf nghttpx: Fix crash in OCSP response verification 2017-05-30 23:52:38 +09:00
Tatsuhiro Tsujikawa
e5889ce622 Bump up version number to 1.24.0-DEV 2017-05-26 23:07:50 +09:00
34 changed files with 682 additions and 273 deletions

10
AUTHORS
View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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::

View File

@@ -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"`

View File

@@ -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

View File

@@ -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)/*

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
. .

View File

@@ -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
. .

View File

@@ -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

View File

@@ -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>

View File

@@ -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:

View File

@@ -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}

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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. */

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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}

View File

@@ -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.;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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, "

View File

@@ -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();
} }

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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,

View File

@@ -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']