mirror of
https://gitee.com/openharmony/third_party_nghttp2
synced 2024-11-27 10:00:40 +00:00
Merge branch 'master' into simple-extensions
This commit is contained in:
commit
34bf153653
81
AUTHORS
81
AUTHORS
@ -1 +1,80 @@
|
||||
Tatsuhiro Tsujikawa <t-tujikawa at users dot sourceforge dot net>
|
||||
nghttp2 project was started as a fork of spdylay project [1]. Both
|
||||
projects were started by Tatsuhiro Tsujikawa, who is still the main
|
||||
author of these projects. Meanwhile, we have many contributions, and
|
||||
we are not here without them. We sincerely thank you to all who made
|
||||
a contribution. Here is the all individuals/organizations who
|
||||
contributed to nghttp2 and spdylay project at which we forked. These
|
||||
names are retrieved from git commit log. If you have made a
|
||||
contribution, but you are missing in the list, please let us know via
|
||||
github issues [2].
|
||||
|
||||
[1] https://github.com/tatsuhiro-t/spdylay
|
||||
[2] https://github.com/tatsuhiro-t/nghttp2/issues
|
||||
|
||||
--------
|
||||
|
||||
187j3x1
|
||||
Alek Storm
|
||||
Alex Nalivko
|
||||
Alexis La Goutte
|
||||
Anders Bakken
|
||||
Andreas Pohl
|
||||
Andy Davies
|
||||
Ant Bryan
|
||||
Bernard Spil
|
||||
Brian Card
|
||||
Daniel Stenberg
|
||||
Dave Reisner
|
||||
David Beitey
|
||||
David Weekly
|
||||
Etienne Cimon
|
||||
Fabian Möller
|
||||
Fabian Wiesel
|
||||
Gabi Davar
|
||||
Janusz Dziemidowicz
|
||||
Jay Satiro
|
||||
Jim Morrison
|
||||
José F. Calcerrada
|
||||
Kamil Dudka
|
||||
Kazuho Oku
|
||||
Kenny (kang-yen) Peng
|
||||
Kenny Peng
|
||||
Kit Chan
|
||||
Kyle Schomp
|
||||
Lucas Pardue
|
||||
MATSUMOTO Ryosuke
|
||||
Mike Frysinger
|
||||
Nicholas Hurley
|
||||
Nora Shoemaker
|
||||
Peeyush Aggarwal
|
||||
Peter Wu
|
||||
Piotr Sikora
|
||||
Raul Gutierrez Segales
|
||||
Remo E
|
||||
Reza Tavakoli
|
||||
Ross Smith II
|
||||
Scott Mitchell
|
||||
Stefan Eissing
|
||||
Stephen Ludin
|
||||
Sunpoet Po-Chuan Hsieh
|
||||
Svante Signell
|
||||
Syohei YOSHIDA
|
||||
Tatsuhiko Kubo
|
||||
Tatsuhiro Tsujikawa
|
||||
Tom Harwood
|
||||
Tomasz Buchert
|
||||
Vernon Tang
|
||||
Viacheslav Biriukov
|
||||
Viktor Szépe
|
||||
Xiaoguang Sun
|
||||
Zhuoyun Wei
|
||||
acesso
|
||||
ayanamist
|
||||
bxshi
|
||||
es
|
||||
fangdingjun
|
||||
kumagi
|
||||
mod-h2-dev
|
||||
moparisthebest
|
||||
snnn
|
||||
yuuki-kodama
|
||||
|
1
COPYING
1
COPYING
@ -1,6 +1,7 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
|
||||
Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
30
README.rst
30
README.rst
@ -58,9 +58,9 @@ To build the documentation, you need to install:
|
||||
|
||||
* sphinx (http://sphinx-doc.org/)
|
||||
|
||||
To build and run the application programs (``nghttp``, ``nghttpd`` and
|
||||
``nghttpx``) in the ``src`` directory, the following packages are
|
||||
required:
|
||||
To build and run the application programs (``nghttp``, ``nghttpd``,
|
||||
``nghttpx`` and ``h2load``) in the ``src`` directory, the following packages
|
||||
are required:
|
||||
|
||||
* OpenSSL >= 1.0.1
|
||||
* libev >= 4.15
|
||||
@ -110,8 +110,9 @@ If you are using Ubuntu 14.04 LTS (trusty) or Debian 7.0 (wheezy) and above run
|
||||
zlib1g-dev libcunit1-dev libssl-dev libxml2-dev libev-dev libevent-dev libjansson-dev \
|
||||
libjemalloc-dev cython python3-dev python-setuptools
|
||||
|
||||
spdylay is not packaged in Ubuntu, so you need to build it yourself:
|
||||
http://tatsuhiro-t.github.io/spdylay/
|
||||
From Ubuntu 15.10, spdylay has been available as a package named
|
||||
`libspdylay-dev`. For the earlier Ubuntu release, you need to build
|
||||
it yourself: http://tatsuhiro-t.github.io/spdylay/
|
||||
|
||||
To enable mruby support for nghttpx, `mruby
|
||||
<https://github.com/mruby/mruby>`_ is required. We need to build
|
||||
@ -160,6 +161,17 @@ To compile the source code, gcc >= 4.8.3 or clang >= 3.4 is required.
|
||||
them from crashing. A patch is welcome to make multi threading work
|
||||
on Mac OS X platform.
|
||||
|
||||
.. note::
|
||||
|
||||
To compile the associated applications (nghttp, nghttpd, nghttpx
|
||||
and h2load), you must use the ``--enable-app`` configure option and
|
||||
ensure that the specified requirements above are met. Normally,
|
||||
configure script checks required dependencies to build these
|
||||
applications, and enable ``--enable-app`` automatically, so you
|
||||
don't have to use it explicitly. But if you found that
|
||||
applications were not built, then using ``--enable-app`` may find
|
||||
that cause, such as the missing dependency.
|
||||
|
||||
Notes for building on Windows (Mingw/Cygwin)
|
||||
--------------------------------------------
|
||||
|
||||
@ -639,7 +651,9 @@ push.
|
||||
<https://istlsfastyet.com/#server-performance>`_ in TLS, such as
|
||||
session IDs, session tickets (with automatic key rotation), OCSP
|
||||
stapling, dynamic record sizing, ALPN/NPN, forward secrecy and SPDY &
|
||||
HTTP/2.
|
||||
HTTP/2. ``nghttpx`` also offers the functionality to share session
|
||||
cache and ticket keys among multiple ``nghttpx`` instances via
|
||||
memcached.
|
||||
|
||||
``nghttpx`` has several operational modes:
|
||||
|
||||
@ -661,7 +675,9 @@ The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use
|
||||
SSL/TLS in the frontend connection by default. To disable SSL/TLS,
|
||||
use the ``--frontend-no-tls`` option. If that option is used, SPDY is
|
||||
disabled in the frontend and incoming HTTP/1.1 connections can be
|
||||
upgraded to HTTP/2 through HTTP Upgrade.
|
||||
upgraded to HTTP/2 through HTTP Upgrade. In these modes, HTTP/1
|
||||
backend connections are cleartext by default. To enable TLS, use
|
||||
``--backend-http1-tls`` opiton.
|
||||
|
||||
The ``--http2-bridge``, ``--client`` and ``--client-proxy`` modes use
|
||||
SSL/TLS in the backend connection by default. To disable SSL/TLS, use
|
||||
|
22
configure.ac
22
configure.ac
@ -25,7 +25,7 @@ dnl Do not change user variables!
|
||||
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [1.7.1-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [1.8.0-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@ -76,7 +76,7 @@ AC_ARG_ENABLE([threads],
|
||||
|
||||
AC_ARG_ENABLE([app],
|
||||
[AS_HELP_STRING([--enable-app],
|
||||
[Build applications (nghttp, nghttpd and nghttpx) [default=check]])],
|
||||
[Build applications (nghttp, nghttpd, nghttpx and h2load) [default=check]])],
|
||||
[request_app=$enableval], [request_app=check])
|
||||
|
||||
AC_ARG_ENABLE([hpack-tools],
|
||||
@ -185,8 +185,8 @@ if test "x$GCC" = "xyes" -o "x$CC" = "xclang" ; then
|
||||
AC_DEFINE([_U_], [__attribute__((unused))], [Hint to the compiler that a function parameters is not used])
|
||||
AC_DEFINE([NGHTTP2_NORETURN], [__attribute__((noreturn))], [Hint to the compiler that a function never return])
|
||||
else
|
||||
AC_DEFINE([_U_], , [Hint to the compiler that a function parameters is not use AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
|
||||
d])
|
||||
AC_DEFINE([_U_], , [Hint to the compiler that a function parameter is not used])
|
||||
AC_DEFINE([NGHTTP2_NORETURN], , [Hint to the compiler that a function never return])
|
||||
fi
|
||||
|
||||
save_CXXFLAGS="$CXXFLAGS"
|
||||
@ -352,7 +352,10 @@ fi
|
||||
# libxml2 (for src/nghttp)
|
||||
have_libxml2=no
|
||||
if test "x${request_libxml2}" != "xno"; then
|
||||
AM_PATH_XML2(2.7.7, [have_libxml2=yes], [have_libxml2=no])
|
||||
m4_ifdef([AM_PATH_XML2],
|
||||
[AM_PATH_XML2(2.7.7, [have_libxml2=yes], [have_libxml2=no])],
|
||||
[AC_MSG_WARN([configure was created without libxml2 detection macro; libxml2 detection is disabled])])
|
||||
|
||||
if test "x${have_libxml2}" = "xyes"; then
|
||||
AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have `libxml2` library.])
|
||||
fi
|
||||
@ -651,8 +654,13 @@ AC_CHECK_FUNC([timerfd_create],
|
||||
|
||||
# For cygwin: we can link initgroups, so AC_CHECK_FUNCS succeeds, but
|
||||
# cygwin disables initgroups due to feature test macro magic with our
|
||||
# configuration.
|
||||
AC_CHECK_DECLS([initgroups], [], [], [[#include <grp.h>]])
|
||||
# configuration. FreeBSD declares initgroups() in unistd.h.
|
||||
AC_CHECK_DECLS([initgroups], [], [], [[
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <grp.h>
|
||||
]])
|
||||
|
||||
# Checks for epoll availability, primarily for examples/tiny-nghttpd
|
||||
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
|
||||
|
@ -150,15 +150,18 @@ APIDOCS= \
|
||||
nghttp2_submit_window_update.rst \
|
||||
nghttp2_version.rst
|
||||
|
||||
EXTRA_DIST = \
|
||||
mkapiref.py \
|
||||
RST_FILES = \
|
||||
README.rst \
|
||||
programmers-guide.rst \
|
||||
$(APIDOCS) \
|
||||
nghttp.1.rst \
|
||||
nghttpd.1.rst \
|
||||
nghttpx.1.rst \
|
||||
h2load.1.rst \
|
||||
h2load.1.rst
|
||||
|
||||
EXTRA_DIST = \
|
||||
mkapiref.py \
|
||||
$(RST_FILES) \
|
||||
$(APIDOCS) \
|
||||
sources/index.rst \
|
||||
sources/tutorial-client.rst \
|
||||
sources/tutorial-server.rst \
|
||||
@ -232,7 +235,8 @@ help:
|
||||
|
||||
apiref.rst: \
|
||||
$(top_builddir)/lib/includes/nghttp2/nghttp2ver.h \
|
||||
$(top_builddir)/lib/includes/nghttp2/nghttp2.h
|
||||
$(top_srcdir)/lib/includes/nghttp2/nghttp2.h
|
||||
for i in $(RST_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
|
||||
$(PYTHON) $(top_srcdir)/doc/mkapiref.py \
|
||||
apiref.rst macros.rst enums.rst types.rst . $^
|
||||
|
||||
|
@ -8,7 +8,7 @@ _nghttpd()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--htdocs --verbose --daemon --echo-upload --error-gzip --push --header-table-size --padding --hexdump --max-concurrent-streams --no-tls --mime-types-file --no-content-length --workers --version --color --early-response --dh-param-file --trailer --address --verify-client --help ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--htdocs --verbose --daemon --echo-upload --error-gzip --push --header-table-size --padding --hexdump --max-concurrent-streams --no-tls --connection-window-bits --mime-types-file --no-content-length --workers --version --color --early-response --dh-param-file --trailer --address --window-bits --verify-client --help ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
@ -8,7 +8,7 @@ _nghttpx()
|
||||
_get_comp_words_by_ref cur prev
|
||||
case $cur in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --include --backend-request-buffer --backend-http2-connection-window-bits --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --mruby-file --stream-read-timeout --tls-ticket-key-memcached --forwarded-for --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --tls-dyn-rec-warmup-threshold --no-via --ocsp-update-interval --backend-write-timeout --client --tls-ticket-key-memcached-max-retry --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --tls-ticket-key-cipher --read-burst --backend-ipv4 --backend-ipv6 --backend --insecure --log-level --host-rewrite --tls-proto-list --backend-http2-connections-per-worker --tls-ticket-key-memcached-interval --dh-param-file --worker-frontend-connections --syslog-facility --fastopen --no-location-rewrite --tls-session-cache-memcached --no-ocsp --backend-response-buffer --workers --add-forwarded --frontend-http2-window-bits --worker-write-rate --add-request-header --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --user --add-x-forwarded-for --header-field-buffer --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --no-server-push --backend-http2-window-bits --padding --stream-write-timeout --cacert --forwarded-by --version --add-response-header --backend-read-timeout --frontend --accesslog-file --http2-proxy --max-header-fields --backend-no-tls --client-private-key-file --client-cert-file --accept-proxy-protocol --tls-dyn-rec-idle-timeout --verify-client --read-rate --strip-incoming-forwarded ' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W '--worker-read-rate --frontend-no-tls --frontend-http2-dump-response-header --backend-http1-connections-per-frontend --tls-ticket-key-file --verify-client-cacert --include --max-response-header-fields --backend-request-buffer --max-request-header-fields --backend-http2-connection-window-bits --backend-tls-session-cache-per-worker --conf --worker-write-burst --npn-list --fetch-ocsp-response-file --no-http2-cipher-black-list --mruby-file --stream-read-timeout --tls-ticket-key-memcached --forwarded-for --accesslog-syslog --frontend-http2-read-timeout --listener-disable-timeout --frontend-http2-connection-window-bits --ciphers --strip-incoming-x-forwarded-for --private-key-passwd-file --backend-keep-alive-timeout --backend-http-proxy-uri --backend-http1-connections-per-host --rlimit-nofile --tls-dyn-rec-warmup-threshold --no-via --ocsp-update-interval --backend-write-timeout --client --tls-ticket-key-memcached-max-retry --http2-no-cookie-crumbling --worker-read-burst --client-proxy --http2-bridge --accesslog-format --errorlog-syslog --request-header-field-buffer --errorlog-file --http2-max-concurrent-streams --frontend-write-timeout --tls-ticket-key-cipher --read-burst --backend-ipv4 --backend-ipv6 --backend --insecure --log-level --host-rewrite --tls-proto-list --backend-http2-connections-per-worker --tls-ticket-key-memcached-interval --dh-param-file --worker-frontend-connections --backend-http1-tls --syslog-facility --fastopen --no-location-rewrite --tls-session-cache-memcached --no-ocsp --backend-response-buffer --workers --add-forwarded --frontend-http2-window-bits --worker-write-rate --add-request-header --backend-tls-sni-field --subcert --help --frontend-frame-debug --pid-file --frontend-http2-dump-request-header --daemon --write-rate --altsvc --user --add-x-forwarded-for --frontend-read-timeout --tls-ticket-key-memcached-max-fail --backlog --write-burst --no-server-push --backend-http2-window-bits --response-header-field-buffer --padding --stream-write-timeout --cacert --forwarded-by --version --add-response-header --backend-read-timeout --frontend --accesslog-file --http2-proxy --backend-no-tls --client-private-key-file --client-cert-file --accept-proxy-protocol --tls-dyn-rec-idle-timeout --verify-client --read-rate --strip-incoming-forwarded ' -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
_filedir
|
||||
|
@ -41,7 +41,7 @@ import sys, os
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
sys.path.append(os.path.abspath('_exts'))
|
||||
sys.path.append(os.path.abspath('@top_srcdir@/doc/_exts'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "H2LOAD" "1" "January 25, 2016" "1.7.0" "nghttp2"
|
||||
.TH "H2LOAD" "1" "February 14, 2016" "1.8.0-DEV" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTP" "1" "January 25, 2016" "1.7.0" "nghttp2"
|
||||
.TH "NGHTTP" "1" "February 14, 2016" "1.8.0-DEV" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 client
|
||||
.
|
||||
|
@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPD" "1" "January 25, 2016" "1.7.0" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "February 14, 2016" "1.8.0-DEV" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 server
|
||||
.
|
||||
@ -139,6 +139,17 @@ Make error response gzipped.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-w, \-\-window\-bits=<N>
|
||||
Sets the stream level initial window size to 2**<N>\-1.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-W, \-\-connection\-window\-bits=<N>
|
||||
Sets the connection level initial window size to
|
||||
2**<N>\-1.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-dh\-param\-file=<PATH>
|
||||
Path to file that contains DH parameters in PEM format.
|
||||
Without this option, DHE cipher suites are not
|
||||
|
@ -104,6 +104,15 @@ OPTIONS
|
||||
|
||||
Make error response gzipped.
|
||||
|
||||
.. option:: -w, --window-bits=<N>
|
||||
|
||||
Sets the stream level initial window size to 2\*\*<N>-1.
|
||||
|
||||
.. option:: -W, --connection-window-bits=<N>
|
||||
|
||||
Sets the connection level initial window size to
|
||||
2\*\*<N>-1.
|
||||
|
||||
.. option:: --dh-param-file=<PATH>
|
||||
|
||||
Path to file that contains DH parameters in PEM format.
|
||||
|
202
doc/nghttpx.1
202
doc/nghttpx.1
@ -1,6 +1,6 @@
|
||||
.\" Man page generated from reStructuredText.
|
||||
.
|
||||
.TH "NGHTTPX" "1" "January 25, 2016" "1.7.0" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "February 14, 2016" "1.8.0-DEV" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 proxy
|
||||
.
|
||||
@ -121,7 +121,9 @@ Default: \fB127.0.0.1,80\fP
|
||||
Set frontend host and port. If <HOST> is \(aq*\(aq, it
|
||||
assumes all addresses including both IPv4 and IPv6.
|
||||
UNIX domain socket can be specified by prefixing path
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
|
||||
This option can be used multiple times to listen to
|
||||
multiple addresses.
|
||||
.sp
|
||||
Default: \fB*,3000\fP
|
||||
.UNINDENT
|
||||
@ -134,13 +136,13 @@ Default: \fB512\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-ipv4
|
||||
Resolve backend hostname to IPv4 address only.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-ipv6
|
||||
Resolve backend hostname to IPv6 address only.
|
||||
.B \-\-backend\-address\-family=(auto|IPv4|IPv6)
|
||||
Specify address family of backend connections. If
|
||||
"auto" is given, both IPv4 and IPv6 are considered. If
|
||||
"IPv4" is given, only IPv4 address is considered. If
|
||||
"IPv6" is given, only IPv6 address is considered.
|
||||
.sp
|
||||
Default: \fBauto\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -163,6 +165,22 @@ be specified by \fI\%\-\-backend\-read\-timeout\fP and
|
||||
.B \-\-accept\-proxy\-protocol
|
||||
Accept PROXY protocol version 1 on frontend connection.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-no\-tls
|
||||
Disable SSL/TLS on backend connections. For HTTP/2
|
||||
backend connections, TLS is enabled by default. For
|
||||
HTTP/1 backend connections, TLS is disabled by default,
|
||||
and can be enabled by \fI\%\-\-backend\-http1\-tls\fP option. If
|
||||
both \fI\%\-\-backend\-no\-tls\fP and \fI\%\-\-backend\-http1\-tls\fP options
|
||||
are used, \fI\%\-\-backend\-no\-tls\fP has the precedence.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-http1\-tls
|
||||
Enable SSL/TLS on backend HTTP/1 connections. See also
|
||||
\fI\%\-\-backend\-no\-tls\fP option.
|
||||
.UNINDENT
|
||||
.SS Performance
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -396,19 +414,17 @@ described in OpenSSL ciphers(1).
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-k, \-\-insecure
|
||||
Don\(aqt verify backend server\(aqs certificate if \fI\%\-p\fP,
|
||||
\fI\%\-\-client\fP or \fI\%\-\-http2\-bridge\fP are given and
|
||||
\fI\%\-\-backend\-no\-tls\fP is not given.
|
||||
Don\(aqt verify backend server\(aqs certificate if TLS is
|
||||
enabled for backend connections.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-cacert=<PATH>
|
||||
Set path to trusted CA certificate file if \fI\%\-p\fP, \fI\%\-\-client\fP
|
||||
or \fI\%\-\-http2\-bridge\fP are given and \fI\%\-\-backend\-no\-tls\fP is not
|
||||
given. The file must be in 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.
|
||||
Set path to trusted CA certificate file used in backend
|
||||
TLS connections. The file must be in 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
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -518,16 +534,27 @@ required.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ticket\-key\-memcached=<HOST>,<PORT>
|
||||
Specify address of memcached server to store session
|
||||
cache. This enables shared TLS ticket key between
|
||||
multiple nghttpx instances. nghttpx does not set TLS
|
||||
ticket key to memcached. The external ticket key
|
||||
generator is required. nghttpx just gets TLS ticket
|
||||
keys from memcached, and use them, possibly replacing
|
||||
current set of keys. It is up to extern TLS ticket key
|
||||
generator to rotate keys frequently. See "TLS SESSION
|
||||
TICKET RESUMPTION" section in manual page to know the
|
||||
data format in memcached entry.
|
||||
Specify address of memcached server to get TLS ticket
|
||||
keys for session resumption. This enables shared TLS
|
||||
ticket key between multiple nghttpx instances. nghttpx
|
||||
does not set TLS ticket key to memcached. The external
|
||||
ticket key generator is required. nghttpx just gets TLS
|
||||
ticket keys from memcached, and use them, possibly
|
||||
replacing current set of keys. It is up to extern TLS
|
||||
ticket key generator to rotate keys frequently. See
|
||||
"TLS SESSION TICKET RESUMPTION" section in manual page
|
||||
to know the data format in memcached entry.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ticket\-key\-memcached\-address\-family=(auto|IPv4|IPv6)
|
||||
Specify address family of memcached connections to get
|
||||
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
.sp
|
||||
Default: \fBauto\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -565,6 +592,24 @@ aes\-128\-cbc is used.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ticket\-key\-memcached\-tls
|
||||
Enable SSL/TLS on memcached connections to get TLS
|
||||
ticket keys.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ticket\-key\-memcached\-cert\-file=<PATH>
|
||||
Path to client certificate for memcached connections to
|
||||
get TLS ticket keys.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-ticket\-key\-memcached\-private\-key\-file=<PATH>
|
||||
Path to client private key for memcached connections to
|
||||
get TLS ticket keys.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-fetch\-ocsp\-response\-file=<PATH>
|
||||
Path to fetch\-ocsp\-response script file. It should be
|
||||
absolute path.
|
||||
@ -592,6 +637,35 @@ multiple nghttpx instances.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-session\-cache\-memcached\-address\-family=(auto|IPv4|IPv6)
|
||||
Specify address family of memcached connections to store
|
||||
session cache. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
.sp
|
||||
Default: \fBauto\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-session\-cache\-memcached\-tls
|
||||
Enable SSL/TLS on memcached connections to store session
|
||||
cache.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-session\-cache\-memcached\-cert\-file=<PATH>
|
||||
Path to client certificate for memcached connections to
|
||||
store session cache.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-session\-cache\-memcached\-private\-key\-file=<PATH>
|
||||
Path to client private key for memcached connections to
|
||||
store session cache.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-tls\-dyn\-rec\-warmup\-threshold=<SIZE>
|
||||
Specify the threshold size for TLS dynamic record size
|
||||
behaviour. During a TLS session, after the threshold
|
||||
@ -616,6 +690,21 @@ TLS HTTP/2 backends.
|
||||
.sp
|
||||
Default: \fB1s\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-no\-http2\-cipher\-black\-list
|
||||
Allow black listed cipher suite on HTTP/2 connection.
|
||||
See \fI\%https://tools.ietf.org/html/rfc7540#appendix\-A\fP for
|
||||
the complete HTTP/2 cipher suites black list.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-tls\-session\-cache\-per\-worker=<N>
|
||||
Set the maximum number of backend TLS session cache
|
||||
stored per worker.
|
||||
.sp
|
||||
Default: \fB10000\fP
|
||||
.UNINDENT
|
||||
.SS HTTP/2 and SPDY
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -666,11 +755,6 @@ Default: \fB16\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-backend\-no\-tls
|
||||
Disable SSL/TLS on backend connections.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-http2\-no\-cookie\-crumbling
|
||||
Don\(aqt crumble cookie header field.
|
||||
.UNINDENT
|
||||
@ -868,11 +952,12 @@ Specify the parameter value sent out with "by" parameter
|
||||
of Forwarded header field. If "obfuscated" is given,
|
||||
the string is randomly generated at startup. If "ip" is
|
||||
given, the interface address of the connection,
|
||||
including port number, is sent with "by" parameter.
|
||||
User can also specify the static obfuscated string. The
|
||||
limitation is that it must start with "_", and only
|
||||
consists of character set [A\-Za\-z0\-9._\-], as described
|
||||
in RFC 7239.
|
||||
including port number, is sent with "by" parameter. In
|
||||
case of UNIX domain socket, "localhost" is used instead
|
||||
of address and port. User can also specify the static
|
||||
obfuscated string. The limitation is that it must start
|
||||
with "_", and only consists of character set
|
||||
[A\-Za\-z0\-9._\-], as described in RFC 7239.
|
||||
.sp
|
||||
Default: \fBobfuscated\fP
|
||||
.UNINDENT
|
||||
@ -884,7 +969,8 @@ parameter of Forwarded header field. If "obfuscated" is
|
||||
given, the string is randomly generated for each client
|
||||
connection. If "ip" is given, the remote client address
|
||||
of the connection, without port number, is sent with
|
||||
"for" parameter.
|
||||
"for" parameter. In case of UNIX domain socket,
|
||||
"localhost" is used instead of address.
|
||||
.sp
|
||||
Default: \fBobfuscated\fP
|
||||
.UNINDENT
|
||||
@ -940,22 +1026,42 @@ Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-header\-field\-buffer=<SIZE>
|
||||
.B \-\-request\-header\-field\-buffer=<SIZE>
|
||||
Set maximum buffer size for incoming HTTP request header
|
||||
field list. This is the sum of header name and value in
|
||||
bytes.
|
||||
bytes. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
.sp
|
||||
Default: \fB64K\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-max\-header\-fields=<N>
|
||||
.B \-\-max\-request\-header\-fields=<N>
|
||||
Set maximum number of incoming HTTP request header
|
||||
fields, which appear in one request or response header
|
||||
field list.
|
||||
fields. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
.sp
|
||||
Default: \fB100\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-response\-header\-field\-buffer=<SIZE>
|
||||
Set maximum buffer size for incoming HTTP response
|
||||
header field list. This is the sum of header name and
|
||||
value in bytes. If trailer fields exist, they are
|
||||
counted towards this number.
|
||||
.sp
|
||||
Default: \fB64K\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \-\-max\-response\-header\-fields=<N>
|
||||
Set maximum number of incoming HTTP response header
|
||||
fields. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
.sp
|
||||
Default: \fB500\fP
|
||||
.UNINDENT
|
||||
.SS Debug
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@ -1203,6 +1309,10 @@ insert serialized session data to memcached with
|
||||
\fBnghttpx:tls\-session\-cache:\fP + lowercased hex string of session ID
|
||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||
is set to 12 hours.
|
||||
.sp
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use \fI\%\-\-tls\-session\-cache\-memcached\-tls\fP
|
||||
option.
|
||||
.SS TLS SESSION TICKET RESUMPTION
|
||||
.sp
|
||||
By default, session ticket is shared by all worker threads. The
|
||||
@ -1247,6 +1357,10 @@ used, LEN must be 48. If
|
||||
keys. The key appeared first is used as encryption key. All the
|
||||
remaining keys are used as decryption only.
|
||||
.sp
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use \fI\%\-\-tls\-ticket\-key\-memcached\-tls\fP
|
||||
option.
|
||||
.sp
|
||||
If \fI\%\-\-tls\-ticket\-key\-file\fP is given, encryption key is read
|
||||
from the given file. In this case, nghttpx does not rotate key
|
||||
automatically. To rotate key, one has to restart nghttpx (see
|
||||
|
@ -104,7 +104,9 @@ Connections
|
||||
Set frontend host and port. If <HOST> is '\*', it
|
||||
assumes all addresses including both IPv4 and IPv6.
|
||||
UNIX domain socket can be specified by prefixing path
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock)
|
||||
name with "unix:" (e.g., unix:/var/run/nghttpx.sock).
|
||||
This option can be used multiple times to listen to
|
||||
multiple addresses.
|
||||
|
||||
Default: ``*,3000``
|
||||
|
||||
@ -114,13 +116,14 @@ Connections
|
||||
|
||||
Default: ``512``
|
||||
|
||||
.. option:: --backend-ipv4
|
||||
.. option:: --backend-address-family=(auto|IPv4|IPv6)
|
||||
|
||||
Resolve backend hostname to IPv4 address only.
|
||||
Specify address family of backend connections. If
|
||||
"auto" is given, both IPv4 and IPv6 are considered. If
|
||||
"IPv4" is given, only IPv4 address is considered. If
|
||||
"IPv6" is given, only IPv6 address is considered.
|
||||
|
||||
.. option:: --backend-ipv6
|
||||
|
||||
Resolve backend hostname to IPv6 address only.
|
||||
Default: ``auto``
|
||||
|
||||
.. option:: --backend-http-proxy-uri=<URI>
|
||||
|
||||
@ -141,6 +144,20 @@ Connections
|
||||
|
||||
Accept PROXY protocol version 1 on frontend connection.
|
||||
|
||||
.. option:: --backend-no-tls
|
||||
|
||||
Disable SSL/TLS on backend connections. For HTTP/2
|
||||
backend connections, TLS is enabled by default. For
|
||||
HTTP/1 backend connections, TLS is disabled by default,
|
||||
and can be enabled by :option:`--backend-http1-tls` option. If
|
||||
both :option:`--backend-no-tls` and :option:`\--backend-http1-tls` options
|
||||
are used, :option:`--backend-no-tls` has the precedence.
|
||||
|
||||
.. option:: --backend-http1-tls
|
||||
|
||||
Enable SSL/TLS on backend HTTP/1 connections. See also
|
||||
:option:`--backend-no-tls` option.
|
||||
|
||||
|
||||
Performance
|
||||
~~~~~~~~~~~
|
||||
@ -354,18 +371,16 @@ SSL/TLS
|
||||
|
||||
.. option:: -k, --insecure
|
||||
|
||||
Don't verify backend server's certificate if :option:`-p`\,
|
||||
:option:`--client` or :option:`\--http2-bridge` are given and
|
||||
:option:`--backend-no-tls` is not given.
|
||||
Don't verify backend server's certificate if TLS is
|
||||
enabled for backend connections.
|
||||
|
||||
.. option:: --cacert=<PATH>
|
||||
|
||||
Set path to trusted CA certificate file if :option:`-p`\, :option:`--client`
|
||||
or :option:`--http2-bridge` are given and :option:`\--backend-no-tls` is not
|
||||
given. The file must be in 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.
|
||||
Set path to trusted CA certificate file used in backend
|
||||
TLS connections. The file must be in 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>
|
||||
|
||||
@ -463,16 +478,26 @@ SSL/TLS
|
||||
|
||||
.. option:: --tls-ticket-key-memcached=<HOST>,<PORT>
|
||||
|
||||
Specify address of memcached server to store session
|
||||
cache. This enables shared TLS ticket key between
|
||||
multiple nghttpx instances. nghttpx does not set TLS
|
||||
ticket key to memcached. The external ticket key
|
||||
generator is required. nghttpx just gets TLS ticket
|
||||
keys from memcached, and use them, possibly replacing
|
||||
current set of keys. It is up to extern TLS ticket key
|
||||
generator to rotate keys frequently. See "TLS SESSION
|
||||
TICKET RESUMPTION" section in manual page to know the
|
||||
data format in memcached entry.
|
||||
Specify address of memcached server to get TLS ticket
|
||||
keys for session resumption. This enables shared TLS
|
||||
ticket key between multiple nghttpx instances. nghttpx
|
||||
does not set TLS ticket key to memcached. The external
|
||||
ticket key generator is required. nghttpx just gets TLS
|
||||
ticket keys from memcached, and use them, possibly
|
||||
replacing current set of keys. It is up to extern TLS
|
||||
ticket key generator to rotate keys frequently. See
|
||||
"TLS SESSION TICKET RESUMPTION" section in manual page
|
||||
to know the data format in memcached entry.
|
||||
|
||||
.. option:: --tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
|
||||
|
||||
Specify address family of memcached connections to get
|
||||
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
|
||||
Default: ``auto``
|
||||
|
||||
.. option:: --tls-ticket-key-memcached-interval=<DURATION>
|
||||
|
||||
@ -504,6 +529,21 @@ SSL/TLS
|
||||
either aes-128-cbc or aes-256-cbc. By default,
|
||||
aes-128-cbc is used.
|
||||
|
||||
.. option:: --tls-ticket-key-memcached-tls
|
||||
|
||||
Enable SSL/TLS on memcached connections to get TLS
|
||||
ticket keys.
|
||||
|
||||
.. option:: --tls-ticket-key-memcached-cert-file=<PATH>
|
||||
|
||||
Path to client certificate for memcached connections to
|
||||
get TLS ticket keys.
|
||||
|
||||
.. option:: --tls-ticket-key-memcached-private-key-file=<PATH>
|
||||
|
||||
Path to client private key for memcached connections to
|
||||
get TLS ticket keys.
|
||||
|
||||
.. option:: --fetch-ocsp-response-file=<PATH>
|
||||
|
||||
Path to fetch-ocsp-response script file. It should be
|
||||
@ -527,6 +567,31 @@ SSL/TLS
|
||||
cache. This enables shared session cache between
|
||||
multiple nghttpx instances.
|
||||
|
||||
.. option:: --tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
|
||||
|
||||
Specify address family of memcached connections to store
|
||||
session cache. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
|
||||
Default: ``auto``
|
||||
|
||||
.. option:: --tls-session-cache-memcached-tls
|
||||
|
||||
Enable SSL/TLS on memcached connections to store session
|
||||
cache.
|
||||
|
||||
.. option:: --tls-session-cache-memcached-cert-file=<PATH>
|
||||
|
||||
Path to client certificate for memcached connections to
|
||||
store session cache.
|
||||
|
||||
.. option:: --tls-session-cache-memcached-private-key-file=<PATH>
|
||||
|
||||
Path to client private key for memcached connections to
|
||||
store session cache.
|
||||
|
||||
.. option:: --tls-dyn-rec-warmup-threshold=<SIZE>
|
||||
|
||||
Specify the threshold size for TLS dynamic record size
|
||||
@ -551,6 +616,19 @@ SSL/TLS
|
||||
|
||||
Default: ``1s``
|
||||
|
||||
.. option:: --no-http2-cipher-black-list
|
||||
|
||||
Allow black listed cipher suite on HTTP/2 connection.
|
||||
See https://tools.ietf.org/html/rfc7540#appendix-A for
|
||||
the complete HTTP/2 cipher suites black list.
|
||||
|
||||
.. option:: --backend-tls-session-cache-per-worker=<N>
|
||||
|
||||
Set the maximum number of backend TLS session cache
|
||||
stored per worker.
|
||||
|
||||
Default: ``10000``
|
||||
|
||||
|
||||
HTTP/2 and SPDY
|
||||
~~~~~~~~~~~~~~~
|
||||
@ -596,10 +674,6 @@ HTTP/2 and SPDY
|
||||
|
||||
Default: ``16``
|
||||
|
||||
.. option:: --backend-no-tls
|
||||
|
||||
Disable SSL/TLS on backend connections.
|
||||
|
||||
.. option:: --http2-no-cookie-crumbling
|
||||
|
||||
Don't crumble cookie header field.
|
||||
@ -773,11 +847,12 @@ HTTP
|
||||
of Forwarded header field. If "obfuscated" is given,
|
||||
the string is randomly generated at startup. If "ip" is
|
||||
given, the interface address of the connection,
|
||||
including port number, is sent with "by" parameter.
|
||||
User can also specify the static obfuscated string. The
|
||||
limitation is that it must start with "_", and only
|
||||
consists of character set [A-Za-z0-9._-], as described
|
||||
in RFC 7239.
|
||||
including port number, is sent with "by" parameter. In
|
||||
case of UNIX domain socket, "localhost" is used instead
|
||||
of address and port. User can also specify the static
|
||||
obfuscated string. The limitation is that it must start
|
||||
with "_", and only consists of character set
|
||||
[A-Za-z0-9._-], as described in RFC 7239.
|
||||
|
||||
Default: ``obfuscated``
|
||||
|
||||
@ -788,7 +863,8 @@ HTTP
|
||||
given, the string is randomly generated for each client
|
||||
connection. If "ip" is given, the remote client address
|
||||
of the connection, without port number, is sent with
|
||||
"for" parameter.
|
||||
"for" parameter. In case of UNIX domain socket,
|
||||
"localhost" is used instead of address.
|
||||
|
||||
Default: ``obfuscated``
|
||||
|
||||
@ -836,22 +912,40 @@ HTTP
|
||||
used several times to specify multiple header fields.
|
||||
Example: :option:`--add-response-header`\="foo: bar"
|
||||
|
||||
.. option:: --header-field-buffer=<SIZE>
|
||||
.. option:: --request-header-field-buffer=<SIZE>
|
||||
|
||||
Set maximum buffer size for incoming HTTP request header
|
||||
field list. This is the sum of header name and value in
|
||||
bytes.
|
||||
bytes. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
|
||||
Default: ``64K``
|
||||
|
||||
.. option:: --max-header-fields=<N>
|
||||
.. option:: --max-request-header-fields=<N>
|
||||
|
||||
Set maximum number of incoming HTTP request header
|
||||
fields, which appear in one request or response header
|
||||
field list.
|
||||
fields. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
|
||||
Default: ``100``
|
||||
|
||||
.. option:: --response-header-field-buffer=<SIZE>
|
||||
|
||||
Set maximum buffer size for incoming HTTP response
|
||||
header field list. This is the sum of header name and
|
||||
value in bytes. If trailer fields exist, they are
|
||||
counted towards this number.
|
||||
|
||||
Default: ``64K``
|
||||
|
||||
.. option:: --max-response-header-fields=<N>
|
||||
|
||||
Set maximum number of incoming HTTP response header
|
||||
fields. If trailer fields exist, they are counted
|
||||
towards this number.
|
||||
|
||||
Default: ``500``
|
||||
|
||||
|
||||
Debug
|
||||
~~~~~
|
||||
@ -1091,6 +1185,10 @@ insert serialized session data to memcached with
|
||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||
is set to 12 hours.
|
||||
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use :option:`--tls-session-cache-memcached-tls`
|
||||
option.
|
||||
|
||||
TLS SESSION TICKET RESUMPTION
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -1130,6 +1228,10 @@ used, LEN must be 48. If
|
||||
keys. The key appeared first is used as encryption key. All the
|
||||
remaining keys are used as decryption only.
|
||||
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use :option:`--tls-ticket-key-memcached-tls`
|
||||
option.
|
||||
|
||||
If :option:`--tls-ticket-key-file` is given, encryption key is read
|
||||
from the given file. In this case, nghttpx does not rotate key
|
||||
automatically. To rotate key, one has to restart nghttpx (see
|
||||
@ -1372,6 +1474,12 @@ addresses:
|
||||
|
||||
App.new
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
1. nghttpx - HTTP/2 proxy - HOW-TO
|
||||
https://nghttp2.org/documentation/nghttpx-howto.html
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
|
@ -150,6 +150,10 @@ insert serialized session data to memcached with
|
||||
as a memcached entry key, with expiry time 12 hours. Session timeout
|
||||
is set to 12 hours.
|
||||
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use :option:`--tls-session-cache-memcached-tls`
|
||||
option.
|
||||
|
||||
TLS SESSION TICKET RESUMPTION
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -189,6 +193,10 @@ used, LEN must be 48. If
|
||||
keys. The key appeared first is used as encryption key. All the
|
||||
remaining keys are used as decryption only.
|
||||
|
||||
By default, connections to memcached server are not encrypted. To
|
||||
enable encryption, use :option:`--tls-ticket-key-memcached-tls`
|
||||
option.
|
||||
|
||||
If :option:`--tls-ticket-key-file` is given, encryption key is read
|
||||
from the given file. In this case, nghttpx does not rotate key
|
||||
automatically. To rotate key, one has to restart nghttpx (see
|
||||
|
@ -1,6 +1,62 @@
|
||||
Programmers' Guide
|
||||
==================
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
The most notable point in nghttp2 library architecture is it does not
|
||||
perform any I/O. nghttp2 only performs HTTP/2 protocol stuff based on
|
||||
input byte strings. It will calls callback functions set by
|
||||
applications while processing input. The output of nghttp2 is just
|
||||
byte string. An application is responsible to send these output to
|
||||
the remote peer. The callback functions may be called while producing
|
||||
output.
|
||||
|
||||
Not doing I/O makes embedding nghttp2 library in the existing code
|
||||
base very easy. Usually, the existing applications have its own I/O
|
||||
event loops. It is very hard to use nghttp2 in that situation if
|
||||
nghttp2 does its own I/O. It also makes light weight language wrapper
|
||||
for nghttp2 easy with the same reason. The down side is that an
|
||||
application author has to write more code to write complete
|
||||
application using nghttp2. This is especially true for simple "toy"
|
||||
application. For the real applications, however, this is not the
|
||||
case. This is because you probably want to support HTTP/1 which
|
||||
nghttp2 does not provide, and to do that, you will need to write your
|
||||
own HTTP/1 stack or use existing third-party library, and bind them
|
||||
together with nghttp2 and I/O event loop. In this point, not
|
||||
performing I/O in nghttp2 has more point than doing it.
|
||||
|
||||
The primary object that an application uses is :type:`nghttp2_session`
|
||||
object, which is opaque struct and its details are hidden in order to
|
||||
ensure the upgrading its internal architecture without breaking the
|
||||
backward compatibility. An application can set callbacks to
|
||||
:type:`nghttp2_session` object through the dedicated object and
|
||||
functions, and it also interacts with it via many API function calls.
|
||||
|
||||
An application can create as many :type:`nghttp2_session` object as it
|
||||
wants. But single :type:`nghttp2_session` object must be used by a
|
||||
single thread at the same time. This is not so hard to enforce since
|
||||
most event-based architecture applicatons use is single thread per
|
||||
core, and handling one connection I/O is done by single thread.
|
||||
|
||||
To feed input to :type:`nghttp2_session` object, one can use
|
||||
`nghttp2_session_recv()` or `nghttp2_session_mem_recv()` functions.
|
||||
They behave similarly, and the difference is that
|
||||
`nghttp2_session_recv()` will use :type:`nghttp2_read_callback` to get
|
||||
input. On the other hand, `nghttp2_session_mem_recv()` will take
|
||||
input as its parameter. If in doubt, use `nghttp2_session_mem_recv()`
|
||||
since it is simpler, and could be faster since it avoids calling
|
||||
callback function.
|
||||
|
||||
To get output from :type:`nghttp2_session` object, one can use
|
||||
`nghttp2_session_send()` or `nghttp2_session_mem_send()`. The
|
||||
difference between them is that the former uses
|
||||
:type:`nghttp2_send_callback` to pass output to an application. On
|
||||
the other hand, the latter returns the output to the caller. If in
|
||||
doubt, use `nghttp2_session_mem_send()` since it is simpler. But
|
||||
`nghttp2_session_send()` might be easier to use if the output buffer
|
||||
an application has is fixed sized.
|
||||
|
||||
Includes
|
||||
--------
|
||||
|
||||
|
@ -1,33 +1,43 @@
|
||||
.. program:: h2load
|
||||
|
||||
h2load - HTTP/2 benchmarking tool - HOW-TO
|
||||
==========================================
|
||||
|
||||
h2load is benchmarking tool for HTTP/2 and HTTP/1.1. If built with
|
||||
spdylay (http://tatsuhiro-t.github.io/spdylay/) library, it also
|
||||
supports SPDY protocol. It supports SSL/TLS and clear text for all
|
||||
supported protocols.
|
||||
:doc:`h2load.1` is benchmarking tool for HTTP/2 and HTTP/1.1. If
|
||||
built with spdylay (http://tatsuhiro-t.github.io/spdylay/) library, it
|
||||
also supports SPDY protocol. It supports SSL/TLS and clear text for
|
||||
all supported protocols.
|
||||
|
||||
Compiling from source
|
||||
---------------------
|
||||
|
||||
h2load is compiled alongside nghttp2 and requires that the
|
||||
``--enable-apps`` flag is passed to ``./configure`` and `required
|
||||
dependencies <https://github.com/tatsuhiro-t/nghttp2#requirements>`_
|
||||
are available during compilation. For details on compiling, see
|
||||
`nghttp2: Building from Git
|
||||
<https://github.com/tatsuhiro-t/nghttp2#building-from-git>`_.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
In order to set benchmark settings, specify following 3 options.
|
||||
|
||||
``-n``
|
||||
:option:`-n`
|
||||
The number of total requests. Default: 1
|
||||
|
||||
``-c``
|
||||
:option:`-c`
|
||||
The number of concurrent clients. Default: 1
|
||||
|
||||
``-m``
|
||||
The max concurrent streams to issue per client.
|
||||
If ``auto`` is given, the number of given URIs is used.
|
||||
Default: ``auto``
|
||||
:option:`-m`
|
||||
The max concurrent streams to issue per client. Default: 1
|
||||
|
||||
For SSL/TLS connection, the protocol will be negotiated via ALPN/NPN.
|
||||
You can set specific protocols in ``--npn-list`` option. For
|
||||
You can set specific protocols in :option:`--npn-list` option. For
|
||||
cleartext connection, the default protocol is HTTP/2. To change the
|
||||
protocol in cleartext connection, use ``--no-tls-proto`` option. For
|
||||
convenience, ``--h1`` option forces HTTP/1.1 for both cleartext and
|
||||
SSL/TLS connections.
|
||||
protocol in cleartext connection, use :option:`--no-tls-proto` option.
|
||||
For convenience, :option:`--h1` option forces HTTP/1.1 for both
|
||||
cleartext and SSL/TLS connections.
|
||||
|
||||
Here is a command-line to perform benchmark to URI \https://localhost
|
||||
using total 100000 requests, 100 concurrent clients and 10 max
|
||||
@ -62,11 +72,11 @@ benchmarking results. By default, h2load uses large enough flow
|
||||
control window, which effectively disables flow control. To adjust
|
||||
receiver flow control window size, there are following options:
|
||||
|
||||
``-w``
|
||||
:option:`-w`
|
||||
Sets the stream level initial window size to
|
||||
(2**<N>)-1. For SPDY, 2**<N> is used instead.
|
||||
|
||||
``-W``
|
||||
:option:`-W`
|
||||
Sets the connection level initial window size to
|
||||
(2**<N>)-1. For SPDY, if <N> is strictly less
|
||||
than 16, this option is ignored. Otherwise
|
||||
@ -76,17 +86,17 @@ Multi-Threading
|
||||
---------------
|
||||
|
||||
Sometimes benchmarking client itself becomes a bottleneck. To remedy
|
||||
this situation, use ``-t`` option to specify the number of native
|
||||
this situation, use :option:`-t` option to specify the number of native
|
||||
thread to use.
|
||||
|
||||
``-t``
|
||||
:option:`-t`
|
||||
The number of native threads. Default: 1
|
||||
|
||||
Selecting protocol for clear text
|
||||
---------------------------------
|
||||
|
||||
By default, if \http:// URI is given, HTTP/2 protocol is used. To
|
||||
change the protocol to use for clear text, use ``-p`` option.
|
||||
change the protocol to use for clear text, use :option:`-p` option.
|
||||
|
||||
Multiple URIs
|
||||
-------------
|
||||
@ -97,3 +107,12 @@ If multiple URIs are specified, they are used in round robin manner.
|
||||
|
||||
Please note that h2load uses scheme, host and port in the first URI
|
||||
and ignores those parts in the rest of the URIs.
|
||||
|
||||
UNIX domain socket
|
||||
------------------
|
||||
|
||||
To request against UNIX domain socket, use :option:`--base-uri`, and
|
||||
specify ``unix:`` followed by the path to UNIX domain socket. For
|
||||
example, if UNIX domain socket is ``/tmp/nghttpx.sock``, use
|
||||
``--base-uri=unix:/tmp/nghttpx.sock``. h2load uses scheme, host and
|
||||
port in the first URI in command-line or input file.
|
||||
|
@ -1,30 +1,33 @@
|
||||
.. program:: nghttpx
|
||||
|
||||
nghttpx - HTTP/2 proxy - HOW-TO
|
||||
===============================
|
||||
|
||||
nghttpx is a proxy translating protocols between HTTP/2 and other
|
||||
protocols (e.g., HTTP/1, SPDY). It operates in several modes and each
|
||||
mode may require additional programs to work with. This article
|
||||
describes each operation mode and explains the intended use-cases. It
|
||||
also covers some useful options later.
|
||||
:doc:`nghttpx.1` is a proxy translating protocols between HTTP/2 and
|
||||
other protocols (e.g., HTTP/1, SPDY). It operates in several modes
|
||||
and each mode may require additional programs to work with. This
|
||||
article describes each operation mode and explains the intended
|
||||
use-cases. It also covers some useful options later.
|
||||
|
||||
Default mode
|
||||
------------
|
||||
|
||||
If nghttpx is invoked without any ``-s``, ``-p`` and ``--client``, it
|
||||
operates in default mode. In this mode, nghttpx frontend listens for
|
||||
HTTP/2 requests and translates them to HTTP/1 requests. Thus it works
|
||||
as reverse proxy (gateway) for HTTP/2 clients to HTTP/1 web server.
|
||||
This is also known as "HTTP/2 router". HTTP/1 requests are also
|
||||
supported in frontend as a fallback. If nghttpx is linked with
|
||||
spdylay library and frontend connection is SSL/TLS, the frontend also
|
||||
supports SPDY protocol.
|
||||
If nghttpx is invoked without any :option:`--http2-proxy`,
|
||||
:option:`--client`, and :option:`--client-proxy`, it operates in
|
||||
default mode. In this mode, nghttpx frontend listens for HTTP/2
|
||||
requests and translates them to HTTP/1 requests. Thus it works as
|
||||
reverse proxy (gateway) for HTTP/2 clients to HTTP/1 web server. This
|
||||
is also known as "HTTP/2 router". HTTP/1 requests are also supported
|
||||
in frontend as a fallback. If nghttpx is linked with spdylay library
|
||||
and frontend connection is SSL/TLS, the frontend also supports SPDY
|
||||
protocol.
|
||||
|
||||
By default, this mode's frontend connection is encrypted using
|
||||
SSL/TLS. So server's private key and certificate must be supplied to
|
||||
the command line (or through configuration file). In this case, the
|
||||
frontend protocol selection will be done via ALPN or NPN.
|
||||
|
||||
With ``--frontend-no-tls`` option, user can turn off SSL/TLS in
|
||||
With :option:`--frontend-no-tls` option, user can turn off SSL/TLS in
|
||||
frontend connection. In this case, SPDY protocol is not available
|
||||
even if spdylay library is liked to nghttpx. HTTP/2 and HTTP/1 are
|
||||
available on the frontend and a HTTP/1 connection can be upgraded to
|
||||
@ -32,8 +35,9 @@ HTTP/2 using HTTP Upgrade. Starting HTTP/2 connection by sending
|
||||
HTTP/2 connection preface is also supported.
|
||||
|
||||
By default, backend HTTP/1 connections are not encrypted. To enable
|
||||
TLS on HTTP/1 backend connections, use ``--backend-http1-tls`` option.
|
||||
This applies to all mode whose backend connections are HTTP/1.
|
||||
TLS on HTTP/1 backend connections, use :option:`--backend-http1-tls`
|
||||
option. This applies to all mode whose backend connections are
|
||||
HTTP/1.
|
||||
|
||||
The backend is supposed to be HTTP/1 Web server. For example, to make
|
||||
nghttpx listen to encrypted HTTP/2 requests at port 8443, and a
|
||||
@ -50,19 +54,19 @@ example, you can send GET request to the server using nghttp::
|
||||
HTTP/2 proxy mode
|
||||
-----------------
|
||||
|
||||
If nghttpx is invoked with ``-s`` option, it operates in HTTP/2 proxy
|
||||
mode. The supported protocols in frontend and backend connections are
|
||||
the same in `default mode`_. The difference is that this mode acts
|
||||
like forward proxy and assumes the backend is HTTP/1 proxy server
|
||||
(e.g., squid, traffic server). So HTTP/1 request must include
|
||||
absolute URI in request line.
|
||||
If nghttpx is invoked with :option:`--http2-proxy` (or its shorthand
|
||||
:option:`-s`) option, it operates in HTTP/2 proxy mode. The supported
|
||||
protocols in frontend and backend connections are the same in `default
|
||||
mode`_. The difference is that this mode acts like forward proxy and
|
||||
assumes the backend is HTTP/1 proxy server (e.g., squid, traffic
|
||||
server). So HTTP/1 request must include absolute URI in request line.
|
||||
|
||||
By default, frontend connection is encrypted. So this mode is also
|
||||
called secure proxy. If nghttpx is linked with spdylay, it supports
|
||||
SPDY protocols and it works as so called SPDY proxy.
|
||||
|
||||
With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
|
||||
connection, so the connection gets insecure.
|
||||
With :option:`--frontend-no-tls` option, SSL/TLS is turned off in
|
||||
frontend connection, so the connection gets insecure.
|
||||
|
||||
The backend must be HTTP/1 proxy server. nghttpx supports multiple
|
||||
backend server addresses. It translates incoming requests to HTTP/1
|
||||
@ -96,7 +100,9 @@ Chromium require valid certificate for secure proxy.
|
||||
For Firefox, open Preference window and select Advanced then click
|
||||
Network tab. Clicking Connection Settings button will show the
|
||||
dialog. Select "Automatic proxy configuration URL" and enter the path
|
||||
to proxy.pac file, something like this::
|
||||
to proxy.pac file, something like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
file:///path/to/proxy.pac
|
||||
|
||||
@ -112,25 +118,27 @@ configuration items to edit::
|
||||
CONFIG proxy.config.url_remap.remap_required INT 0
|
||||
|
||||
Consult Traffic server `documentation
|
||||
<https://docs.trafficserver.apache.org/en/latest/admin/forward-proxy.en.html>`_
|
||||
<http://trafficserver.readthedocs.org/en/latest/admin-guide/configuration/transparent-forward-proxying.en.html>`_
|
||||
to know how to configure traffic server as forward proxy and its
|
||||
security implications.
|
||||
|
||||
Client mode
|
||||
-----------
|
||||
|
||||
If nghttpx is invoked with ``--client`` option, it operates in client
|
||||
mode. In this mode, nghttpx listens for plain, unencrypted HTTP/2 and
|
||||
HTTP/1 requests and translates them to encrypted HTTP/2 requests to
|
||||
the backend. User cannot enable SSL/TLS in frontend connection.
|
||||
If nghttpx is invoked with :option:`--client` option, it operates in
|
||||
client mode. In this mode, nghttpx listens for plain, unencrypted
|
||||
HTTP/2 and HTTP/1 requests and translates them to encrypted HTTP/2
|
||||
requests to the backend. User cannot enable SSL/TLS in frontend
|
||||
connection.
|
||||
|
||||
HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
|
||||
Upgrade. To disable SSL/TLS in backend connection, use
|
||||
``--backend-no-tls`` option.
|
||||
:option:`--backend-no-tls` option.
|
||||
|
||||
By default, the number of backend HTTP/2 connections per worker
|
||||
(thread) is determined by number of ``-b`` option. To adjust this
|
||||
value, use ``--backend-http2-connections-per-worker`` option.
|
||||
(thread) is determined by number of :option:`--backend` option. To
|
||||
adjust this value, use
|
||||
:option:`--backend-http2-connections-per-worker` option.
|
||||
|
||||
The backend server is supporsed to be a HTTP/2 web server (e.g.,
|
||||
nghttpd). The one use-case of this mode is utilize existing HTTP/1
|
||||
@ -142,9 +150,10 @@ mode to access to that web server::
|
||||
|
||||
.. note::
|
||||
|
||||
You may need ``-k`` option if HTTP/2 server enables SSL/TLS and
|
||||
its certificate is self-signed. But please note that it is
|
||||
insecure.
|
||||
You may need :option:`--insecure` (or its shorthand :option:`-k`)
|
||||
option if HTTP/2 server enables SSL/TLS and its certificate is
|
||||
self-signed. But please note that it is insecure, and you should
|
||||
know what you are doing.
|
||||
|
||||
Then you can use curl to access HTTP/2 server via nghttpx::
|
||||
|
||||
@ -153,18 +162,19 @@ Then you can use curl to access HTTP/2 server via nghttpx::
|
||||
Client proxy mode
|
||||
-----------------
|
||||
|
||||
If nghttpx is invoked with ``-p`` option, it operates in client proxy
|
||||
mode. This mode behaves like `client mode`_, but it works like
|
||||
forward proxy. So HTTP/1 request must include absolute URI in request
|
||||
line.
|
||||
If nghttpx is invoked with :option:`--client-proxy` (or its shorthand
|
||||
:option:`-p`) option, it operates in client proxy mode. This mode
|
||||
behaves like `client mode`_, but it works like forward proxy. So
|
||||
HTTP/1 request must include absolute URI in request line.
|
||||
|
||||
HTTP/1 frontend connection can be upgraded to HTTP/2 using HTTP
|
||||
Upgrade. To disable SSL/TLS in backend connection, use
|
||||
``--backend-no-tls`` option.
|
||||
:option:`--backend-no-tls` option.
|
||||
|
||||
By default, the number of backend HTTP/2 connections per worker
|
||||
(thread) is determined by number of ``-b`` option. To adjust this
|
||||
value, use ``--backend-http2-connections-per-worker`` option.
|
||||
(thread) is determined by number of :option:`--backend` option. To
|
||||
adjust this value, use
|
||||
:option:`--backend-http2-connections-per-worker` option.
|
||||
|
||||
The backend server must be a HTTP/2 proxy. You can use nghttpx in
|
||||
`HTTP/2 proxy mode`_ as backend server. The one use-case of this mode
|
||||
@ -182,8 +192,9 @@ that server, invoke nghttpx like this::
|
||||
|
||||
.. note::
|
||||
|
||||
You may need ``-k`` option if HTTP/2 server's certificate is
|
||||
self-signed. But please note that it is insecure.
|
||||
You may need :option:`--insecure` (or its shorthand :option:`-k`)
|
||||
option if HTTP/2 server's certificate is self-signed. But please
|
||||
note that it is insecure, and you should know what you are doing.
|
||||
|
||||
Then you can use curl to issue HTTP request via HTTP/2 proxy::
|
||||
|
||||
@ -195,23 +206,24 @@ proxy.
|
||||
HTTP/2 bridge mode
|
||||
------------------
|
||||
|
||||
If nghttpx is invoked with ``--http2-bridge`` option, it operates in
|
||||
HTTP/2 bridge mode. The supported protocols in frontend connections
|
||||
are the same in `default mode`_. The protocol in backend is HTTP/2
|
||||
only.
|
||||
If nghttpx is invoked with :option:`--http2-bridge` option, it
|
||||
operates in HTTP/2 bridge mode. The supported protocols in frontend
|
||||
connections are the same in `default mode`_. The protocol in backend
|
||||
is HTTP/2 only.
|
||||
|
||||
With ``--frontend-no-tls`` option, SSL/TLS is turned off in frontend
|
||||
connection, so the connection gets insecure. To disable SSL/TLS in
|
||||
backend connection, use ``--backend-no-tls`` option.
|
||||
With :option:`--frontend-no-tls` option, SSL/TLS is turned off in
|
||||
frontend connection, so the connection gets insecure. To disable
|
||||
SSL/TLS in backend connection, use :option:`--backend-no-tls` option.
|
||||
|
||||
By default, the number of backend HTTP/2 connections per worker
|
||||
(thread) is determined by number of ``-b`` option. To adjust this
|
||||
value, use ``--backend-http2-connections-per-worker`` option.
|
||||
(thread) is determined by number of :option:`--backend` option. To
|
||||
adjust this value, use
|
||||
:option:`--backend-http2-connections-per-worker` option.
|
||||
|
||||
The backend server is supporsed to be a HTTP/2 web server or HTTP/2
|
||||
proxy. If backend server is HTTP/2 proxy, use
|
||||
``--no-location-rewrite`` and ``--no-host-rewrite`` options to disable
|
||||
rewriting location, host and :authority header field.
|
||||
:option:`--no-location-rewrite` option to disable rewriting
|
||||
``Location`` header field.
|
||||
|
||||
The use-case of this mode is aggregate the incoming connections to one
|
||||
HTTP/2 connection. One backend HTTP/2 connection is created per
|
||||
@ -222,26 +234,48 @@ Disable SSL/TLS
|
||||
|
||||
In `default mode`_, `HTTP/2 proxy mode`_ and `HTTP/2 bridge mode`_,
|
||||
frontend connections are encrypted with SSL/TLS by default. To turn
|
||||
off SSL/TLS, use ``--frontend-no-tls`` option. If this option is
|
||||
used, the private key and certificate are not required to run nghttpx.
|
||||
off SSL/TLS, use :option:`--frontend-no-tls` option. If this option
|
||||
is used, the private key and certificate are not required to run
|
||||
nghttpx.
|
||||
|
||||
In `client mode`_, `client proxy mode`_ and `HTTP/2 bridge mode`_,
|
||||
backend connections are encrypted with SSL/TLS by default. To turn
|
||||
off SSL/TLS, use ``--backend-no-tls`` option.
|
||||
off SSL/TLS, use :option:`--backend-no-tls` option.
|
||||
|
||||
Enable SSL/TLS on HTTP/1 backend
|
||||
--------------------------------
|
||||
|
||||
In all modes which use HTTP/1 as backend protocol, backend HTTP/1
|
||||
connection is not encrypted by default. To enable encryption, use
|
||||
:option:`--backend-http1-tls` option.
|
||||
|
||||
Enable SSL/TLS on memcached connection
|
||||
--------------------------------------
|
||||
|
||||
By default, memcached connection is not encrypted. To enable
|
||||
encryption, use :option:`--tls-ticket-key-memcached-tls` for TLS
|
||||
ticket key, and use :option:`--tls-session-cache-memcached-tls` for
|
||||
TLS session cache.
|
||||
|
||||
Specifying additional server certificates
|
||||
-----------------------------------------
|
||||
|
||||
nghttpx accepts additional server private key and certificate pairs
|
||||
using :option:`--subcert` option. It can be used multiple times.
|
||||
|
||||
Specifying additional CA certificate
|
||||
------------------------------------
|
||||
|
||||
By default, nghttpx tries to read CA certificate from system. But
|
||||
depending on the system you use, this may fail or is not supported.
|
||||
To specify CA certificate manually, use ``--cacert`` option. The
|
||||
specified file must be PEM format and can contain multiple
|
||||
To specify CA certificate manually, use :option:`--cacert` option.
|
||||
The specified file must be PEM format and can contain multiple
|
||||
certificates.
|
||||
|
||||
By default, nghttpx validates server's certificate. If you want to
|
||||
turn off this validation, knowing this is really insecure and what you
|
||||
are doing, you can use ``-k`` option to disable certificate
|
||||
validation.
|
||||
are doing, you can use :option:`--insecure` option to disable
|
||||
certificate validation.
|
||||
|
||||
Read/write rate limit
|
||||
---------------------
|
||||
@ -250,9 +284,9 @@ nghttpx supports transfer rate limiting on frontend connections. You
|
||||
can do rate limit per frontend connection for reading and writing
|
||||
individually.
|
||||
|
||||
To perform rate limit for reading, use ``--read-rate`` and
|
||||
``--read-burst`` options. For writing, use ``--write-rate`` and
|
||||
``--write-burst``.
|
||||
To perform rate limit for reading, use :option:`--read-rate` and
|
||||
:option:`--read-burst` options. For writing, use
|
||||
:option:`--write-rate` and :option:`--write-burst`.
|
||||
|
||||
Please note that rate limit is performed on top of TCP and nothing to
|
||||
do with HTTP/2 flow control.
|
||||
@ -294,14 +328,64 @@ Re-opening log files
|
||||
When rotating log files, it is desirable to re-open log files after
|
||||
log rotation daemon renamed existing log files. To tell nghttpx to
|
||||
re-open log files, send USR1 signal to nghttpx process. It will
|
||||
re-open files specified by ``--accesslog-file`` and
|
||||
``--errorlog-file`` options.
|
||||
re-open files specified by :option:`--accesslog-file` and
|
||||
:option:`--errorlog-file` options.
|
||||
|
||||
Multiple backend addresses
|
||||
--------------------------
|
||||
|
||||
nghttpx supports multiple backend addresses. To specify them, just
|
||||
use ``-b`` option repeatedly. For example, to use backend1:8080 and
|
||||
backend2:8080, use command-line like this: ``-bbackend1,8080
|
||||
-bbackend2,8080``. For HTTP/2 backend, see also
|
||||
``--backend-http2-connections-per-worker`` option.
|
||||
use :option:`--backend` (or its shorthand :option:`-b`) option
|
||||
repeatedly. For example, to use ``192.168.0.10:8080`` and
|
||||
``192.168.0.11:8080``, use command-line like this:
|
||||
``-b192.168.0.10,8080 -b192.168.0.11,8080``. In configuration file,
|
||||
this looks like:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
backend=192.168.0.10,8080
|
||||
backend=192.168.0.11,8008
|
||||
|
||||
nghttpx can route request to different backend according to request
|
||||
host and path. For example, to route request destined to host
|
||||
``doc.example.com`` to backend server ``docserv:3000``, you can write
|
||||
like so:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
backend=docserv,3000;doc.example.com/
|
||||
|
||||
When you write this option in command-line, you should enclose
|
||||
argument with single or double quotes, since the character ``;`` has a
|
||||
special meaning in shell.
|
||||
|
||||
To route, request to request path whose prefix is ``/foo`` to backend
|
||||
server ``[::1]:8080``, you can write like so:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
backend=::1,8080;/foo
|
||||
|
||||
Of course, you can specify both host and request path at the same
|
||||
time.
|
||||
|
||||
One important thing you have to remember is that we have to specify
|
||||
default routing pattern for so called "catch all" pattern. To write
|
||||
"catch all" pattern, just specify backend server address, without
|
||||
pattern.
|
||||
|
||||
Usually, host is the value of ``Host`` header field. In HTTP/2, the
|
||||
value of ``:authority`` pseudo header field is used.
|
||||
|
||||
When you write multiple backend addresses sharing the same routing
|
||||
pattern, they are used as load balancing. For example, to use 2
|
||||
servers ``serv1:3000`` and ``serv2:3000`` for request host
|
||||
``example.com`` and path ``/myservice``, you can write like so:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
backend=serv1,3000;example.com/myservice
|
||||
backend=serv2,3000;example.com/myservice
|
||||
|
||||
For HTTP/2 backend, see also
|
||||
:option:`--backend-http2-connections-per-worker` option.
|
||||
|
@ -289,8 +289,6 @@ static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_OUTLEN 4096
|
||||
|
||||
/*
|
||||
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
||||
* use this function to print the received response body.
|
||||
|
@ -295,7 +295,7 @@ static size_t http_date(char *buf, time_t t) {
|
||||
static char date[29];
|
||||
static size_t datelen;
|
||||
|
||||
static void update_date() { datelen = http_date(date, time(NULL)); }
|
||||
static void update_date(void) { datelen = http_date(date, time(NULL)); }
|
||||
|
||||
static size_t utos(char *buf, size_t len, uint64_t n) {
|
||||
size_t nwrite = 0;
|
||||
|
@ -62,11 +62,67 @@ HEADERS = [
|
||||
('vary', 58),
|
||||
('via', 59),
|
||||
('www-authenticate', 60),
|
||||
('te', None),
|
||||
('accept-ch', None),
|
||||
('accept-datetime', None),
|
||||
('accept-features', None),
|
||||
('accept-patch', None),
|
||||
('access-control-allow-credentials', None),
|
||||
('access-control-allow-headers', None),
|
||||
('access-control-allow-methods', None),
|
||||
('access-control-expose-headers', None),
|
||||
('access-control-max-age', None),
|
||||
('access-control-request-headers', None),
|
||||
('access-control-request-method', None),
|
||||
('alt-svc', None),
|
||||
('alternates', None),
|
||||
('connection', None),
|
||||
('keep-alive',None),
|
||||
('content-md5', None),
|
||||
('content-security-policy', None),
|
||||
('content-security-policy-report-only', None),
|
||||
('dnt', None),
|
||||
('forwarded', None),
|
||||
('front-end-https', None),
|
||||
('keep-alive', None),
|
||||
('last-event-id', None),
|
||||
('negotiate', None),
|
||||
('origin', None),
|
||||
('p3p', None),
|
||||
('pragma', None),
|
||||
('proxy-connection', None),
|
||||
('public-key-pins', None),
|
||||
('sec-websocket-extensions', None),
|
||||
('sec-websocket-key', None),
|
||||
('sec-websocket-origin', None),
|
||||
('sec-websocket-protocol', None),
|
||||
('sec-websocket-version', None),
|
||||
('set-cookie2', None),
|
||||
('status', None),
|
||||
('tcn', None),
|
||||
('te', None),
|
||||
('trailer', None),
|
||||
('tsv', None),
|
||||
('upgrade', None),
|
||||
('upgrade-insecure-requests', None),
|
||||
('variant-vary', None),
|
||||
('warning', None),
|
||||
('x-api-version', None),
|
||||
('x-att-deviceid', None),
|
||||
('x-cache', None),
|
||||
('x-cache-lookup', None),
|
||||
('x-content-duration', None),
|
||||
('x-content-security-policy', None),
|
||||
('x-content-type-options', None),
|
||||
('x-dnsprefetch-control', None),
|
||||
('x-forwarded-for', None),
|
||||
('x-forwarded-host', None),
|
||||
('x-forwarded-proto', None),
|
||||
('x-frame-options', None),
|
||||
('x-powered-by', None),
|
||||
('x-requested-with', None),
|
||||
('x-ua-compatible', None),
|
||||
('x-wap-profile', None),
|
||||
('x-webkit-csp', None),
|
||||
('x-xss-protection', None),
|
||||
]
|
||||
|
||||
def to_enum_hd(k):
|
||||
|
@ -92,6 +92,7 @@ OPTIONS = [
|
||||
"tls-ticket-key-cipher",
|
||||
"host-rewrite",
|
||||
"tls-session-cache-memcached",
|
||||
"tls-session-cache-memcached-tls",
|
||||
"tls-ticket-key-memcached",
|
||||
"tls-ticket-key-memcached-interval",
|
||||
"tls-ticket-key-memcached-max-retry",
|
||||
@ -114,7 +115,15 @@ OPTIONS = [
|
||||
"max-header-fields",
|
||||
"no-http2-cipher-black-list",
|
||||
"backend-http1-tls",
|
||||
"backend-tls-session-cache-per-worker"
|
||||
"backend-tls-session-cache-per-worker",
|
||||
"tls-session-cache-memcached-cert-file",
|
||||
"tls-session-cache-memcached-private-key-file",
|
||||
"tls-session-cache-memcached-address-family",
|
||||
"tls-ticket-key-memcached-tls",
|
||||
"tls-ticket-key-memcached-cert-file",
|
||||
"tls-ticket-key-memcached-private-key-file",
|
||||
"tls-ticket-key-memcached-address-family",
|
||||
"backend-address-family"
|
||||
]
|
||||
|
||||
LOGVARS = [
|
||||
|
@ -21,11 +21,14 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
EXTRA_DIST = \
|
||||
GO_FILES = \
|
||||
nghttpx_http1_test.go \
|
||||
nghttpx_http2_test.go \
|
||||
nghttpx_spdy_test.go \
|
||||
server_tester.go \
|
||||
server_tester.go
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(GO_FILES) \
|
||||
server.key \
|
||||
server.crt \
|
||||
alt-server.key \
|
||||
@ -43,4 +46,5 @@ itprep-local:
|
||||
go get -d -v golang.org/x/net/websocket
|
||||
|
||||
it-local:
|
||||
for i in $(GO_FILES); do [ -e $(builddir)/$$i ] || cp $(srcdir)/$$i $(builddir); done
|
||||
sh setenv go test -v
|
||||
|
@ -2,4 +2,5 @@ package nghttp2
|
||||
|
||||
const (
|
||||
buildDir = "@top_builddir@"
|
||||
sourceDir = "@top_srcdir@"
|
||||
)
|
||||
|
@ -29,7 +29,8 @@ import (
|
||||
const (
|
||||
serverBin = buildDir + "/src/nghttpx"
|
||||
serverPort = 3009
|
||||
testDir = buildDir + "/integration-tests"
|
||||
testDir = sourceDir + "/integration-tests"
|
||||
logDir = buildDir + "/integration-tests"
|
||||
)
|
||||
|
||||
func pair(name, value string) hpack.HeaderField {
|
||||
@ -124,7 +125,7 @@ func newServerTesterInternal(args []string, t *testing.T, handler http.Handler,
|
||||
// "127.0.0.1,8080"
|
||||
b := "-b" + strings.Replace(backendURL.Host, ":", ",", -1)
|
||||
args = append(args, fmt.Sprintf("-f127.0.0.1,%v", serverPort), b,
|
||||
"--errorlog-file="+testDir+"/log.txt", "-LINFO")
|
||||
"--errorlog-file="+logDir+"/log.txt", "-LINFO")
|
||||
|
||||
authority := fmt.Sprintf("127.0.0.1:%v", serverPort)
|
||||
|
||||
|
@ -1612,6 +1612,14 @@ typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
|
||||
*
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_header_callback()`.
|
||||
*
|
||||
* .. warning::
|
||||
*
|
||||
* Application should properly limit the total buffer size to store
|
||||
* incoming header fields. Without it, peer may send large number
|
||||
* of header fields or large header fields to cause out of memory in
|
||||
* local endpoint. Due to how HPACK works, peer can do this
|
||||
* effectively without using much memory on their own.
|
||||
*/
|
||||
typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
|
306
lib/nghttp2_hd.c
306
lib/nghttp2_hd.c
@ -137,6 +137,26 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_AGE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lstreq("tc", name, 2)) {
|
||||
return NGHTTP2_TOKEN_TCN;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (lstreq("p3", name, 2)) {
|
||||
return NGHTTP2_TOKEN_P3P;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lstreq("dn", name, 2)) {
|
||||
return NGHTTP2_TOKEN_DNT;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (lstreq("ts", name, 2)) {
|
||||
return NGHTTP2_TOKEN_TSV;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
@ -197,16 +217,31 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
case 6:
|
||||
switch (name[5]) {
|
||||
case 'a':
|
||||
if (lstreq("pragm", name, 5)) {
|
||||
return NGHTTP2_TOKEN_PRAGMA;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (lstreq("cooki", name, 5)) {
|
||||
return NGHTTP2_TOKEN_COOKIE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lstreq("origi", name, 5)) {
|
||||
return NGHTTP2_TOKEN_ORIGIN;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (lstreq("serve", name, 5)) {
|
||||
return NGHTTP2_TOKEN_SERVER;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("statu", name, 5)) {
|
||||
return NGHTTP2_TOKEN_STATUS;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lstreq("accep", name, 5)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT;
|
||||
@ -219,6 +254,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
case 7:
|
||||
switch (name[6]) {
|
||||
case 'c':
|
||||
if (lstreq("alt-sv", name, 6)) {
|
||||
return NGHTTP2_TOKEN_ALT_SVC;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (lstreq(":metho", name, 6)) {
|
||||
return NGHTTP2_TOKEN__METHOD;
|
||||
@ -237,6 +277,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
if (lstreq("upgrad", name, 6)) {
|
||||
return NGHTTP2_TOKEN_UPGRADE;
|
||||
}
|
||||
if (lstreq("x-cach", name, 6)) {
|
||||
return NGHTTP2_TOKEN_X_CACHE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (lstreq("warnin", name, 6)) {
|
||||
return NGHTTP2_TOKEN_WARNING;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("refres", name, 6)) {
|
||||
@ -247,6 +295,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
if (lstreq("refere", name, 6)) {
|
||||
return NGHTTP2_TOKEN_REFERER;
|
||||
}
|
||||
if (lstreq("traile", name, 6)) {
|
||||
return NGHTTP2_TOKEN_TRAILER;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq(":statu", name, 6)) {
|
||||
@ -295,6 +346,25 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
switch (name[8]) {
|
||||
case 'd':
|
||||
if (lstreq("forwarde", name, 8)) {
|
||||
return NGHTTP2_TOKEN_FORWARDED;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (lstreq("negotiat", name, 8)) {
|
||||
return NGHTTP2_TOKEN_NEGOTIATE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("accept-c", name, 8)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_CH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
switch (name[9]) {
|
||||
case 'e':
|
||||
@ -310,6 +380,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_CONNECTION;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("alternate", name, 9)) {
|
||||
return NGHTTP2_TOKEN_ALTERNATES;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lstreq("user-agen", name, 9)) {
|
||||
return NGHTTP2_TOKEN_USER_AGENT;
|
||||
@ -324,6 +399,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
case 11:
|
||||
switch (name[10]) {
|
||||
case '2':
|
||||
if (lstreq("set-cookie", name, 10)) {
|
||||
return NGHTTP2_TOKEN_SET_COOKIE2;
|
||||
}
|
||||
break;
|
||||
case '5':
|
||||
if (lstreq("content-md", name, 10)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_MD5;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (lstreq("retry-afte", name, 10)) {
|
||||
return NGHTTP2_TOKEN_RETRY_AFTER;
|
||||
@ -338,16 +423,37 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_CONTENT_TYPE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("accept-patc", name, 11)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_PATCH;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (lstreq("x-webkit-cs", name, 11)) {
|
||||
return NGHTTP2_TOKEN_X_WEBKIT_CSP;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("max-forward", name, 11)) {
|
||||
return NGHTTP2_TOKEN_MAX_FORWARDS;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (lstreq("variant-var", name, 11)) {
|
||||
return NGHTTP2_TOKEN_VARIANT_VARY;
|
||||
}
|
||||
if (lstreq("x-powered-b", name, 11)) {
|
||||
return NGHTTP2_TOKEN_X_POWERED_BY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (name[12]) {
|
||||
case 'd':
|
||||
if (lstreq("last-event-i", name, 12)) {
|
||||
return NGHTTP2_TOKEN_LAST_EVENT_ID;
|
||||
}
|
||||
if (lstreq("last-modifie", name, 12)) {
|
||||
return NGHTTP2_TOKEN_LAST_MODIFIED;
|
||||
}
|
||||
@ -356,6 +462,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
if (lstreq("content-rang", name, 12)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_RANGE;
|
||||
}
|
||||
if (lstreq("x-wap-profil", name, 12)) {
|
||||
return NGHTTP2_TOKEN_X_WAP_PROFILE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("if-none-matc", name, 12)) {
|
||||
@ -371,6 +480,9 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
if (lstreq("authorizatio", name, 12)) {
|
||||
return NGHTTP2_TOKEN_AUTHORIZATION;
|
||||
}
|
||||
if (lstreq("x-api-versio", name, 12)) {
|
||||
return NGHTTP2_TOKEN_X_API_VERSION;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("accept-range", name, 12)) {
|
||||
@ -381,11 +493,21 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
case 14:
|
||||
switch (name[13]) {
|
||||
case 'd':
|
||||
if (lstreq("x-att-devicei", name, 13)) {
|
||||
return NGHTTP2_TOKEN_X_ATT_DEVICEID;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("content-lengt", name, 13)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (lstreq("x-cache-looku", name, 13)) {
|
||||
return NGHTTP2_TOKEN_X_CACHE_LOOKUP;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lstreq("accept-charse", name, 13)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_CHARSET;
|
||||
@ -396,15 +518,40 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
case 15:
|
||||
switch (name[14]) {
|
||||
case 'e':
|
||||
if (lstreq("accept-datetim", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_DATETIME;
|
||||
}
|
||||
if (lstreq("accept-languag", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
|
||||
}
|
||||
if (lstreq("x-ua-compatibl", name, 14)) {
|
||||
return NGHTTP2_TOKEN_X_UA_COMPATIBLE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (lstreq("accept-encodin", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_ENCODING;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (lstreq("x-forwarded-fo", name, 14)) {
|
||||
return NGHTTP2_TOKEN_X_FORWARDED_FOR;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("accept-feature", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_FEATURES;
|
||||
}
|
||||
if (lstreq("front-end-http", name, 14)) {
|
||||
return NGHTTP2_TOKEN_FRONT_END_HTTPS;
|
||||
}
|
||||
if (lstreq("public-key-pin", name, 14)) {
|
||||
return NGHTTP2_TOKEN_PUBLIC_KEY_PINS;
|
||||
}
|
||||
if (lstreq("x-frame-option", name, 14)) {
|
||||
return NGHTTP2_TOKEN_X_FRAME_OPTIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
@ -422,6 +569,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_CONTENT_ENCODING;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (lstreq("x-requested-wit", name, 15)) {
|
||||
return NGHTTP2_TOKEN_X_REQUESTED_WITH;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lstreq("content-locatio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LOCATION;
|
||||
@ -429,6 +581,14 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
if (lstreq("proxy-connectio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_PROXY_CONNECTION;
|
||||
}
|
||||
if (lstreq("x-xss-protectio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_X_XSS_PROTECTION;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (lstreq("x-forwarded-hos", name, 15)) {
|
||||
return NGHTTP2_TOKEN_X_FORWARDED_HOST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -444,6 +604,16 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (lstreq("x-forwarded-prot", name, 16)) {
|
||||
return NGHTTP2_TOKEN_X_FORWARDED_PROTO;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (lstreq("sec-websocket-ke", name, 16)) {
|
||||
return NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
@ -453,6 +623,11 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lstreq("x-content-duratio", name, 17)) {
|
||||
return NGHTTP2_TOKEN_X_CONTENT_DURATION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
@ -472,12 +647,80 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 20:
|
||||
switch (name[19]) {
|
||||
case 'n':
|
||||
if (lstreq("sec-websocket-origi", name, 19)) {
|
||||
return NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
switch (name[20]) {
|
||||
case 'l':
|
||||
if (lstreq("x-dnsprefetch-contro", name, 20)) {
|
||||
return NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (lstreq("sec-websocket-versio", name, 20)) {
|
||||
return NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 22:
|
||||
switch (name[21]) {
|
||||
case 'e':
|
||||
if (lstreq("access-control-max-ag", name, 21)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (lstreq("sec-websocket-protoco", name, 21)) {
|
||||
return NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("x-content-type-option", name, 21)) {
|
||||
return NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
switch (name[22]) {
|
||||
case 'y':
|
||||
if (lstreq("content-security-polic", name, 22)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
switch (name[23]) {
|
||||
case 's':
|
||||
if (lstreq("sec-websocket-extension", name, 23)) {
|
||||
return NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 25:
|
||||
switch (name[24]) {
|
||||
case 's':
|
||||
if (lstreq("upgrade-insecure-request", name, 24)) {
|
||||
return NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (lstreq("strict-transport-securit", name, 24)) {
|
||||
return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
|
||||
}
|
||||
if (lstreq("x-content-security-polic", name, 24)) {
|
||||
return NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -490,6 +733,59 @@ static int lookup_token(const uint8_t *name, size_t namelen) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 28:
|
||||
switch (name[27]) {
|
||||
case 's':
|
||||
if (lstreq("access-control-allow-header", name, 27)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS;
|
||||
}
|
||||
if (lstreq("access-control-allow-method", name, 27)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 29:
|
||||
switch (name[28]) {
|
||||
case 'd':
|
||||
if (lstreq("access-control-request-metho", name, 28)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (lstreq("access-control-expose-header", name, 28)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 30:
|
||||
switch (name[29]) {
|
||||
case 's':
|
||||
if (lstreq("access-control-request-header", name, 29)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
switch (name[31]) {
|
||||
case 's':
|
||||
if (lstreq("access-control-allow-credential", name, 31)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 35:
|
||||
switch (name[34]) {
|
||||
case 'y':
|
||||
if (lstreq("content-security-policy-report-onl", name, 34)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -617,8 +913,8 @@ static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
|
||||
*exact_match = 0;
|
||||
|
||||
for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) {
|
||||
if (hash != p->hash || token != p->token ||
|
||||
(token == -1 && !name_eq(&p->nv, nv))) {
|
||||
if (token != p->token ||
|
||||
(token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) {
|
||||
continue;
|
||||
}
|
||||
if (!res) {
|
||||
@ -1444,7 +1740,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
||||
int indexing_mode;
|
||||
int token;
|
||||
nghttp2_mem *mem;
|
||||
uint32_t hash;
|
||||
uint32_t hash = 0;
|
||||
|
||||
DEBUGF(fprintf(stderr, "deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen,
|
||||
nv->name, (int)nv->valuelen, nv->value));
|
||||
@ -1452,9 +1748,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
token = lookup_token(nv->name, nv->namelen);
|
||||
if (token == -1 || token > NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
||||
if (token == -1) {
|
||||
hash = name_hash(nv);
|
||||
} else {
|
||||
} else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
||||
hash = static_table[token].hash;
|
||||
}
|
||||
|
||||
|
@ -105,11 +105,67 @@ typedef enum {
|
||||
NGHTTP2_TOKEN_VARY = 58,
|
||||
NGHTTP2_TOKEN_VIA = 59,
|
||||
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_ACCEPT_CH,
|
||||
NGHTTP2_TOKEN_ACCEPT_DATETIME,
|
||||
NGHTTP2_TOKEN_ACCEPT_FEATURES,
|
||||
NGHTTP2_TOKEN_ACCEPT_PATCH,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_CREDENTIALS,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_HEADERS,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_METHODS,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_EXPOSE_HEADERS,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_MAX_AGE,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_HEADERS,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_REQUEST_METHOD,
|
||||
NGHTTP2_TOKEN_ALT_SVC,
|
||||
NGHTTP2_TOKEN_ALTERNATES,
|
||||
NGHTTP2_TOKEN_CONNECTION,
|
||||
NGHTTP2_TOKEN_CONTENT_MD5,
|
||||
NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY,
|
||||
NGHTTP2_TOKEN_CONTENT_SECURITY_POLICY_REPORT_ONLY,
|
||||
NGHTTP2_TOKEN_DNT,
|
||||
NGHTTP2_TOKEN_FORWARDED,
|
||||
NGHTTP2_TOKEN_FRONT_END_HTTPS,
|
||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||
NGHTTP2_TOKEN_LAST_EVENT_ID,
|
||||
NGHTTP2_TOKEN_NEGOTIATE,
|
||||
NGHTTP2_TOKEN_ORIGIN,
|
||||
NGHTTP2_TOKEN_P3P,
|
||||
NGHTTP2_TOKEN_PRAGMA,
|
||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||
NGHTTP2_TOKEN_UPGRADE
|
||||
NGHTTP2_TOKEN_PUBLIC_KEY_PINS,
|
||||
NGHTTP2_TOKEN_SEC_WEBSOCKET_EXTENSIONS,
|
||||
NGHTTP2_TOKEN_SEC_WEBSOCKET_KEY,
|
||||
NGHTTP2_TOKEN_SEC_WEBSOCKET_ORIGIN,
|
||||
NGHTTP2_TOKEN_SEC_WEBSOCKET_PROTOCOL,
|
||||
NGHTTP2_TOKEN_SEC_WEBSOCKET_VERSION,
|
||||
NGHTTP2_TOKEN_SET_COOKIE2,
|
||||
NGHTTP2_TOKEN_STATUS,
|
||||
NGHTTP2_TOKEN_TCN,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_TRAILER,
|
||||
NGHTTP2_TOKEN_TSV,
|
||||
NGHTTP2_TOKEN_UPGRADE,
|
||||
NGHTTP2_TOKEN_UPGRADE_INSECURE_REQUESTS,
|
||||
NGHTTP2_TOKEN_VARIANT_VARY,
|
||||
NGHTTP2_TOKEN_WARNING,
|
||||
NGHTTP2_TOKEN_X_API_VERSION,
|
||||
NGHTTP2_TOKEN_X_ATT_DEVICEID,
|
||||
NGHTTP2_TOKEN_X_CACHE,
|
||||
NGHTTP2_TOKEN_X_CACHE_LOOKUP,
|
||||
NGHTTP2_TOKEN_X_CONTENT_DURATION,
|
||||
NGHTTP2_TOKEN_X_CONTENT_SECURITY_POLICY,
|
||||
NGHTTP2_TOKEN_X_CONTENT_TYPE_OPTIONS,
|
||||
NGHTTP2_TOKEN_X_DNSPREFETCH_CONTROL,
|
||||
NGHTTP2_TOKEN_X_FORWARDED_FOR,
|
||||
NGHTTP2_TOKEN_X_FORWARDED_HOST,
|
||||
NGHTTP2_TOKEN_X_FORWARDED_PROTO,
|
||||
NGHTTP2_TOKEN_X_FRAME_OPTIONS,
|
||||
NGHTTP2_TOKEN_X_POWERED_BY,
|
||||
NGHTTP2_TOKEN_X_REQUESTED_WITH,
|
||||
NGHTTP2_TOKEN_X_UA_COMPATIBLE,
|
||||
NGHTTP2_TOKEN_X_WAP_PROFILE,
|
||||
NGHTTP2_TOKEN_X_WEBKIT_CSP,
|
||||
NGHTTP2_TOKEN_X_XSS_PROTECTION,
|
||||
} nghttp2_token;
|
||||
|
||||
typedef enum {
|
||||
|
@ -25,9 +25,9 @@
|
||||
#ifndef NGHTTP2_NPN_H
|
||||
#define NGHTTP2_NPN_H
|
||||
|
||||
#ifdef HAVE_CONFIG
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG */
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
|
@ -1221,11 +1221,12 @@ int nghttp2_session_adjust_idle_stream(nghttp2_session *session) {
|
||||
size_t max;
|
||||
int rv;
|
||||
|
||||
/* Make minimum number of idle streams 16, which is arbitrary chosen
|
||||
number. */
|
||||
max = nghttp2_max(16,
|
||||
nghttp2_min(session->local_settings.max_concurrent_streams,
|
||||
session->pending_local_max_concurrent_stream));
|
||||
/* Make minimum number of idle streams 16, and maximum 100, which
|
||||
are arbitrary chosen numbers. */
|
||||
max = nghttp2_min(
|
||||
100, nghttp2_max(
|
||||
16, nghttp2_min(session->local_settings.max_concurrent_streams,
|
||||
session->pending_local_max_concurrent_stream)));
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: adjusting kept idle streams "
|
||||
"num_idle_streams=%zu, max=%zu\n",
|
||||
@ -5763,10 +5764,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
||||
|
||||
readlen = inbound_frame_payload_readlen(iframe, in, last);
|
||||
|
||||
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
|
||||
if (readlen > 0) {
|
||||
iframe->lbuf.last = nghttp2_cpymem(iframe->lbuf.last, in, readlen);
|
||||
|
||||
iframe->payloadleft -= readlen;
|
||||
in += readlen;
|
||||
iframe->payloadleft -= readlen;
|
||||
in += readlen;
|
||||
}
|
||||
|
||||
DEBUGF(fprintf(stderr, "recv: readlen=%zu, payloadleft=%zu\n", readlen,
|
||||
iframe->payloadleft));
|
||||
|
@ -30,14 +30,32 @@
|
||||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
/* Maximum distance between any two stream's cycle in the same
|
||||
prirority queue. Imagine stream A's cycle is A, and stream B's
|
||||
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
||||
may get overflow. Because of how we calculate the next cycle
|
||||
value, if B - A is less than or equals to
|
||||
NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
|
||||
words, B is really greater than or equal to A. Otherwise, A is a
|
||||
result of overflow, and it is actually A > B if we consider that
|
||||
fact. */
|
||||
#define NGHTTP2_MAX_CYCLE_DISTANCE (16384 * 256 + 255)
|
||||
|
||||
static int stream_less(const void *lhsx, const void *rhsx) {
|
||||
const nghttp2_stream *lhs, *rhs;
|
||||
|
||||
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
|
||||
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
|
||||
|
||||
return lhs->cycle < rhs->cycle ||
|
||||
(lhs->cycle == rhs->cycle && lhs->seq < rhs->seq);
|
||||
if (lhs->cycle == rhs->cycle) {
|
||||
return lhs->seq < rhs->seq;
|
||||
}
|
||||
|
||||
if (lhs->cycle < rhs->cycle) {
|
||||
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
|
||||
}
|
||||
|
||||
return lhs->cycle - rhs->cycle > NGHTTP2_MAX_CYCLE_DISTANCE;
|
||||
}
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
@ -116,14 +134,14 @@ static int stream_subtree_active(nghttp2_stream *stream) {
|
||||
/*
|
||||
* Returns next cycle for |stream|.
|
||||
*/
|
||||
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
|
||||
size_t penalty;
|
||||
static void stream_next_cycle(nghttp2_stream *stream, uint32_t last_cycle) {
|
||||
uint32_t penalty;
|
||||
|
||||
penalty =
|
||||
stream->last_writelen * NGHTTP2_MAX_WEIGHT + stream->pending_penalty;
|
||||
penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
|
||||
stream->pending_penalty;
|
||||
|
||||
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
|
||||
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
|
||||
stream->pending_penalty = penalty % (uint32_t)stream->weight;
|
||||
}
|
||||
|
||||
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
|
||||
@ -229,9 +247,9 @@ void nghttp2_stream_reschedule(nghttp2_stream *stream) {
|
||||
|
||||
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
|
||||
nghttp2_stream *dep_stream;
|
||||
uint64_t last_cycle;
|
||||
uint32_t last_cycle;
|
||||
int32_t old_weight;
|
||||
size_t wlen_penalty;
|
||||
uint32_t wlen_penalty;
|
||||
|
||||
if (stream->weight == weight) {
|
||||
return;
|
||||
@ -254,7 +272,7 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
|
||||
|
||||
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
wlen_penalty = stream->last_writelen * NGHTTP2_MAX_WEIGHT;
|
||||
wlen_penalty = (uint32_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
|
||||
|
||||
/* Compute old stream->pending_penalty we used to calculate
|
||||
stream->cycle */
|
||||
@ -270,7 +288,9 @@ void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
|
||||
place */
|
||||
stream_next_cycle(stream, last_cycle);
|
||||
|
||||
if (stream->cycle < dep_stream->descendant_last_cycle) {
|
||||
if (stream->cycle < dep_stream->descendant_last_cycle &&
|
||||
(dep_stream->descendant_last_cycle - stream->cycle) <=
|
||||
NGHTTP2_MAX_CYCLE_DISTANCE) {
|
||||
stream->cycle = dep_stream->descendant_last_cycle;
|
||||
}
|
||||
|
||||
|
@ -147,9 +147,9 @@ struct nghttp2_stream {
|
||||
/* Received body so far */
|
||||
int64_t recv_content_length;
|
||||
/* Base last_cycle for direct descendent streams. */
|
||||
uint64_t descendant_last_cycle;
|
||||
uint32_t descendant_last_cycle;
|
||||
/* Next scheduled time to sent item */
|
||||
uint64_t cycle;
|
||||
uint32_t cycle;
|
||||
/* Next seq used for direct descendant streams */
|
||||
uint64_t descendant_next_seq;
|
||||
/* Secondary key for prioritization to break a tie for cycle. This
|
||||
|
@ -308,7 +308,6 @@ public:
|
||||
}
|
||||
auto handler =
|
||||
make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
|
||||
handler->setup_bev();
|
||||
if (!ssl) {
|
||||
if (handler->connection_made() != 0) {
|
||||
return;
|
||||
@ -447,6 +446,7 @@ Stream::Stream(Http2Handler *handler, int32_t stream_id)
|
||||
file_ent(nullptr),
|
||||
body_length(0),
|
||||
body_offset(0),
|
||||
header_buffer_size(0),
|
||||
stream_id(stream_id),
|
||||
echo_upload(false) {
|
||||
auto config = handler->get_config();
|
||||
@ -574,7 +574,9 @@ struct ev_loop *Http2Handler::get_loop() const {
|
||||
|
||||
Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
|
||||
|
||||
int Http2Handler::setup_bev() { return 0; }
|
||||
void Http2Handler::start_settings_timer() {
|
||||
ev_timer_start(sessions_->get_loop(), &settings_timerev_);
|
||||
}
|
||||
|
||||
int Http2Handler::fill_wb() {
|
||||
if (data_pending_) {
|
||||
@ -869,8 +871,6 @@ int Http2Handler::connection_made() {
|
||||
}
|
||||
}
|
||||
|
||||
ev_timer_start(sessions_->get_loop(), &settings_timerev_);
|
||||
|
||||
if (ssl_ && !nghttp2::ssl::check_http2_requirement(ssl_)) {
|
||||
terminate_session(NGHTTP2_INADEQUATE_SECURITY);
|
||||
}
|
||||
@ -1389,6 +1389,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream->header_buffer_size + namelen + valuelen > 64_k) {
|
||||
hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->header_buffer_size += namelen + valuelen;
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
http2::index_header(stream->hdidx, token, stream->headers.size());
|
||||
@ -1530,6 +1537,15 @@ int hd_on_frame_send_callback(nghttp2_session *session,
|
||||
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_SETTINGS: {
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hd->start_settings_timer();
|
||||
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
auto promised_stream_id = frame->push_promise.promised_stream_id;
|
||||
auto promised_stream = hd->get_stream(promised_stream_id);
|
||||
|
@ -119,6 +119,9 @@ struct Stream {
|
||||
ev_timer wtimer;
|
||||
int64_t body_length;
|
||||
int64_t body_offset;
|
||||
// Total amount of bytes (sum of name and value length) used in
|
||||
// headers.
|
||||
size_t header_buffer_size;
|
||||
int32_t stream_id;
|
||||
http2::HeaderIndex hdidx;
|
||||
bool echo_upload;
|
||||
@ -134,7 +137,7 @@ public:
|
||||
~Http2Handler();
|
||||
|
||||
void remove_self();
|
||||
int setup_bev();
|
||||
void start_settings_timer();
|
||||
int on_read();
|
||||
int on_write();
|
||||
int connection_made();
|
||||
|
@ -62,7 +62,7 @@ HELPER_OBJECTS = util.cc \
|
||||
http2.cc timegm.c app_helper.cc nghttp2_gzip.c
|
||||
HELPER_HFILES = util.h \
|
||||
http2.h timegm.h app_helper.h nghttp2_config.h \
|
||||
nghttp2_gzip.h
|
||||
nghttp2_gzip.h network.h
|
||||
|
||||
HTML_PARSER_OBJECTS =
|
||||
HTML_PARSER_HFILES = HtmlParser.h
|
||||
|
@ -32,7 +32,7 @@ namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
request_impl::request_impl() : strm_(nullptr) {}
|
||||
request_impl::request_impl() : strm_(nullptr), header_buffer_size_(0) {}
|
||||
|
||||
void request_impl::write_trailer(header_map h) {
|
||||
auto sess = strm_->session();
|
||||
@ -105,6 +105,12 @@ void request_impl::method(std::string s) { method_ = std::move(s); }
|
||||
|
||||
const std::string &request_impl::method() const { return method_; }
|
||||
|
||||
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
|
||||
|
||||
void request_impl::update_header_buffer_size(size_t len) {
|
||||
header_buffer_size_ += len;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
@ -75,6 +75,9 @@ public:
|
||||
void method(std::string s);
|
||||
const std::string &method() const;
|
||||
|
||||
size_t header_buffer_size() const;
|
||||
void update_header_buffer_size(size_t len);
|
||||
|
||||
private:
|
||||
header_map header_;
|
||||
response_cb response_cb_;
|
||||
@ -84,6 +87,7 @@ private:
|
||||
class stream *strm_;
|
||||
uri_ref uri_;
|
||||
std::string method_;
|
||||
size_t header_buffer_size_;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
@ -30,7 +30,8 @@ namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace client {
|
||||
|
||||
response_impl::response_impl() : content_length_(-1), status_code_(0) {}
|
||||
response_impl::response_impl()
|
||||
: content_length_(-1), header_buffer_size_(0), status_code_(0) {}
|
||||
|
||||
void response_impl::on_data(data_cb cb) { data_cb_ = std::move(cb); }
|
||||
|
||||
@ -52,6 +53,12 @@ header_map &response_impl::header() { return header_; }
|
||||
|
||||
const header_map &response_impl::header() const { return header_; }
|
||||
|
||||
size_t response_impl::header_buffer_size() const { return header_buffer_size_; }
|
||||
|
||||
void response_impl::update_header_buffer_size(size_t len) {
|
||||
header_buffer_size_ += len;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
@ -53,12 +53,16 @@ public:
|
||||
header_map &header();
|
||||
const header_map &header() const;
|
||||
|
||||
size_t header_buffer_size() const;
|
||||
void update_header_buffer_size(size_t len);
|
||||
|
||||
private:
|
||||
data_cb data_cb_;
|
||||
|
||||
header_map header_;
|
||||
|
||||
int64_t content_length_;
|
||||
size_t header_buffer_size_;
|
||||
int status_code_;
|
||||
};
|
||||
|
||||
|
@ -183,6 +183,12 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
if (token == http2::HD__STATUS) {
|
||||
res.status_code(util::parse_uint(value, valuelen));
|
||||
} else {
|
||||
if (res.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
res.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
res.content_length(util::parse_uint(value, valuelen));
|
||||
@ -223,6 +229,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
req.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
req.header().emplace(
|
||||
std::string(name, name + namelen),
|
||||
header_value{std::string(value, value + valuelen),
|
||||
|
@ -105,6 +105,13 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
}
|
||||
// fall through
|
||||
default:
|
||||
if (req.header_buffer_size() + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
break;
|
||||
}
|
||||
req.update_header_buffer_size(namelen + valuelen);
|
||||
|
||||
req.header().emplace(std::string(name, name + namelen),
|
||||
header_value{std::string(value, value + valuelen),
|
||||
(flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0});
|
||||
|
@ -28,7 +28,7 @@ namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
request_impl::request_impl() : strm_(nullptr) {}
|
||||
request_impl::request_impl() : strm_(nullptr), header_buffer_size_(0) {}
|
||||
|
||||
const header_map &request_impl::header() const { return header_; }
|
||||
|
||||
@ -62,6 +62,12 @@ void request_impl::remote_endpoint(boost::asio::ip::tcp::endpoint ep) {
|
||||
remote_ep_ = std::move(ep);
|
||||
}
|
||||
|
||||
size_t request_impl::header_buffer_size() const { return header_buffer_size_; }
|
||||
|
||||
void request_impl::update_header_buffer_size(size_t len) {
|
||||
header_buffer_size_ += len;
|
||||
}
|
||||
|
||||
} // namespace server
|
||||
} // namespace asio_http2
|
||||
} // namespace nghttp2
|
||||
|
@ -58,6 +58,9 @@ public:
|
||||
const boost::asio::ip::tcp::endpoint &remote_endpoint() const;
|
||||
void remote_endpoint(boost::asio::ip::tcp::endpoint ep);
|
||||
|
||||
size_t header_buffer_size() const;
|
||||
void update_header_buffer_size(size_t len);
|
||||
|
||||
private:
|
||||
class stream *strm_;
|
||||
header_map header_;
|
||||
@ -65,6 +68,7 @@ private:
|
||||
uri_ref uri_;
|
||||
data_cb on_data_cb_;
|
||||
boost::asio::ip::tcp::endpoint remote_ep_;
|
||||
size_t header_buffer_size_;
|
||||
};
|
||||
|
||||
} // namespace server
|
||||
|
55
src/http2.cc
55
src/http2.cc
@ -271,7 +271,7 @@ void copy_url_component(std::string &dest, const http_parser_url *u, int field,
|
||||
|
||||
Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index, int16_t token) {
|
||||
bool no_index, int32_t token) {
|
||||
return Header(std::string(reinterpret_cast<const char *>(name), namelen),
|
||||
std::string(reinterpret_cast<const char *>(value), valuelen),
|
||||
no_index, token);
|
||||
@ -279,7 +279,7 @@ Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
|
||||
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, bool no_index,
|
||||
int16_t token) {
|
||||
int32_t token) {
|
||||
if (valuelen > 0) {
|
||||
size_t i, j;
|
||||
for (i = 0; i < valuelen && (value[i] == ' ' || value[i] == '\t'); ++i)
|
||||
@ -760,7 +760,7 @@ void init_hdidx(HeaderIndex &hdidx) {
|
||||
std::fill(std::begin(hdidx), std::end(hdidx), -1);
|
||||
}
|
||||
|
||||
void index_header(HeaderIndex &hdidx, int16_t token, size_t idx) {
|
||||
void index_header(HeaderIndex &hdidx, int32_t token, size_t idx) {
|
||||
if (token == -1) {
|
||||
return;
|
||||
}
|
||||
@ -768,52 +768,7 @@ void index_header(HeaderIndex &hdidx, int16_t token, size_t idx) {
|
||||
hdidx[token] = idx;
|
||||
}
|
||||
|
||||
bool check_http2_request_pseudo_header(const HeaderIndex &hdidx,
|
||||
int16_t token) {
|
||||
switch (token) {
|
||||
case HD__AUTHORITY:
|
||||
case HD__METHOD:
|
||||
case HD__PATH:
|
||||
case HD__SCHEME:
|
||||
return hdidx[token] == -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool check_http2_response_pseudo_header(const HeaderIndex &hdidx,
|
||||
int16_t token) {
|
||||
switch (token) {
|
||||
case HD__STATUS:
|
||||
return hdidx[token] == -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool http2_header_allowed(int16_t token) {
|
||||
switch (token) {
|
||||
case HD_CONNECTION:
|
||||
case HD_KEEP_ALIVE:
|
||||
case HD_PROXY_CONNECTION:
|
||||
case HD_TRANSFER_ENCODING:
|
||||
case HD_UPGRADE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool http2_mandatory_request_headers_presence(const HeaderIndex &hdidx) {
|
||||
if (hdidx[HD__METHOD] == -1 || hdidx[HD__PATH] == -1 ||
|
||||
hdidx[HD__SCHEME] == -1 ||
|
||||
(hdidx[HD__AUTHORITY] == -1 && hdidx[HD_HOST] == -1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
|
||||
const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
|
||||
const Headers &nva) {
|
||||
auto i = hdidx[token];
|
||||
if (i == -1) {
|
||||
@ -822,7 +777,7 @@ const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
|
||||
return &nva[i];
|
||||
}
|
||||
|
||||
Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
|
||||
Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
|
||||
Headers &nva) {
|
||||
auto i = hdidx[token];
|
||||
if (i == -1) {
|
||||
|
31
src/http2.h
31
src/http2.h
@ -44,7 +44,7 @@ namespace nghttp2 {
|
||||
|
||||
struct Header {
|
||||
Header(std::string name, std::string value, bool no_index = false,
|
||||
int16_t token = -1)
|
||||
int32_t token = -1)
|
||||
: name(std::move(name)),
|
||||
value(std::move(value)),
|
||||
token(token),
|
||||
@ -62,7 +62,7 @@ struct Header {
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
int16_t token;
|
||||
int32_t token;
|
||||
bool no_index;
|
||||
};
|
||||
|
||||
@ -89,14 +89,14 @@ void copy_url_component(std::string &dest, const http_parser_url *u, int field,
|
||||
|
||||
Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index, int16_t token);
|
||||
bool no_index, int32_t token);
|
||||
|
||||
// Add name/value pairs to |nva|. If |no_index| is true, this
|
||||
// name/value pair won't be indexed when it is forwarded to the next
|
||||
// hop. This function strips white spaces around |value|.
|
||||
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, bool no_index,
|
||||
int16_t token);
|
||||
int32_t token);
|
||||
|
||||
// Returns pointer to the entry in |nva| which has name |name|. If
|
||||
// more than one entries which have the name |name|, last occurrence
|
||||
@ -277,30 +277,13 @@ int lookup_token(const std::string &name);
|
||||
// array containing at least HD_MAXIDX elements.
|
||||
void init_hdidx(HeaderIndex &hdidx);
|
||||
// Indexes header |token| using index |idx|.
|
||||
void index_header(HeaderIndex &hdidx, int16_t token, size_t idx);
|
||||
|
||||
// Returns true if HTTP/2 request pseudo header |token| is not indexed
|
||||
// yet and not -1.
|
||||
bool check_http2_request_pseudo_header(const HeaderIndex &hdidx, int16_t token);
|
||||
|
||||
// Returns true if HTTP/2 response pseudo header |token| is not
|
||||
// indexed yet and not -1.
|
||||
bool check_http2_response_pseudo_header(const HeaderIndex &hdidx,
|
||||
int16_t token);
|
||||
|
||||
// Returns true if header field denoted by |token| is allowed for
|
||||
// HTTP/2.
|
||||
bool http2_header_allowed(int16_t token);
|
||||
|
||||
// Returns true that |hdidx| contains mandatory HTTP/2 request
|
||||
// headers.
|
||||
bool http2_mandatory_request_headers_presence(const HeaderIndex &hdidx);
|
||||
void index_header(HeaderIndex &hdidx, int32_t token, size_t idx);
|
||||
|
||||
// Returns header denoted by |token| using index |hdidx|.
|
||||
const Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
|
||||
const Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
|
||||
const Headers &nva);
|
||||
|
||||
Headers::value_type *get_header(const HeaderIndex &hdidx, int16_t token,
|
||||
Headers::value_type *get_header(const HeaderIndex &hdidx, int32_t token,
|
||||
Headers &nva);
|
||||
|
||||
struct LinkHeader {
|
||||
|
@ -271,53 +271,6 @@ void test_http2_lookup_token(void) {
|
||||
CU_ASSERT(http2::HD_EXPECT == http2::lookup_token("expect"));
|
||||
}
|
||||
|
||||
void test_http2_check_http2_pseudo_header(void) {
|
||||
http2::HeaderIndex hdidx;
|
||||
http2::init_hdidx(hdidx);
|
||||
|
||||
CU_ASSERT(http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
|
||||
hdidx[http2::HD__PATH] = 0;
|
||||
CU_ASSERT(http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
|
||||
hdidx[http2::HD__METHOD] = 1;
|
||||
CU_ASSERT(
|
||||
!http2::check_http2_request_pseudo_header(hdidx, http2::HD__METHOD));
|
||||
CU_ASSERT(!http2::check_http2_request_pseudo_header(hdidx, http2::HD_VIA));
|
||||
|
||||
http2::init_hdidx(hdidx);
|
||||
|
||||
CU_ASSERT(
|
||||
http2::check_http2_response_pseudo_header(hdidx, http2::HD__STATUS));
|
||||
hdidx[http2::HD__STATUS] = 0;
|
||||
CU_ASSERT(
|
||||
!http2::check_http2_response_pseudo_header(hdidx, http2::HD__STATUS));
|
||||
CU_ASSERT(!http2::check_http2_response_pseudo_header(hdidx, http2::HD_VIA));
|
||||
}
|
||||
|
||||
void test_http2_http2_header_allowed(void) {
|
||||
CU_ASSERT(http2::http2_header_allowed(http2::HD__PATH));
|
||||
CU_ASSERT(http2::http2_header_allowed(http2::HD_CONTENT_LENGTH));
|
||||
CU_ASSERT(!http2::http2_header_allowed(http2::HD_CONNECTION));
|
||||
}
|
||||
|
||||
void test_http2_mandatory_request_headers_presence(void) {
|
||||
http2::HeaderIndex hdidx;
|
||||
http2::init_hdidx(hdidx);
|
||||
|
||||
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
hdidx[http2::HD__AUTHORITY] = 0;
|
||||
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
hdidx[http2::HD__METHOD] = 1;
|
||||
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
hdidx[http2::HD__PATH] = 2;
|
||||
CU_ASSERT(!http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
hdidx[http2::HD__SCHEME] = 3;
|
||||
CU_ASSERT(http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
|
||||
hdidx[http2::HD__AUTHORITY] = -1;
|
||||
hdidx[http2::HD_HOST] = 0;
|
||||
CU_ASSERT(http2::http2_mandatory_request_headers_presence(hdidx));
|
||||
}
|
||||
|
||||
void test_http2_parse_link_header(void) {
|
||||
{
|
||||
// only URI appears; we don't extract URI unless it bears rel=preload
|
||||
|
@ -40,9 +40,6 @@ void test_http2_rewrite_location_uri(void);
|
||||
void test_http2_parse_http_status_code(void);
|
||||
void test_http2_index_header(void);
|
||||
void test_http2_lookup_token(void);
|
||||
void test_http2_check_http2_pseudo_header(void);
|
||||
void test_http2_http2_header_allowed(void);
|
||||
void test_http2_mandatory_request_headers_presence(void);
|
||||
void test_http2_parse_link_header(void);
|
||||
void test_http2_path_join(void);
|
||||
void test_http2_normalize_path(void);
|
||||
|
61
src/network.h
Normal file
61
src/network.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NETWORK_H
|
||||
#define NETWORK_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif // HAVE_SYS_SOCKET_H
|
||||
#include <sys/un.h>
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif // HAVE_NETINET_IN_H
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif // HAVE_ARPA_INET_H
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr_storage storage;
|
||||
sockaddr sa;
|
||||
sockaddr_in6 in6;
|
||||
sockaddr_in in;
|
||||
sockaddr_un un;
|
||||
};
|
||||
|
||||
struct Address {
|
||||
size_t len;
|
||||
union sockaddr_union su;
|
||||
};
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // NETWORK_H
|
@ -155,6 +155,7 @@ Request::Request(const std::string &uri, const http_parser_url &u,
|
||||
inflater(nullptr),
|
||||
html_parser(nullptr),
|
||||
data_prd(data_prd),
|
||||
header_buffer_size(0),
|
||||
stream_id(-1),
|
||||
status(0),
|
||||
level(level),
|
||||
@ -272,34 +273,7 @@ bool Request::is_ipv6_literal_addr() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool Request::response_pseudo_header_allowed(int16_t token) const {
|
||||
if (!res_nva.empty() && res_nva.back().name.c_str()[0] != ':') {
|
||||
return false;
|
||||
}
|
||||
switch (token) {
|
||||
case http2::HD__STATUS:
|
||||
return res_hdidx[token] == -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Request::push_request_pseudo_header_allowed(int16_t token) const {
|
||||
if (!req_nva.empty() && req_nva.back().name.c_str()[0] != ':') {
|
||||
return false;
|
||||
}
|
||||
switch (token) {
|
||||
case http2::HD__AUTHORITY:
|
||||
case http2::HD__METHOD:
|
||||
case http2::HD__PATH:
|
||||
case http2::HD__SCHEME:
|
||||
return req_hdidx[token] == -1;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Headers::value_type *Request::get_res_header(int16_t token) {
|
||||
Headers::value_type *Request::get_res_header(int32_t token) {
|
||||
auto idx = res_hdidx[token];
|
||||
if (idx == -1) {
|
||||
return nullptr;
|
||||
@ -307,7 +281,7 @@ Headers::value_type *Request::get_res_header(int16_t token) {
|
||||
return &res_nva[idx];
|
||||
}
|
||||
|
||||
Headers::value_type *Request::get_req_header(int16_t token) {
|
||||
Headers::value_type *Request::get_req_header(int32_t token) {
|
||||
auto idx = req_hdidx[token];
|
||||
if (idx == -1) {
|
||||
return nullptr;
|
||||
@ -1736,6 +1710,14 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
break;
|
||||
}
|
||||
|
||||
if (req->header_buffer_size + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, frame->hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->header_buffer_size += namelen + valuelen;
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
http2::index_header(req->res_hdidx, token, req->res_nva.size());
|
||||
@ -1751,6 +1733,15 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
break;
|
||||
}
|
||||
|
||||
if (req->header_buffer_size + namelen + valuelen > 64_k) {
|
||||
nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->push_promise.promised_stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
req->header_buffer_size += namelen + valuelen;
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
http2::index_header(req->req_hdidx, token, req->req_nva.size());
|
||||
@ -1838,6 +1829,10 @@ int on_frame_recv_callback2(nghttp2_session *session,
|
||||
if (!req) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset for response header field reception
|
||||
req->header_buffer_size = 0;
|
||||
|
||||
auto scheme = req->get_req_header(http2::HD__SCHEME);
|
||||
auto authority = req->get_req_header(http2::HD__AUTHORITY);
|
||||
auto path = req->get_req_header(http2::HD__PATH);
|
||||
|
@ -125,11 +125,8 @@ struct Request {
|
||||
|
||||
bool is_ipv6_literal_addr() const;
|
||||
|
||||
bool response_pseudo_header_allowed(int16_t token) const;
|
||||
bool push_request_pseudo_header_allowed(int16_t token) const;
|
||||
|
||||
Headers::value_type *get_res_header(int16_t token);
|
||||
Headers::value_type *get_req_header(int16_t token);
|
||||
Headers::value_type *get_res_header(int32_t token);
|
||||
Headers::value_type *get_req_header(int32_t token);
|
||||
|
||||
void record_request_start_time();
|
||||
void record_response_start_time();
|
||||
@ -150,6 +147,7 @@ struct Request {
|
||||
nghttp2_gzip *inflater;
|
||||
HtmlParser *html_parser;
|
||||
const nghttp2_data_provider *data_prd;
|
||||
size_t header_buffer_size;
|
||||
int32_t stream_id;
|
||||
int status;
|
||||
// Recursion level: 0: first entity, 1: entity linked from first entity
|
||||
|
@ -89,12 +89,6 @@ int main(int argc, char *argv[]) {
|
||||
shrpx::test_http2_index_header) ||
|
||||
!CU_add_test(pSuite, "http2_lookup_token",
|
||||
shrpx::test_http2_lookup_token) ||
|
||||
!CU_add_test(pSuite, "http2_check_http2_pseudo_header",
|
||||
shrpx::test_http2_check_http2_pseudo_header) ||
|
||||
!CU_add_test(pSuite, "http2_http2_header_allowed",
|
||||
shrpx::test_http2_http2_header_allowed) ||
|
||||
!CU_add_test(pSuite, "http2_mandatory_request_headers_presence",
|
||||
shrpx::test_http2_mandatory_request_headers_presence) ||
|
||||
!CU_add_test(pSuite, "http2_parse_link_header",
|
||||
shrpx::test_http2_parse_link_header) ||
|
||||
!CU_add_test(pSuite, "http2_path_join", shrpx::test_http2_path_join) ||
|
||||
@ -106,8 +100,8 @@ int main(int argc, char *argv[]) {
|
||||
shrpx::test_http2_get_pure_path_component) ||
|
||||
!CU_add_test(pSuite, "http2_construct_push_component",
|
||||
shrpx::test_http2_construct_push_component) ||
|
||||
!CU_add_test(pSuite, "downstream_field_store_index_headers",
|
||||
shrpx::test_downstream_field_store_index_headers) ||
|
||||
!CU_add_test(pSuite, "downstream_field_store_add_header_lower",
|
||||
shrpx::test_downstream_field_store_add_header_lower) ||
|
||||
!CU_add_test(pSuite, "downstream_field_store_header",
|
||||
shrpx::test_downstream_field_store_header) ||
|
||||
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
|
||||
@ -167,6 +161,10 @@ int main(int argc, char *argv[]) {
|
||||
!CU_add_test(pSuite, "util_get_uint64", shrpx::test_util_get_uint64) ||
|
||||
!CU_add_test(pSuite, "util_parse_config_str_list",
|
||||
shrpx::test_util_parse_config_str_list) ||
|
||||
!CU_add_test(pSuite, "util_make_http_hostport",
|
||||
shrpx::test_util_make_http_hostport) ||
|
||||
!CU_add_test(pSuite, "util_make_hostport",
|
||||
shrpx::test_util_make_hostport) ||
|
||||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
|
||||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
|
||||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||
|
||||
|
250
src/shrpx.cc
250
src/shrpx.cc
@ -199,18 +199,18 @@ int chown_to_running_user(const char *path) {
|
||||
|
||||
namespace {
|
||||
void save_pid() {
|
||||
std::ofstream out(get_config()->pid_file.get(), std::ios::binary);
|
||||
std::ofstream out(get_config()->pid_file.c_str(), std::ios::binary);
|
||||
out << get_config()->pid << "\n";
|
||||
out.close();
|
||||
if (!out) {
|
||||
LOG(ERROR) << "Could not save PID to file " << get_config()->pid_file.get();
|
||||
LOG(ERROR) << "Could not save PID to file " << get_config()->pid_file;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (get_config()->uid != 0) {
|
||||
if (chown_to_running_user(get_config()->pid_file.get()) == -1) {
|
||||
if (chown_to_running_user(get_config()->pid_file.c_str()) == -1) {
|
||||
auto error = errno;
|
||||
LOG(WARN) << "Changing owner of pid file " << get_config()->pid_file.get()
|
||||
LOG(WARN) << "Changing owner of pid file " << get_config()->pid_file
|
||||
<< " failed: " << strerror(error);
|
||||
}
|
||||
}
|
||||
@ -656,7 +656,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
|
||||
}
|
||||
|
||||
faddr.fd = fd;
|
||||
faddr.hostport = util::make_hostport(host.data(), faddr.port);
|
||||
faddr.hostport = util::make_http_hostport(host.data(), faddr.port);
|
||||
|
||||
LOG(NOTICE) << "Listening on " << faddr.hostport;
|
||||
|
||||
@ -946,7 +946,7 @@ int event_loop() {
|
||||
redirect_stderr_to_errorlog();
|
||||
}
|
||||
|
||||
if (get_config()->pid_file) {
|
||||
if (!get_config()->pid_file.empty()) {
|
||||
save_pid();
|
||||
}
|
||||
|
||||
@ -1040,7 +1040,7 @@ void fill_default_config() {
|
||||
*mod_config() = {};
|
||||
|
||||
mod_config()->num_worker = 1;
|
||||
mod_config()->conf_path = strcopy("/etc/nghttpx/nghttpx.conf");
|
||||
mod_config()->conf_path = "/etc/nghttpx/nghttpx.conf";
|
||||
mod_config()->pid = getpid();
|
||||
|
||||
auto &tlsconf = mod_config()->tls;
|
||||
@ -1051,6 +1051,13 @@ void fill_default_config() {
|
||||
memcachedconf.max_retry = 3;
|
||||
memcachedconf.max_fail = 2;
|
||||
memcachedconf.interval = 10_min;
|
||||
memcachedconf.family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
auto &session_cacheconf = tlsconf.session_cache;
|
||||
{
|
||||
auto &memcachedconf = session_cacheconf.memcached;
|
||||
memcachedconf.family = AF_UNSPEC;
|
||||
}
|
||||
|
||||
ticketconf.cipher = EVP_aes_128_cbc();
|
||||
@ -1060,8 +1067,7 @@ void fill_default_config() {
|
||||
auto &ocspconf = tlsconf.ocsp;
|
||||
// ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
|
||||
ocspconf.update_interval = 4_h;
|
||||
ocspconf.fetch_ocsp_response_file =
|
||||
strcopy(PKGDATADIR "/fetch-ocsp-response");
|
||||
ocspconf.fetch_ocsp_response_file = PKGDATADIR "/fetch-ocsp-response";
|
||||
}
|
||||
|
||||
{
|
||||
@ -1115,7 +1121,7 @@ void fill_default_config() {
|
||||
accessconf.format = parse_log_format(DEFAULT_ACCESSLOG_FORMAT);
|
||||
|
||||
auto &errorconf = loggingconf.error;
|
||||
errorconf.file = strcopy("/dev/stderr");
|
||||
errorconf.file = "/dev/stderr";
|
||||
}
|
||||
|
||||
loggingconf.syslog_facility = LOG_DAEMON;
|
||||
@ -1159,6 +1165,7 @@ void fill_default_config() {
|
||||
downstreamconf.connections_per_host = 8;
|
||||
downstreamconf.request_buffer_size = 16_k;
|
||||
downstreamconf.response_buffer_size = 128_k;
|
||||
downstreamconf.family = AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,10 +1270,12 @@ Connections:
|
||||
--backlog=<N>
|
||||
Set listen backlog size.
|
||||
Default: )" << get_config()->conn.listener.backlog << R"(
|
||||
--backend-ipv4
|
||||
Resolve backend hostname to IPv4 address only.
|
||||
--backend-ipv6
|
||||
Resolve backend hostname to IPv6 address only.
|
||||
--backend-address-family=(auto|IPv4|IPv6)
|
||||
Specify address family of backend connections. If
|
||||
"auto" is given, both IPv4 and IPv6 are considered. If
|
||||
"IPv4" is given, only IPv4 address is considered. If
|
||||
"IPv6" is given, only IPv6 address is considered.
|
||||
Default: auto
|
||||
--backend-http-proxy-uri=<URI>
|
||||
Specify proxy URI in the form
|
||||
http://[<USER>:<PASS>@]<PROXY>:<PORT>. If a proxy
|
||||
@ -1520,16 +1529,23 @@ SSL/TLS:
|
||||
ticket key sharing between nghttpx instances is not
|
||||
required.
|
||||
--tls-ticket-key-memcached=<HOST>,<PORT>
|
||||
Specify address of memcached server to store session
|
||||
cache. This enables shared TLS ticket key between
|
||||
multiple nghttpx instances. nghttpx does not set TLS
|
||||
ticket key to memcached. The external ticket key
|
||||
generator is required. nghttpx just gets TLS ticket
|
||||
keys from memcached, and use them, possibly replacing
|
||||
current set of keys. It is up to extern TLS ticket key
|
||||
generator to rotate keys frequently. See "TLS SESSION
|
||||
TICKET RESUMPTION" section in manual page to know the
|
||||
data format in memcached entry.
|
||||
Specify address of memcached server to get TLS ticket
|
||||
keys for session resumption. This enables shared TLS
|
||||
ticket key between multiple nghttpx instances. nghttpx
|
||||
does not set TLS ticket key to memcached. The external
|
||||
ticket key generator is required. nghttpx just gets TLS
|
||||
ticket keys from memcached, and use them, possibly
|
||||
replacing current set of keys. It is up to extern TLS
|
||||
ticket key generator to rotate keys frequently. See
|
||||
"TLS SESSION TICKET RESUMPTION" section in manual page
|
||||
to know the data format in memcached entry.
|
||||
--tls-ticket-key-memcached-address-family=(auto|IPv4|IPv6)
|
||||
Specify address family of memcached connections to get
|
||||
TLS ticket keys. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
Default: auto
|
||||
--tls-ticket-key-memcached-interval=<DURATION>
|
||||
Set interval to get TLS ticket keys from memcached.
|
||||
Default: )"
|
||||
@ -1550,11 +1566,20 @@ SSL/TLS:
|
||||
Specify cipher to encrypt TLS session ticket. Specify
|
||||
either aes-128-cbc or aes-256-cbc. By default,
|
||||
aes-128-cbc is used.
|
||||
--tls-ticket-key-memcached-tls
|
||||
Enable SSL/TLS on memcached connections to get TLS
|
||||
ticket keys.
|
||||
--tls-ticket-key-memcached-cert-file=<PATH>
|
||||
Path to client certificate for memcached connections to
|
||||
get TLS ticket keys.
|
||||
--tls-ticket-key-memcached-private-key-file=<PATH>
|
||||
Path to client private key for memcached connections to
|
||||
get TLS ticket keys.
|
||||
--fetch-ocsp-response-file=<PATH>
|
||||
Path to fetch-ocsp-response script file. It should be
|
||||
absolute path.
|
||||
Default: )"
|
||||
<< get_config()->tls.ocsp.fetch_ocsp_response_file.get() << R"(
|
||||
Default: )" << get_config()->tls.ocsp.fetch_ocsp_response_file
|
||||
<< R"(
|
||||
--ocsp-update-interval=<DURATION>
|
||||
Set interval to update OCSP response cache.
|
||||
Default: )"
|
||||
@ -1564,6 +1589,22 @@ SSL/TLS:
|
||||
Specify address of memcached server to store session
|
||||
cache. This enables shared session cache between
|
||||
multiple nghttpx instances.
|
||||
--tls-session-cache-memcached-address-family=(auto|IPv4|IPv6)
|
||||
Specify address family of memcached connections to store
|
||||
session cache. If "auto" is given, both IPv4 and IPv6
|
||||
are considered. If "IPv4" is given, only IPv4 address
|
||||
is considered. If "IPv6" is given, only IPv6 address is
|
||||
considered.
|
||||
Default: auto
|
||||
--tls-session-cache-memcached-tls
|
||||
Enable SSL/TLS on memcached connections to store session
|
||||
cache.
|
||||
--tls-session-cache-memcached-cert-file=<PATH>
|
||||
Path to client certificate for memcached connections to
|
||||
store session cache.
|
||||
--tls-session-cache-memcached-private-key-file=<PATH>
|
||||
Path to client private key for memcached connections to
|
||||
store session cache.
|
||||
--tls-dyn-rec-warmup-threshold=<SIZE>
|
||||
Specify the threshold size for TLS dynamic record size
|
||||
behaviour. During a TLS session, after the threshold
|
||||
@ -1711,7 +1752,7 @@ Logging:
|
||||
Set path to write error log. To reopen file, send USR1
|
||||
signal to nghttpx. stderr will be redirected to the
|
||||
error log file unless --errorlog-syslog is used.
|
||||
Default: )" << get_config()->logging.error.file.get() << R"(
|
||||
Default: )" << get_config()->logging.error.file << R"(
|
||||
--errorlog-syslog
|
||||
Send error log to syslog. If this option is used,
|
||||
--errorlog-file option is ignored.
|
||||
@ -1852,7 +1893,7 @@ Scripting:
|
||||
Misc:
|
||||
--conf=<PATH>
|
||||
Load configuration from <PATH>.
|
||||
Default: )" << get_config()->conf_path.get() << R"(
|
||||
Default: )" << get_config()->conf_path << R"(
|
||||
--include=<PATH>
|
||||
Load additional configurations from <PATH>. File <PATH>
|
||||
is read when configuration parser encountered this
|
||||
@ -1878,11 +1919,11 @@ namespace {
|
||||
void process_options(
|
||||
int argc, char **argv,
|
||||
std::vector<std::pair<const char *, const char *>> &cmdcfgs) {
|
||||
if (conf_exists(get_config()->conf_path.get())) {
|
||||
if (conf_exists(get_config()->conf_path.c_str())) {
|
||||
std::set<std::string> include_set;
|
||||
if (load_config(get_config()->conf_path.get(), include_set) == -1) {
|
||||
if (load_config(get_config()->conf_path.c_str(), include_set) == -1) {
|
||||
LOG(FATAL) << "Failed to load configuration from "
|
||||
<< get_config()->conf_path.get();
|
||||
<< get_config()->conf_path;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
assert(include_set.empty());
|
||||
@ -1945,8 +1986,8 @@ void process_options(
|
||||
{
|
||||
auto &dumpconf = http2conf.upstream.debug.dump;
|
||||
|
||||
if (dumpconf.request_header_file) {
|
||||
auto path = dumpconf.request_header_file.get();
|
||||
if (!dumpconf.request_header_file.empty()) {
|
||||
auto path = dumpconf.request_header_file.c_str();
|
||||
auto f = open_file_for_write(path);
|
||||
|
||||
if (f == nullptr) {
|
||||
@ -1966,8 +2007,8 @@ void process_options(
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpconf.response_header_file) {
|
||||
auto path = dumpconf.response_header_file.get();
|
||||
if (!dumpconf.response_header_file.empty()) {
|
||||
auto path = dumpconf.response_header_file.c_str();
|
||||
auto f = open_file_for_write(path);
|
||||
|
||||
if (f == nullptr) {
|
||||
@ -2016,12 +2057,6 @@ void process_options(
|
||||
listenerconf.addrs.push_back(std::move(addr));
|
||||
}
|
||||
|
||||
if (downstreamconf.ipv4 && downstreamconf.ipv6) {
|
||||
LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
|
||||
<< "same time.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (upstreamconf.worker_connections == 0) {
|
||||
upstreamconf.worker_connections = std::numeric_limits<size_t>::max();
|
||||
}
|
||||
@ -2050,7 +2085,7 @@ void process_options(
|
||||
}
|
||||
|
||||
if (!upstreamconf.no_tls &&
|
||||
(!tlsconf.private_key_file || !tlsconf.cert_file)) {
|
||||
(tlsconf.private_key_file.empty() || tlsconf.cert_file.empty())) {
|
||||
print_usage(std::cerr);
|
||||
LOG(FATAL) << "Too few arguments";
|
||||
exit(EXIT_FAILURE);
|
||||
@ -2058,10 +2093,10 @@ void process_options(
|
||||
|
||||
if (!upstreamconf.no_tls && !tlsconf.ocsp.disabled) {
|
||||
struct stat buf;
|
||||
if (stat(tlsconf.ocsp.fetch_ocsp_response_file.get(), &buf) != 0) {
|
||||
if (stat(tlsconf.ocsp.fetch_ocsp_response_file.c_str(), &buf) != 0) {
|
||||
tlsconf.ocsp.disabled = true;
|
||||
LOG(WARN) << "--fetch-ocsp-response-file: "
|
||||
<< tlsconf.ocsp.fetch_ocsp_response_file.get()
|
||||
<< tlsconf.ocsp.fetch_ocsp_response_file
|
||||
<< " not found. OCSP stapling has been disabled.";
|
||||
}
|
||||
}
|
||||
@ -2069,18 +2104,18 @@ void process_options(
|
||||
auto &addr_groups = downstreamconf.addr_groups;
|
||||
|
||||
if (addr_groups.empty()) {
|
||||
DownstreamAddr addr;
|
||||
DownstreamAddr addr{};
|
||||
addr.host = ImmutableString::from_lit(DEFAULT_DOWNSTREAM_HOST);
|
||||
addr.port = DEFAULT_DOWNSTREAM_PORT;
|
||||
|
||||
DownstreamAddrGroup g("/");
|
||||
DownstreamAddrGroup g(StringRef::from_lit("/"));
|
||||
g.addrs.push_back(std::move(addr));
|
||||
mod_config()->router.add_route(g.pattern.get(), 1, addr_groups.size());
|
||||
mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size());
|
||||
addr_groups.push_back(std::move(g));
|
||||
} else if (get_config()->http2_proxy || get_config()->client_proxy) {
|
||||
// We don't support host mapping in these cases. Move all
|
||||
// non-catch-all patterns to catch-all pattern.
|
||||
DownstreamAddrGroup catch_all("/");
|
||||
DownstreamAddrGroup catch_all(StringRef::from_lit("/"));
|
||||
for (auto &g : addr_groups) {
|
||||
std::move(std::begin(g.addrs), std::end(g.addrs),
|
||||
std::back_inserter(catch_all.addrs));
|
||||
@ -2088,7 +2123,7 @@ void process_options(
|
||||
std::vector<DownstreamAddrGroup>().swap(addr_groups);
|
||||
// maybe not necessary?
|
||||
mod_config()->router = Router();
|
||||
mod_config()->router.add_route(catch_all.pattern.get(), 1,
|
||||
mod_config()->router.add_route(StringRef{catch_all.pattern},
|
||||
addr_groups.size());
|
||||
addr_groups.push_back(std::move(catch_all));
|
||||
}
|
||||
@ -2100,11 +2135,11 @@ void process_options(
|
||||
ssize_t catch_all_group = -1;
|
||||
for (size_t i = 0; i < addr_groups.size(); ++i) {
|
||||
auto &g = addr_groups[i];
|
||||
if (util::streq(g.pattern.get(), "/")) {
|
||||
if (g.pattern == "/") {
|
||||
catch_all_group = i;
|
||||
}
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern.get()
|
||||
LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern
|
||||
<< "'";
|
||||
for (auto &addr : g.addrs) {
|
||||
LOG(INFO) << "group " << i << " -> " << addr.host.c_str()
|
||||
@ -2142,8 +2177,10 @@ void process_options(
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LOG(INFO) << "Use UNIX domain socket path " << path
|
||||
<< " for backend connection";
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Use UNIX domain socket path " << path
|
||||
<< " for backend connection";
|
||||
}
|
||||
|
||||
addr.addr.su.un.sun_family = AF_UNIX;
|
||||
// copy path including terminal NULL
|
||||
@ -2153,47 +2190,63 @@ void process_options(
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.hostport =
|
||||
ImmutableString(util::make_hostport(addr.host.c_str(), addr.port));
|
||||
addr.hostport = ImmutableString(
|
||||
util::make_http_hostport(StringRef(addr.host), addr.port));
|
||||
|
||||
if (resolve_hostname(
|
||||
&addr.addr, addr.host.c_str(), addr.port,
|
||||
downstreamconf.ipv4
|
||||
? AF_INET
|
||||
: (downstreamconf.ipv6 ? AF_INET6 : AF_UNSPEC)) == -1) {
|
||||
auto hostport = util::make_hostport(addr.host.c_str(), addr.port);
|
||||
|
||||
if (resolve_hostname(&addr.addr, addr.host.c_str(), addr.port,
|
||||
downstreamconf.family) == -1) {
|
||||
LOG(FATAL) << "Resolving backend address failed: " << hostport;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(NOTICE) << "Resolved backend address: " << hostport << " -> "
|
||||
<< util::to_numeric_addr(&addr.addr);
|
||||
}
|
||||
}
|
||||
|
||||
auto &proxy = mod_config()->downstream_http_proxy;
|
||||
if (!proxy.host.empty()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Resolving backend http proxy address";
|
||||
}
|
||||
auto hostport = util::make_hostport(proxy.host.c_str(), proxy.port);
|
||||
if (resolve_hostname(&proxy.addr, proxy.host.c_str(), proxy.port,
|
||||
AF_UNSPEC) == -1) {
|
||||
LOG(FATAL) << "Resolving backend HTTP proxy address failed: " << hostport;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(NOTICE) << "Backend HTTP proxy address: " << hostport << " -> "
|
||||
<< util::to_numeric_addr(&proxy.addr);
|
||||
}
|
||||
|
||||
{
|
||||
auto &memcachedconf = tlsconf.session_cache.memcached;
|
||||
if (memcachedconf.host) {
|
||||
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(),
|
||||
memcachedconf.port, AF_UNSPEC) == -1) {
|
||||
if (!memcachedconf.host.empty()) {
|
||||
auto hostport = util::make_hostport(StringRef{memcachedconf.host},
|
||||
memcachedconf.port);
|
||||
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
|
||||
memcachedconf.port, memcachedconf.family) == -1) {
|
||||
LOG(FATAL)
|
||||
<< "Resolving memcached address for TLS session cache failed: "
|
||||
<< hostport;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(NOTICE) << "Memcached address for TLS session cache: " << hostport
|
||||
<< " -> " << util::to_numeric_addr(&memcachedconf.addr);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto &memcachedconf = tlsconf.ticket.memcached;
|
||||
if (memcachedconf.host) {
|
||||
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.get(),
|
||||
memcachedconf.port, AF_UNSPEC) == -1) {
|
||||
if (!memcachedconf.host.empty()) {
|
||||
auto hostport = util::make_hostport(StringRef{memcachedconf.host},
|
||||
memcachedconf.port);
|
||||
if (resolve_hostname(&memcachedconf.addr, memcachedconf.host.c_str(),
|
||||
memcachedconf.port, memcachedconf.family) == -1) {
|
||||
LOG(FATAL) << "Resolving memcached address for TLS ticket key failed: "
|
||||
<< hostport;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(NOTICE) << "Memcached address for TLS ticket key: " << hostport
|
||||
<< " -> " << util::to_numeric_addr(&memcachedconf.addr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2400,6 +2453,21 @@ int main(int argc, char **argv) {
|
||||
{SHRPX_OPT_BACKEND_HTTP1_TLS, no_argument, &flag, 106},
|
||||
{SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER, required_argument,
|
||||
&flag, 107},
|
||||
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS, no_argument, &flag, 108},
|
||||
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE, required_argument,
|
||||
&flag, 109},
|
||||
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
|
||||
required_argument, &flag, 110},
|
||||
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS, no_argument, &flag, 111},
|
||||
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE, required_argument, &flag,
|
||||
112},
|
||||
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE, required_argument,
|
||||
&flag, 113},
|
||||
{SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY, required_argument,
|
||||
&flag, 114},
|
||||
{SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
|
||||
required_argument, &flag, 115},
|
||||
{SHRPX_OPT_BACKEND_ADDRESS_FAMILY, required_argument, &flag, 116},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
int option_index = 0;
|
||||
@ -2493,7 +2561,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
case 12:
|
||||
// --conf
|
||||
mod_config()->conf_path = strcopy(optarg);
|
||||
mod_config()->conf_path = optarg;
|
||||
break;
|
||||
case 14:
|
||||
// --syslog-facility
|
||||
@ -2858,6 +2926,48 @@ int main(int argc, char **argv) {
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER,
|
||||
optarg);
|
||||
break;
|
||||
case 108:
|
||||
// --tls-session-cache-memcached-tls
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS, "yes");
|
||||
break;
|
||||
case 109:
|
||||
// --tls-session-cache-memcached-cert-file
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
|
||||
optarg);
|
||||
break;
|
||||
case 110:
|
||||
// --tls-session-cache-memcached-private-key-file
|
||||
cmdcfgs.emplace_back(
|
||||
SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE, optarg);
|
||||
break;
|
||||
case 111:
|
||||
// --tls-ticket-key-memcached-tls
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS, "yes");
|
||||
break;
|
||||
case 112:
|
||||
// --tls-ticket-key-memcached-cert-file
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
|
||||
optarg);
|
||||
break;
|
||||
case 113:
|
||||
// --tls-ticket-key-memcached-private-key-file
|
||||
cmdcfgs.emplace_back(
|
||||
SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE, optarg);
|
||||
break;
|
||||
case 114:
|
||||
// --tls-ticket-key-memcached-address-family
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
|
||||
optarg);
|
||||
break;
|
||||
case 115:
|
||||
// --tls-session-cache-memcached-address-family
|
||||
cmdcfgs.emplace_back(
|
||||
SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY, optarg);
|
||||
break;
|
||||
case 116:
|
||||
// --backend-address-family
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_ADDRESS_FAMILY, optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -389,7 +389,7 @@ ClientHandler::ClientHandler(Worker *worker, int fd, SSL *ssl,
|
||||
pinned_http2sessions_(
|
||||
get_config()->conn.downstream.proto == PROTO_HTTP2
|
||||
? make_unique<std::vector<ssize_t>>(
|
||||
get_config()->conn.downstream.addr_groups.size(), -1)
|
||||
worker->get_downstream_addr_groups().size(), -1)
|
||||
: nullptr),
|
||||
ipaddr_(ipaddr),
|
||||
port_(port),
|
||||
@ -664,8 +664,8 @@ std::unique_ptr<DownstreamConnection>
|
||||
ClientHandler::get_downstream_connection(Downstream *downstream) {
|
||||
size_t group;
|
||||
auto &downstreamconf = get_config()->conn.downstream;
|
||||
auto &groups = downstreamconf.addr_groups;
|
||||
auto catch_all = downstreamconf.addr_group_catch_all;
|
||||
auto &groups = worker_->get_downstream_addr_groups();
|
||||
|
||||
const auto &req = downstream->request();
|
||||
|
||||
@ -681,16 +681,19 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
|
||||
} else {
|
||||
auto &router = get_config()->router;
|
||||
if (!req.authority.empty()) {
|
||||
group = match_downstream_addr_group(router, req.authority, req.path,
|
||||
groups, catch_all);
|
||||
group =
|
||||
match_downstream_addr_group(router, StringRef{req.authority},
|
||||
StringRef{req.path}, groups, catch_all);
|
||||
} else {
|
||||
auto h = req.fs.header(http2::HD_HOST);
|
||||
if (h) {
|
||||
group = match_downstream_addr_group(router, h->value, req.path, groups,
|
||||
catch_all);
|
||||
group =
|
||||
match_downstream_addr_group(router, StringRef{h->value},
|
||||
StringRef{req.path}, groups, catch_all);
|
||||
} else {
|
||||
group = match_downstream_addr_group(router, "", req.path, groups,
|
||||
catch_all);
|
||||
group =
|
||||
match_downstream_addr_group(router, StringRef::from_lit(""),
|
||||
StringRef{req.path}, groups, catch_all);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -743,10 +746,6 @@ MemchunkPool *ClientHandler::get_mcpool() { return worker_->get_mcpool(); }
|
||||
|
||||
SSL *ClientHandler::get_ssl() const { return conn_.tls.ssl; }
|
||||
|
||||
ConnectBlocker *ClientHandler::get_connect_blocker() const {
|
||||
return worker_->get_connect_blocker();
|
||||
}
|
||||
|
||||
void ClientHandler::direct_http2_upgrade() {
|
||||
upstream_ = make_unique<Http2Upstream>(this);
|
||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||
|
@ -99,7 +99,6 @@ public:
|
||||
get_downstream_connection(Downstream *downstream);
|
||||
MemchunkPool *get_mcpool();
|
||||
SSL *get_ssl() const;
|
||||
ConnectBlocker *get_connect_blocker() const;
|
||||
// Call this function when HTTP/2 connection header is received at
|
||||
// the start of the connection.
|
||||
void direct_http2_upgrade();
|
||||
|
@ -54,9 +54,7 @@
|
||||
#include "shrpx_log.h"
|
||||
#include "shrpx_ssl.h"
|
||||
#include "shrpx_http.h"
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
#include "template.h"
|
||||
#include "base64.h"
|
||||
|
||||
namespace shrpx {
|
||||
@ -80,42 +78,6 @@ TicketKeys::~TicketKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
DownstreamAddr::DownstreamAddr(const DownstreamAddr &other)
|
||||
: addr(other.addr),
|
||||
host(other.host),
|
||||
hostport(other.hostport),
|
||||
port(other.port),
|
||||
host_unix(other.host_unix) {}
|
||||
|
||||
DownstreamAddr &DownstreamAddr::operator=(const DownstreamAddr &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
addr = other.addr;
|
||||
host = other.host;
|
||||
hostport = other.hostport;
|
||||
port = other.port;
|
||||
host_unix = other.host_unix;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
DownstreamAddrGroup::DownstreamAddrGroup(const DownstreamAddrGroup &other)
|
||||
: pattern(strcopy(other.pattern)), addrs(other.addrs) {}
|
||||
|
||||
DownstreamAddrGroup &DownstreamAddrGroup::
|
||||
operator=(const DownstreamAddrGroup &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
pattern = strcopy(other.pattern);
|
||||
addrs = other.addrs;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace {
|
||||
int split_host_port(char *host, size_t hostlen, uint16_t *port_ptr,
|
||||
const char *hostport, size_t hostportlen) {
|
||||
@ -279,7 +241,7 @@ std::string read_passwd_from_file(const char *filename) {
|
||||
return line;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> parse_header(const char *optarg) {
|
||||
Headers::value_type parse_header(const char *optarg) {
|
||||
const auto *colon = strchr(optarg, ':');
|
||||
|
||||
if (colon == nullptr || colon == optarg) {
|
||||
@ -290,16 +252,15 @@ std::pair<std::string, std::string> parse_header(const char *optarg) {
|
||||
for (; *value == '\t' || *value == ' '; ++value)
|
||||
;
|
||||
|
||||
auto p = std::make_pair(std::string(optarg, colon),
|
||||
std::string(value, strlen(value)));
|
||||
util::inp_strlower(p.first);
|
||||
auto p =
|
||||
Header(std::string(optarg, colon), std::string(value, strlen(value)));
|
||||
util::inp_strlower(p.name);
|
||||
|
||||
if (!nghttp2_check_header_name(
|
||||
reinterpret_cast<const uint8_t *>(p.first.c_str()), p.first.size()) ||
|
||||
reinterpret_cast<const uint8_t *>(p.name.c_str()), p.name.size()) ||
|
||||
!nghttp2_check_header_value(
|
||||
reinterpret_cast<const uint8_t *>(p.second.c_str()),
|
||||
p.second.size())) {
|
||||
return {"", ""};
|
||||
reinterpret_cast<const uint8_t *>(p.value.c_str()), p.value.size())) {
|
||||
return Header();
|
||||
}
|
||||
|
||||
return p;
|
||||
@ -575,6 +536,26 @@ std::vector<LogFragment> parse_log_format(const char *optarg) {
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace {
|
||||
int parse_address_family(int *dest, const char *opt, const char *optarg) {
|
||||
if (util::strieq("auto", optarg)) {
|
||||
*dest = AF_UNSPEC;
|
||||
return 0;
|
||||
}
|
||||
if (util::strieq("IPv4", optarg)) {
|
||||
*dest = AF_INET;
|
||||
return 0;
|
||||
}
|
||||
if (util::strieq("IPv6", optarg)) {
|
||||
*dest = AF_INET6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
|
||||
return -1;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
|
||||
auto t = util::parse_duration_with_unit(optarg);
|
||||
@ -616,7 +597,7 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) {
|
||||
pattern += http2::normalize_path(slash, raw_pattern.second);
|
||||
}
|
||||
for (auto &g : addr_groups) {
|
||||
if (g.pattern.get() == pattern) {
|
||||
if (g.pattern == pattern) {
|
||||
g.addrs.push_back(addr);
|
||||
done = true;
|
||||
break;
|
||||
@ -625,11 +606,10 @@ void parse_mapping(const DownstreamAddr &addr, const char *src) {
|
||||
if (done) {
|
||||
continue;
|
||||
}
|
||||
DownstreamAddrGroup g(pattern);
|
||||
DownstreamAddrGroup g(StringRef{pattern});
|
||||
g.addrs.push_back(addr);
|
||||
|
||||
mod_config()->router.add_route(g.pattern.get(), strlen(g.pattern.get()),
|
||||
addr_groups.size());
|
||||
mod_config()->router.add_route(StringRef{g.pattern}, addr_groups.size());
|
||||
|
||||
addr_groups.push_back(std::move(g));
|
||||
}
|
||||
@ -673,6 +653,7 @@ enum {
|
||||
SHRPX_OPTID_ADD_X_FORWARDED_FOR,
|
||||
SHRPX_OPTID_ALTSVC,
|
||||
SHRPX_OPTID_BACKEND,
|
||||
SHRPX_OPTID_BACKEND_ADDRESS_FAMILY,
|
||||
SHRPX_OPTID_BACKEND_HTTP_PROXY_URI,
|
||||
SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_FRONTEND,
|
||||
SHRPX_OPTID_BACKEND_HTTP1_CONNECTIONS_PER_HOST,
|
||||
@ -758,12 +739,20 @@ enum {
|
||||
SHRPX_OPTID_TLS_DYN_REC_WARMUP_THRESHOLD,
|
||||
SHRPX_OPTID_TLS_PROTO_LIST,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE,
|
||||
SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_CIPHER,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_FILE,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_INTERVAL,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_FAIL,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_MAX_RETRY,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE,
|
||||
SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS,
|
||||
SHRPX_OPTID_USER,
|
||||
SHRPX_OPTID_VERIFY_CLIENT,
|
||||
SHRPX_OPTID_VERIFY_CLIENT_CACERT,
|
||||
@ -1204,6 +1193,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
return SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (util::strieq_l("backend-address-famil", name, 21)) {
|
||||
return SHRPX_OPTID_BACKEND_ADDRESS_FAMILY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
@ -1325,6 +1319,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
if (util::strieq_l("http2-max-concurrent-stream", name, 27)) {
|
||||
return SHRPX_OPTID_HTTP2_MAX_CONCURRENT_STREAMS;
|
||||
}
|
||||
if (util::strieq_l("tls-ticket-key-memcached-tl", name, 27)) {
|
||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1337,6 +1334,15 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 31:
|
||||
switch (name[30]) {
|
||||
case 's':
|
||||
if (util::strieq_l("tls-session-cache-memcached-tl", name, 30)) {
|
||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 33:
|
||||
switch (name[32]) {
|
||||
case 'l':
|
||||
@ -1351,6 +1357,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
break;
|
||||
case 34:
|
||||
switch (name[33]) {
|
||||
case 'e':
|
||||
if (util::strieq_l("tls-ticket-key-memcached-cert-fil", name, 33)) {
|
||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (util::strieq_l("frontend-http2-dump-request-heade", name, 33)) {
|
||||
return SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER;
|
||||
@ -1396,6 +1407,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
break;
|
||||
case 37:
|
||||
switch (name[36]) {
|
||||
case 'e':
|
||||
if (util::strieq_l("tls-session-cache-memcached-cert-fil", name, 36)) {
|
||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (util::strieq_l("frontend-http2-connection-window-bit", name, 36)) {
|
||||
return SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS;
|
||||
@ -1412,6 +1428,45 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 39:
|
||||
switch (name[38]) {
|
||||
case 'y':
|
||||
if (util::strieq_l("tls-ticket-key-memcached-address-famil", name, 38)) {
|
||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 41:
|
||||
switch (name[40]) {
|
||||
case 'e':
|
||||
if (util::strieq_l("tls-ticket-key-memcached-private-key-fil", name,
|
||||
40)) {
|
||||
return SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 42:
|
||||
switch (name[41]) {
|
||||
case 'y':
|
||||
if (util::strieq_l("tls-session-cache-memcached-address-famil", name,
|
||||
41)) {
|
||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 44:
|
||||
switch (name[43]) {
|
||||
case 'e':
|
||||
if (util::strieq_l("tls-session-cache-memcached-private-key-fil", name,
|
||||
43)) {
|
||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -1431,7 +1486,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
if (!pat_delim) {
|
||||
pat_delim = optarg + optarglen;
|
||||
}
|
||||
DownstreamAddr addr;
|
||||
DownstreamAddr addr{};
|
||||
if (util::istarts_with(optarg, SHRPX_UNIX_PATH_PREFIX)) {
|
||||
auto path = optarg + str_size(SHRPX_UNIX_PATH_PREFIX);
|
||||
addr.host = ImmutableString(path, pat_delim);
|
||||
@ -1567,7 +1622,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
return parse_duration(&mod_config()->http2.timeout.stream_write, opt,
|
||||
optarg);
|
||||
case SHRPX_OPTID_ACCESSLOG_FILE:
|
||||
mod_config()->logging.access.file = strcopy(optarg);
|
||||
mod_config()->logging.access.file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_ACCESSLOG_SYSLOG:
|
||||
@ -1579,7 +1634,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_ERRORLOG_FILE:
|
||||
mod_config()->logging.error.file = strcopy(optarg);
|
||||
mod_config()->logging.error.file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_ERRORLOG_SYSLOG:
|
||||
@ -1673,7 +1728,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_PID_FILE:
|
||||
mod_config()->pid_file = strcopy(optarg);
|
||||
mod_config()->pid_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_USER: {
|
||||
@ -1683,14 +1738,14 @@ int parse_config(const char *opt, const char *optarg,
|
||||
<< strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
mod_config()->user = strcopy(pwd->pw_name);
|
||||
mod_config()->user = pwd->pw_name;
|
||||
mod_config()->uid = pwd->pw_uid;
|
||||
mod_config()->gid = pwd->pw_gid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case SHRPX_OPTID_PRIVATE_KEY_FILE:
|
||||
mod_config()->tls.private_key_file = strcopy(optarg);
|
||||
mod_config()->tls.private_key_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE: {
|
||||
@ -1699,16 +1754,16 @@ int parse_config(const char *opt, const char *optarg,
|
||||
LOG(ERROR) << opt << ": Couldn't read key file's passwd from " << optarg;
|
||||
return -1;
|
||||
}
|
||||
mod_config()->tls.private_key_passwd = strcopy(passwd);
|
||||
mod_config()->tls.private_key_passwd = passwd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case SHRPX_OPTID_CERTIFICATE_FILE:
|
||||
mod_config()->tls.cert_file = strcopy(optarg);
|
||||
mod_config()->tls.cert_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_DH_PARAM_FILE:
|
||||
mod_config()->tls.dh_param_file = strcopy(optarg);
|
||||
mod_config()->tls.dh_param_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_SUBCERT: {
|
||||
@ -1749,7 +1804,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
return 0;
|
||||
}
|
||||
case SHRPX_OPTID_CIPHERS:
|
||||
mod_config()->tls.ciphers = strcopy(optarg);
|
||||
mod_config()->tls.ciphers = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_CLIENT:
|
||||
@ -1761,15 +1816,21 @@ int parse_config(const char *opt, const char *optarg,
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_CACERT:
|
||||
mod_config()->tls.cacert = strcopy(optarg);
|
||||
mod_config()->tls.cacert = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_BACKEND_IPV4:
|
||||
mod_config()->conn.downstream.ipv4 = util::strieq(optarg, "yes");
|
||||
LOG(WARN) << opt
|
||||
<< ": deprecated. Use backend-address-family=IPv4 instead.";
|
||||
|
||||
mod_config()->conn.downstream.family = AF_INET;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_BACKEND_IPV6:
|
||||
mod_config()->conn.downstream.ipv6 = util::strieq(optarg, "yes");
|
||||
LOG(WARN) << opt
|
||||
<< ": deprecated. Use backend-address-family=IPv6 instead.";
|
||||
|
||||
mod_config()->conn.downstream.family = AF_INET6;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_BACKEND_HTTP_PROXY_URI: {
|
||||
@ -1846,25 +1907,23 @@ int parse_config(const char *opt, const char *optarg,
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_VERIFY_CLIENT_CACERT:
|
||||
mod_config()->tls.client_verify.cacert = strcopy(optarg);
|
||||
mod_config()->tls.client_verify.cacert = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_CLIENT_PRIVATE_KEY_FILE:
|
||||
mod_config()->tls.client.private_key_file = strcopy(optarg);
|
||||
mod_config()->tls.client.private_key_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_CLIENT_CERT_FILE:
|
||||
mod_config()->tls.client.cert_file = strcopy(optarg);
|
||||
mod_config()->tls.client.cert_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER:
|
||||
mod_config()->http2.upstream.debug.dump.request_header_file =
|
||||
strcopy(optarg);
|
||||
mod_config()->http2.upstream.debug.dump.request_header_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER:
|
||||
mod_config()->http2.upstream.debug.dump.response_header_file =
|
||||
strcopy(optarg);
|
||||
mod_config()->http2.upstream.debug.dump.response_header_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_HTTP2_NO_COOKIE_CRUMBLING:
|
||||
@ -1927,7 +1986,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
case SHRPX_OPTID_ADD_REQUEST_HEADER:
|
||||
case SHRPX_OPTID_ADD_RESPONSE_HEADER: {
|
||||
auto p = parse_header(optarg);
|
||||
if (p.first.empty()) {
|
||||
if (p.name.empty()) {
|
||||
LOG(ERROR) << opt << ": invalid header field: " << optarg;
|
||||
return -1;
|
||||
}
|
||||
@ -2025,7 +2084,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
return parse_uint(&mod_config()->http2.downstream.connections_per_worker,
|
||||
opt, optarg);
|
||||
case SHRPX_OPTID_FETCH_OCSP_RESPONSE_FILE:
|
||||
mod_config()->tls.ocsp.fetch_ocsp_response_file = strcopy(optarg);
|
||||
mod_config()->tls.ocsp.fetch_ocsp_response_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_OCSP_UPDATE_INTERVAL:
|
||||
@ -2093,7 +2152,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
}
|
||||
|
||||
auto &memcachedconf = mod_config()->tls.session_cache.memcached;
|
||||
memcachedconf.host = strcopy(host);
|
||||
memcachedconf.host = host;
|
||||
memcachedconf.port = port;
|
||||
|
||||
return 0;
|
||||
@ -2105,7 +2164,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
}
|
||||
|
||||
auto &memcachedconf = mod_config()->tls.ticket.memcached;
|
||||
memcachedconf.host = strcopy(host);
|
||||
memcachedconf.host = host;
|
||||
memcachedconf.port = port;
|
||||
|
||||
return 0;
|
||||
@ -2146,7 +2205,7 @@ int parse_config(const char *opt, const char *optarg,
|
||||
|
||||
case SHRPX_OPTID_MRUBY_FILE:
|
||||
#ifdef HAVE_MRUBY
|
||||
mod_config()->mruby_file = strcopy(optarg);
|
||||
mod_config()->mruby_file = optarg;
|
||||
#else // !HAVE_MRUBY
|
||||
LOG(WARN) << opt
|
||||
<< ": ignored because mruby support is disabled at build time.";
|
||||
@ -2229,6 +2288,39 @@ int parse_config(const char *opt, const char *optarg,
|
||||
case SHRPX_OPTID_BACKEND_TLS_SESSION_CACHE_PER_WORKER:
|
||||
return parse_uint(&mod_config()->tls.downstream_session_cache_per_worker,
|
||||
opt, optarg);
|
||||
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS:
|
||||
mod_config()->tls.session_cache.memcached.tls = util::strieq(optarg, "yes");
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE:
|
||||
mod_config()->tls.session_cache.memcached.cert_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE:
|
||||
mod_config()->tls.session_cache.memcached.private_key_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_TLS:
|
||||
mod_config()->tls.ticket.memcached.tls = util::strieq(optarg, "yes");
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_CERT_FILE:
|
||||
mod_config()->tls.ticket.memcached.cert_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE:
|
||||
mod_config()->tls.ticket.memcached.private_key_file = optarg;
|
||||
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY:
|
||||
return parse_address_family(&mod_config()->tls.ticket.memcached.family, opt,
|
||||
optarg);
|
||||
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY:
|
||||
return parse_address_family(
|
||||
&mod_config()->tls.session_cache.memcached.family, opt, optarg);
|
||||
case SHRPX_OPTID_BACKEND_ADDRESS_FAMILY:
|
||||
return parse_address_family(&mod_config()->conn.downstream.family, opt,
|
||||
optarg);
|
||||
case SHRPX_OPTID_CONF:
|
||||
LOG(WARN) << "conf: ignored";
|
||||
|
||||
@ -2409,17 +2501,15 @@ int int_syslog_facility(const char *strfacility) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
size_t
|
||||
match_downstream_addr_group_host(const Router &router, const std::string &host,
|
||||
const char *path, size_t pathlen,
|
||||
const std::vector<DownstreamAddrGroup> &groups,
|
||||
size_t catch_all) {
|
||||
if (pathlen == 0 || *path != '/') {
|
||||
auto group = router.match(host, "/", 1);
|
||||
size_t match_downstream_addr_group_host(
|
||||
const Router &router, const StringRef &host, const StringRef &path,
|
||||
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all) {
|
||||
if (path.empty() || path[0] != '/') {
|
||||
auto group = router.match(host, StringRef::from_lit("/"));
|
||||
if (group != -1) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Found pattern with query " << host
|
||||
<< ", matched pattern=" << groups[group].pattern.get();
|
||||
<< ", matched pattern=" << groups[group].pattern;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
@ -2428,24 +2518,23 @@ match_downstream_addr_group_host(const Router &router, const std::string &host,
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Perform mapping selection, using host=" << host
|
||||
<< ", path=" << std::string(path, pathlen);
|
||||
<< ", path=" << path;
|
||||
}
|
||||
|
||||
auto group = router.match(host, path, pathlen);
|
||||
auto group = router.match(host, path);
|
||||
if (group != -1) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Found pattern with query " << host
|
||||
<< std::string(path, pathlen)
|
||||
<< ", matched pattern=" << groups[group].pattern.get();
|
||||
LOG(INFO) << "Found pattern with query " << host << path
|
||||
<< ", matched pattern=" << groups[group].pattern;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
group = router.match("", path, pathlen);
|
||||
group = router.match("", path);
|
||||
if (group != -1) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Found pattern with query " << std::string(path, pathlen)
|
||||
<< ", matched pattern=" << groups[group].pattern.get();
|
||||
LOG(INFO) << "Found pattern with query " << path
|
||||
<< ", matched pattern=" << groups[group].pattern;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
@ -2457,11 +2546,9 @@ match_downstream_addr_group_host(const Router &router, const std::string &host,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
size_t
|
||||
match_downstream_addr_group(const Router &router, const std::string &hostport,
|
||||
const std::string &raw_path,
|
||||
const std::vector<DownstreamAddrGroup> &groups,
|
||||
size_t catch_all) {
|
||||
size_t match_downstream_addr_group(
|
||||
const Router &router, const StringRef &hostport, const StringRef &raw_path,
|
||||
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all) {
|
||||
if (std::find(std::begin(hostport), std::end(hostport), '/') !=
|
||||
std::end(hostport)) {
|
||||
// We use '/' specially, and if '/' is included in host, it breaks
|
||||
@ -2471,12 +2558,11 @@ match_downstream_addr_group(const Router &router, const std::string &hostport,
|
||||
|
||||
auto fragment = std::find(std::begin(raw_path), std::end(raw_path), '#');
|
||||
auto query = std::find(std::begin(raw_path), fragment, '?');
|
||||
auto path = raw_path.c_str();
|
||||
auto pathlen = query - std::begin(raw_path);
|
||||
auto path = StringRef{std::begin(raw_path), query};
|
||||
|
||||
if (hostport.empty()) {
|
||||
return match_downstream_addr_group_host(router, hostport, path, pathlen,
|
||||
groups, catch_all);
|
||||
return match_downstream_addr_group_host(router, hostport, path, groups,
|
||||
catch_all);
|
||||
}
|
||||
|
||||
std::string host;
|
||||
@ -2499,7 +2585,7 @@ match_downstream_addr_group(const Router &router, const std::string &hostport,
|
||||
}
|
||||
|
||||
util::inp_strlower(host);
|
||||
return match_downstream_addr_group_host(router, host, path, pathlen, groups,
|
||||
return match_downstream_addr_group_host(router, StringRef{host}, path, groups,
|
||||
catch_all);
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,15 @@
|
||||
|
||||
#include "shrpx_router.h"
|
||||
#include "template.h"
|
||||
#include "http2.h"
|
||||
#include "network.h"
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
struct LogFragment;
|
||||
class ConnectBlocker;
|
||||
|
||||
namespace ssl {
|
||||
|
||||
@ -209,22 +212,26 @@ constexpr char SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST[] =
|
||||
constexpr char SHRPX_OPT_BACKEND_HTTP1_TLS[] = "backend-http1-tls";
|
||||
constexpr char SHRPX_OPT_BACKEND_TLS_SESSION_CACHE_PER_WORKER[] =
|
||||
"backend-tls-session-cache-per-worker";
|
||||
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_TLS[] =
|
||||
"tls-session-cache-memcached-tls";
|
||||
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_CERT_FILE[] =
|
||||
"tls-session-cache-memcached-cert-file";
|
||||
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_PRIVATE_KEY_FILE[] =
|
||||
"tls-session-cache-memcached-private-key-file";
|
||||
constexpr char SHRPX_OPT_TLS_SESSION_CACHE_MEMCACHED_ADDRESS_FAMILY[] =
|
||||
"tls-session-cache-memcached-address-family";
|
||||
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_TLS[] =
|
||||
"tls-ticket-key-memcached-tls";
|
||||
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_CERT_FILE[] =
|
||||
"tls-ticket-key-memcached-cert-file";
|
||||
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_PRIVATE_KEY_FILE[] =
|
||||
"tls-ticket-key-memcached-private-key-file";
|
||||
constexpr char SHRPX_OPT_TLS_TICKET_KEY_MEMCACHED_ADDRESS_FAMILY[] =
|
||||
"tls-ticket-key-memcached-address-family";
|
||||
constexpr char SHRPX_OPT_BACKEND_ADDRESS_FAMILY[] = "backend-address-family";
|
||||
|
||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr_storage storage;
|
||||
sockaddr sa;
|
||||
sockaddr_in6 in6;
|
||||
sockaddr_in in;
|
||||
sockaddr_un un;
|
||||
};
|
||||
|
||||
struct Address {
|
||||
size_t len;
|
||||
union sockaddr_union su;
|
||||
};
|
||||
|
||||
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };
|
||||
|
||||
enum shrpx_forwarded_param {
|
||||
@ -270,18 +277,23 @@ struct UpstreamAddr {
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct DownstreamAddr {
|
||||
DownstreamAddr() : addr{}, port(0), host_unix(false) {}
|
||||
DownstreamAddr(const DownstreamAddr &other);
|
||||
DownstreamAddr(DownstreamAddr &&) = default;
|
||||
DownstreamAddr &operator=(const DownstreamAddr &other);
|
||||
DownstreamAddr &operator=(DownstreamAddr &&other) = default;
|
||||
struct TLSSessionCache {
|
||||
// ASN1 representation of SSL_SESSION object. See
|
||||
// i2d_SSL_SESSION(3SSL).
|
||||
std::vector<uint8_t> session_data;
|
||||
// The last time stamp when this cache entry is created or updated.
|
||||
ev_tstamp last_updated;
|
||||
};
|
||||
|
||||
struct DownstreamAddr {
|
||||
Address addr;
|
||||
// backend address. If |host_unix| is true, this is UNIX domain
|
||||
// socket path.
|
||||
ImmutableString host;
|
||||
ImmutableString hostport;
|
||||
ConnectBlocker *connect_blocker;
|
||||
// Client side TLS session cache
|
||||
TLSSessionCache tls_session_cache;
|
||||
// backend port. 0 if |host_unix| is true.
|
||||
uint16_t port;
|
||||
// true if |host| contains UNIX domain socket path.
|
||||
@ -289,13 +301,10 @@ struct DownstreamAddr {
|
||||
};
|
||||
|
||||
struct DownstreamAddrGroup {
|
||||
DownstreamAddrGroup(const std::string &pattern) : pattern(strcopy(pattern)) {}
|
||||
DownstreamAddrGroup(const DownstreamAddrGroup &other);
|
||||
DownstreamAddrGroup(DownstreamAddrGroup &&) = default;
|
||||
DownstreamAddrGroup &operator=(const DownstreamAddrGroup &other);
|
||||
DownstreamAddrGroup &operator=(DownstreamAddrGroup &&) = default;
|
||||
DownstreamAddrGroup(const StringRef &pattern)
|
||||
: pattern(pattern.c_str(), pattern.size()) {}
|
||||
|
||||
std::unique_ptr<char[]> pattern;
|
||||
ImmutableString pattern;
|
||||
std::vector<DownstreamAddr> addrs;
|
||||
};
|
||||
|
||||
@ -334,7 +343,12 @@ struct TLSConfig {
|
||||
struct {
|
||||
Address addr;
|
||||
uint16_t port;
|
||||
std::unique_ptr<char[]> host;
|
||||
// Hostname of memcached server. This is also used as SNI field
|
||||
// if TLS is enabled.
|
||||
ImmutableString host;
|
||||
// Client private key and certificate for authentication
|
||||
ImmutableString private_key_file;
|
||||
ImmutableString cert_file;
|
||||
ev_tstamp interval;
|
||||
// Maximum number of retries when getting TLS ticket key from
|
||||
// mamcached, due to network error.
|
||||
@ -342,6 +356,10 @@ struct TLSConfig {
|
||||
// Maximum number of consecutive error from memcached, when this
|
||||
// limit reached, TLS ticket is disabled.
|
||||
size_t max_fail;
|
||||
// Address family of memcached connection. One of either
|
||||
// AF_INET, AF_INET6 or AF_UNSPEC.
|
||||
int family;
|
||||
bool tls;
|
||||
} memcached;
|
||||
std::vector<std::string> files;
|
||||
const EVP_CIPHER *cipher;
|
||||
@ -354,7 +372,16 @@ struct TLSConfig {
|
||||
struct {
|
||||
Address addr;
|
||||
uint16_t port;
|
||||
std::unique_ptr<char[]> host;
|
||||
// Hostname of memcached server. This is also used as SNI field
|
||||
// if TLS is enabled.
|
||||
ImmutableString host;
|
||||
// Client private key and certificate for authentication
|
||||
ImmutableString private_key_file;
|
||||
ImmutableString cert_file;
|
||||
// Address family of memcached connection. One of either
|
||||
// AF_INET, AF_INET6 or AF_UNSPEC.
|
||||
int family;
|
||||
bool tls;
|
||||
} memcached;
|
||||
} session_cache;
|
||||
|
||||
@ -367,7 +394,7 @@ struct TLSConfig {
|
||||
// OCSP realted configurations
|
||||
struct {
|
||||
ev_tstamp update_interval;
|
||||
std::unique_ptr<char[]> fetch_ocsp_response_file;
|
||||
ImmutableString fetch_ocsp_response_file;
|
||||
bool disabled;
|
||||
} ocsp;
|
||||
|
||||
@ -375,14 +402,14 @@ struct TLSConfig {
|
||||
struct {
|
||||
// Path to file containing CA certificate solely used for client
|
||||
// certificate validation
|
||||
std::unique_ptr<char[]> cacert;
|
||||
ImmutableString cacert;
|
||||
bool enabled;
|
||||
} client_verify;
|
||||
|
||||
// Client private key and certificate used in backend connections.
|
||||
struct {
|
||||
std::unique_ptr<char[]> private_key_file;
|
||||
std::unique_ptr<char[]> cert_file;
|
||||
ImmutableString private_key_file;
|
||||
ImmutableString cert_file;
|
||||
} client;
|
||||
|
||||
// The list of (private key file, certificate file) pair
|
||||
@ -399,12 +426,12 @@ struct TLSConfig {
|
||||
long int tls_proto_mask;
|
||||
std::string backend_sni_name;
|
||||
std::chrono::seconds session_timeout;
|
||||
std::unique_ptr<char[]> private_key_file;
|
||||
std::unique_ptr<char[]> private_key_passwd;
|
||||
std::unique_ptr<char[]> cert_file;
|
||||
std::unique_ptr<char[]> dh_param_file;
|
||||
std::unique_ptr<char[]> ciphers;
|
||||
std::unique_ptr<char[]> cacert;
|
||||
ImmutableString private_key_file;
|
||||
ImmutableString private_key_passwd;
|
||||
ImmutableString cert_file;
|
||||
ImmutableString dh_param_file;
|
||||
ImmutableString ciphers;
|
||||
ImmutableString cacert;
|
||||
bool insecure;
|
||||
bool no_http2_cipher_black_list;
|
||||
};
|
||||
@ -430,8 +457,8 @@ struct HttpConfig {
|
||||
bool strip_incoming;
|
||||
} xff;
|
||||
std::vector<AltSvc> altsvcs;
|
||||
std::vector<std::pair<std::string, std::string>> add_request_headers;
|
||||
std::vector<std::pair<std::string, std::string>> add_response_headers;
|
||||
Headers add_request_headers;
|
||||
Headers add_response_headers;
|
||||
StringRef server_name;
|
||||
size_t request_header_field_buffer;
|
||||
size_t max_request_header_fields;
|
||||
@ -446,8 +473,8 @@ struct Http2Config {
|
||||
struct {
|
||||
struct {
|
||||
struct {
|
||||
std::unique_ptr<char[]> request_header_file;
|
||||
std::unique_ptr<char[]> response_header_file;
|
||||
ImmutableString request_header_file;
|
||||
ImmutableString response_header_file;
|
||||
FILE *request_header;
|
||||
FILE *response_header;
|
||||
} dump;
|
||||
@ -477,12 +504,12 @@ struct Http2Config {
|
||||
struct LoggingConfig {
|
||||
struct {
|
||||
std::vector<LogFragment> format;
|
||||
std::unique_ptr<char[]> file;
|
||||
ImmutableString file;
|
||||
// Send accesslog to syslog, ignoring accesslog_file.
|
||||
bool syslog;
|
||||
} access;
|
||||
struct {
|
||||
std::unique_ptr<char[]> file;
|
||||
ImmutableString file;
|
||||
// Send errorlog to syslog, ignoring errorlog_file.
|
||||
bool syslog;
|
||||
} error;
|
||||
@ -537,13 +564,12 @@ struct ConnectionConfig {
|
||||
size_t response_buffer_size;
|
||||
// downstream protocol; this will be determined by given options.
|
||||
shrpx_proto proto;
|
||||
// Address family of backend connection. One of either AF_INET,
|
||||
// AF_INET6 or AF_UNSPEC. This is ignored if backend connection
|
||||
// is made via Unix domain socket.
|
||||
int family;
|
||||
bool no_tls;
|
||||
bool http1_tls;
|
||||
// true if IPv4 only; ipv4 and ipv6 are mutually exclusive; and
|
||||
// (ipv4 && ipv6) must be false.
|
||||
bool ipv4;
|
||||
// true if IPv6 only
|
||||
bool ipv6;
|
||||
} downstream;
|
||||
};
|
||||
|
||||
@ -555,10 +581,10 @@ struct Config {
|
||||
TLSConfig tls;
|
||||
LoggingConfig logging;
|
||||
ConnectionConfig conn;
|
||||
std::unique_ptr<char[]> pid_file;
|
||||
std::unique_ptr<char[]> conf_path;
|
||||
std::unique_ptr<char[]> user;
|
||||
std::unique_ptr<char[]> mruby_file;
|
||||
ImmutableString pid_file;
|
||||
ImmutableString conf_path;
|
||||
ImmutableString user;
|
||||
ImmutableString mruby_file;
|
||||
char **original_argv;
|
||||
char **argv;
|
||||
char *cwd;
|
||||
@ -603,7 +629,7 @@ std::string read_passwd_from_file(const char *filename);
|
||||
// like "NAME: VALUE". We require that NAME is non empty string. ":"
|
||||
// is allowed at the start of the NAME, but NAME == ":" is not
|
||||
// allowed. This function returns pair of NAME and VALUE.
|
||||
std::pair<std::string, std::string> parse_header(const char *optarg);
|
||||
Headers::value_type parse_header(const char *optarg);
|
||||
|
||||
std::vector<LogFragment> parse_log_format(const char *optarg);
|
||||
|
||||
@ -630,7 +656,7 @@ read_tls_ticket_key_file(const std::vector<std::string> &files,
|
||||
// group. The catch-all group index is given in |catch_all|. All
|
||||
// patterns are given in |groups|.
|
||||
size_t match_downstream_addr_group(
|
||||
const Router &router, const std::string &hostport, const std::string &path,
|
||||
const Router &router, const StringRef &hostport, const StringRef &path,
|
||||
const std::vector<DownstreamAddrGroup> &groups, size_t catch_all);
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -38,32 +38,32 @@ namespace shrpx {
|
||||
|
||||
void test_shrpx_config_parse_header(void) {
|
||||
auto p = parse_header("a: b");
|
||||
CU_ASSERT("a" == p.first);
|
||||
CU_ASSERT("b" == p.second);
|
||||
CU_ASSERT("a" == p.name);
|
||||
CU_ASSERT("b" == p.value);
|
||||
|
||||
p = parse_header("a: b");
|
||||
CU_ASSERT("a" == p.first);
|
||||
CU_ASSERT("b" == p.second);
|
||||
CU_ASSERT("a" == p.name);
|
||||
CU_ASSERT("b" == p.value);
|
||||
|
||||
p = parse_header(":a: b");
|
||||
CU_ASSERT(p.first.empty());
|
||||
CU_ASSERT(p.name.empty());
|
||||
|
||||
p = parse_header("a: :b");
|
||||
CU_ASSERT("a" == p.first);
|
||||
CU_ASSERT(":b" == p.second);
|
||||
CU_ASSERT("a" == p.name);
|
||||
CU_ASSERT(":b" == p.value);
|
||||
|
||||
p = parse_header(": b");
|
||||
CU_ASSERT(p.first.empty());
|
||||
CU_ASSERT(p.name.empty());
|
||||
|
||||
p = parse_header("alpha: bravo charlie");
|
||||
CU_ASSERT("alpha" == p.first);
|
||||
CU_ASSERT("bravo charlie" == p.second);
|
||||
CU_ASSERT("alpha" == p.name);
|
||||
CU_ASSERT("bravo charlie" == p.value);
|
||||
|
||||
p = parse_header("a,: b");
|
||||
CU_ASSERT(p.first.empty());
|
||||
CU_ASSERT(p.name.empty());
|
||||
|
||||
p = parse_header("a: b\x0a");
|
||||
CU_ASSERT(p.first.empty());
|
||||
CU_ASSERT(p.name.empty());
|
||||
}
|
||||
|
||||
void test_shrpx_config_parse_log_format(void) {
|
||||
@ -256,7 +256,7 @@ void test_shrpx_config_match_downstream_addr_group(void) {
|
||||
|
||||
for (size_t i = 0; i < groups.size(); ++i) {
|
||||
auto &g = groups[i];
|
||||
router.add_route(g.pattern.get(), strlen(g.pattern.get()), i);
|
||||
router.add_route(StringRef{g.pattern}, i);
|
||||
}
|
||||
|
||||
CU_ASSERT(0 == match_downstream_addr_group(router, "nghttp2.org", "/", groups,
|
||||
|
@ -26,20 +26,16 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
namespace {
|
||||
const ev_tstamp INITIAL_SLEEP = 2.;
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void connect_blocker_cb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "unblock downstream connection";
|
||||
LOG(INFO) << "Unblock";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ConnectBlocker::ConnectBlocker(struct ev_loop *loop)
|
||||
: loop_(loop), sleep_(INITIAL_SLEEP) {
|
||||
ConnectBlocker::ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop)
|
||||
: gen_(gen), loop_(loop), fail_count_(0) {
|
||||
ev_timer_init(&timer_, connect_blocker_cb, 0., 0.);
|
||||
}
|
||||
|
||||
@ -47,18 +43,27 @@ ConnectBlocker::~ConnectBlocker() { ev_timer_stop(loop_, &timer_); }
|
||||
|
||||
bool ConnectBlocker::blocked() const { return ev_is_active(&timer_); }
|
||||
|
||||
void ConnectBlocker::on_success() { sleep_ = INITIAL_SLEEP; }
|
||||
void ConnectBlocker::on_success() { fail_count_ = 0; }
|
||||
|
||||
namespace {
|
||||
constexpr size_t MAX_BACKOFF_EXP = 10;
|
||||
} // namespace
|
||||
|
||||
void ConnectBlocker::on_failure() {
|
||||
if (ev_is_active(&timer_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sleep_ = std::min(128., sleep_ * 2);
|
||||
++fail_count_;
|
||||
|
||||
LOG(WARN) << "connect failure, start sleeping " << sleep_;
|
||||
auto max_backoff = (1 << std::min(MAX_BACKOFF_EXP, fail_count_)) - 1;
|
||||
auto dist = std::uniform_int_distribution<>(0, max_backoff);
|
||||
auto backoff = dist(gen_);
|
||||
|
||||
ev_timer_set(&timer_, sleep_, 0.);
|
||||
LOG(WARN) << "Could not connect " << fail_count_
|
||||
<< " times in a row; sleep for " << backoff << " seconds";
|
||||
|
||||
ev_timer_set(&timer_, backoff, 0.);
|
||||
ev_timer_start(loop_, &timer_);
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,15 @@
|
||||
|
||||
#include "shrpx.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
class ConnectBlocker {
|
||||
public:
|
||||
ConnectBlocker(struct ev_loop *loop);
|
||||
ConnectBlocker(std::mt19937 &gen, struct ev_loop *loop);
|
||||
~ConnectBlocker();
|
||||
|
||||
// Returns true if making connection is not allowed.
|
||||
@ -41,14 +43,18 @@ public:
|
||||
// Call this function if connect operation succeeded. This will
|
||||
// reset sleep_ to minimum value.
|
||||
void on_success();
|
||||
// Call this function if connect operation failed. This will start
|
||||
// timer and blocks connection establishment for sleep_ seconds.
|
||||
// Call this function if connect operations failed. This will start
|
||||
// timer and blocks connection establishment with exponential
|
||||
// backoff.
|
||||
void on_failure();
|
||||
|
||||
private:
|
||||
std::mt19937 gen_;
|
||||
ev_timer timer_;
|
||||
struct ev_loop *loop_;
|
||||
ev_tstamp sleep_;
|
||||
// The number of consecutive connection failure. Reset to 0 on
|
||||
// success.
|
||||
size_t fail_count_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -183,7 +183,7 @@ int ConnectionHandler::create_single_worker() {
|
||||
nb_.get()
|
||||
#endif // HAVE_NEVERBLEED
|
||||
);
|
||||
auto cl_ssl_ctx = ssl::setup_client_ssl_context(
|
||||
auto cl_ssl_ctx = ssl::setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_.get()
|
||||
#endif // HAVE_NEVERBLEED
|
||||
@ -193,8 +193,23 @@ int ConnectionHandler::create_single_worker() {
|
||||
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
||||
}
|
||||
|
||||
single_worker_ = make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
|
||||
ticket_keys_);
|
||||
auto &tlsconf = get_config()->tls;
|
||||
auto &memcachedconf = get_config()->tls.session_cache.memcached;
|
||||
|
||||
SSL_CTX *session_cache_ssl_ctx = nullptr;
|
||||
if (memcachedconf.tls) {
|
||||
session_cache_ssl_ctx = ssl::create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_.get(),
|
||||
#endif // HAVE_NEVERBLEED
|
||||
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
|
||||
StringRef{memcachedconf.private_key_file}, StringRef(), nullptr);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
}
|
||||
|
||||
single_worker_ =
|
||||
make_unique<Worker>(loop_, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
|
||||
cert_tree, ticket_keys_);
|
||||
#ifdef HAVE_MRUBY
|
||||
if (single_worker_->create_mruby_context() != 0) {
|
||||
return -1;
|
||||
@ -215,7 +230,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||
nb_.get()
|
||||
#endif // HAVE_NEVERBLEED
|
||||
);
|
||||
auto cl_ssl_ctx = ssl::setup_client_ssl_context(
|
||||
auto cl_ssl_ctx = ssl::setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_.get()
|
||||
#endif // HAVE_NEVERBLEED
|
||||
@ -225,11 +240,25 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||
all_ssl_ctx_.push_back(cl_ssl_ctx);
|
||||
}
|
||||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
auto &memcachedconf = get_config()->tls.session_cache.memcached;
|
||||
|
||||
for (size_t i = 0; i < num; ++i) {
|
||||
auto loop = ev_loop_new(0);
|
||||
|
||||
auto worker = make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, cert_tree,
|
||||
ticket_keys_);
|
||||
SSL_CTX *session_cache_ssl_ctx = nullptr;
|
||||
if (memcachedconf.tls) {
|
||||
session_cache_ssl_ctx = ssl::create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_.get(),
|
||||
#endif // HAVE_NEVERBLEED
|
||||
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
|
||||
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr);
|
||||
all_ssl_ctx_.push_back(session_cache_ssl_ctx);
|
||||
}
|
||||
auto worker =
|
||||
make_unique<Worker>(loop, sv_ssl_ctx, cl_ssl_ctx, session_cache_ssl_ctx,
|
||||
cert_tree, ticket_keys_);
|
||||
#ifdef HAVE_MRUBY
|
||||
if (worker->create_mruby_context() != 0) {
|
||||
return -1;
|
||||
@ -432,7 +461,8 @@ int ConnectionHandler::start_ocsp_update(const char *cert_file) {
|
||||
assert(!ev_is_active(&ocsp_.chldev));
|
||||
|
||||
char *const argv[] = {
|
||||
const_cast<char *>(get_config()->tls.ocsp.fetch_ocsp_response_file.get()),
|
||||
const_cast<char *>(
|
||||
get_config()->tls.ocsp.fetch_ocsp_response_file.c_str()),
|
||||
const_cast<char *>(cert_file), nullptr};
|
||||
char *const envp[] = {nullptr};
|
||||
|
||||
@ -728,6 +758,22 @@ void ConnectionHandler::schedule_next_tls_ticket_key_memcached_get(
|
||||
ev_timer_start(loop_, w);
|
||||
}
|
||||
|
||||
SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
||||
auto &tlsconf = get_config()->tls;
|
||||
auto &memcachedconf = get_config()->tls.ticket.memcached;
|
||||
|
||||
auto ssl_ctx = ssl::create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb_.get(),
|
||||
#endif // HAVE_NEVERBLEED
|
||||
StringRef{tlsconf.cacert}, StringRef{memcachedconf.cert_file},
|
||||
StringRef{memcachedconf.private_key_file}, StringRef{}, nullptr);
|
||||
|
||||
all_ssl_ctx_.push_back(ssl_ctx);
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) {
|
||||
nb_ = std::move(nb);
|
||||
|
@ -129,6 +129,7 @@ public:
|
||||
on_tls_ticket_key_get_success(const std::shared_ptr<TicketKeys> &ticket_keys,
|
||||
ev_timer *w);
|
||||
void schedule_next_tls_ticket_key_memcached_get(ev_timer *w);
|
||||
SSL_CTX *create_tls_ticket_key_memcached_ssl_ctx();
|
||||
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
void set_neverbleed(std::unique_ptr<neverbleed_t> nb);
|
||||
|
@ -237,15 +237,15 @@ void Downstream::force_resume_read() {
|
||||
}
|
||||
|
||||
namespace {
|
||||
const Headers::value_type *search_header_linear(const Headers &headers,
|
||||
const StringRef &name) {
|
||||
const Headers::value_type *res = nullptr;
|
||||
for (auto &kv : headers) {
|
||||
const Headers::value_type *
|
||||
search_header_linear_backwards(const Headers &headers, const StringRef &name) {
|
||||
for (auto it = headers.rbegin(); it != headers.rend(); ++it) {
|
||||
auto &kv = *it;
|
||||
if (kv.name == name) {
|
||||
res = &kv;
|
||||
return &kv;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return nullptr;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -329,23 +329,20 @@ void Downstream::crumble_request_cookie(std::vector<nghttp2_nv> &nva) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
void add_header(bool &key_prev, size_t &sum, Headers &headers, std::string name,
|
||||
std::string value) {
|
||||
void add_header(bool &key_prev, size_t &sum, Headers &headers,
|
||||
const StringRef &name, const StringRef &value, bool no_index,
|
||||
int32_t token) {
|
||||
key_prev = true;
|
||||
sum += name.size() + value.size();
|
||||
headers.emplace_back(std::move(name), std::move(value));
|
||||
headers.emplace_back(name.str(), value.str(), no_index, token);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void add_header(size_t &sum, Headers &headers, const uint8_t *name,
|
||||
size_t namelen, const uint8_t *value, size_t valuelen,
|
||||
bool no_index, int16_t token) {
|
||||
sum += namelen + valuelen;
|
||||
headers.emplace_back(
|
||||
std::string(reinterpret_cast<const char *>(name), namelen),
|
||||
std::string(reinterpret_cast<const char *>(value), valuelen), no_index,
|
||||
token);
|
||||
void add_header(size_t &sum, Headers &headers, const StringRef &name,
|
||||
const StringRef &value, bool no_index, int32_t token) {
|
||||
sum += name.size() + value.size();
|
||||
headers.emplace_back(name.str(), value.str(), no_index, token);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -356,6 +353,8 @@ void append_last_header_key(bool &key_prev, size_t &sum, Headers &headers,
|
||||
sum += len;
|
||||
auto &item = headers.back();
|
||||
item.name.append(data, len);
|
||||
util::inp_strlower(item.name);
|
||||
item.token = http2::lookup_token(item.name);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -369,67 +368,62 @@ void append_last_header_value(bool &key_prev, size_t &sum, Headers &headers,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int FieldStore::index_headers() {
|
||||
http2::init_hdidx(hdidx_);
|
||||
int FieldStore::parse_content_length() {
|
||||
content_length = -1;
|
||||
|
||||
for (size_t i = 0; i < headers_.size(); ++i) {
|
||||
auto &kv = headers_[i];
|
||||
util::inp_strlower(kv.name);
|
||||
|
||||
auto token = http2::lookup_token(
|
||||
reinterpret_cast<const uint8_t *>(kv.name.c_str()), kv.name.size());
|
||||
if (token < 0) {
|
||||
for (auto &kv : headers_) {
|
||||
if (kv.token != http2::HD_CONTENT_LENGTH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kv.token = token;
|
||||
http2::index_header(hdidx_, token, i);
|
||||
|
||||
if (token == http2::HD_CONTENT_LENGTH) {
|
||||
auto len = util::parse_uint(kv.value);
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (content_length != -1) {
|
||||
return -1;
|
||||
}
|
||||
content_length = len;
|
||||
auto len = util::parse_uint(kv.value);
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (content_length != -1) {
|
||||
return -1;
|
||||
}
|
||||
content_length = len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Headers::value_type *FieldStore::header(int16_t token) const {
|
||||
return http2::get_header(hdidx_, token, headers_);
|
||||
const Headers::value_type *FieldStore::header(int32_t token) const {
|
||||
for (auto it = headers_.rbegin(); it != headers_.rend(); ++it) {
|
||||
auto &kv = *it;
|
||||
if (kv.token == token) {
|
||||
return &kv;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Headers::value_type *FieldStore::header(int16_t token) {
|
||||
return http2::get_header(hdidx_, token, headers_);
|
||||
Headers::value_type *FieldStore::header(int32_t token) {
|
||||
for (auto it = headers_.rbegin(); it != headers_.rend(); ++it) {
|
||||
auto &kv = *it;
|
||||
if (kv.token == token) {
|
||||
return &kv;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Headers::value_type *FieldStore::header(const StringRef &name) const {
|
||||
return search_header_linear(headers_, name);
|
||||
return search_header_linear_backwards(headers_, name);
|
||||
}
|
||||
|
||||
void FieldStore::add_header(std::string name, std::string value) {
|
||||
shrpx::add_header(header_key_prev_, buffer_size_, headers_, std::move(name),
|
||||
std::move(value));
|
||||
void FieldStore::add_header_lower(const StringRef &name, const StringRef &value,
|
||||
bool no_index) {
|
||||
auto low_name = name.str();
|
||||
util::inp_strlower(low_name);
|
||||
auto token = http2::lookup_token(low_name);
|
||||
shrpx::add_header(header_key_prev_, buffer_size_, headers_,
|
||||
StringRef{low_name}, value, no_index, token);
|
||||
}
|
||||
|
||||
void FieldStore::add_header(std::string name, std::string value,
|
||||
int16_t token) {
|
||||
http2::index_header(hdidx_, token, headers_.size());
|
||||
buffer_size_ += name.size() + value.size();
|
||||
headers_.emplace_back(std::move(name), std::move(value), false, token);
|
||||
}
|
||||
|
||||
void FieldStore::add_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index, int16_t token) {
|
||||
http2::index_header(hdidx_, token, headers_.size());
|
||||
shrpx::add_header(buffer_size_, headers_, name, namelen, value, valuelen,
|
||||
no_index, token);
|
||||
void FieldStore::add_header_token(const StringRef &name, const StringRef &value,
|
||||
bool no_index, int32_t token) {
|
||||
shrpx::add_header(buffer_size_, headers_, name, value, no_index, token);
|
||||
}
|
||||
|
||||
void FieldStore::append_last_header_key(const char *data, size_t len) {
|
||||
@ -442,23 +436,23 @@ void FieldStore::append_last_header_value(const char *data, size_t len) {
|
||||
data, len);
|
||||
}
|
||||
|
||||
void FieldStore::clear_headers() {
|
||||
headers_.clear();
|
||||
http2::init_hdidx(hdidx_);
|
||||
void FieldStore::clear_headers() { headers_.clear(); }
|
||||
|
||||
void FieldStore::add_trailer_lower(const StringRef &name,
|
||||
const StringRef &value, bool no_index) {
|
||||
auto low_name = name.str();
|
||||
util::inp_strlower(low_name);
|
||||
auto token = http2::lookup_token(low_name);
|
||||
shrpx::add_header(trailer_key_prev_, buffer_size_, trailers_,
|
||||
StringRef{low_name}, value, no_index, token);
|
||||
}
|
||||
|
||||
void FieldStore::add_trailer(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index, int16_t token) {
|
||||
// we never index trailer fields. Header size limit should be
|
||||
// applied to all header and trailer fields combined.
|
||||
shrpx::add_header(buffer_size_, trailers_, name, namelen, value, valuelen,
|
||||
no_index, -1);
|
||||
}
|
||||
|
||||
void FieldStore::add_trailer(std::string name, std::string value) {
|
||||
shrpx::add_header(trailer_key_prev_, buffer_size_, trailers_, std::move(name),
|
||||
std::move(value));
|
||||
void FieldStore::add_trailer_token(const StringRef &name,
|
||||
const StringRef &value, bool no_index,
|
||||
int32_t token) {
|
||||
// Header size limit should be applied to all header and trailer
|
||||
// fields combined.
|
||||
shrpx::add_header(buffer_size_, trailers_, name, value, no_index, token);
|
||||
}
|
||||
|
||||
void FieldStore::append_last_trailer_key(const char *data, size_t len) {
|
||||
|
@ -56,7 +56,6 @@ public:
|
||||
buffer_size_(0),
|
||||
header_key_prev_(false),
|
||||
trailer_key_prev_(false) {
|
||||
http2::init_hdidx(hdidx_);
|
||||
headers_.reserve(headers_initial_capacity);
|
||||
}
|
||||
|
||||
@ -74,33 +73,33 @@ public:
|
||||
// multiple header have |name| as name, return last occurrence from
|
||||
// the beginning. If no such header is found, returns nullptr.
|
||||
// This function must be called after headers are indexed
|
||||
const Headers::value_type *header(int16_t token) const;
|
||||
Headers::value_type *header(int16_t token);
|
||||
const Headers::value_type *header(int32_t token) const;
|
||||
Headers::value_type *header(int32_t token);
|
||||
// Returns pointer to the header field with the name |name|. If no
|
||||
// such header is found, returns nullptr.
|
||||
const Headers::value_type *header(const StringRef &name) const;
|
||||
|
||||
void add_header(std::string name, std::string value);
|
||||
void add_header(std::string name, std::string value, int16_t token);
|
||||
void add_header(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, bool no_index, int16_t token);
|
||||
void add_header_lower(const StringRef &name, const StringRef &value,
|
||||
bool no_index);
|
||||
void add_header_token(const StringRef &name, const StringRef &value,
|
||||
bool no_index, int32_t token);
|
||||
|
||||
void append_last_header_key(const char *data, size_t len);
|
||||
void append_last_header_value(const char *data, size_t len);
|
||||
|
||||
bool header_key_prev() const { return header_key_prev_; }
|
||||
|
||||
// Lower the header field names and indexes header fields. If there
|
||||
// is any invalid headers (e.g., multiple Content-Length having
|
||||
// different values), returns -1.
|
||||
int index_headers();
|
||||
// Parses content-length, and records it in the field. If there are
|
||||
// multiple Content-Length, returns -1.
|
||||
int parse_content_length();
|
||||
|
||||
// Empties headers.
|
||||
void clear_headers();
|
||||
|
||||
void add_trailer(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, bool no_index, int16_t token);
|
||||
void add_trailer(std::string name, std::string value);
|
||||
void add_trailer_lower(const StringRef &name, const StringRef &value,
|
||||
bool no_index);
|
||||
void add_trailer_token(const StringRef &name, const StringRef &value,
|
||||
bool no_index, int32_t token);
|
||||
|
||||
void append_last_trailer_key(const char *data, size_t len);
|
||||
void append_last_trailer_value(const char *data, size_t len);
|
||||
@ -115,7 +114,6 @@ private:
|
||||
// trailer fields. For HTTP/1.1, trailer fields are only included
|
||||
// with chunked encoding. For HTTP/2, there is no such limit.
|
||||
Headers trailers_;
|
||||
http2::HeaderIndex hdidx_;
|
||||
// Sum of the length of name and value in headers_ and trailers_.
|
||||
// This could also be increased by add_extra_buffer_size() to take
|
||||
// into account for request URI in case of HTTP/1.x request.
|
||||
|
@ -32,17 +32,24 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
void test_downstream_field_store_index_headers(void) {
|
||||
void test_downstream_field_store_add_header_lower(void) {
|
||||
FieldStore fs(0);
|
||||
fs.add_header("1", "0");
|
||||
fs.add_header("2", "1");
|
||||
fs.add_header("Charlie", "2");
|
||||
fs.add_header("Alpha", "3");
|
||||
fs.add_header("Delta", "4");
|
||||
fs.add_header("BravO", "5");
|
||||
fs.add_header(":method", "6");
|
||||
fs.add_header(":authority", "7");
|
||||
fs.index_headers();
|
||||
fs.add_header_lower(StringRef::from_lit("1"), StringRef::from_lit("0"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit("2"), StringRef::from_lit("1"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit("Charlie"), StringRef::from_lit("2"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit("Alpha"), StringRef::from_lit("3"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit("Delta"), StringRef::from_lit("4"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit("BravO"), StringRef::from_lit("5"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit(":method"), StringRef::from_lit("6"),
|
||||
false);
|
||||
fs.add_header_lower(StringRef::from_lit(":authority"),
|
||||
StringRef::from_lit("7"), false);
|
||||
|
||||
auto ans = Headers{{"1", "0"},
|
||||
{"2", "1"},
|
||||
@ -57,10 +64,13 @@ void test_downstream_field_store_index_headers(void) {
|
||||
|
||||
void test_downstream_field_store_header(void) {
|
||||
FieldStore fs(0);
|
||||
fs.add_header("alpha", "0");
|
||||
fs.add_header(":authority", "1");
|
||||
fs.add_header("content-length", "2");
|
||||
fs.index_headers();
|
||||
fs.add_header_token(StringRef::from_lit("alpha"), StringRef::from_lit("0"),
|
||||
false, -1);
|
||||
fs.add_header_token(StringRef::from_lit(":authority"),
|
||||
StringRef::from_lit("1"), false, http2::HD__AUTHORITY);
|
||||
fs.add_header_token(StringRef::from_lit("content-length"),
|
||||
StringRef::from_lit("2"), false,
|
||||
http2::HD_CONTENT_LENGTH);
|
||||
|
||||
// By token
|
||||
CU_ASSERT(Header(":authority", "1") == *fs.header(http2::HD__AUTHORITY));
|
||||
@ -74,14 +84,18 @@ void test_downstream_field_store_header(void) {
|
||||
void test_downstream_crumble_request_cookie(void) {
|
||||
Downstream d(nullptr, nullptr, 0);
|
||||
auto &req = d.request();
|
||||
req.fs.add_header(":method", "get");
|
||||
req.fs.add_header(":path", "/");
|
||||
auto val = "alpha; bravo; ; ;; charlie;;";
|
||||
req.fs.add_header(
|
||||
reinterpret_cast<const uint8_t *>("cookie"), sizeof("cookie") - 1,
|
||||
reinterpret_cast<const uint8_t *>(val), strlen(val), true, -1);
|
||||
req.fs.add_header("cookie", ";delta");
|
||||
req.fs.add_header("cookie", "echo");
|
||||
req.fs.add_header_token(StringRef::from_lit(":method"),
|
||||
StringRef::from_lit("get"), false, -1);
|
||||
req.fs.add_header_token(StringRef::from_lit(":path"),
|
||||
StringRef::from_lit("/"), false, -1);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("alpha; bravo; ; ;; charlie;;"),
|
||||
true, http2::HD_COOKIE);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit(";delta"), false,
|
||||
http2::HD_COOKIE);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("echo"), false, http2::HD_COOKIE);
|
||||
|
||||
std::vector<nghttp2_nv> nva;
|
||||
d.crumble_request_cookie(nva);
|
||||
@ -114,12 +128,22 @@ void test_downstream_crumble_request_cookie(void) {
|
||||
void test_downstream_assemble_request_cookie(void) {
|
||||
Downstream d(nullptr, nullptr, 0);
|
||||
auto &req = d.request();
|
||||
req.fs.add_header(":method", "get");
|
||||
req.fs.add_header(":path", "/");
|
||||
req.fs.add_header("cookie", "alpha");
|
||||
req.fs.add_header("cookie", "bravo;");
|
||||
req.fs.add_header("cookie", "charlie; ");
|
||||
req.fs.add_header("cookie", "delta;;");
|
||||
req.fs.add_header_token(StringRef::from_lit(":method"),
|
||||
StringRef::from_lit("get"), false, -1);
|
||||
req.fs.add_header_token(StringRef::from_lit(":path"),
|
||||
StringRef::from_lit("/"), false, -1);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("alpha"), false,
|
||||
http2::HD_COOKIE);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("bravo;"), false,
|
||||
http2::HD_COOKIE);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("charlie; "), false,
|
||||
http2::HD_COOKIE);
|
||||
req.fs.add_header_token(StringRef::from_lit("cookie"),
|
||||
StringRef::from_lit("delta;;"), false,
|
||||
http2::HD_COOKIE);
|
||||
CU_ASSERT("alpha; bravo; charlie; delta" == d.assemble_request_cookie());
|
||||
}
|
||||
|
||||
@ -129,8 +153,9 @@ void test_downstream_rewrite_location_response_header(void) {
|
||||
auto &resp = d.response();
|
||||
d.set_request_downstream_host("localhost2");
|
||||
req.authority = "localhost:8443";
|
||||
resp.fs.add_header("location", "http://localhost2:3000/");
|
||||
resp.fs.index_headers();
|
||||
resp.fs.add_header_token(StringRef::from_lit("location"),
|
||||
StringRef::from_lit("http://localhost2:3000/"),
|
||||
false, http2::HD_LOCATION);
|
||||
d.rewrite_location_response_header("https");
|
||||
auto location = resp.fs.header(http2::HD_LOCATION);
|
||||
CU_ASSERT("https://localhost:8443/" == (*location).value);
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
void test_downstream_field_store_index_headers(void);
|
||||
void test_downstream_field_store_add_header_lower(void);
|
||||
void test_downstream_field_store_header(void);
|
||||
void test_downstream_crumble_request_cookie(void);
|
||||
void test_downstream_assemble_request_cookie(void);
|
||||
|
@ -98,6 +98,9 @@ int Http2DownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||
http2session_->add_downstream_connection(this);
|
||||
if (http2session_->get_state() == Http2Session::DISCONNECTED) {
|
||||
http2session_->signal_write();
|
||||
if (http2session_->get_state() == Http2Session::DISCONNECTED) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
downstream_ = downstream;
|
||||
@ -422,7 +425,7 @@ int Http2DownstreamConnection::push_request_headers() {
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_request_headers) {
|
||||
nva.push_back(http2::make_nv_nocopy(p.first, p.second));
|
||||
nva.push_back(http2::make_nv_nocopy(p.name, p.value));
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
|
@ -147,8 +147,7 @@ void writecb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
} // namespace
|
||||
|
||||
Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||
ConnectBlocker *connect_blocker, Worker *worker,
|
||||
size_t group, size_t idx)
|
||||
Worker *worker, size_t group, size_t idx)
|
||||
: conn_(loop, -1, nullptr, worker->get_mcpool(),
|
||||
get_config()->conn.downstream.timeout.write,
|
||||
get_config()->conn.downstream.timeout.read, {}, {}, writecb, readcb,
|
||||
@ -156,7 +155,6 @@ Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||
get_config()->tls.dyn_rec.idle_timeout),
|
||||
wb_(worker->get_mcpool()),
|
||||
worker_(worker),
|
||||
connect_blocker_(connect_blocker),
|
||||
ssl_ctx_(ssl_ctx),
|
||||
addr_(nullptr),
|
||||
session_(nullptr),
|
||||
@ -254,30 +252,58 @@ int Http2Session::disconnect(bool hard) {
|
||||
int Http2Session::initiate_connection() {
|
||||
int rv = 0;
|
||||
|
||||
auto &addrs = get_config()->conn.downstream.addr_groups[group_].addrs;
|
||||
auto &groups = worker_->get_downstream_addr_groups();
|
||||
auto &addrs = groups[group_].addrs;
|
||||
auto worker_blocker = worker_->get_connect_blocker();
|
||||
|
||||
if (state_ == DISCONNECTED) {
|
||||
if (connect_blocker_->blocked()) {
|
||||
if (worker_blocker->blocked()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DCLOG(INFO, this)
|
||||
<< "Downstream connection was blocked by connect_blocker";
|
||||
SSLOG(INFO, this)
|
||||
<< "Worker wide backend connection was blocked temporarily";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
||||
addr_ = &addrs[next_downstream];
|
||||
auto end = next_downstream;
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Using downstream address idx=" << next_downstream
|
||||
<< " out of " << addrs.size();
|
||||
}
|
||||
for (;;) {
|
||||
auto &addr = addrs[next_downstream];
|
||||
|
||||
if (++next_downstream >= addrs.size()) {
|
||||
next_downstream = 0;
|
||||
if (++next_downstream >= addrs.size()) {
|
||||
next_downstream = 0;
|
||||
}
|
||||
|
||||
auto &connect_blocker = addr.connect_blocker;
|
||||
|
||||
if (connect_blocker->blocked()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Backend server "
|
||||
<< util::to_numeric_addr(&addr.addr)
|
||||
<< " was not available temporarily";
|
||||
}
|
||||
|
||||
if (end == next_downstream) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Using downstream address idx=" << next_downstream
|
||||
<< " out of " << addrs.size();
|
||||
}
|
||||
|
||||
addr_ = &addr;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto &connect_blocker = addr_->connect_blocker;
|
||||
|
||||
const auto &proxy = get_config()->downstream_http_proxy;
|
||||
if (!proxy.host.empty() && state_ == DISCONNECTED) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
@ -288,15 +314,25 @@ int Http2Session::initiate_connection() {
|
||||
conn_.fd = util::create_nonblock_socket(proxy.addr.su.storage.ss_family);
|
||||
|
||||
if (conn_.fd == -1) {
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this) << "Backend proxy socket() failed; addr="
|
||||
<< util::to_numeric_addr(&proxy.addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
worker_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
worker_blocker->on_success();
|
||||
|
||||
rv = connect(conn_.fd, &proxy.addr.su.sa, proxy.addr.len);
|
||||
if (rv != 0 && errno != EINPROGRESS) {
|
||||
SSLOG(ERROR, this) << "Failed to connect to the proxy " << proxy.host
|
||||
<< ":" << proxy.port;
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this) << "Backend proxy connect() failed; addr="
|
||||
<< util::to_numeric_addr(&proxy.addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
connect_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -356,16 +392,28 @@ int Http2Session::initiate_connection() {
|
||||
conn_.fd =
|
||||
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
||||
if (conn_.fd == -1) {
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this)
|
||||
<< "socket() failed; addr=" << util::to_numeric_addr(&addr_->addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
worker_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
worker_blocker->on_success();
|
||||
|
||||
rv = connect(conn_.fd,
|
||||
// TODO maybe not thread-safe?
|
||||
const_cast<sockaddr *>(&addr_->addr.su.sa),
|
||||
addr_->addr.len);
|
||||
if (rv != 0 && errno != EINPROGRESS) {
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this) << "connect() failed; addr="
|
||||
<< util::to_numeric_addr(&addr_->addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
connect_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -383,14 +431,26 @@ int Http2Session::initiate_connection() {
|
||||
util::create_nonblock_socket(addr_->addr.su.storage.ss_family);
|
||||
|
||||
if (conn_.fd == -1) {
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this)
|
||||
<< "socket() failed; addr=" << util::to_numeric_addr(&addr_->addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
worker_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
worker_blocker->on_success();
|
||||
|
||||
rv = connect(conn_.fd, const_cast<sockaddr *>(&addr_->addr.su.sa),
|
||||
addr_->addr.len);
|
||||
if (rv != 0 && errno != EINPROGRESS) {
|
||||
connect_blocker_->on_failure();
|
||||
auto error = errno;
|
||||
SSLOG(WARN, this) << "connect() failed; addr="
|
||||
<< util::to_numeric_addr(&addr_->addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
connect_blocker->on_failure();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -735,17 +795,18 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
auto no_index = flags & NGHTTP2_NV_FLAG_NO_INDEX;
|
||||
|
||||
if (trailer) {
|
||||
// just store header fields for trailer part
|
||||
resp.fs.add_trailer(name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
|
||||
resp.fs.add_trailer_token(StringRef{name, namelen},
|
||||
StringRef{value, valuelen}, no_index, token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
resp.fs.add_header(name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
resp.fs.add_header_token(StringRef{name, namelen},
|
||||
StringRef{value, valuelen}, no_index, token);
|
||||
return 0;
|
||||
}
|
||||
case NGHTTP2_PUSH_PROMISE: {
|
||||
@ -778,8 +839,9 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
promised_req.fs.add_header(name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
promised_req.fs.add_header_token(StringRef{name, namelen},
|
||||
StringRef{value, valuelen},
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -926,8 +988,9 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
|
||||
// Otherwise, use chunked encoding to keep upstream connection
|
||||
// open. In HTTP2, we are supporsed not to receive
|
||||
// transfer-encoding.
|
||||
resp.fs.add_header("transfer-encoding", "chunked",
|
||||
http2::HD_TRANSFER_ENCODING);
|
||||
resp.fs.add_header_token(StringRef::from_lit("transfer-encoding"),
|
||||
StringRef::from_lit("chunked"), false,
|
||||
http2::HD_TRANSFER_ENCODING);
|
||||
downstream->set_chunked_response(true);
|
||||
}
|
||||
}
|
||||
@ -1612,11 +1675,20 @@ int Http2Session::read_noop(const uint8_t *data, size_t datalen) { return 0; }
|
||||
int Http2Session::write_noop() { return 0; }
|
||||
|
||||
int Http2Session::connected() {
|
||||
auto &connect_blocker = addr_->connect_blocker;
|
||||
|
||||
if (!util::check_socket_connected(conn_.fd)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Backend connect failed; addr="
|
||||
<< util::to_numeric_addr(&addr_->addr);
|
||||
}
|
||||
|
||||
connect_blocker->on_failure();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
connect_blocker_->on_success();
|
||||
connect_blocker->on_success();
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
SSLOG(INFO, this) << "Connection established";
|
||||
|
@ -48,7 +48,6 @@ namespace shrpx {
|
||||
|
||||
class Http2DownstreamConnection;
|
||||
class Worker;
|
||||
class ConnectBlocker;
|
||||
|
||||
struct StreamData {
|
||||
StreamData *dlnext, *dlprev;
|
||||
@ -57,9 +56,8 @@ struct StreamData {
|
||||
|
||||
class Http2Session {
|
||||
public:
|
||||
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||
ConnectBlocker *connect_blocker, Worker *worker, size_t group,
|
||||
size_t idx);
|
||||
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker,
|
||||
size_t group, size_t idx);
|
||||
~Http2Session();
|
||||
|
||||
// If hard is true, all pending requests are abandoned and
|
||||
@ -203,7 +201,6 @@ private:
|
||||
// Used to parse the response from HTTP proxy
|
||||
std::unique_ptr<http_parser> proxy_htp_;
|
||||
Worker *worker_;
|
||||
ConnectBlocker *connect_blocker_;
|
||||
// NULL if no TLS is configured
|
||||
SSL_CTX *ssl_ctx_;
|
||||
// Address of remote endpoint
|
||||
|
@ -201,17 +201,18 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
auto no_index = flags & NGHTTP2_NV_FLAG_NO_INDEX;
|
||||
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
|
||||
// just store header fields for trailer part
|
||||
req.fs.add_trailer(name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
|
||||
req.fs.add_trailer_token(StringRef{name, namelen},
|
||||
StringRef{value, valuelen}, no_index, token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto token = http2::lookup_token(name, namelen);
|
||||
|
||||
req.fs.add_header(name, namelen, value, valuelen,
|
||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
req.fs.add_header_token(StringRef{name, namelen}, StringRef{value, valuelen},
|
||||
no_index, token);
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
@ -593,8 +594,9 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
req.path = http2::rewrite_clean_path(nv.value, nv.value + nv.valuelen);
|
||||
break;
|
||||
}
|
||||
req.fs.add_header(nv.name, nv.namelen, nv.value, nv.valuelen,
|
||||
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
req.fs.add_header_token(StringRef{nv.name, nv.namelen},
|
||||
StringRef{nv.value, nv.valuelen},
|
||||
nv.flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||
}
|
||||
|
||||
promised_downstream->inspect_http2_request();
|
||||
@ -1206,11 +1208,12 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||
}
|
||||
|
||||
const auto &resp = downstream->response();
|
||||
auto &httpconf = get_config()->http;
|
||||
|
||||
const auto &headers = resp.fs.headers();
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
// 2 for :status and server
|
||||
nva.reserve(2 + headers.size());
|
||||
nva.reserve(2 + headers.size() + httpconf.add_response_headers.size());
|
||||
|
||||
std::string status_code_str;
|
||||
auto response_status_const = http2::stringify_status(resp.http_status);
|
||||
@ -1242,6 +1245,10 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||
http2::make_nv_ls_nocopy("server", get_config()->http.server_name));
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
nva.push_back(http2::make_nv_nocopy(p.name, p.value));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
|
||||
nva.data(), nva.size(), data_prd_ptr);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
@ -1436,7 +1443,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
nva.push_back(http2::make_nv_nocopy(p.first, p.second));
|
||||
nva.push_back(http2::make_nv_nocopy(p.name, p.value));
|
||||
}
|
||||
|
||||
if (downstream->get_stream_id() % 2 == 0) {
|
||||
@ -1553,7 +1560,9 @@ int Http2Upstream::adjust_pushed_stream_priority(Downstream *downstream) {
|
||||
}
|
||||
|
||||
if (!util::istarts_with_l(ct->value, "application/javascript") &&
|
||||
!util::istarts_with_l(ct->value, "text/css")) {
|
||||
!util::istarts_with_l(ct->value, "text/css") &&
|
||||
// for polymer...
|
||||
!util::istarts_with_l(ct->value, "text/html")) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -129,33 +129,25 @@ HttpDownstreamConnection::HttpDownstreamConnection(
|
||||
response_htp_{0},
|
||||
group_(group) {}
|
||||
|
||||
HttpDownstreamConnection::~HttpDownstreamConnection() {
|
||||
if (conn_.tls.ssl) {
|
||||
auto session = SSL_get1_session(conn_.tls.ssl);
|
||||
if (session) {
|
||||
worker_->cache_downstream_tls_session(addr_, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
HttpDownstreamConnection::~HttpDownstreamConnection() {}
|
||||
|
||||
int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
|
||||
}
|
||||
|
||||
auto worker_blocker = worker_->get_connect_blocker();
|
||||
if (worker_blocker->blocked()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DCLOG(INFO, this)
|
||||
<< "Worker wide backend connection was blocked temporarily";
|
||||
}
|
||||
return SHRPX_ERR_NETWORK;
|
||||
}
|
||||
|
||||
auto &downstreamconf = get_config()->conn.downstream;
|
||||
|
||||
if (conn_.fd == -1) {
|
||||
auto connect_blocker = client_handler_->get_connect_blocker();
|
||||
|
||||
if (connect_blocker->blocked()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DCLOG(INFO, this)
|
||||
<< "Downstream connection was blocked by connect_blocker";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssl_ctx_) {
|
||||
auto ssl = ssl::create_ssl(ssl_ctx_);
|
||||
if (!ssl) {
|
||||
@ -167,7 +159,8 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||
|
||||
auto &next_downstream = worker_->get_dgrp(group_)->next;
|
||||
auto end = next_downstream;
|
||||
auto &addrs = downstreamconf.addr_groups[group_].addrs;
|
||||
auto &groups = worker_->get_downstream_addr_groups();
|
||||
auto &addrs = groups[group_].addrs;
|
||||
for (;;) {
|
||||
auto &addr = addrs[next_downstream];
|
||||
|
||||
@ -175,22 +168,44 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||
next_downstream = 0;
|
||||
}
|
||||
|
||||
auto &connect_blocker = addr.connect_blocker;
|
||||
|
||||
if (connect_blocker->blocked()) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DCLOG(INFO, this) << "Backend server "
|
||||
<< util::to_numeric_addr(&addr.addr)
|
||||
<< " was not available temporarily";
|
||||
}
|
||||
|
||||
if (end == next_downstream) {
|
||||
return SHRPX_ERR_NETWORK;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
conn_.fd = util::create_nonblock_socket(addr.addr.su.storage.ss_family);
|
||||
|
||||
if (conn_.fd == -1) {
|
||||
auto error = errno;
|
||||
DCLOG(WARN, this) << "socket() failed; errno=" << error;
|
||||
DCLOG(WARN, this) << "socket() failed; addr="
|
||||
<< util::to_numeric_addr(&addr.addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
connect_blocker->on_failure();
|
||||
worker_blocker->on_failure();
|
||||
|
||||
return SHRPX_ERR_NETWORK;
|
||||
}
|
||||
|
||||
worker_blocker->on_success();
|
||||
|
||||
int rv;
|
||||
rv = connect(conn_.fd, &addr.addr.su.sa, addr.addr.len);
|
||||
if (rv != 0 && errno != EINPROGRESS) {
|
||||
auto error = errno;
|
||||
DCLOG(WARN, this) << "connect() failed; errno=" << error;
|
||||
DCLOG(WARN, this) << "connect() failed; addr="
|
||||
<< util::to_numeric_addr(&addr.addr)
|
||||
<< ", errno=" << error;
|
||||
|
||||
connect_blocker->on_failure();
|
||||
close(conn_.fd);
|
||||
@ -218,7 +233,7 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) {
|
||||
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
|
||||
}
|
||||
|
||||
auto session = worker_->reuse_downstream_tls_session(addr_);
|
||||
auto session = ssl::reuse_tls_session(addr_);
|
||||
if (session) {
|
||||
SSL_set_session(conn_.tls.ssl, session);
|
||||
SSL_SESSION_free(session);
|
||||
@ -417,9 +432,9 @@ int HttpDownstreamConnection::push_request_headers() {
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_request_headers) {
|
||||
buf->append(p.first);
|
||||
buf->append(p.name);
|
||||
buf->append(": ");
|
||||
buf->append(p.second);
|
||||
buf->append(p.value);
|
||||
buf->append("\r\n");
|
||||
}
|
||||
|
||||
@ -571,7 +586,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||
resp.http_major = htp->http_major;
|
||||
resp.http_minor = htp->http_minor;
|
||||
|
||||
if (resp.fs.index_headers() != 0) {
|
||||
if (resp.fs.parse_content_length() != 0) {
|
||||
downstream->set_response_state(Downstream::MSG_BAD_HEADER);
|
||||
return -1;
|
||||
}
|
||||
@ -690,7 +705,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
if (ensure_max_header_fields(downstream, httpconf) != 0) {
|
||||
return -1;
|
||||
}
|
||||
resp.fs.add_header(std::string(data, len), "");
|
||||
resp.fs.add_header_lower(StringRef{data, len}, StringRef{}, false);
|
||||
}
|
||||
} else {
|
||||
// trailer part
|
||||
@ -703,7 +718,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
// wrong place or crash if trailer fields are currently empty.
|
||||
return -1;
|
||||
}
|
||||
resp.fs.add_trailer(std::string(data, len), "");
|
||||
resp.fs.add_trailer_lower(StringRef(data, len), StringRef{}, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -868,6 +883,13 @@ int HttpDownstreamConnection::tls_handshake() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SSL_session_reused(conn_.tls.ssl)) {
|
||||
auto session = SSL_get0_session(conn_.tls.ssl);
|
||||
if (session) {
|
||||
ssl::try_cache_tls_session(addr_, session, ev_now(conn_.loop));
|
||||
}
|
||||
}
|
||||
|
||||
do_read_ = &HttpDownstreamConnection::read_tls;
|
||||
do_write_ = &HttpDownstreamConnection::write_tls;
|
||||
|
||||
@ -1011,22 +1033,25 @@ int HttpDownstreamConnection::process_input(const uint8_t *data,
|
||||
}
|
||||
|
||||
int HttpDownstreamConnection::connected() {
|
||||
auto connect_blocker = client_handler_->get_connect_blocker();
|
||||
auto connect_blocker = addr_->connect_blocker;
|
||||
|
||||
if (!util::check_socket_connected(conn_.fd)) {
|
||||
conn_.wlimit.stopw();
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, this) << "downstream connect failed";
|
||||
DCLOG(INFO, this) << "Backend connect failed; addr="
|
||||
<< util::to_numeric_addr(&addr_->addr);
|
||||
}
|
||||
|
||||
connect_blocker->on_failure();
|
||||
|
||||
downstream_->set_request_state(Downstream::CONNECT_FAIL);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, this) << "Connected to downstream host";
|
||||
DCLOG(INFO, this) << "Connected to downstream host";
|
||||
}
|
||||
|
||||
connect_blocker->on_success();
|
||||
|
@ -82,7 +82,7 @@ private:
|
||||
// nullptr if TLS is not used.
|
||||
SSL_CTX *ssl_ctx_;
|
||||
// Address of remote endpoint
|
||||
const DownstreamAddr *addr_;
|
||||
DownstreamAddr *addr_;
|
||||
IOControl ioctrl_;
|
||||
http_parser response_htp_;
|
||||
size_t group_;
|
||||
|
@ -142,7 +142,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
|
||||
return -1;
|
||||
}
|
||||
req.fs.add_header(std::string(data, len), "");
|
||||
req.fs.add_header_lower(StringRef{data, len}, StringRef{}, false);
|
||||
}
|
||||
} else {
|
||||
// trailer part
|
||||
@ -156,7 +156,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
req.fs.add_trailer(std::string(data, len), "");
|
||||
req.fs.add_trailer_lower(StringRef{data, len}, StringRef{}, false);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -270,7 +270,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||
ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
|
||||
}
|
||||
|
||||
if (req.fs.index_headers() != 0) {
|
||||
if (req.fs.parse_content_length() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -798,6 +798,15 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||
output->append("\r\n");
|
||||
}
|
||||
|
||||
auto &httpconf = get_config()->http;
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
output->append(p.name);
|
||||
output->append(": ");
|
||||
output->append(p.value);
|
||||
output->append("\r\n");
|
||||
}
|
||||
|
||||
output->append("\r\n");
|
||||
|
||||
output->append(body, bodylen);
|
||||
@ -1022,9 +1031,9 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
buf->append(p.first);
|
||||
buf->append(p.name);
|
||||
buf->append(": ");
|
||||
buf->append(p.second);
|
||||
buf->append(p.value);
|
||||
buf->append("\r\n");
|
||||
}
|
||||
|
||||
|
@ -393,23 +393,23 @@ int reopen_log_files() {
|
||||
auto &accessconf = get_config()->logging.access;
|
||||
auto &errorconf = get_config()->logging.error;
|
||||
|
||||
if (!accessconf.syslog && accessconf.file) {
|
||||
new_accesslog_fd = util::open_log_file(accessconf.file.get());
|
||||
if (!accessconf.syslog && !accessconf.file.empty()) {
|
||||
new_accesslog_fd = util::open_log_file(accessconf.file.c_str());
|
||||
|
||||
if (new_accesslog_fd == -1) {
|
||||
LOG(ERROR) << "Failed to open accesslog file " << accessconf.file.get();
|
||||
LOG(ERROR) << "Failed to open accesslog file " << accessconf.file;
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!errorconf.syslog && errorconf.file) {
|
||||
new_errorlog_fd = util::open_log_file(errorconf.file.get());
|
||||
if (!errorconf.syslog && !errorconf.file.empty()) {
|
||||
new_errorlog_fd = util::open_log_file(errorconf.file.c_str());
|
||||
|
||||
if (new_errorlog_fd == -1) {
|
||||
if (lgconf->errorlog_fd != -1) {
|
||||
LOG(ERROR) << "Failed to open errorlog file " << errorconf.file.get();
|
||||
LOG(ERROR) << "Failed to open errorlog file " << errorconf.file;
|
||||
} else {
|
||||
std::cerr << "Failed to open errorlog file " << errorconf.file.get()
|
||||
std::cerr << "Failed to open errorlog file " << errorconf.file
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "shrpx_memcached_request.h"
|
||||
#include "shrpx_memcached_result.h"
|
||||
#include "shrpx_config.h"
|
||||
#include "shrpx_ssl.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace shrpx {
|
||||
@ -78,7 +79,7 @@ void connectcb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
auto conn = static_cast<Connection *>(w->data);
|
||||
auto mconn = static_cast<MemcachedConnection *>(conn->data);
|
||||
|
||||
if (mconn->on_connect() != 0) {
|
||||
if (mconn->connected() != 0) {
|
||||
mconn->disconnect();
|
||||
return;
|
||||
}
|
||||
@ -91,11 +92,17 @@ constexpr ev_tstamp write_timeout = 10.;
|
||||
constexpr ev_tstamp read_timeout = 10.;
|
||||
|
||||
MemcachedConnection::MemcachedConnection(const Address *addr,
|
||||
struct ev_loop *loop)
|
||||
: conn_(loop, -1, nullptr, nullptr, write_timeout, read_timeout, {}, {},
|
||||
struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||
const StringRef &sni_name,
|
||||
MemchunkPool *mcpool)
|
||||
: conn_(loop, -1, nullptr, mcpool, write_timeout, read_timeout, {}, {},
|
||||
connectcb, readcb, timeoutcb, this, 0, 0.),
|
||||
do_read_(&MemcachedConnection::noop),
|
||||
do_write_(&MemcachedConnection::noop),
|
||||
sni_name_(sni_name.str()),
|
||||
parse_state_{},
|
||||
addr_(addr),
|
||||
ssl_ctx_(ssl_ctx),
|
||||
sendsum_(0),
|
||||
connected_(false) {}
|
||||
|
||||
@ -127,11 +134,21 @@ void MemcachedConnection::disconnect() {
|
||||
|
||||
assert(recvbuf_.rleft() == 0);
|
||||
recvbuf_.reset();
|
||||
|
||||
do_read_ = do_write_ = &MemcachedConnection::noop;
|
||||
}
|
||||
|
||||
int MemcachedConnection::initiate_connection() {
|
||||
assert(conn_.fd == -1);
|
||||
|
||||
if (ssl_ctx_ && !conn_.tls.ssl) {
|
||||
auto ssl = ssl::create_ssl(ssl_ctx_);
|
||||
if (!ssl) {
|
||||
return -1;
|
||||
}
|
||||
conn_.set_ssl(ssl);
|
||||
}
|
||||
|
||||
conn_.fd = util::create_nonblock_socket(addr_->su.storage.ss_family);
|
||||
|
||||
if (conn_.fd == -1) {
|
||||
@ -153,6 +170,14 @@ int MemcachedConnection::initiate_connection() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ssl_ctx_) {
|
||||
if (!util::numeric_host(sni_name_.c_str())) {
|
||||
SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name_.c_str());
|
||||
}
|
||||
|
||||
conn_.prepare_client_handshake();
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
MCLOG(INFO, this) << "Connecting to memcached server";
|
||||
}
|
||||
@ -168,7 +193,7 @@ int MemcachedConnection::initiate_connection() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MemcachedConnection::on_connect() {
|
||||
int MemcachedConnection::connected() {
|
||||
if (!util::check_socket_connected(conn_.fd)) {
|
||||
conn_.wlimit.stopw();
|
||||
|
||||
@ -185,15 +210,59 @@ int MemcachedConnection::on_connect() {
|
||||
|
||||
connected_ = true;
|
||||
|
||||
ev_set_cb(&conn_.wev, writecb);
|
||||
|
||||
conn_.rlimit.startw();
|
||||
ev_timer_again(conn_.loop, &conn_.rt);
|
||||
|
||||
ev_set_cb(&conn_.wev, writecb);
|
||||
|
||||
if (conn_.tls.ssl) {
|
||||
do_read_ = &MemcachedConnection::tls_handshake;
|
||||
do_write_ = &MemcachedConnection::tls_handshake;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
do_read_ = &MemcachedConnection::read_clear;
|
||||
do_write_ = &MemcachedConnection::write_clear;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MemcachedConnection::on_write() {
|
||||
int MemcachedConnection::on_write() { return do_write_(*this); }
|
||||
int MemcachedConnection::on_read() { return do_read_(*this); }
|
||||
|
||||
int MemcachedConnection::tls_handshake() {
|
||||
ERR_clear_error();
|
||||
|
||||
ev_timer_again(conn_.loop, &conn_.rt);
|
||||
|
||||
auto rv = conn_.tls_handshake();
|
||||
if (rv == SHRPX_ERR_INPROGRESS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "SSL/TLS handshake completed";
|
||||
}
|
||||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
|
||||
if (!tlsconf.insecure &&
|
||||
ssl::check_cert(conn_.tls.ssl, addr_, StringRef(sni_name_)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
do_read_ = &MemcachedConnection::read_tls;
|
||||
do_write_ = &MemcachedConnection::write_tls;
|
||||
|
||||
return on_write();
|
||||
}
|
||||
|
||||
int MemcachedConnection::write_tls() {
|
||||
if (!connected_) {
|
||||
return 0;
|
||||
}
|
||||
@ -207,19 +276,30 @@ int MemcachedConnection::on_write() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rv;
|
||||
std::array<struct iovec, MAX_WR_IOVCNT> iov;
|
||||
std::array<uint8_t, 16_k> buf;
|
||||
|
||||
for (; !sendq_.empty();) {
|
||||
rv = send_request();
|
||||
auto iovcnt = fill_request_buffer(iov.data(), iov.size());
|
||||
auto p = std::begin(buf);
|
||||
for (size_t i = 0; i < iovcnt; ++i) {
|
||||
auto &v = iov[i];
|
||||
auto n = std::min(static_cast<size_t>(std::end(buf) - p), v.iov_len);
|
||||
p = std::copy_n(static_cast<uint8_t *>(v.iov_base), n, p);
|
||||
if (p == std::end(buf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rv < 0) {
|
||||
auto nwrite = conn_.write_tls(buf.data(), p - std::begin(buf));
|
||||
if (nwrite < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rv == 1) {
|
||||
// blocked
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
drain_send_queue(nwrite);
|
||||
}
|
||||
|
||||
conn_.wlimit.stopw();
|
||||
@ -228,7 +308,70 @@ int MemcachedConnection::on_write() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MemcachedConnection::on_read() {
|
||||
int MemcachedConnection::read_tls() {
|
||||
if (!connected_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev_timer_again(conn_.loop, &conn_.rt);
|
||||
|
||||
for (;;) {
|
||||
auto nread = conn_.read_tls(recvbuf_.last, recvbuf_.wleft());
|
||||
|
||||
if (nread == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
recvbuf_.write(nread);
|
||||
|
||||
if (parse_packet() != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MemcachedConnection::write_clear() {
|
||||
if (!connected_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev_timer_again(conn_.loop, &conn_.rt);
|
||||
|
||||
if (sendq_.empty()) {
|
||||
conn_.wlimit.stopw();
|
||||
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::array<struct iovec, MAX_WR_IOVCNT> iov;
|
||||
|
||||
for (; !sendq_.empty();) {
|
||||
auto iovcnt = fill_request_buffer(iov.data(), iov.size());
|
||||
auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
|
||||
if (nwrite < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (nwrite == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
drain_send_queue(nwrite);
|
||||
}
|
||||
|
||||
conn_.wlimit.stopw();
|
||||
ev_timer_stop(conn_.loop, &conn_.wt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MemcachedConnection::read_clear() {
|
||||
if (!connected_) {
|
||||
return 0;
|
||||
}
|
||||
@ -415,9 +558,8 @@ int MemcachedConnection::parse_packet() {
|
||||
#define MAX_WR_IOVCNT DEFAULT_WR_IOVCNT
|
||||
#endif // !defined(IOV_MAX) || IOV_MAX >= DEFAULT_WR_IOVCNT
|
||||
|
||||
int MemcachedConnection::send_request() {
|
||||
ssize_t nwrite;
|
||||
|
||||
size_t MemcachedConnection::fill_request_buffer(struct iovec *iov,
|
||||
size_t iovlen) {
|
||||
if (sendsum_ == 0) {
|
||||
for (auto &req : sendq_) {
|
||||
if (req->canceled) {
|
||||
@ -438,32 +580,27 @@ int MemcachedConnection::send_request() {
|
||||
}
|
||||
}
|
||||
|
||||
std::array<struct iovec, DEFAULT_WR_IOVCNT> iov;
|
||||
size_t iovlen = 0;
|
||||
size_t iovcnt = 0;
|
||||
for (auto &buf : sendbufv_) {
|
||||
if (iovlen + 2 > iov.size()) {
|
||||
if (iovcnt + 2 > iovlen) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto req = buf.req;
|
||||
if (buf.headbuf.rleft()) {
|
||||
iov[iovlen++] = {buf.headbuf.pos, buf.headbuf.rleft()};
|
||||
iov[iovcnt++] = {buf.headbuf.pos, buf.headbuf.rleft()};
|
||||
}
|
||||
if (buf.send_value_left) {
|
||||
iov[iovlen++] = {req->value.data() + req->value.size() -
|
||||
iov[iovcnt++] = {req->value.data() + req->value.size() -
|
||||
buf.send_value_left,
|
||||
buf.send_value_left};
|
||||
}
|
||||
}
|
||||
|
||||
nwrite = conn_.writev_clear(iov.data(), iovlen);
|
||||
if (nwrite < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (nwrite == 0) {
|
||||
return 1;
|
||||
}
|
||||
return iovcnt;
|
||||
}
|
||||
|
||||
void MemcachedConnection::drain_send_queue(size_t nwrite) {
|
||||
sendsum_ -= nwrite;
|
||||
|
||||
while (nwrite > 0) {
|
||||
@ -488,8 +625,6 @@ int MemcachedConnection::send_request() {
|
||||
recvq_.push_back(std::move(sendq_.front()));
|
||||
sendq_.pop_front();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t MemcachedConnection::serialized_size(MemcachedRequest *req) {
|
||||
@ -549,4 +684,6 @@ int MemcachedConnection::add_request(std::unique_ptr<MemcachedRequest> req) {
|
||||
// TODO should we start write timer too?
|
||||
void MemcachedConnection::signal_write() { conn_.wlimit.startw(); }
|
||||
|
||||
int MemcachedConnection::noop() { return 0; }
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -35,12 +35,13 @@
|
||||
#include "shrpx_connection.h"
|
||||
#include "buffer.h"
|
||||
|
||||
#include "network.h"
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
struct MemcachedRequest;
|
||||
struct Address;
|
||||
|
||||
enum {
|
||||
MEMCACHED_PARSE_HEADER24,
|
||||
@ -93,7 +94,9 @@ constexpr uint8_t MEMCACHED_RES_MAGIC = 0x81;
|
||||
// https://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
|
||||
class MemcachedConnection {
|
||||
public:
|
||||
MemcachedConnection(const Address *addr, struct ev_loop *loop);
|
||||
MemcachedConnection(const Address *addr, struct ev_loop *loop,
|
||||
SSL_CTX *ssl_ctx, const StringRef &sni_name,
|
||||
MemchunkPool *mcpool);
|
||||
~MemcachedConnection();
|
||||
|
||||
void disconnect();
|
||||
@ -101,23 +104,38 @@ public:
|
||||
int add_request(std::unique_ptr<MemcachedRequest> req);
|
||||
int initiate_connection();
|
||||
|
||||
int on_connect();
|
||||
int connected();
|
||||
int on_write();
|
||||
int on_read();
|
||||
int send_request();
|
||||
|
||||
int write_clear();
|
||||
int read_clear();
|
||||
|
||||
int tls_handshake();
|
||||
int write_tls();
|
||||
int read_tls();
|
||||
|
||||
size_t fill_request_buffer(struct iovec *iov, size_t iovlen);
|
||||
void drain_send_queue(size_t nwrite);
|
||||
|
||||
void make_request(MemcachedSendbuf *sendbuf, MemcachedRequest *req);
|
||||
int parse_packet();
|
||||
size_t serialized_size(MemcachedRequest *req);
|
||||
|
||||
void signal_write();
|
||||
|
||||
int noop();
|
||||
|
||||
private:
|
||||
Connection conn_;
|
||||
std::deque<std::unique_ptr<MemcachedRequest>> recvq_;
|
||||
std::deque<std::unique_ptr<MemcachedRequest>> sendq_;
|
||||
std::deque<MemcachedSendbuf> sendbufv_;
|
||||
std::function<int(MemcachedConnection &)> do_read_, do_write_;
|
||||
std::string sni_name_;
|
||||
MemcachedParseState parse_state_;
|
||||
const Address *addr_;
|
||||
SSL_CTX *ssl_ctx_;
|
||||
// Sum of the bytes to be transmitted in sendbufv_.
|
||||
size_t sendsum_;
|
||||
bool connected_;
|
||||
|
@ -31,8 +31,12 @@
|
||||
namespace shrpx {
|
||||
|
||||
MemcachedDispatcher::MemcachedDispatcher(const Address *addr,
|
||||
struct ev_loop *loop)
|
||||
: loop_(loop), mconn_(make_unique<MemcachedConnection>(addr, loop_)) {}
|
||||
struct ev_loop *loop, SSL_CTX *ssl_ctx,
|
||||
const StringRef &sni_name,
|
||||
MemchunkPool *mcpool)
|
||||
: loop_(loop),
|
||||
mconn_(make_unique<MemcachedConnection>(addr, loop_, ssl_ctx, sni_name,
|
||||
mcpool)) {}
|
||||
|
||||
MemcachedDispatcher::~MemcachedDispatcher() {}
|
||||
|
||||
|
@ -31,15 +31,21 @@
|
||||
|
||||
#include <ev.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "memchunk.h"
|
||||
#include "network.h"
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
struct MemcachedRequest;
|
||||
class MemcachedConnection;
|
||||
struct Address;
|
||||
|
||||
class MemcachedDispatcher {
|
||||
public:
|
||||
MemcachedDispatcher(const Address *addr, struct ev_loop *loop);
|
||||
MemcachedDispatcher(const Address *addr, struct ev_loop *loop,
|
||||
SSL_CTX *ssl_ctx, const StringRef &sni_name,
|
||||
MemchunkPool *mcpool);
|
||||
~MemcachedDispatcher();
|
||||
|
||||
int add_request(std::unique_ptr<MemcachedRequest> req);
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "shrpx_config.h"
|
||||
#include "shrpx_mruby_module.h"
|
||||
#include "shrpx_downstream_connection.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
@ -95,14 +94,6 @@ int MRubyContext::run_app(Downstream *downstream, int phase) {
|
||||
|
||||
mrb_->ud = nullptr;
|
||||
|
||||
if (data.request_headers_dirty) {
|
||||
downstream->request().fs.index_headers();
|
||||
}
|
||||
|
||||
if (data.response_headers_dirty) {
|
||||
downstream->response().fs.index_headers();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -146,12 +137,12 @@ mrb_value instantiate_app(mrb_state *mrb, RProc *proc) {
|
||||
// very hard to write these kind of code because mruby has almost no
|
||||
// documentation aobut compiling or generating code, at least at the
|
||||
// time of this writing.
|
||||
RProc *compile(mrb_state *mrb, const char *filename) {
|
||||
if (filename == nullptr) {
|
||||
RProc *compile(mrb_state *mrb, const StringRef &filename) {
|
||||
if (filename.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto infile = fopen(filename, "rb");
|
||||
auto infile = fopen(filename.c_str(), "rb");
|
||||
if (infile == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -185,8 +176,8 @@ RProc *compile(mrb_state *mrb, const char *filename) {
|
||||
return proc;
|
||||
}
|
||||
|
||||
std::unique_ptr<MRubyContext> create_mruby_context(const char *filename) {
|
||||
if (!filename) {
|
||||
std::unique_ptr<MRubyContext> create_mruby_context(const StringRef &filename) {
|
||||
if (filename.empty()) {
|
||||
return make_unique<MRubyContext>(nullptr, mrb_nil_value(), mrb_nil_value());
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/proc.h>
|
||||
|
||||
#include "template.h"
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
namespace shrpx {
|
||||
@ -65,13 +67,11 @@ enum {
|
||||
struct MRubyAssocData {
|
||||
Downstream *downstream;
|
||||
int phase;
|
||||
bool request_headers_dirty;
|
||||
bool response_headers_dirty;
|
||||
};
|
||||
|
||||
RProc *compile(mrb_state *mrb, const char *filename);
|
||||
RProc *compile(mrb_state *mrb, const StringRef &filename);
|
||||
|
||||
std::unique_ptr<MRubyContext> create_mruby_context(const char *filename);
|
||||
std::unique_ptr<MRubyContext> create_mruby_context(const StringRef &filename);
|
||||
|
||||
// Return interned |ptr|.
|
||||
mrb_sym intern_ptr(mrb_state *mrb, void *ptr);
|
||||
|
@ -216,17 +216,20 @@ mrb_value request_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||
|
||||
key = mrb_funcall(mrb, key, "downcase", 0);
|
||||
|
||||
auto keyref =
|
||||
StringRef{RSTRING_PTR(key), static_cast<size_t>(RSTRING_LEN(key))};
|
||||
auto token = http2::lookup_token(keyref.byte(), keyref.size());
|
||||
|
||||
if (repl) {
|
||||
size_t p = 0;
|
||||
auto &headers = req.fs.headers();
|
||||
for (size_t i = 0; i < headers.size(); ++i) {
|
||||
auto &hd = headers[i];
|
||||
if (util::streq(std::begin(hd.name), hd.name.size(), RSTRING_PTR(key),
|
||||
RSTRING_LEN(key))) {
|
||||
auto &kv = headers[i];
|
||||
if (kv.name == keyref) {
|
||||
continue;
|
||||
}
|
||||
if (i != p) {
|
||||
headers[p++] = std::move(hd);
|
||||
headers[p++] = std::move(kv);
|
||||
}
|
||||
}
|
||||
headers.resize(p);
|
||||
@ -236,16 +239,18 @@ mrb_value request_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||
auto n = mrb_ary_len(mrb, values);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
auto value = mrb_ary_entry(values, i);
|
||||
req.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||
std::string(RSTRING_PTR(value), RSTRING_LEN(value)));
|
||||
req.fs.add_header_token(
|
||||
keyref, StringRef{RSTRING_PTR(value),
|
||||
static_cast<size_t>(RSTRING_LEN(value))},
|
||||
false, token);
|
||||
}
|
||||
} else if (!mrb_nil_p(values)) {
|
||||
req.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||
std::string(RSTRING_PTR(values), RSTRING_LEN(values)));
|
||||
req.fs.add_header_token(keyref,
|
||||
StringRef{RSTRING_PTR(values),
|
||||
static_cast<size_t>(RSTRING_LEN(values))},
|
||||
false, token);
|
||||
}
|
||||
|
||||
data->request_headers_dirty = true;
|
||||
|
||||
return mrb_nil_value();
|
||||
}
|
||||
} // namespace
|
||||
|
@ -117,17 +117,20 @@ mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||
|
||||
key = mrb_funcall(mrb, key, "downcase", 0);
|
||||
|
||||
auto keyref =
|
||||
StringRef{RSTRING_PTR(key), static_cast<size_t>(RSTRING_LEN(key))};
|
||||
auto token = http2::lookup_token(keyref.byte(), keyref.size());
|
||||
|
||||
if (repl) {
|
||||
size_t p = 0;
|
||||
auto &headers = resp.fs.headers();
|
||||
for (size_t i = 0; i < headers.size(); ++i) {
|
||||
auto &hd = headers[i];
|
||||
if (util::streq(std::begin(hd.name), hd.name.size(), RSTRING_PTR(key),
|
||||
RSTRING_LEN(key))) {
|
||||
auto &kv = headers[i];
|
||||
if (kv.name == keyref) {
|
||||
continue;
|
||||
}
|
||||
if (i != p) {
|
||||
headers[p++] = std::move(hd);
|
||||
headers[p++] = std::move(kv);
|
||||
}
|
||||
}
|
||||
headers.resize(p);
|
||||
@ -137,16 +140,18 @@ mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||
auto n = mrb_ary_len(mrb, values);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
auto value = mrb_ary_entry(values, i);
|
||||
resp.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||
std::string(RSTRING_PTR(value), RSTRING_LEN(value)));
|
||||
resp.fs.add_header_token(
|
||||
keyref, StringRef{RSTRING_PTR(value),
|
||||
static_cast<size_t>(RSTRING_LEN(value))},
|
||||
false, token);
|
||||
}
|
||||
} else if (!mrb_nil_p(values)) {
|
||||
resp.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||
std::string(RSTRING_PTR(values), RSTRING_LEN(values)));
|
||||
resp.fs.add_header_token(
|
||||
keyref, StringRef{RSTRING_PTR(values),
|
||||
static_cast<size_t>(RSTRING_LEN(values))},
|
||||
false, token);
|
||||
}
|
||||
|
||||
data->response_headers_dirty = true;
|
||||
|
||||
return mrb_nil_value();
|
||||
}
|
||||
} // namespace
|
||||
@ -197,11 +202,6 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||
resp.http_status = 200;
|
||||
}
|
||||
|
||||
if (data->response_headers_dirty) {
|
||||
resp.fs.index_headers();
|
||||
data->response_headers_dirty = false;
|
||||
}
|
||||
|
||||
if (downstream->expect_response_body() && vallen > 0) {
|
||||
body = reinterpret_cast<const uint8_t *>(val);
|
||||
bodylen = vallen;
|
||||
@ -211,8 +211,9 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||
if (cl) {
|
||||
cl->value = util::utos(bodylen);
|
||||
} else {
|
||||
resp.fs.add_header("content-length", util::utos(bodylen),
|
||||
http2::HD_CONTENT_LENGTH);
|
||||
resp.fs.add_header_token(StringRef::from_lit("content-length"),
|
||||
StringRef{util::utos(bodylen)}, false,
|
||||
http2::HD_CONTENT_LENGTH);
|
||||
}
|
||||
resp.fs.content_length = bodylen;
|
||||
|
||||
@ -220,7 +221,9 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||
if (!date) {
|
||||
auto lgconf = log_config();
|
||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||
resp.fs.add_header("date", lgconf->time_http_str, http2::HD_DATE);
|
||||
resp.fs.add_header_token(StringRef::from_lit("date"),
|
||||
StringRef{lgconf->time_http_str}, false,
|
||||
http2::HD_DATE);
|
||||
}
|
||||
|
||||
auto upstream = downstream->get_upstream();
|
||||
|
@ -66,21 +66,21 @@ void Router::add_node(RNode *node, const char *pattern, size_t patlen,
|
||||
add_next_node(node, std::move(new_node));
|
||||
}
|
||||
|
||||
bool Router::add_route(const char *pattern, size_t patlen, size_t index) {
|
||||
bool Router::add_route(const StringRef &pattern, size_t index) {
|
||||
auto node = &root_;
|
||||
size_t i = 0;
|
||||
|
||||
for (;;) {
|
||||
auto next_node = find_next_node(node, pattern[i]);
|
||||
if (next_node == nullptr) {
|
||||
add_node(node, pattern + i, patlen - i, index);
|
||||
add_node(node, pattern.c_str() + i, pattern.size() - i, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
node = next_node;
|
||||
|
||||
auto slen = patlen - i;
|
||||
auto s = pattern + i;
|
||||
auto slen = pattern.size() - i;
|
||||
auto s = pattern.c_str() + i;
|
||||
auto n = std::min(node->len, slen);
|
||||
size_t j;
|
||||
for (j = 0; j < n && node->s[j] == s[j]; ++j)
|
||||
@ -125,8 +125,8 @@ bool Router::add_route(const char *pattern, size_t patlen, size_t index) {
|
||||
|
||||
i += j;
|
||||
|
||||
assert(patlen > i);
|
||||
add_node(node, pattern + i, patlen - i, index);
|
||||
assert(pattern.size() > i);
|
||||
add_node(node, pattern.c_str() + i, pattern.size() - i, index);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -259,18 +259,16 @@ const RNode *match_partial(const RNode *node, size_t offset, const char *first,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ssize_t Router::match(const std::string &host, const char *path,
|
||||
size_t pathlen) const {
|
||||
ssize_t Router::match(const StringRef &host, const StringRef &path) const {
|
||||
const RNode *node;
|
||||
size_t offset;
|
||||
|
||||
node =
|
||||
match_complete(&offset, &root_, host.c_str(), host.c_str() + host.size());
|
||||
node = match_complete(&offset, &root_, std::begin(host), std::end(host));
|
||||
if (node == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = match_partial(node, offset, path, path + pathlen);
|
||||
node = match_partial(node, offset, std::begin(path), std::end(path));
|
||||
if (node == nullptr || node == &root_) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -55,11 +55,10 @@ struct RNode {
|
||||
class Router {
|
||||
public:
|
||||
Router();
|
||||
// Adds route |pattern| of size |patlen| with its |index|.
|
||||
bool add_route(const char *pattern, size_t patlen, size_t index);
|
||||
// Adds route |pattern| with its |index|.
|
||||
bool add_route(const StringRef &pattern, size_t index);
|
||||
// Returns the matched index of pattern. -1 if there is no match.
|
||||
ssize_t match(const std::string &host, const char *path,
|
||||
size_t pathlen) const;
|
||||
ssize_t match(const StringRef &host, const StringRef &path) const;
|
||||
|
||||
void add_node(RNode *node, const char *pattern, size_t patlen, size_t index);
|
||||
|
||||
|
@ -188,10 +188,13 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
||||
}
|
||||
|
||||
for (size_t i = 0; nv[i]; i += 2) {
|
||||
req.fs.add_header(nv[i], nv[i + 1]);
|
||||
auto name = StringRef{nv[i]};
|
||||
auto value = StringRef{nv[i + 1]};
|
||||
auto token = http2::lookup_token(name.byte(), name.size());
|
||||
req.fs.add_header_token(name, value, false, token);
|
||||
}
|
||||
|
||||
if (req.fs.index_headers() != 0) {
|
||||
if (req.fs.parse_content_length() != 0) {
|
||||
if (upstream->error_reply(downstream, 400) != 0) {
|
||||
ULOG(FATAL, upstream) << "error_reply failed";
|
||||
}
|
||||
@ -850,9 +853,12 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||
|
||||
const auto &headers = resp.fs.headers();
|
||||
|
||||
auto &httpconf = get_config()->http;
|
||||
|
||||
auto nva = std::vector<const char *>();
|
||||
// 3 for :status, :version and server
|
||||
nva.reserve(3 + headers.size());
|
||||
// 6 for :status, :version and server. 1 for last terminal nullptr.
|
||||
nva.reserve(6 + headers.size() * 2 +
|
||||
httpconf.add_response_headers.size() * 2 + 1);
|
||||
|
||||
nva.push_back(":status");
|
||||
nva.push_back(status_string.c_str());
|
||||
@ -879,6 +885,11 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||
nva.push_back(get_config()->http.server_name.c_str());
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
nva.push_back(p.name.c_str());
|
||||
nva.push_back(p.value.c_str());
|
||||
}
|
||||
|
||||
nva.push_back(nullptr);
|
||||
|
||||
rv = spdylay_submit_response(session_, downstream->get_stream_id(),
|
||||
@ -1064,8 +1075,8 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||
}
|
||||
|
||||
for (auto &p : httpconf.add_response_headers) {
|
||||
nv[hdidx++] = p.first.c_str();
|
||||
nv[hdidx++] = p.second.c_str();
|
||||
nv[hdidx++] = p.name.c_str();
|
||||
nv[hdidx++] = p.value.c_str();
|
||||
}
|
||||
|
||||
nv[hdidx++] = 0;
|
||||
|
198
src/shrpx_ssl.cc
198
src/shrpx_ssl.cc
@ -36,6 +36,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/x509.h>
|
||||
@ -124,13 +125,13 @@ set_alpn_prefs(const std::vector<std::string> &protos) {
|
||||
namespace {
|
||||
int ssl_pem_passwd_cb(char *buf, int size, int rwflag, void *user_data) {
|
||||
auto config = static_cast<Config *>(user_data);
|
||||
int len = (int)strlen(config->tls.private_key_passwd.get());
|
||||
auto len = static_cast<int>(config->tls.private_key_passwd.size());
|
||||
if (size < len + 1) {
|
||||
LOG(ERROR) << "ssl_pem_passwd_cb: buf is too small " << size;
|
||||
return 0;
|
||||
}
|
||||
// Copy string including last '\0'.
|
||||
memcpy(buf, config->tls.private_key_passwd.get(), len + 1);
|
||||
memcpy(buf, config->tls.private_key_passwd.c_str(), len + 1);
|
||||
return len;
|
||||
}
|
||||
} // namespace
|
||||
@ -485,7 +486,7 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1);
|
||||
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
|
||||
|
||||
if (tlsconf.session_cache.memcached.host) {
|
||||
if (!tlsconf.session_cache.memcached.host.empty()) {
|
||||
SSL_CTX_sess_set_new_cb(ssl_ctx, tls_session_new_cb);
|
||||
SSL_CTX_sess_set_get_cb(ssl_ctx, tls_session_get_cb);
|
||||
}
|
||||
@ -493,8 +494,8 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
SSL_CTX_set_timeout(ssl_ctx, tlsconf.session_timeout.count());
|
||||
|
||||
const char *ciphers;
|
||||
if (tlsconf.ciphers) {
|
||||
ciphers = tlsconf.ciphers.get();
|
||||
if (!tlsconf.ciphers.empty()) {
|
||||
ciphers = tlsconf.ciphers.c_str();
|
||||
} else {
|
||||
ciphers = nghttp2::ssl::DEFAULT_CIPHER_LIST;
|
||||
}
|
||||
@ -527,9 +528,9 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
|
||||
#endif // OPENSSL_NO_EC
|
||||
|
||||
if (tlsconf.dh_param_file) {
|
||||
if (!tlsconf.dh_param_file.empty()) {
|
||||
// Read DH parameters from file
|
||||
auto bio = BIO_new_file(tlsconf.dh_param_file.get(), "r");
|
||||
auto bio = BIO_new_file(tlsconf.dh_param_file.c_str(), "r");
|
||||
if (bio == nullptr) {
|
||||
LOG(FATAL) << "BIO_new_file() failed: "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
@ -548,7 +549,7 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
if (tlsconf.private_key_passwd) {
|
||||
if (!tlsconf.private_key_passwd.empty()) {
|
||||
SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb);
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)get_config());
|
||||
}
|
||||
@ -579,12 +580,12 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
DIE();
|
||||
}
|
||||
if (tlsconf.client_verify.enabled) {
|
||||
if (tlsconf.client_verify.cacert) {
|
||||
if (!tlsconf.client_verify.cacert.empty()) {
|
||||
if (SSL_CTX_load_verify_locations(
|
||||
ssl_ctx, tlsconf.client_verify.cacert.get(), nullptr) != 1) {
|
||||
ssl_ctx, tlsconf.client_verify.cacert.c_str(), nullptr) != 1) {
|
||||
|
||||
LOG(FATAL) << "Could not load trusted ca certificates from "
|
||||
<< tlsconf.client_verify.cacert.get() << ": "
|
||||
<< tlsconf.client_verify.cacert << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
@ -592,10 +593,10 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
// error even though it returns success. See
|
||||
// http://forum.nginx.org/read.php?29,242540
|
||||
ERR_clear_error();
|
||||
auto list = SSL_load_client_CA_file(tlsconf.client_verify.cacert.get());
|
||||
auto list = SSL_load_client_CA_file(tlsconf.client_verify.cacert.c_str());
|
||||
if (!list) {
|
||||
LOG(FATAL) << "Could not load ca certificates from "
|
||||
<< tlsconf.client_verify.cacert.get() << ": "
|
||||
<< tlsconf.client_verify.cacert << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
@ -660,9 +661,13 @@ int select_h1_next_proto_cb(SSL *ssl, unsigned char **out,
|
||||
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
) {
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file, const StringRef &alpn,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg)) {
|
||||
auto ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if (!ssl_ctx) {
|
||||
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
|
||||
@ -679,8 +684,8 @@ SSL_CTX *create_ssl_client_context(
|
||||
SSL_CTX_set_options(ssl_ctx, ssl_opts | tlsconf.tls_proto_mask);
|
||||
|
||||
const char *ciphers;
|
||||
if (tlsconf.ciphers) {
|
||||
ciphers = tlsconf.ciphers.get();
|
||||
if (!tlsconf.ciphers.empty()) {
|
||||
ciphers = tlsconf.ciphers.c_str();
|
||||
} else {
|
||||
ciphers = nghttp2::ssl::DEFAULT_CIPHER_LIST;
|
||||
}
|
||||
@ -698,71 +703,52 @@ SSL_CTX *create_ssl_client_context(
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
}
|
||||
|
||||
if (tlsconf.cacert) {
|
||||
if (SSL_CTX_load_verify_locations(ssl_ctx, tlsconf.cacert.get(), nullptr) !=
|
||||
1) {
|
||||
if (!cacert.empty()) {
|
||||
if (SSL_CTX_load_verify_locations(ssl_ctx, cacert.c_str(), nullptr) != 1) {
|
||||
|
||||
LOG(FATAL) << "Could not load trusted ca certificates from "
|
||||
<< tlsconf.cacert.get() << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
LOG(FATAL) << "Could not load trusted ca certificates from " << cacert
|
||||
<< ": " << ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
}
|
||||
|
||||
if (tlsconf.client.private_key_file) {
|
||||
if (!cert_file.empty()) {
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file.c_str()) != 1) {
|
||||
|
||||
LOG(FATAL) << "Could not load client certificate from " << cert_file
|
||||
<< ": " << ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
}
|
||||
|
||||
if (!private_key_file.empty()) {
|
||||
#ifndef HAVE_NEVERBLEED
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx,
|
||||
tlsconf.client.private_key_file.get(),
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key_file.c_str(),
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
LOG(FATAL) << "Could not load client private key from "
|
||||
<< tlsconf.client.private_key_file.get() << ": "
|
||||
<< private_key_file << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
#else // HAVE_NEVERBLEED
|
||||
std::array<char, NEVERBLEED_ERRBUF_SIZE> errbuf;
|
||||
if (neverbleed_load_private_key_file(nb, ssl_ctx,
|
||||
tlsconf.client.private_key_file.get(),
|
||||
if (neverbleed_load_private_key_file(nb, ssl_ctx, private_key_file.c_str(),
|
||||
errbuf.data()) != 1) {
|
||||
LOG(FATAL) << "neverbleed_load_private_key_file failed: "
|
||||
LOG(FATAL) << "neverbleed_load_private_key_file: could not load client "
|
||||
"private key from " << private_key_file << ": "
|
||||
<< errbuf.data();
|
||||
DIE();
|
||||
}
|
||||
#endif // HAVE_NEVERBLEED
|
||||
}
|
||||
if (tlsconf.client.cert_file) {
|
||||
if (SSL_CTX_use_certificate_chain_file(
|
||||
ssl_ctx, tlsconf.client.cert_file.get()) != 1) {
|
||||
|
||||
LOG(FATAL) << "Could not load client certificate from "
|
||||
<< tlsconf.client.cert_file.get() << ": "
|
||||
<< ERR_error_string(ERR_get_error(), nullptr);
|
||||
DIE();
|
||||
}
|
||||
}
|
||||
|
||||
auto &downstreamconf = get_config()->conn.downstream;
|
||||
|
||||
if (downstreamconf.proto == PROTO_HTTP2) {
|
||||
// NPN selection callback
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_h2_next_proto_cb, nullptr);
|
||||
// NPN selection callback
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_cb, nullptr);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
// ALPN advertisement; We only advertise HTTP/2
|
||||
auto proto_list = util::get_default_alpn();
|
||||
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size());
|
||||
// ALPN advertisement
|
||||
SSL_CTX_set_alpn_protos(ssl_ctx, alpn.byte(), alpn.size());
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
} else {
|
||||
// NPN selection callback
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_h1_next_proto_cb, nullptr);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_CTX_set_alpn_protos(
|
||||
ssl_ctx, reinterpret_cast<const unsigned char *>(NGHTTP2_H1_1_ALPN),
|
||||
str_size(NGHTTP2_H1_1_ALPN));
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
}
|
||||
|
||||
return ssl_ctx;
|
||||
}
|
||||
@ -997,7 +983,7 @@ int verify_hostname(X509 *cert, const char *hostname, size_t hlen,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int check_cert(SSL *ssl, const DownstreamAddr *addr) {
|
||||
int check_cert(SSL *ssl, const Address *addr, const StringRef &host) {
|
||||
auto cert = SSL_get_peer_certificate(ssl);
|
||||
if (!cert) {
|
||||
LOG(ERROR) << "No certificate found";
|
||||
@ -1011,18 +997,21 @@ int check_cert(SSL *ssl, const DownstreamAddr *addr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto &backend_sni_name = get_config()->tls.backend_sni_name;
|
||||
|
||||
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
|
||||
: StringRef(addr->host);
|
||||
if (verify_hostname(cert, hostname.c_str(), hostname.size(), &addr->addr) !=
|
||||
0) {
|
||||
if (verify_hostname(cert, host.c_str(), host.size(), addr) != 0) {
|
||||
LOG(ERROR) << "Certificate verification failed: hostname does not match";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_cert(SSL *ssl, const DownstreamAddr *addr) {
|
||||
auto &backend_sni_name = get_config()->tls.backend_sni_name;
|
||||
|
||||
auto hostname = !backend_sni_name.empty() ? StringRef(backend_sni_name)
|
||||
: StringRef(addr->host);
|
||||
return check_cert(ssl, &addr->addr, hostname);
|
||||
}
|
||||
|
||||
CertLookupTree::CertLookupTree() {
|
||||
root_.ssl_ctx = nullptr;
|
||||
root_.str = nullptr;
|
||||
@ -1257,8 +1246,8 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
||||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
|
||||
auto ssl_ctx = ssl::create_ssl_context(tlsconf.private_key_file.get(),
|
||||
tlsconf.cert_file.get()
|
||||
auto ssl_ctx = ssl::create_ssl_context(tlsconf.private_key_file.c_str(),
|
||||
tlsconf.cert_file.c_str()
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
,
|
||||
nb
|
||||
@ -1293,8 +1282,8 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
if (ssl::cert_lookup_tree_add_cert_from_file(cert_tree, ssl_ctx,
|
||||
tlsconf.cert_file.get()) == -1) {
|
||||
if (ssl::cert_lookup_tree_add_cert_from_file(
|
||||
cert_tree, ssl_ctx, tlsconf.cert_file.c_str()) == -1) {
|
||||
LOG(FATAL) << "Failed to add default certificate.";
|
||||
DIE();
|
||||
}
|
||||
@ -1304,7 +1293,7 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
||||
|
||||
bool downstream_tls_enabled() { return !get_config()->conn.downstream.no_tls; }
|
||||
|
||||
SSL_CTX *setup_client_ssl_context(
|
||||
SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb
|
||||
#endif // HAVE_NEVERBLEED
|
||||
@ -1313,11 +1302,30 @@ SSL_CTX *setup_client_ssl_context(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &tlsconf = get_config()->tls;
|
||||
auto &downstreamconf = get_config()->conn.downstream;
|
||||
|
||||
std::vector<unsigned char> h2alpn;
|
||||
StringRef alpn;
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg);
|
||||
|
||||
if (downstreamconf.proto == PROTO_HTTP2) {
|
||||
h2alpn = util::get_default_alpn();
|
||||
alpn = StringRef(h2alpn.data(), h2alpn.size());
|
||||
next_proto_select_cb = select_h2_next_proto_cb;
|
||||
} else {
|
||||
alpn = StringRef::from_lit(NGHTTP2_H1_1_ALPN);
|
||||
next_proto_select_cb = select_h1_next_proto_cb;
|
||||
}
|
||||
|
||||
return ssl::create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
nb
|
||||
nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
);
|
||||
StringRef{tlsconf.cacert}, StringRef{tlsconf.client.cert_file},
|
||||
StringRef{tlsconf.client.private_key_file}, alpn, next_proto_select_cb);
|
||||
}
|
||||
|
||||
CertLookupTree *create_cert_lookup_tree() {
|
||||
@ -1328,6 +1336,50 @@ CertLookupTree *create_cert_lookup_tree() {
|
||||
return new ssl::CertLookupTree();
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::vector<uint8_t> serialize_ssl_session(SSL_SESSION *session) {
|
||||
auto len = i2d_SSL_SESSION(session, nullptr);
|
||||
auto buf = std::vector<uint8_t>(len);
|
||||
auto p = buf.data();
|
||||
i2d_SSL_SESSION(session, &p);
|
||||
|
||||
return buf;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void try_cache_tls_session(DownstreamAddr *addr, SSL_SESSION *session,
|
||||
ev_tstamp t) {
|
||||
auto &cache = addr->tls_session_cache;
|
||||
|
||||
if (cache.last_updated + 1_min > t) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Cache for addr=" << util::to_numeric_addr(&addr->addr)
|
||||
<< " is still host. Not updating.";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Update cache entry for SSL_SESSION=" << session
|
||||
<< ", addr=" << util::to_numeric_addr(&addr->addr)
|
||||
<< ", timestamp=" << std::fixed << std::setprecision(6) << t;
|
||||
}
|
||||
|
||||
cache.session_data = serialize_ssl_session(session);
|
||||
cache.last_updated = t;
|
||||
}
|
||||
|
||||
SSL_SESSION *reuse_tls_session(const DownstreamAddr *addr) {
|
||||
auto &cache = addr->tls_session_cache;
|
||||
|
||||
if (cache.session_data.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto p = cache.session_data.data();
|
||||
return d2i_SSL_SESSION(nullptr, &p, cache.session_data.size());
|
||||
}
|
||||
|
||||
} // namespace ssl
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -39,6 +39,8 @@
|
||||
#include <neverbleed.h>
|
||||
#endif // HAVE_NEVERBLEED
|
||||
|
||||
#include "network.h"
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
class ClientHandler;
|
||||
@ -72,16 +74,19 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file
|
||||
// Create client side SSL_CTX
|
||||
SSL_CTX *create_ssl_client_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb
|
||||
neverbleed_t *nb,
|
||||
#endif // HAVE_NEVERBLEED
|
||||
);
|
||||
const StringRef &cacert, const StringRef &cert_file,
|
||||
const StringRef &private_key_file, const StringRef &alpn,
|
||||
int (*next_proto_select_cb)(SSL *s, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg));
|
||||
|
||||
ClientHandler *accept_connection(Worker *worker, int fd, sockaddr *addr,
|
||||
int addrlen, const UpstreamAddr *faddr);
|
||||
|
||||
// Check peer's certificate against first downstream address in
|
||||
// Config::downstream_addrs. We only consider first downstream since
|
||||
// we use this function for HTTP/2 downstream link only.
|
||||
// Check peer's certificate against given |address| and |host|.
|
||||
int check_cert(SSL *ssl, const Address *addr, const StringRef &host);
|
||||
int check_cert(SSL *ssl, const DownstreamAddr *addr);
|
||||
|
||||
// Retrieves DNS and IP address in subjectAltNames and commonName from
|
||||
@ -190,7 +195,7 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
||||
// Setups client side SSL_CTX. This function inspects get_config()
|
||||
// and if downstream_no_tls is true, returns nullptr. Otherwise, only
|
||||
// construct SSL_CTX if either client_mode or http2_bridge is true.
|
||||
SSL_CTX *setup_client_ssl_context(
|
||||
SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb
|
||||
#endif // HAVE_NEVERBLEED
|
||||
@ -212,6 +217,17 @@ bool downstream_tls_enabled();
|
||||
bool tls_hostname_match(const char *pattern, size_t plen, const char *hostname,
|
||||
size_t hlen);
|
||||
|
||||
// Caches |session| which is associated to remote address |addr|.
|
||||
// |session| is serialized into ASN1 representation, and stored. |t|
|
||||
// is used as a time stamp. Depending on the existing cache's time
|
||||
// stamp, |session| might not be cached.
|
||||
void try_cache_tls_session(DownstreamAddr *addr, SSL_SESSION *session,
|
||||
ev_tstamp t);
|
||||
|
||||
// Returns cached session associated |addr|. If no cache entry is
|
||||
// found associated to |addr|, nullptr will be returned.
|
||||
SSL_SESSION *reuse_tls_session(const DownstreamAddr *addr);
|
||||
|
||||
} // namespace ssl
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -67,19 +67,20 @@ std::random_device rd;
|
||||
} // namespace
|
||||
|
||||
Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||
SSL_CTX *tls_session_cache_memcached_ssl_ctx,
|
||||
ssl::CertLookupTree *cert_tree,
|
||||
const std::shared_ptr<TicketKeys> &ticket_keys)
|
||||
: randgen_(rd()),
|
||||
dconn_pool_(get_config()->conn.downstream.addr_groups.size()),
|
||||
worker_stat_(get_config()->conn.downstream.addr_groups.size()),
|
||||
dgrps_(get_config()->conn.downstream.addr_groups.size()),
|
||||
downstream_tls_session_cache_size_(0),
|
||||
loop_(loop),
|
||||
sv_ssl_ctx_(sv_ssl_ctx),
|
||||
cl_ssl_ctx_(cl_ssl_ctx),
|
||||
cert_tree_(cert_tree),
|
||||
ticket_keys_(ticket_keys),
|
||||
connect_blocker_(make_unique<ConnectBlocker>(loop_)),
|
||||
downstream_addr_groups_(get_config()->conn.downstream.addr_groups),
|
||||
connect_blocker_(make_unique<ConnectBlocker>(randgen_, loop_)),
|
||||
graceful_shutdown_(false) {
|
||||
ev_async_init(&w_, eventcb);
|
||||
w_.data = this;
|
||||
@ -90,9 +91,11 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||
|
||||
auto &session_cacheconf = get_config()->tls.session_cache;
|
||||
|
||||
if (session_cacheconf.memcached.host) {
|
||||
if (!session_cacheconf.memcached.host.empty()) {
|
||||
session_cache_memcached_dispatcher_ = make_unique<MemcachedDispatcher>(
|
||||
&session_cacheconf.memcached.addr, loop);
|
||||
&session_cacheconf.memcached.addr, loop,
|
||||
tls_session_cache_memcached_ssl_ctx,
|
||||
StringRef{session_cacheconf.memcached.host}, &mcpool_);
|
||||
}
|
||||
|
||||
auto &downstreamconf = get_config()->conn.downstream;
|
||||
@ -106,21 +109,27 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||
m = downstreamconf.addr_groups[group].addrs.size();
|
||||
}
|
||||
for (size_t idx = 0; idx < m; ++idx) {
|
||||
dgrp.http2sessions.push_back(make_unique<Http2Session>(
|
||||
loop_, cl_ssl_ctx, connect_blocker_.get(), this, group, idx));
|
||||
dgrp.http2sessions.push_back(
|
||||
make_unique<Http2Session>(loop_, cl_ssl_ctx, this, group, idx));
|
||||
}
|
||||
++group;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &group : downstream_addr_groups_) {
|
||||
for (auto &addr : group.addrs) {
|
||||
addr.connect_blocker = new ConnectBlocker(randgen_, loop_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Worker::~Worker() {
|
||||
ev_async_stop(loop_, &w_);
|
||||
ev_timer_stop(loop_, &mcpool_clear_timer_);
|
||||
|
||||
for (auto &p : downstream_tls_session_cache_) {
|
||||
for (auto session : p.second) {
|
||||
SSL_SESSION_free(session);
|
||||
for (auto &group : downstream_addr_groups_) {
|
||||
for (auto &addr : group.addrs) {
|
||||
delete addr.connect_blocker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -262,10 +271,6 @@ Http2Session *Worker::next_http2_session(size_t group) {
|
||||
return res;
|
||||
}
|
||||
|
||||
ConnectBlocker *Worker::get_connect_blocker() const {
|
||||
return connect_blocker_.get();
|
||||
}
|
||||
|
||||
struct ev_loop *Worker::get_loop() const {
|
||||
return loop_;
|
||||
}
|
||||
@ -293,8 +298,7 @@ std::mt19937 &Worker::get_randgen() { return randgen_; }
|
||||
|
||||
#ifdef HAVE_MRUBY
|
||||
int Worker::create_mruby_context() {
|
||||
auto mruby_file = get_config()->mruby_file.get();
|
||||
mruby_ctx_ = mruby::create_mruby_context(mruby_file);
|
||||
mruby_ctx_ = mruby::create_mruby_context(StringRef{get_config()->mruby_file});
|
||||
if (!mruby_ctx_) {
|
||||
return -1;
|
||||
}
|
||||
@ -307,57 +311,12 @@ mruby::MRubyContext *Worker::get_mruby_context() const {
|
||||
}
|
||||
#endif // HAVE_MRUBY
|
||||
|
||||
void Worker::cache_downstream_tls_session(const DownstreamAddr *addr,
|
||||
SSL_SESSION *session) {
|
||||
auto &tlsconf = get_config()->tls;
|
||||
|
||||
auto max = tlsconf.downstream_session_cache_per_worker;
|
||||
if (max == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (downstream_tls_session_cache_size_ >= max) {
|
||||
// It is implementation dependent which item is returned from
|
||||
// std::begin(). Probably, this depends on hash algorithm. If it
|
||||
// is random fashion, then we are mostly OK.
|
||||
auto it = std::begin(downstream_tls_session_cache_);
|
||||
assert(it != std::end(downstream_tls_session_cache_));
|
||||
auto &v = (*it).second;
|
||||
assert(!v.empty());
|
||||
auto sess = v.front();
|
||||
v.pop_front();
|
||||
SSL_SESSION_free(sess);
|
||||
if (v.empty()) {
|
||||
downstream_tls_session_cache_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
auto it = downstream_tls_session_cache_.find(addr);
|
||||
if (it == std::end(downstream_tls_session_cache_)) {
|
||||
std::tie(it, std::ignore) = downstream_tls_session_cache_.emplace(
|
||||
addr, std::deque<SSL_SESSION *>());
|
||||
}
|
||||
(*it).second.push_back(session);
|
||||
++downstream_tls_session_cache_size_;
|
||||
std::vector<DownstreamAddrGroup> &Worker::get_downstream_addr_groups() {
|
||||
return downstream_addr_groups_;
|
||||
}
|
||||
|
||||
SSL_SESSION *Worker::reuse_downstream_tls_session(const DownstreamAddr *addr) {
|
||||
auto it = downstream_tls_session_cache_.find(addr);
|
||||
if (it == std::end(downstream_tls_session_cache_)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto &v = (*it).second;
|
||||
assert(!v.empty());
|
||||
auto session = v.back();
|
||||
v.pop_back();
|
||||
--downstream_tls_session_cache_size_;
|
||||
|
||||
if (v.empty()) {
|
||||
downstream_tls_session_cache_.erase(it);
|
||||
}
|
||||
|
||||
return session;
|
||||
ConnectBlocker *Worker::get_connect_blocker() const {
|
||||
return connect_blocker_.get();
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -104,6 +104,7 @@ struct WorkerEvent {
|
||||
class Worker {
|
||||
public:
|
||||
Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
||||
SSL_CTX *tls_session_cache_memcached_ssl_ctx,
|
||||
ssl::CertLookupTree *cert_tree,
|
||||
const std::shared_ptr<TicketKeys> &ticket_keys);
|
||||
~Worker();
|
||||
@ -122,7 +123,6 @@ public:
|
||||
WorkerStat *get_worker_stat();
|
||||
DownstreamConnectionPool *get_dconn_pool();
|
||||
Http2Session *next_http2_session(size_t group);
|
||||
ConnectBlocker *get_connect_blocker() const;
|
||||
struct ev_loop *get_loop() const;
|
||||
SSL_CTX *get_sv_ssl_ctx() const;
|
||||
SSL_CTX *get_cl_ssl_ctx() const;
|
||||
@ -145,16 +145,9 @@ public:
|
||||
mruby::MRubyContext *get_mruby_context() const;
|
||||
#endif // HAVE_MRUBY
|
||||
|
||||
// Caches |session| which is associated to downstream address
|
||||
// |addr|. The caller is responsible to increment the reference
|
||||
// count of |session|, since this function does not do so.
|
||||
void cache_downstream_tls_session(const DownstreamAddr *addr,
|
||||
SSL_SESSION *session);
|
||||
// Returns cached session associated |addr|. If non-nullptr value
|
||||
// is returned, its cache entry was successfully removed from cache.
|
||||
// If no cache entry is found associated to |addr|, nullptr will be
|
||||
// returned.
|
||||
SSL_SESSION *reuse_downstream_tls_session(const DownstreamAddr *addr);
|
||||
std::vector<DownstreamAddrGroup> &get_downstream_addr_groups();
|
||||
|
||||
ConnectBlocker *get_connect_blocker() const;
|
||||
|
||||
private:
|
||||
#ifndef NOTHREADS
|
||||
@ -170,15 +163,6 @@ private:
|
||||
WorkerStat worker_stat_;
|
||||
std::vector<DownstreamGroup> dgrps_;
|
||||
|
||||
// Cache for SSL_SESSION for downstream connections. SSL_SESSION is
|
||||
// associated to downstream address. One address has multiple
|
||||
// SSL_SESSION objects. New SSL_SESSION is appended to the deque.
|
||||
// When doing eviction due to storage limitation, the SSL_SESSION
|
||||
// which sits at the front of deque is removed.
|
||||
std::unordered_map<const DownstreamAddr *, std::deque<SSL_SESSION *>>
|
||||
downstream_tls_session_cache_;
|
||||
size_t downstream_tls_session_cache_size_;
|
||||
|
||||
std::unique_ptr<MemcachedDispatcher> session_cache_memcached_dispatcher_;
|
||||
#ifdef HAVE_MRUBY
|
||||
std::unique_ptr<mruby::MRubyContext> mruby_ctx_;
|
||||
@ -192,6 +176,9 @@ private:
|
||||
ssl::CertLookupTree *cert_tree_;
|
||||
|
||||
std::shared_ptr<TicketKeys> ticket_keys_;
|
||||
std::vector<DownstreamAddrGroup> downstream_addr_groups_;
|
||||
// Worker level blocker for downstream connection. For example,
|
||||
// this is used when file decriptor is exhausted.
|
||||
std::unique_ptr<ConnectBlocker> connect_blocker_;
|
||||
|
||||
bool graceful_shutdown_;
|
||||
|
@ -64,7 +64,7 @@ void drop_privileges(
|
||||
#endif // HAVE_NEVERBLEED
|
||||
) {
|
||||
if (getuid() == 0 && get_config()->uid != 0) {
|
||||
if (initgroups(get_config()->user.get(), get_config()->gid) != 0) {
|
||||
if (initgroups(get_config()->user.c_str(), get_config()->gid) != 0) {
|
||||
auto error = errno;
|
||||
LOG(FATAL) << "Could not change supplementary groups: "
|
||||
<< strerror(error);
|
||||
@ -86,7 +86,7 @@ void drop_privileges(
|
||||
}
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
if (nb) {
|
||||
neverbleed_setuidgid(nb, get_config()->user.get(), 1);
|
||||
neverbleed_setuidgid(nb, get_config()->user.c_str(), 1);
|
||||
}
|
||||
#endif // HAVE_NEVERBLEED
|
||||
}
|
||||
@ -420,13 +420,24 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||
|
||||
#endif // HAVE_NEVERBLEED
|
||||
|
||||
MemchunkPool mcpool;
|
||||
|
||||
ev_timer renew_ticket_key_timer;
|
||||
if (!upstreamconf.no_tls) {
|
||||
auto &ticketconf = get_config()->tls.ticket;
|
||||
auto &memcachedconf = ticketconf.memcached;
|
||||
|
||||
if (!memcachedconf.host.empty()) {
|
||||
SSL_CTX *ssl_ctx = nullptr;
|
||||
|
||||
if (memcachedconf.tls) {
|
||||
ssl_ctx = conn_handler.create_tls_ticket_key_memcached_ssl_ctx();
|
||||
}
|
||||
|
||||
if (ticketconf.memcached.host) {
|
||||
conn_handler.set_tls_ticket_key_memcached_dispatcher(
|
||||
make_unique<MemcachedDispatcher>(&ticketconf.memcached.addr, loop));
|
||||
make_unique<MemcachedDispatcher>(
|
||||
&ticketconf.memcached.addr, loop, ssl_ctx,
|
||||
StringRef{memcachedconf.host}, &mcpool));
|
||||
|
||||
ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
|
||||
0.);
|
||||
|
600
src/ssl.cc
600
src/ssl.cc
@ -36,19 +36,21 @@ namespace nghttp2 {
|
||||
|
||||
namespace ssl {
|
||||
|
||||
// Recommended general purpose "Non-Backward Compatible" cipher by
|
||||
// mozilla.
|
||||
// Recommended general purpose "Intermediate compatibility" cipher
|
||||
// suites by mozilla.
|
||||
//
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS
|
||||
const char *const DEFAULT_CIPHER_LIST =
|
||||
"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-"
|
||||
"AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:"
|
||||
"DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-"
|
||||
"AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-"
|
||||
"AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-"
|
||||
"AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:"
|
||||
"DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:"
|
||||
"!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK";
|
||||
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-"
|
||||
"AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-"
|
||||
"SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-"
|
||||
"AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-"
|
||||
"ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-"
|
||||
"AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-"
|
||||
"SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-"
|
||||
"ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-"
|
||||
"SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-"
|
||||
"SHA:DES-CBC3-SHA:!DSS";
|
||||
|
||||
namespace {
|
||||
std::vector<std::mutex> ssl_global_locks;
|
||||
@ -117,571 +119,25 @@ TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) {
|
||||
return tls_info;
|
||||
}
|
||||
|
||||
// The black listed cipher suites for HTTP/2 described in RFC 7540.
|
||||
enum {
|
||||
TLS_NULL_WITH_NULL_NULL = 0x0000u,
|
||||
TLS_RSA_WITH_NULL_MD5 = 0x0001u,
|
||||
TLS_RSA_WITH_NULL_SHA = 0x0002u,
|
||||
TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003u,
|
||||
TLS_RSA_WITH_RC4_128_MD5 = 0x0004u,
|
||||
TLS_RSA_WITH_RC4_128_SHA = 0x0005u,
|
||||
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006u,
|
||||
TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007u,
|
||||
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008u,
|
||||
TLS_RSA_WITH_DES_CBC_SHA = 0x0009u,
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000Au,
|
||||
TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000Bu,
|
||||
TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000Cu,
|
||||
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000Du,
|
||||
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000Eu,
|
||||
TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000Fu,
|
||||
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010u,
|
||||
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011u,
|
||||
TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012u,
|
||||
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013u,
|
||||
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014u,
|
||||
TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015u,
|
||||
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016u,
|
||||
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017u,
|
||||
TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018u,
|
||||
TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019u,
|
||||
TLS_DH_anon_WITH_DES_CBC_SHA = 0x001Au,
|
||||
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001Bu,
|
||||
TLS_KRB5_WITH_DES_CBC_SHA = 0x001Eu,
|
||||
TLS_KRB5_WITH_3DES_EDE_CBC_SHA = 0x001Fu,
|
||||
TLS_KRB5_WITH_RC4_128_SHA = 0x0020u,
|
||||
TLS_KRB5_WITH_IDEA_CBC_SHA = 0x0021u,
|
||||
TLS_KRB5_WITH_DES_CBC_MD5 = 0x0022u,
|
||||
TLS_KRB5_WITH_3DES_EDE_CBC_MD5 = 0x0023u,
|
||||
TLS_KRB5_WITH_RC4_128_MD5 = 0x0024u,
|
||||
TLS_KRB5_WITH_IDEA_CBC_MD5 = 0x0025u,
|
||||
TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA = 0x0026u,
|
||||
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = 0x0027u,
|
||||
TLS_KRB5_EXPORT_WITH_RC4_40_SHA = 0x0028u,
|
||||
TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 = 0x0029u,
|
||||
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = 0x002Au,
|
||||
TLS_KRB5_EXPORT_WITH_RC4_40_MD5 = 0x002Bu,
|
||||
TLS_PSK_WITH_NULL_SHA = 0x002Cu,
|
||||
TLS_DHE_PSK_WITH_NULL_SHA = 0x002Du,
|
||||
TLS_RSA_PSK_WITH_NULL_SHA = 0x002Eu,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002Fu,
|
||||
TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030u,
|
||||
TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031u,
|
||||
TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032u,
|
||||
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033u,
|
||||
TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034u,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035u,
|
||||
TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036u,
|
||||
TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037u,
|
||||
TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038u,
|
||||
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039u,
|
||||
TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003Au,
|
||||
TLS_RSA_WITH_NULL_SHA256 = 0x003Bu,
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003Cu,
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003Du,
|
||||
TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003Eu,
|
||||
TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003Fu,
|
||||
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040u,
|
||||
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041u,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042u,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043u,
|
||||
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044u,
|
||||
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045u,
|
||||
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046u,
|
||||
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067u,
|
||||
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068u,
|
||||
TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069u,
|
||||
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006Au,
|
||||
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006Bu,
|
||||
TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006Cu,
|
||||
TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006Du,
|
||||
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084u,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085u,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086u,
|
||||
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087u,
|
||||
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088u,
|
||||
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089u,
|
||||
TLS_PSK_WITH_RC4_128_SHA = 0x008Au,
|
||||
TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008Bu,
|
||||
TLS_PSK_WITH_AES_128_CBC_SHA = 0x008Cu,
|
||||
TLS_PSK_WITH_AES_256_CBC_SHA = 0x008Du,
|
||||
TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008Eu,
|
||||
TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008Fu,
|
||||
TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090u,
|
||||
TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091u,
|
||||
TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092u,
|
||||
TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093u,
|
||||
TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094u,
|
||||
TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095u,
|
||||
TLS_RSA_WITH_SEED_CBC_SHA = 0x0096u,
|
||||
TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097u,
|
||||
TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098u,
|
||||
TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099u,
|
||||
TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009Au,
|
||||
TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009Bu,
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009Cu,
|
||||
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009Du,
|
||||
TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0u,
|
||||
TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1u,
|
||||
TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4u,
|
||||
TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5u,
|
||||
TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6u,
|
||||
TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7u,
|
||||
TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8u,
|
||||
TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9u,
|
||||
TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00ACu,
|
||||
TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00ADu,
|
||||
TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AEu,
|
||||
TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AFu,
|
||||
TLS_PSK_WITH_NULL_SHA256 = 0x00B0u,
|
||||
TLS_PSK_WITH_NULL_SHA384 = 0x00B1u,
|
||||
TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2u,
|
||||
TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3u,
|
||||
TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4u,
|
||||
TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5u,
|
||||
TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6u,
|
||||
TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7u,
|
||||
TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8u,
|
||||
TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9u,
|
||||
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BAu,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BBu,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BCu,
|
||||
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BDu,
|
||||
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BEu,
|
||||
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BFu,
|
||||
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0u,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1u,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2u,
|
||||
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3u,
|
||||
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4u,
|
||||
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5u,
|
||||
TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FFu,
|
||||
TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001u,
|
||||
TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002u,
|
||||
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003u,
|
||||
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004u,
|
||||
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005u,
|
||||
TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006u,
|
||||
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007u,
|
||||
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008u,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009u,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00Au,
|
||||
TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00Bu,
|
||||
TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00Cu,
|
||||
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00Du,
|
||||
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00Eu,
|
||||
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00Fu,
|
||||
TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010u,
|
||||
TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011u,
|
||||
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012u,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013u,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014u,
|
||||
TLS_ECDH_anon_WITH_NULL_SHA = 0xC015u,
|
||||
TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016u,
|
||||
TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017u,
|
||||
TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018u,
|
||||
TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019u,
|
||||
TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01Au,
|
||||
TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01Bu,
|
||||
TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01Cu,
|
||||
TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01Du,
|
||||
TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01Eu,
|
||||
TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01Fu,
|
||||
TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020u,
|
||||
TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021u,
|
||||
TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022u,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023u,
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024u,
|
||||
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025u,
|
||||
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026u,
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027u,
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028u,
|
||||
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029u,
|
||||
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02Au,
|
||||
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02Du,
|
||||
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02Eu,
|
||||
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031u,
|
||||
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032u,
|
||||
TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033u,
|
||||
TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034u,
|
||||
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035u,
|
||||
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036u,
|
||||
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037u,
|
||||
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038u,
|
||||
TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039u,
|
||||
TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03Au,
|
||||
TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03Bu,
|
||||
TLS_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC03Cu,
|
||||
TLS_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC03Du,
|
||||
TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC03Eu,
|
||||
TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC03Fu,
|
||||
TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC040u,
|
||||
TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC041u,
|
||||
TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = 0xC042u,
|
||||
TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = 0xC043u,
|
||||
TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC044u,
|
||||
TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC045u,
|
||||
TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = 0xC046u,
|
||||
TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = 0xC047u,
|
||||
TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC048u,
|
||||
TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC049u,
|
||||
TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = 0xC04Au,
|
||||
TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = 0xC04Bu,
|
||||
TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04Cu,
|
||||
TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04Du,
|
||||
TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = 0xC04Eu,
|
||||
TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = 0xC04Fu,
|
||||
TLS_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC050u,
|
||||
TLS_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC051u,
|
||||
TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC054u,
|
||||
TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC055u,
|
||||
TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC058u,
|
||||
TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC059u,
|
||||
TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = 0xC05Au,
|
||||
TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = 0xC05Bu,
|
||||
TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05Eu,
|
||||
TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05Fu,
|
||||
TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC062u,
|
||||
TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC063u,
|
||||
TLS_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC064u,
|
||||
TLS_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC065u,
|
||||
TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC066u,
|
||||
TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC067u,
|
||||
TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC068u,
|
||||
TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC069u,
|
||||
TLS_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06Au,
|
||||
TLS_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06Bu,
|
||||
TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06Eu,
|
||||
TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06Fu,
|
||||
TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = 0xC070u,
|
||||
TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = 0xC071u,
|
||||
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072u,
|
||||
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073u,
|
||||
TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074u,
|
||||
TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075u,
|
||||
TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076u,
|
||||
TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077u,
|
||||
TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078u,
|
||||
TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079u,
|
||||
TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07Au,
|
||||
TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07Bu,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07Eu,
|
||||
TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07Fu,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082u,
|
||||
TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083u,
|
||||
TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084u,
|
||||
TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085u,
|
||||
TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088u,
|
||||
TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089u,
|
||||
TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08Cu,
|
||||
TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08Du,
|
||||
TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08Eu,
|
||||
TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08Fu,
|
||||
TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092u,
|
||||
TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093u,
|
||||
TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094u,
|
||||
TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095u,
|
||||
TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096u,
|
||||
TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097u,
|
||||
TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098u,
|
||||
TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099u,
|
||||
TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09Au,
|
||||
TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09Bu,
|
||||
TLS_RSA_WITH_AES_128_CCM = 0xC09Cu,
|
||||
TLS_RSA_WITH_AES_256_CCM = 0xC09Du,
|
||||
TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0u,
|
||||
TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1u,
|
||||
TLS_PSK_WITH_AES_128_CCM = 0xC0A4u,
|
||||
TLS_PSK_WITH_AES_256_CCM = 0xC0A5u,
|
||||
TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8u,
|
||||
TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9u,
|
||||
};
|
||||
/* Conditional logic w/ lookup tables to check if id is one of the
|
||||
the black listed cipher suites for HTTP/2 described in RFC 7540.
|
||||
https://github.com/jay/http2_blacklisted_ciphers
|
||||
*/
|
||||
#define IS_CIPHER_BANNED_METHOD2(id) ( \
|
||||
(0x0000 <= id && id <= 0x00FF && \
|
||||
"\xFF\xFF\xFF\xCF\xFF\xFF\xFF\xFF\x7F\x00\x00\x00\x80\x3F\x00\x00" \
|
||||
"\xF0\xFF\xFF\x3F\xF3\xF3\xFF\xFF\x3F\x00\x00\x00\x00\x00\x00\x80" \
|
||||
[(id & 0xFF) / 8] & (1 << (id % 8))) || \
|
||||
(0xC000 <= id && id <= 0xC0FF && \
|
||||
"\xFE\xFF\xFF\xFF\xFF\x67\xFE\xFF\xFF\xFF\x33\xCF\xFC\xCF\xFF\xCF" \
|
||||
"\x3C\xF3\xFC\x3F\x33\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
|
||||
[(id & 0xFF) / 8] & (1 << (id % 8))) \
|
||||
)
|
||||
|
||||
bool check_http2_cipher_black_list(SSL *ssl) {
|
||||
auto cipher = SSL_get_current_cipher(ssl);
|
||||
int id = SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)) & 0xFFFFFF;
|
||||
|
||||
// Cipher suites in RFC 7540 black list are not allowed in HTTP/2.
|
||||
switch (SSL_CIPHER_get_id(cipher) & 0xffffu) {
|
||||
case TLS_NULL_WITH_NULL_NULL:
|
||||
case TLS_RSA_WITH_NULL_MD5:
|
||||
case TLS_RSA_WITH_NULL_SHA:
|
||||
case TLS_RSA_EXPORT_WITH_RC4_40_MD5:
|
||||
case TLS_RSA_WITH_RC4_128_MD5:
|
||||
case TLS_RSA_WITH_RC4_128_SHA:
|
||||
case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
|
||||
case TLS_RSA_WITH_IDEA_CBC_SHA:
|
||||
case TLS_RSA_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_DES_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_DES_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_DES_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_DES_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DH_anon_EXPORT_WITH_RC4_40_MD5:
|
||||
case TLS_DH_anon_WITH_RC4_128_MD5:
|
||||
case TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_DES_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_KRB5_WITH_DES_CBC_SHA:
|
||||
case TLS_KRB5_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_KRB5_WITH_RC4_128_SHA:
|
||||
case TLS_KRB5_WITH_IDEA_CBC_SHA:
|
||||
case TLS_KRB5_WITH_DES_CBC_MD5:
|
||||
case TLS_KRB5_WITH_3DES_EDE_CBC_MD5:
|
||||
case TLS_KRB5_WITH_RC4_128_MD5:
|
||||
case TLS_KRB5_WITH_IDEA_CBC_MD5:
|
||||
case TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA:
|
||||
case TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA:
|
||||
case TLS_KRB5_EXPORT_WITH_RC4_40_SHA:
|
||||
case TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5:
|
||||
case TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5:
|
||||
case TLS_KRB5_EXPORT_WITH_RC4_40_MD5:
|
||||
case TLS_PSK_WITH_NULL_SHA:
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA:
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA:
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_AES_256_CBC_SHA:
|
||||
case TLS_RSA_WITH_NULL_SHA256:
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
|
||||
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
|
||||
case TLS_PSK_WITH_RC4_128_SHA:
|
||||
case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA:
|
||||
case TLS_PSK_WITH_AES_256_CBC_SHA:
|
||||
case TLS_DHE_PSK_WITH_RC4_128_SHA:
|
||||
case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
|
||||
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
|
||||
case TLS_RSA_PSK_WITH_RC4_128_SHA:
|
||||
case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
|
||||
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
|
||||
case TLS_RSA_WITH_SEED_CBC_SHA:
|
||||
case TLS_DH_DSS_WITH_SEED_CBC_SHA:
|
||||
case TLS_DH_RSA_WITH_SEED_CBC_SHA:
|
||||
case TLS_DHE_DSS_WITH_SEED_CBC_SHA:
|
||||
case TLS_DHE_RSA_WITH_SEED_CBC_SHA:
|
||||
case TLS_DH_anon_WITH_SEED_CBC_SHA:
|
||||
case TLS_RSA_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_RSA_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_PSK_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_PSK_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_PSK_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_PSK_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_PSK_WITH_NULL_SHA256:
|
||||
case TLS_PSK_WITH_NULL_SHA384:
|
||||
case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA256:
|
||||
case TLS_DHE_PSK_WITH_NULL_SHA384:
|
||||
case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA256:
|
||||
case TLS_RSA_PSK_WITH_NULL_SHA384:
|
||||
case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
|
||||
case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
|
||||
case TLS_ECDH_ECDSA_WITH_NULL_SHA:
|
||||
case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
|
||||
case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDH_RSA_WITH_NULL_SHA:
|
||||
case TLS_ECDH_RSA_WITH_RC4_128_SHA:
|
||||
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDHE_RSA_WITH_NULL_SHA:
|
||||
case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
|
||||
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDH_anon_WITH_NULL_SHA:
|
||||
case TLS_ECDH_anon_WITH_RC4_128_SHA:
|
||||
case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
|
||||
case TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
|
||||
case TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
|
||||
case TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
|
||||
case TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
|
||||
case TLS_ECDHE_PSK_WITH_RC4_128_SHA:
|
||||
case TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
|
||||
case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
|
||||
case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
|
||||
case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
|
||||
case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
|
||||
case TLS_ECDHE_PSK_WITH_NULL_SHA:
|
||||
case TLS_ECDHE_PSK_WITH_NULL_SHA256:
|
||||
case TLS_ECDHE_PSK_WITH_NULL_SHA384:
|
||||
case TLS_RSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_RSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DH_anon_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DH_anon_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_RSA_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_RSA_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_DH_anon_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_DH_anon_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_PSK_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_PSK_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_PSK_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_PSK_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256:
|
||||
case TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384:
|
||||
case TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384:
|
||||
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
|
||||
case TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
|
||||
case TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
|
||||
case TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
|
||||
case TLS_RSA_WITH_AES_128_CCM:
|
||||
case TLS_RSA_WITH_AES_256_CCM:
|
||||
case TLS_RSA_WITH_AES_128_CCM_8:
|
||||
case TLS_RSA_WITH_AES_256_CCM_8:
|
||||
case TLS_PSK_WITH_AES_128_CCM:
|
||||
case TLS_PSK_WITH_AES_256_CCM:
|
||||
case TLS_PSK_WITH_AES_128_CCM_8:
|
||||
case TLS_PSK_WITH_AES_256_CCM_8:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return IS_CIPHER_BANNED_METHOD2(id);
|
||||
}
|
||||
|
||||
bool check_http2_tls_version(SSL *ssl) {
|
||||
|
@ -387,18 +387,31 @@ public:
|
||||
using const_pointer = const value_type *;
|
||||
using const_iterator = const_pointer;
|
||||
|
||||
StringRef() : base(""), len(0) {}
|
||||
constexpr StringRef() : base(""), len(0) {}
|
||||
explicit StringRef(const std::string &s) : base(s.c_str()), len(s.size()) {}
|
||||
explicit StringRef(const ImmutableString &s)
|
||||
: base(s.c_str()), len(s.size()) {}
|
||||
StringRef(const char *s) : base(s), len(strlen(s)) {}
|
||||
StringRef(const char *s, size_t n) : base(s), len(n) {}
|
||||
template <typename CharT>
|
||||
constexpr StringRef(const CharT *s, size_t n)
|
||||
: base(reinterpret_cast<const char *>(s)), len(n) {}
|
||||
template <typename InputIt>
|
||||
StringRef(InputIt first, InputIt last)
|
||||
: base(&*first), len(std::distance(first, last)) {}
|
||||
template <typename InputIt>
|
||||
StringRef(InputIt *first, InputIt *last)
|
||||
: base(first), len(std::distance(first, last)) {}
|
||||
template <size_t N> static StringRef from_lit(const char(&s)[N]) {
|
||||
template <typename CharT, size_t N>
|
||||
constexpr static StringRef from_lit(const CharT(&s)[N]) {
|
||||
return StringRef(s, N - 1);
|
||||
}
|
||||
static StringRef from_maybe_nullptr(const char *s) {
|
||||
if (s == nullptr) {
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
return StringRef(s);
|
||||
}
|
||||
|
||||
const_iterator begin() const { return base; };
|
||||
const_iterator cbegin() const { return base; };
|
||||
@ -412,6 +425,9 @@ public:
|
||||
const_reference operator[](size_type pos) const { return *(base + pos); }
|
||||
|
||||
std::string str() const { return std::string(base, len); }
|
||||
const uint8_t *byte() const {
|
||||
return reinterpret_cast<const uint8_t *>(base);
|
||||
}
|
||||
|
||||
private:
|
||||
const char *base;
|
||||
|
98
src/util.cc
98
src/util.cc
@ -57,7 +57,6 @@
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "timegm.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
@ -651,6 +650,43 @@ std::string numeric_name(const struct sockaddr *sa, socklen_t salen) {
|
||||
return host.data();
|
||||
}
|
||||
|
||||
std::string to_numeric_addr(const Address *addr) {
|
||||
auto family = addr->su.storage.ss_family;
|
||||
if (family == AF_UNIX) {
|
||||
return addr->su.un.sun_path;
|
||||
}
|
||||
|
||||
std::array<char, NI_MAXHOST> host;
|
||||
std::array<char, NI_MAXSERV> serv;
|
||||
auto rv =
|
||||
getnameinfo(&addr->su.sa, addr->len, host.data(), host.size(),
|
||||
serv.data(), serv.size(), NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if (rv != 0) {
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
auto hostlen = strlen(host.data());
|
||||
auto servlen = strlen(serv.data());
|
||||
|
||||
std::string s;
|
||||
char *p;
|
||||
if (family == AF_INET6) {
|
||||
s.resize(hostlen + servlen + 2 + 1);
|
||||
p = &s[0];
|
||||
*p++ = '[';
|
||||
p = std::copy_n(host.data(), hostlen, p);
|
||||
*p++ = ']';
|
||||
} else {
|
||||
s.resize(hostlen + servlen + 1);
|
||||
p = &s[0];
|
||||
p = std::copy_n(host.data(), hostlen, p);
|
||||
}
|
||||
*p++ = ':';
|
||||
std::copy_n(serv.data(), servlen, p);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int STDERR_COPY = -1;
|
||||
static int STDOUT_COPY = -1;
|
||||
|
||||
@ -1114,25 +1150,53 @@ std::string dtos(double n) {
|
||||
return utos(static_cast<int64_t>(n)) + "." + (f.size() == 1 ? "0" : "") + f;
|
||||
}
|
||||
|
||||
std::string make_hostport(const char *host, uint16_t port) {
|
||||
auto ipv6 = ipv6_numeric_addr(host);
|
||||
std::string hostport;
|
||||
|
||||
if (ipv6) {
|
||||
hostport += '[';
|
||||
}
|
||||
|
||||
hostport += host;
|
||||
|
||||
if (ipv6) {
|
||||
hostport += ']';
|
||||
}
|
||||
|
||||
std::string make_http_hostport(const StringRef &host, uint16_t port) {
|
||||
if (port != 80 && port != 443) {
|
||||
hostport += ':';
|
||||
hostport += utos(port);
|
||||
return make_hostport(host, port);
|
||||
}
|
||||
|
||||
auto ipv6 = ipv6_numeric_addr(host.c_str());
|
||||
|
||||
std::string hostport;
|
||||
hostport.resize(host.size() + (ipv6 ? 2 : 0));
|
||||
|
||||
auto p = &hostport[0];
|
||||
|
||||
if (ipv6) {
|
||||
*p++ = '[';
|
||||
}
|
||||
|
||||
p = std::copy_n(host.c_str(), host.size(), p);
|
||||
|
||||
if (ipv6) {
|
||||
*p++ = ']';
|
||||
}
|
||||
|
||||
return hostport;
|
||||
}
|
||||
|
||||
std::string make_hostport(const StringRef &host, uint16_t port) {
|
||||
auto ipv6 = ipv6_numeric_addr(host.c_str());
|
||||
auto serv = utos(port);
|
||||
|
||||
std::string hostport;
|
||||
hostport.resize(host.size() + (ipv6 ? 2 : 0) + 1 + serv.size());
|
||||
|
||||
auto p = &hostport[0];
|
||||
|
||||
if (ipv6) {
|
||||
*p++ = '[';
|
||||
}
|
||||
|
||||
p = std::copy_n(host.c_str(), host.size(), p);
|
||||
|
||||
if (ipv6) {
|
||||
*p++ = ']';
|
||||
}
|
||||
|
||||
*p++ = ':';
|
||||
std::copy_n(serv.c_str(), serv.size(), p);
|
||||
|
||||
return hostport;
|
||||
}
|
||||
|
||||
|
15
src/util.h
15
src/util.h
@ -49,6 +49,9 @@
|
||||
|
||||
#include "http-parser/http_parser.h"
|
||||
|
||||
#include "template.h"
|
||||
#include "network.h"
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
// The additional HTTP/2 protocol ALPN protocol identifier we also
|
||||
@ -459,6 +462,12 @@ bool numeric_host(const char *hostname, int family);
|
||||
// failed, "unknown" is returned.
|
||||
std::string numeric_name(const struct sockaddr *sa, socklen_t salen);
|
||||
|
||||
// Returns string representation of numeric address and port of
|
||||
// |addr|. If address family is AF_UNIX, this return path to UNIX
|
||||
// domain socket. Otherwise, the format is like <HOST>:<PORT>. For
|
||||
// IPv6 address, address is enclosed by square brackets ([]).
|
||||
std::string to_numeric_addr(const Address *addr);
|
||||
|
||||
// Makes internal copy of stderr (and possibly stdout in the future),
|
||||
// which is then used as pointer to /dev/stderr or /proc/self/fd/2
|
||||
void store_original_fds();
|
||||
@ -618,7 +627,11 @@ std::string format_duration(double t);
|
||||
// Creates "host:port" string using given |host| and |port|. If
|
||||
// |host| is numeric IPv6 address (e.g., ::1), it is enclosed by "["
|
||||
// and "]". If |port| is 80 or 443, port part is omitted.
|
||||
std::string make_hostport(const char *host, uint16_t port);
|
||||
std::string make_http_hostport(const StringRef &host, uint16_t port);
|
||||
|
||||
// Just like make_http_hostport(), but doesn't treat 80 and 443
|
||||
// specially.
|
||||
std::string make_hostport(const StringRef &host, uint16_t port);
|
||||
|
||||
// Dumps |src| of length |len| in the format similar to `hexdump -C`.
|
||||
void hexdump(FILE *out, const uint8_t *src, size_t len);
|
||||
|
@ -455,4 +455,15 @@ void test_util_parse_config_str_list(void) {
|
||||
CU_ASSERT("charlie" == res[2]);
|
||||
}
|
||||
|
||||
void test_util_make_http_hostport(void) {
|
||||
CU_ASSERT("localhost" == util::make_http_hostport("localhost", 80));
|
||||
CU_ASSERT("[::1]" == util::make_http_hostport("::1", 443));
|
||||
CU_ASSERT("localhost:3000" == util::make_http_hostport("localhost", 3000));
|
||||
}
|
||||
|
||||
void test_util_make_hostport(void) {
|
||||
CU_ASSERT("localhost:80" == util::make_hostport("localhost", 80));
|
||||
CU_ASSERT("[::1]:443" == util::make_hostport("::1", 443));
|
||||
}
|
||||
|
||||
} // namespace shrpx
|
||||
|
@ -57,6 +57,8 @@ void test_util_parse_http_date(void);
|
||||
void test_util_localtime_date(void);
|
||||
void test_util_get_uint64(void);
|
||||
void test_util_parse_config_str_list(void);
|
||||
void test_util_make_http_hostport(void);
|
||||
void test_util_make_hostport(void);
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
|
@ -36,10 +36,6 @@
|
||||
#include "nghttp2_test_helper.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
#define OB_CTRL(ITEM) nghttp2_outbound_item_get_ctrl_frame(ITEM)
|
||||
#define OB_CTRL_TYPE(ITEM) nghttp2_outbound_item_get_ctrl_frame_type(ITEM)
|
||||
#define OB_DATA(ITEM) nghttp2_outbound_item_get_data_frame(ITEM)
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[65535];
|
||||
size_t length;
|
||||
|
4
third-party/Makefile.am
vendored
4
third-party/Makefile.am
vendored
@ -55,7 +55,9 @@ mruby:
|
||||
all-local: mruby
|
||||
|
||||
clean-local:
|
||||
-rm -rf "${abs_builddir}/mruby/build"
|
||||
MRUBY_CONFIG="${srcdir}/build_config.rb" \
|
||||
BUILD_DIR="${abs_builddir}/mruby/build" \
|
||||
"${srcdir}/mruby/minirake" -f "${srcdir}/mruby/Rakefile" clean
|
||||
|
||||
endif # HAVE_MRUBY
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user