Compare commits

..

27 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
e8907a073f Update manual pages 2017-10-24 23:10:37 +09:00
Tatsuhiro Tsujikawa
9656ac0254 Fix sphinx warnings 2017-10-24 23:10:23 +09:00
Tatsuhiro Tsujikawa
75624617ce Bump up version number to 1.27.0 2017-10-24 22:51:17 +09:00
Tatsuhiro Tsujikawa
1a8f6578b3 Update AUTHORS 2017-10-24 22:49:51 +09:00
Tatsuhiro Tsujikawa
4f0548b018 travis: Compile mruby and neverbleed in make distcheck
gcc is upgraded to gcc-7.
2017-10-24 21:41:10 +09:00
Tatsuhiro Tsujikawa
5119e82b93 src: Fix memory leak in unit test 2017-10-24 21:40:30 +09:00
Tatsuhiro Tsujikawa
3be5856c82 nghttpx: Fix unused function warnings 2017-10-24 21:40:30 +09:00
Tatsuhiro Tsujikawa
a319143901 nghttpx: Fix bug that header fields are missing in HTTP/1.0 response 2017-10-22 01:11:32 +09:00
Tatsuhiro Tsujikawa
17c88d60c7 Compile with g++ 7.2.1 2017-10-19 23:04:12 +09:00
Tatsuhiro Tsujikawa
7601511fdf Merge pull request #1029 from lazyhamster/master
Fixed accidental compiler flags concatenation for MSVC.
2017-10-19 21:21:46 +09:00
Tatsuhiro Tsujikawa
f507b5eee4 nghttpx: Use an existing h2 backend connection as much as possible
h2load measurement reveals that this strategy is 3 times faster than
the previous implementations.
2017-10-19 21:15:08 +09:00
LazyHamster
93821165be Fixed accidental compiler flags concatenation for MSVC. 2017-10-18 15:25:17 +03:00
Tatsuhiro Tsujikawa
aaa0b858e4 Amend some macro comments 2017-10-14 11:50:16 +09:00
Tatsuhiro Tsujikawa
5fa1938691 clang-format 2017-10-14 11:45:41 +09:00
Tatsuhiro Tsujikawa
56ee3d4820 Merge pull request #1027 from dermojo/mingw
Support for Windows / MinGW
2017-10-14 11:44:57 +09:00
Daniel Evers
c2d9a1ed6f Support for Windows / MinGW 2017-10-12 18:15:12 +02:00
Tatsuhiro Tsujikawa
fcf9ab2798 Merge pull request #1023 from nckx/fix-fuzz-typo
fuzz: Fix typo (‘-fsanitize=adres’) in README.rst
2017-10-12 21:00:18 +09:00
Tobias Geerinckx-Rice
35e445bd04 fuzz: Fix typo (‘-fsanitize=adres’) in README.rst 2017-10-10 22:14:25 +02:00
Tatsuhiro Tsujikawa
88ce3c31b7 Merge pull request #1020 from FireBurn/master
Reduce libxml2 version requirement to 2.6.26
2017-10-07 21:17:33 +09:00
Mike Lothian
16320a0f81 Reduce libxml2 version requirement to 2.6.26
It's currently set at 2.7.7 but reducing this down to 2.6.26 allows
nghttp2 to be built on RHEL5
2017-10-04 14:25:12 +01:00
Tatsuhiro Tsujikawa
8c72fb3539 Merge pull request #1018 from nghttp2/h2load-verbose-h2-headers
h2load: Print out h2 header fields with --verbose option
2017-10-01 12:49:13 +09:00
Tatsuhiro Tsujikawa
8ffe389daa h2load: Print out h2 header fields with --verbose option 2017-09-22 18:12:20 +09:00
Tatsuhiro Tsujikawa
189a4516a1 Merge pull request #1016 from nghttp2/nghttpx-non-final-response
nghttpx: Send non-final response to HTTP/1.1 or HTTP/2 client only
2017-09-21 22:28:51 +09:00
Tatsuhiro Tsujikawa
2576855ded nghttpx: Send non-final response to HTTP/1.1 or HTTP/2 client only 2017-09-21 21:42:56 +09:00
Tatsuhiro Tsujikawa
7d4d48a35e Add timing-based load-testing section to h2load howto 2017-09-21 17:57:32 +09:00
Tatsuhiro Tsujikawa
cc6f759190 src: Add static to constexpr char[] 2017-09-20 23:54:10 +09:00
Tatsuhiro Tsujikawa
c23fc86a23 Bump up version number to 1.27.0-DEV 2017-09-20 22:52:43 +09:00
32 changed files with 225 additions and 93 deletions

View File

@@ -1,3 +1,4 @@
dist: trusty
env: env:
matrix: matrix:
- CI_BUILD=cmake - CI_BUILD=cmake
@@ -6,15 +7,13 @@ language: cpp
compiler: compiler:
- clang - clang
- gcc - gcc
sudo: false sudo: required
addons: addons:
apt: apt:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- george-edison55-precise-backports
packages: packages:
- g++-4.9 - g++-7
- libstdc++-4.9-dev
- autoconf - autoconf
- automake - automake
- autotools-dev - autotools-dev
@@ -33,29 +32,18 @@ addons:
- cmake-data - cmake-data
before_install: before_install:
- $CC --version - $CC --version
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi - if [ "$CXX" = "g++" ]; then export CXX="g++-7" CC="gcc-7"; fi
- $CC --version - $CC --version
- go version - go version
- cmake --version - cmake --version
before_script: before_script:
# First build spdylay, since integration tests require it.
# spdylay is going to be built under third-party/spdylay
- cd third-party
- git clone https://github.com/tatsuhiro-t/spdylay.git
- cd spdylay
- autoreconf -i
# Don't use ASAN for spdylay since failmalloc does not work with it.
- ./configure --disable-src --disable-examples
- make check
- export SPDYLAY_HOME=$PWD
- cd ../..
# Now build nghttp2 # Now build nghttp2
- if [ "$CI_BUILD" = "autotools" ]; then autoreconf -i; fi - if [ "$CI_BUILD" = "autotools" ]; then autoreconf -i; fi
- git submodule update --init - git submodule update --init
- if [ "$CI_BUILD" = "autotools" ]; then ./configure --enable-werror --with-mruby --with-neverbleed LIBSPDYLAY_CFLAGS="-I$SPDYLAY_HOME/lib/includes" LIBSPDYLAY_LIBS="-L$SPDYLAY_HOME/lib/.libs -lspdylay" CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address; fi - if [ "$CI_BUILD" = "autotools" ]; then ./configure --with-mruby; fi
- if [ "$CI_BUILD" = "cmake" ]; then cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1 -DSPDYLAY_INCLUDE_DIR="$SPDYLAY_HOME/lib/includes" -DSPDYLAY_LIBRARY="$SPDYLAY_HOME/lib/.libs/libspdylay.so"; fi - if [ "$CI_BUILD" = "cmake" ]; then cmake -DENABLE_WERROR=1 -DWITH_MRUBY=1 -DWITH_NEVERBLEED=1; fi
script: script:
- if [ "$CI_BUILD" = "autotools" ]; then make distcheck; fi - if [ "$CI_BUILD" = "autotools" ]; then make distcheck DISTCHECK_CONFIGURE_FLAGS="--with-mruby --with-neverbleed --enable-werror CPPFLAGS=-fsanitize=address LDFLAGS=\"-fsanitize=address -fuse-ld=gold\""; fi
- if [ "$CI_BUILD" = "cmake" ]; then make check; fi - if [ "$CI_BUILD" = "cmake" ]; then make check; fi
# As of April, 23, 2016, golang http2 build fails, probably because # As of April, 23, 2016, golang http2 build fails, probably because
# the default go version is too old. # the default go version is too old.

View File

@@ -29,6 +29,7 @@ Benjamin Peterson
Bernard Spil Bernard Spil
Brian Card Brian Card
Brian Suh Brian Suh
Daniel Evers
Daniel Stenberg Daniel Stenberg
Dave Reisner Dave Reisner
David Beitey David Beitey
@@ -53,6 +54,7 @@ Kenny (kang-yen) Peng
Kenny Peng Kenny Peng
Kit Chan Kit Chan
Kyle Schomp Kyle Schomp
LazyHamster
Lucas Pardue Lucas Pardue
MATSUMOTO Ryosuke MATSUMOTO Ryosuke
Marc Bachmann Marc Bachmann
@@ -60,6 +62,7 @@ Matt Rudary
Matt Way Matt Way
Mike Conlen Mike Conlen
Mike Frysinger Mike Frysinger
Mike Lothian
Nicholas Hurley Nicholas Hurley
Nora Shoemaker Nora Shoemaker
Peeyush Aggarwal Peeyush Aggarwal
@@ -82,6 +85,7 @@ Syohei YOSHIDA
Tapanito Tapanito
Tatsuhiko Kubo Tatsuhiko Kubo
Tatsuhiro Tsujikawa Tatsuhiro Tsujikawa
Tobias Geerinckx-Rice
Tom Harwood Tom Harwood
Tomasz Buchert Tomasz Buchert
Tomasz Torcz Tomasz Torcz

View File

@@ -24,7 +24,7 @@
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.26.0) project(nghttp2 VERSION 1.27.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
@@ -79,7 +79,7 @@ else()
set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF) set(ENABLE_PYTHON_BINDINGS_DEFAULT OFF)
endif() endif()
find_package(LibXml2 2.7.7) find_package(LibXml2 2.6.26)
set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND}) set(WITH_LIBXML2_DEFAULT ${LIBXML2_FOUND})
find_package(Jemalloc) find_package(Jemalloc)
set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND}) set(WITH_JEMALLOC_DEFAULT ${JEMALLOC_FOUND})
@@ -106,7 +106,7 @@ endif()
foreach(_build_type "Release" "MinSizeRel" "RelWithDebInfo") foreach(_build_type "Release" "MinSizeRel" "RelWithDebInfo")
foreach(_lang C CXX) foreach(_lang C CXX)
string(TOUPPER "CMAKE_${_lang}_FLAGS_${_build_type}" _var) string(TOUPPER "CMAKE_${_lang}_FLAGS_${_build_type}" _var)
string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" "" ${_var} "${${_var}}") string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " ${_var} "${${_var}}")
endforeach() endforeach()
endforeach() endforeach()

View File

@@ -87,7 +87,7 @@ enabled. SPDY support will be removed soon.
To enable ``-a`` option (getting linked assets from the downloaded To enable ``-a`` option (getting linked assets from the downloaded
resource) in ``nghttp``, the following package is required: resource) in ``nghttp``, the following package is required:
* libxml2 >= 2.7.7 * libxml2 >= 2.6.26
To enable systemd support in nghttpx, the following package is To enable systemd support in nghttpx, the following package is
required: required:

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.26.0], [t-tujikawa@users.sourceforge.net]) AC_INIT([nghttp2], [1.27.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])
@@ -410,7 +410,7 @@ if test "x${request_systemd}" = "xyes" &&
fi fi
# libxml2 (for src/nghttp) # libxml2 (for src/nghttp)
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.7.7], PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.6.26],
[have_libxml2=yes], [have_libxml2=no]) [have_libxml2=yes], [have_libxml2=no])
if test "x${have_libxml2}" = "xyes"; then if test "x${have_libxml2}" = "xyes"; then
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.]) AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
@@ -804,6 +804,9 @@ if test "x$werror" != "xno"; then
AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAGS="$CXXFLAGS -Werror"]) AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAGS="$CXXFLAGS -Werror"])
AX_CHECK_COMPILE_FLAG([-Wformat-security], [CXXFLAGS="$CXXFLAGS -Wformat-security"]) AX_CHECK_COMPILE_FLAG([-Wformat-security], [CXXFLAGS="$CXXFLAGS -Wformat-security"])
AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CXXFLAGS="$CXXFLAGS -Wsometimes-uninitialized"]) AX_CHECK_COMPILE_FLAG([-Wsometimes-uninitialized], [CXXFLAGS="$CXXFLAGS -Wsometimes-uninitialized"])
# Disable noexcept-type warning of g++-7. This is not harmful as
# long as all source files are compiled with the same compiler.
AX_CHECK_COMPILE_FLAG([-Wno-noexcept-type], [CXXFLAGS="$CXXFLAGS -Wno-noexcept-type"])
AC_LANG_POP() AC_LANG_POP()
fi fi

View File

@@ -13,6 +13,7 @@ import re
from docutils import nodes from docutils import nodes
from docutils.parsers.rst import directives from docutils.parsers.rst import directives
from docutils.parsers.rst import Directive
from sphinx import addnodes from sphinx import addnodes
from sphinx import version_info from sphinx import version_info
@@ -21,10 +22,8 @@ from sphinx.locale import l_, _
from sphinx.domains import Domain, ObjType, Index from sphinx.domains import Domain, ObjType, Index
from sphinx.directives import ObjectDescription from sphinx.directives import ObjectDescription
from sphinx.util.nodes import make_refnode from sphinx.util.nodes import make_refnode
from sphinx.util.compat import Directive
from sphinx.util.docfields import Field, GroupedField, TypedField from sphinx.util.docfields import Field, GroupedField, TypedField
# REs for Ruby signatures # REs for Ruby signatures
rb_sig_re = re.compile( rb_sig_re = re.compile(
r'''^ ([\w.]*\.)? # class name(s) r'''^ ([\w.]*\.)? # class name(s)

View File

@@ -157,7 +157,7 @@ html_theme_path = ['@top_srcdir@/doc/_themes']
# If true, SmartyPants will be used to convert quotes and dashes to # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
html_use_smartypants = False #html_use_smartypants = False
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
html_sidebars = { html_sidebars = {

2
doc/docutils.conf Normal file
View File

@@ -0,0 +1,2 @@
[parsers]
smart_quotes=no

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "H2LOAD" "1" "Sep 20, 2017" "1.26.0" "nghttp2" .TH "H2LOAD" "1" "Oct 24, 2017" "1.27.0" "nghttp2"
.SH NAME .SH NAME
h2load \- HTTP/2 benchmarking tool h2load \- HTTP/2 benchmarking tool
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTP" "1" "Sep 20, 2017" "1.26.0" "nghttp2" .TH "NGHTTP" "1" "Oct 24, 2017" "1.27.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" "Sep 20, 2017" "1.26.0" "nghttp2" .TH "NGHTTPD" "1" "Oct 24, 2017" "1.27.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" "Sep 20, 2017" "1.26.0" "nghttp2" .TH "NGHTTPX" "1" "Oct 24, 2017" "1.27.0" "nghttp2"
.SH NAME .SH NAME
nghttpx \- HTTP/2 proxy nghttpx \- HTTP/2 proxy
. .

View File

@@ -64,6 +64,25 @@ The benchmarking result looks like this:
See the h2load manual page :ref:`h2load-1-output` section for the See the h2load manual page :ref:`h2load-1-output` section for the
explanation of the above numbers. explanation of the above numbers.
Timing-based load-testing
-------------------------
As of v1.26.0, h2load supports timing-based load-testing. This method
performs load-testing in terms of a given duration instead of a
pre-defined number of requests. The new option :option:`--duration`
specifies how long the load-testing takes. For example,
``--duration=10`` makes h2load perform load-testing against a server
for 10 seconds. You can also specify a “warming-up” period with
:option:`--warm-up-time`. If :option:`--duration` is used,
:option:`-n` option is ignored.
The following command performs load-testing for 10 seconds after 5
seconds warming up period:
.. code-block:: text
$ h2load -c100 -m100 --duration=10 --warm-up-time=5 https://localhost
Flow Control Flow Control
------------ ------------

View File

@@ -23,8 +23,8 @@ following compiler/linker flags:
.. code-block:: text .. code-block:: text
CPPFLAGS="-fsanitize-coverage=edge -fsanitize=addres" CPPFLAGS="-fsanitize-coverage=edge -fsanitize=address"
LDFLAGS="-fsanitize-coverage=edge -fsanitize=addres" LDFLAGS="-fsanitize-coverage=edge -fsanitize=address"
Then, fuzz_target.cc can be built using the following command: Then, fuzz_target.cc can be built using the following command:

View File

@@ -27,7 +27,9 @@
#include "nghttp2_config.h" #include "nghttp2_config.h"
#ifndef _WIN32
#include <sys/uio.h> #include <sys/uio.h>
#endif // !_WIN32
#include <cassert> #include <cassert>

View File

@@ -24,6 +24,7 @@
*/ */
#include "asio_common.h" #include "asio_common.h"
#include <fcntl.h>
#include <memory> #include <memory>
#include "util.h" #include "util.h"

View File

@@ -26,6 +26,7 @@
#include <cassert> #include <cassert>
#include <cerrno> #include <cerrno>
#include <iostream>
#include "h2load.h" #include "h2load.h"
#include "util.h" #include "util.h"
@@ -52,6 +53,15 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
} }
client->on_header(frame->hd.stream_id, name, namelen, value, valuelen); client->on_header(frame->hd.stream_id, name, namelen, value, valuelen);
client->worker->stats.bytes_head_decomp += namelen + valuelen; client->worker->stats.bytes_head_decomp += namelen + valuelen;
if (client->worker->config->verbose) {
std::cout << "[stream_id=" << frame->hd.stream_id << "] ";
std::cout.write(reinterpret_cast<const char *>(name), namelen);
std::cout << ": ";
std::cout.write(reinterpret_cast<const char *>(value), valuelen);
std::cout << "\n";
}
return 0; return 0;
} }
} // namespace } // namespace

View File

@@ -28,7 +28,15 @@
#include "nghttp2_config.h" #include "nghttp2_config.h"
#include <limits.h> #include <limits.h>
#ifdef _WIN32
/* Structure for scatter/gather I/O. */
struct iovec {
void *iov_base; /* Pointer to data. */
size_t iov_len; /* Length of data. */
};
#else // !_WIN32
#include <sys/uio.h> #include <sys/uio.h>
#endif // !_WIN32
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>

View File

@@ -33,7 +33,11 @@
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> #include <sys/socket.h>
#endif // HAVE_SYS_SOCKET_H #endif // HAVE_SYS_SOCKET_H
#ifdef _WIN32
#include <ws2tcpip.h>
#else // !_WIN32
#include <sys/un.h> #include <sys/un.h>
#endif // !_WIN32
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> #include <netinet/in.h>
#endif // HAVE_NETINET_IN_H #endif // HAVE_NETINET_IN_H
@@ -48,7 +52,9 @@ union sockaddr_union {
sockaddr sa; sockaddr sa;
sockaddr_in6 in6; sockaddr_in6 in6;
sockaddr_in in; sockaddr_in in;
#ifndef _WIN32
sockaddr_un un; sockaddr_un un;
#endif // !_WIN32
}; };
struct Address { struct Address {

View File

@@ -115,6 +115,8 @@ int main(int argc, char *argv[]) {
shrpx::test_downstream_assemble_request_cookie) || shrpx::test_downstream_assemble_request_cookie) ||
!CU_add_test(pSuite, "downstream_rewrite_location_response_header", !CU_add_test(pSuite, "downstream_rewrite_location_response_header",
shrpx::test_downstream_rewrite_location_response_header) || shrpx::test_downstream_rewrite_location_response_header) ||
!CU_add_test(pSuite, "downstream_supports_non_final_response",
shrpx::test_downstream_supports_non_final_response) ||
!CU_add_test(pSuite, "config_parse_header", !CU_add_test(pSuite, "config_parse_header",
shrpx::test_shrpx_config_parse_header) || shrpx::test_shrpx_config_parse_header) ||
!CU_add_test(pSuite, "config_parse_log_format", !CU_add_test(pSuite, "config_parse_log_format",

View File

@@ -804,61 +804,40 @@ bool load_lighter(const DownstreamAddr *lhs, const DownstreamAddr *rhs) {
Http2Session *ClientHandler::select_http2_session( Http2Session *ClientHandler::select_http2_session(
const std::shared_ptr<DownstreamAddrGroup> &group) { const std::shared_ptr<DownstreamAddrGroup> &group) {
auto &shared_addr = group->shared_addr; auto &shared_addr = group->shared_addr;
auto &http2_avail_freelist = shared_addr->http2_avail_freelist;
for (auto session = http2_avail_freelist.head; session;) {
auto next = session->dlnext;
session->remove_from_freelist();
// session may be in graceful shutdown period now.
if (session->max_concurrency_reached(0)) {
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this)
<< "Maximum streams have been reached for Http2Session(" << session
<< "). Skip it";
}
session = next;
// First count the working backend addresses.
size_t min = 0;
for (const auto &addr : shared_addr->addrs) {
if (addr.proto != PROTO_HTTP2 || addr.connect_blocker->blocked()) {
continue; continue;
} }
++min;
}
if (min == 0) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "No working backend address found"; CLOG(INFO, this) << "Use Http2Session " << session
<< " from http2_avail_freelist";
} }
return nullptr; if (session->max_concurrency_reached(1)) {
}
auto &http2_avail_freelist = shared_addr->http2_avail_freelist;
if (http2_avail_freelist.size() >= min) {
for (auto session = http2_avail_freelist.head; session;) {
auto next = session->dlnext;
session->remove_from_freelist();
// session may be in graceful shutdown period now.
if (session->max_concurrency_reached(0)) {
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this)
<< "Maximum streams have been reached for Http2Session("
<< session << "). Skip it";
}
session = next;
continue;
}
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "Use Http2Session " << session CLOG(INFO, this) << "Maximum streams are reached for Http2Session("
<< " from http2_avail_freelist"; << session << ").";
} }
} else {
if (session->max_concurrency_reached(1)) { session->add_to_avail_freelist();
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "Maximum streams are reached for Http2Session("
<< session << ").";
}
} else {
session->add_to_avail_freelist();
}
return session;
} }
return session;
} }
DownstreamAddr *selected_addr = nullptr; DownstreamAddr *selected_addr = nullptr;
@@ -901,7 +880,12 @@ Http2Session *ClientHandler::select_http2_session(
} }
} }
assert(selected_addr); if (selected_addr == nullptr) {
if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "No working backend address found";
}
return nullptr;
}
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "Selected DownstreamAddr=" << selected_addr CLOG(INFO, this) << "Selected DownstreamAddr=" << selected_addr

View File

@@ -743,6 +743,10 @@ bool Downstream::get_non_final_response() const {
return !upgraded_ && resp_.http_status / 100 == 1; return !upgraded_ && resp_.http_status / 100 == 1;
} }
bool Downstream::supports_non_final_response() const {
return req_.http_major == 2 || (req_.http_major == 1 && req_.http_minor == 1);
}
bool Downstream::get_upgraded() const { return upgraded_; } bool Downstream::get_upgraded() const { return upgraded_; }
bool Downstream::get_http2_upgrade_request() const { bool Downstream::get_http2_upgrade_request() const {

View File

@@ -348,6 +348,9 @@ public:
// True if the response is non-final (1xx status code). Note that // True if the response is non-final (1xx status code). Note that
// if connection was upgraded, 101 status code is treated as final. // if connection was upgraded, 101 status code is treated as final.
bool get_non_final_response() const; bool get_non_final_response() const;
// True if protocol version used by client supports non final
// response. Only HTTP/1.1 and HTTP/2 clients support it.
bool supports_non_final_response() const;
void set_expect_final_response(bool f); void set_expect_final_response(bool f);
bool get_expect_final_response() const; bool get_expect_final_response() const;

View File

@@ -164,4 +164,29 @@ void test_downstream_rewrite_location_response_header(void) {
CU_ASSERT("https://localhost:8443/" == (*location).value); CU_ASSERT("https://localhost:8443/" == (*location).value);
} }
void test_downstream_supports_non_final_response(void) {
Downstream d(nullptr, nullptr, 0);
auto &req = d.request();
req.http_major = 2;
req.http_minor = 0;
CU_ASSERT(d.supports_non_final_response());
req.http_major = 1;
req.http_minor = 1;
CU_ASSERT(d.supports_non_final_response());
req.http_major = 1;
req.http_minor = 0;
CU_ASSERT(!d.supports_non_final_response());
req.http_major = 0;
req.http_minor = 9;
CU_ASSERT(!d.supports_non_final_response());
}
} // namespace shrpx } // namespace shrpx

View File

@@ -36,6 +36,7 @@ void test_downstream_field_store_header(void);
void test_downstream_crumble_request_cookie(void); void test_downstream_crumble_request_cookie(void);
void test_downstream_assemble_request_cookie(void); void test_downstream_assemble_request_cookie(void);
void test_downstream_rewrite_location_response_header(void); void test_downstream_rewrite_location_response_header(void);
void test_downstream_supports_non_final_response(void);
} // namespace shrpx } // namespace shrpx

View File

@@ -84,7 +84,7 @@ int exec_read_command(Process &proc, char *const argv[]) {
rv = shrpx_signal_unblock_all(); rv = shrpx_signal_unblock_all();
if (rv != 0) { if (rv != 0) {
constexpr char msg[] = "Unblocking all signals failed\n"; static constexpr char msg[] = "Unblocking all signals failed\n";
while (write(STDERR_FILENO, msg, str_size(msg)) == -1 && errno == EINTR) while (write(STDERR_FILENO, msg, str_size(msg)) == -1 && errno == EINTR)
; ;
nghttp2_Exit(EXIT_FAILURE); nghttp2_Exit(EXIT_FAILURE);
@@ -95,7 +95,7 @@ int exec_read_command(Process &proc, char *const argv[]) {
rv = execv(argv[0], argv); rv = execv(argv[0], argv);
if (rv == -1) { if (rv == -1) {
constexpr char msg[] = "Could not execute command\n"; static constexpr char msg[] = "Could not execute command\n";
while (write(STDERR_FILENO, msg, str_size(msg)) == -1 && errno == EINTR) while (write(STDERR_FILENO, msg, str_size(msg)) == -1 && errno == EINTR)
; ;
nghttp2_Exit(EXIT_FAILURE); nghttp2_Exit(EXIT_FAILURE);

View File

@@ -1022,6 +1022,12 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
auto &resp = downstream->response(); auto &resp = downstream->response();
auto &balloc = downstream->get_block_allocator(); auto &balloc = downstream->get_block_allocator();
if (downstream->get_non_final_response() &&
!downstream->supports_non_final_response()) {
resp.fs.clear_headers();
return 0;
}
#ifdef HAVE_MRUBY #ifdef HAVE_MRUBY
if (!downstream->get_non_final_response()) { if (!downstream->get_non_final_response()) {
auto worker = handler_->get_worker(); auto worker = handler_->get_worker();

View File

@@ -558,6 +558,8 @@ int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
} // namespace } // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
#ifndef TLSEXT_TYPE_signed_certificate_timestamp #ifndef TLSEXT_TYPE_signed_certificate_timestamp
#define TLSEXT_TYPE_signed_certificate_timestamp 18 #define TLSEXT_TYPE_signed_certificate_timestamp 18
#endif // !TLSEXT_TYPE_signed_certificate_timestamp #endif // !TLSEXT_TYPE_signed_certificate_timestamp
@@ -620,8 +622,7 @@ int sct_parse_cb(SSL *ssl, unsigned int ext_type, unsigned int context,
} }
} // namespace } // namespace
#if !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && \ #if !OPENSSL_1_1_1_API
!OPENSSL_1_1_1_API
namespace { namespace {
int legacy_sct_add_cb(SSL *ssl, unsigned int ext_type, int legacy_sct_add_cb(SSL *ssl, unsigned int ext_type,
@@ -646,8 +647,8 @@ int legacy_sct_parse_cb(SSL *ssl, unsigned int ext_type,
} }
} // namespace } // namespace
#endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L && #endif // !OPENSSL_1_1_1_API
// !OPENSSL_1_1_1_API #endif // !LIBRESSL_IN_USE && OPENSSL_VERSION_NUMBER >= 0x10002000L
#if !LIBRESSL_IN_USE #if !LIBRESSL_IN_USE
namespace { namespace {

View File

@@ -70,7 +70,7 @@ void test_shrpx_tls_create_lookup_tree(void) {
CU_ASSERT(-1 == tree->lookup(StringRef{})); CU_ASSERT(-1 == tree->lookup(StringRef{}));
CU_ASSERT(5 == tree->lookup(hostnames[5])); CU_ASSERT(5 == tree->lookup(hostnames[5]));
CU_ASSERT(6 == tree->lookup(hostnames[6])); CU_ASSERT(6 == tree->lookup(hostnames[6]));
constexpr char h6[] = "pdylay.sourceforge.net"; static constexpr char h6[] = "pdylay.sourceforge.net";
for (int i = 0; i < 7; ++i) { for (int i = 0; i < 7; ++i) {
CU_ASSERT(-1 == tree->lookup(StringRef{h6 + i, str_size(h6) - i})); CU_ASSERT(-1 == tree->lookup(StringRef{h6 + i, str_size(h6) - i}));
} }
@@ -119,7 +119,8 @@ void test_shrpx_tls_create_lookup_tree(void) {
void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) { void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) {
int rv; int rv;
constexpr char nghttp2_certfile[] = NGHTTP2_SRC_DIR "/test.nghttp2.org.pem"; static constexpr char nghttp2_certfile[] =
NGHTTP2_SRC_DIR "/test.nghttp2.org.pem";
auto nghttp2_ssl_ctx = SSL_CTX_new(SSLv23_server_method()); auto nghttp2_ssl_ctx = SSL_CTX_new(SSLv23_server_method());
auto nghttp2_ssl_ctx_del = defer(SSL_CTX_free, nghttp2_ssl_ctx); auto nghttp2_ssl_ctx_del = defer(SSL_CTX_free, nghttp2_ssl_ctx);
auto nghttp2_tls_ctx_data = make_unique<tls::TLSContextData>(); auto nghttp2_tls_ctx_data = make_unique<tls::TLSContextData>();
@@ -129,7 +130,8 @@ void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) {
CU_ASSERT(1 == rv); CU_ASSERT(1 == rv);
constexpr char examples_certfile[] = NGHTTP2_SRC_DIR "/test.example.com.pem"; static constexpr char examples_certfile[] =
NGHTTP2_SRC_DIR "/test.example.com.pem";
auto examples_ssl_ctx = SSL_CTX_new(SSLv23_server_method()); auto examples_ssl_ctx = SSL_CTX_new(SSLv23_server_method());
auto examples_ssl_ctx_del = defer(SSL_CTX_free, examples_ssl_ctx); auto examples_ssl_ctx_del = defer(SSL_CTX_free, examples_ssl_ctx);
auto examples_tls_ctx_data = make_unique<tls::TLSContextData>(); auto examples_tls_ctx_data = make_unique<tls::TLSContextData>();

View File

@@ -41,7 +41,12 @@
#ifdef HAVE_NETINET_IN_H #ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> #include <netinet/in.h>
#endif // HAVE_NETINET_IN_H #endif // HAVE_NETINET_IN_H
#ifdef _WIN32
#include <ws2tcpip.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#else // !_WIN32
#include <netinet/tcp.h> #include <netinet/tcp.h>
#endif // !_WIN32
#ifdef HAVE_ARPA_INET_H #ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h> #include <arpa/inet.h>
#endif // HAVE_ARPA_INET_H #endif // HAVE_ARPA_INET_H
@@ -65,6 +70,26 @@ namespace nghttp2 {
namespace util { namespace util {
#ifdef _WIN32
// inet_pton-wrapper for Windows
static int inet_pton(int af, const char *src, void *dst) {
#if _WIN32_WINNT >= 0x0600
return InetPtonA(af, src, dst);
#else
// the function takes a 'char*', so we need to make a copy
char addr[INET6_ADDRSTRLEN + 1];
strncpy(addr, src, sizeof(addr));
addr[sizeof(addr) - 1] = 0;
int size = sizeof(struct in6_addr);
if (WSAStringToAddress(addr, af, NULL, (LPSOCKADDR)dst, &size) == 0)
return 1;
return 0;
#endif
}
#endif // _WIN32
const char UPPER_XDIGITS[] = "0123456789ABCDEF"; const char UPPER_XDIGITS[] = "0123456789ABCDEF";
bool in_rfc3986_unreserved_chars(const char c) { bool in_rfc3986_unreserved_chars(const char c) {
@@ -352,13 +377,34 @@ char *iso8601_date(char *res, int64_t ms) {
return p; return p;
} }
#ifdef _WIN32
namespace bt = boost::posix_time;
// one-time definition of the locale that is used to parse UTC strings
// (note that the time_input_facet is ref-counted and deleted automatically)
static const std::locale
ptime_locale(std::locale::classic(),
new bt::time_input_facet("%a, %d %b %Y %H:%M:%S GMT"));
#endif //_WIN32
time_t parse_http_date(const StringRef &s) { time_t parse_http_date(const StringRef &s) {
#ifdef _WIN32
// there is no strptime - use boost
std::stringstream sstr(s.str());
sstr.imbue(ptime_locale);
bt::ptime ltime;
sstr >> ltime;
if (!sstr)
return 0;
return boost::posix_time::to_time_t(ltime);
#else // !_WIN32
tm tm{}; tm tm{};
char *r = strptime(s.c_str(), "%a, %d %b %Y %H:%M:%S GMT", &tm); char *r = strptime(s.c_str(), "%a, %d %b %Y %H:%M:%S GMT", &tm);
if (r == 0) { if (r == 0) {
return 0; return 0;
} }
return nghttp2_timegm_without_yday(&tm); return nghttp2_timegm_without_yday(&tm);
#endif // !_WIN32
} }
char upcase(char c) { char upcase(char c) {
@@ -628,9 +674,11 @@ std::string numeric_name(const struct sockaddr *sa, socklen_t salen) {
std::string to_numeric_addr(const Address *addr) { std::string to_numeric_addr(const Address *addr) {
auto family = addr->su.storage.ss_family; auto family = addr->su.storage.ss_family;
#ifndef _WIN32
if (family == AF_UNIX) { if (family == AF_UNIX) {
return addr->su.un.sun_path; return addr->su.un.sun_path;
} }
#endif // !_WIN32
std::array<char, NI_MAXHOST> host; std::array<char, NI_MAXHOST> host;
std::array<char, NI_MAXSERV> serv; std::array<char, NI_MAXSERV> serv;
@@ -818,6 +866,10 @@ std::vector<std::string> parse_config_str_list(const StringRef &s, char delim) {
} }
int make_socket_closeonexec(int fd) { int make_socket_closeonexec(int fd) {
#ifdef _WIN32
(void)fd;
return 0;
#else // !_WIN32
int flags; int flags;
int rv; int rv;
while ((flags = fcntl(fd, F_GETFD)) == -1 && errno == EINTR) while ((flags = fcntl(fd, F_GETFD)) == -1 && errno == EINTR)
@@ -825,15 +877,24 @@ int make_socket_closeonexec(int fd) {
while ((rv = fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) == -1 && errno == EINTR) while ((rv = fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) == -1 && errno == EINTR)
; ;
return rv; return rv;
#endif // !_WIN32
} }
int make_socket_nonblocking(int fd) { int make_socket_nonblocking(int fd) {
int flags;
int rv; int rv;
#ifdef _WIN32
u_long mode = 1;
rv = ioctlsocket(fd, FIONBIO, &mode);
#else // !_WIN32
int flags;
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR) while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
; ;
while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR) while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
; ;
#endif // !_WIN32
return rv; return rv;
} }
@@ -874,7 +935,7 @@ int create_nonblock_socket(int family) {
bool check_socket_connected(int fd) { bool check_socket_connected(int fd) {
int error; int error;
socklen_t len = sizeof(error); socklen_t len = sizeof(error);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) { if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
return false; return false;
} }
@@ -884,7 +945,7 @@ bool check_socket_connected(int fd) {
int get_socket_error(int fd) { int get_socket_error(int fd) {
int error; int error;
socklen_t len = sizeof(error); socklen_t len = sizeof(error);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0) { if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&error, &len) != 0) {
return -1; return -1;
} }

View File

@@ -716,7 +716,7 @@ template <typename OutputIt, typename Generator>
OutputIt random_alpha_digit(OutputIt first, OutputIt last, Generator &gen) { OutputIt random_alpha_digit(OutputIt first, OutputIt last, Generator &gen) {
// If we use uint8_t instead char, gcc 6.2.0 complains by shouting // If we use uint8_t instead char, gcc 6.2.0 complains by shouting
// char-array initialized from wide string. // char-array initialized from wide string.
constexpr char s[] = static constexpr char s[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::uniform_int_distribution<> dis(0, 26 * 2 + 10 - 1); std::uniform_int_distribution<> dis(0, 26 * 2 + 10 - 1);
for (; first != last; ++first) { for (; first != last; ++first) {

View File

@@ -473,6 +473,7 @@ void test_util_localtime_date(void) {
if (tz) { if (tz) {
setenv("TZ", tz, 1); setenv("TZ", tz, 1);
free(tz);
} else { } else {
unsetenv("TZ"); unsetenv("TZ");
} }