Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
0caefe20
Commit
0caefe20
authored
Jan 09, 2016
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into simple-extensions
parents
9c84f60b
a7ec9050
Changes
70
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
70 changed files
with
1553 additions
and
628 deletions
+1553
-628
COPYING
COPYING
+1
-1
LICENSE
LICENSE
+1
-0
README.rst
README.rst
+1
-1
configure.ac
configure.ac
+24
-3
doc/conf.py.in
doc/conf.py.in
+1
-1
doc/h2load.1
doc/h2load.1
+23
-1
doc/h2load.1.rst
doc/h2load.1.rst
+17
-0
doc/h2load.h2r
doc/h2load.h2r
+3
-1
doc/nghttp.1
doc/nghttp.1
+3
-2
doc/nghttp.1.rst
doc/nghttp.1.rst
+2
-1
doc/nghttpd.1
doc/nghttpd.1
+1
-1
doc/nghttpx.1
doc/nghttpx.1
+1
-1
doc/sources/h2load-howto.rst
doc/sources/h2load-howto.rst
+26
-18
lib/includes/nghttp2/nghttp2.h
lib/includes/nghttp2/nghttp2.h
+9
-5
lib/nghttp2_outbound_item.h
lib/nghttp2_outbound_item.h
+0
-3
lib/nghttp2_pq.c
lib/nghttp2_pq.c
+7
-5
lib/nghttp2_session.c
lib/nghttp2_session.c
+216
-172
lib/nghttp2_session.h
lib/nghttp2_session.h
+18
-21
lib/nghttp2_stream.c
lib/nghttp2_stream.c
+76
-22
lib/nghttp2_stream.h
lib/nghttp2_stream.h
+10
-1
lib/nghttp2_submit.c
lib/nghttp2_submit.c
+18
-12
src/HttpServer.cc
src/HttpServer.cc
+10
-5
src/HttpServer.h
src/HttpServer.h
+1
-0
src/asio_client_session.cc
src/asio_client_session.cc
+14
-2
src/asio_client_session_impl.cc
src/asio_client_session_impl.cc
+106
-20
src/asio_client_session_impl.h
src/asio_client_session_impl.h
+12
-1
src/asio_client_session_tcp_impl.cc
src/asio_client_session_tcp_impl.cc
+5
-4
src/asio_client_session_tls_impl.cc
src/asio_client_session_tls_impl.cc
+2
-3
src/asio_io_service_pool.cc
src/asio_io_service_pool.cc
+5
-0
src/asio_io_service_pool.h
src/asio_io_service_pool.h
+4
-0
src/asio_server.cc
src/asio_server.cc
+19
-4
src/asio_server.h
src/asio_server.h
+10
-1
src/asio_server_connection.h
src/asio_server_connection.h
+88
-18
src/asio_server_http2.cc
src/asio_server_http2.cc
+13
-0
src/asio_server_http2_handler.cc
src/asio_server_http2_handler.cc
+9
-1
src/asio_server_http2_handler.h
src/asio_server_http2_handler.h
+5
-1
src/asio_server_http2_impl.cc
src/asio_server_http2_impl.cc
+20
-2
src/asio_server_http2_impl.h
src/asio_server_http2_impl.h
+6
-0
src/asio_server_request.cc
src/asio_server_request.cc
+4
-0
src/asio_server_request_impl.cc
src/asio_server_request_impl.cc
+8
-0
src/asio_server_request_impl.h
src/asio_server_request_impl.h
+5
-0
src/h2load.cc
src/h2load.cc
+182
-85
src/h2load.h
src/h2load.h
+28
-6
src/h2load_http1_session.cc
src/h2load_http1_session.cc
+10
-8
src/h2load_http1_session.h
src/h2load_http1_session.h
+1
-2
src/h2load_http2_session.cc
src/h2load_http2_session.cc
+26
-11
src/h2load_http2_session.h
src/h2load_http2_session.h
+1
-1
src/h2load_session.h
src/h2load_session.h
+1
-1
src/h2load_spdy_session.cc
src/h2load_spdy_session.cc
+5
-10
src/h2load_spdy_session.h
src/h2load_spdy_session.h
+1
-1
src/http2.cc
src/http2.cc
+4
-0
src/includes/nghttp2/asio_http2_client.h
src/includes/nghttp2/asio_http2_client.h
+7
-1
src/includes/nghttp2/asio_http2_server.h
src/includes/nghttp2/asio_http2_server.h
+13
-0
src/nghttpd.cc
src/nghttpd.cc
+7
-0
src/shrpx.cc
src/shrpx.cc
+5
-4
src/shrpx.h
src/shrpx.h
+4
-0
src/shrpx_client_handler.cc
src/shrpx_client_handler.cc
+33
-5
src/shrpx_config.cc
src/shrpx_config.cc
+11
-6
src/shrpx_config_test.cc
src/shrpx_config_test.cc
+7
-2
src/shrpx_http2_session.cc
src/shrpx_http2_session.cc
+0
-35
src/shrpx_http2_upstream.cc
src/shrpx_http2_upstream.cc
+2
-1
src/shrpx_http_downstream_connection.cc
src/shrpx_http_downstream_connection.cc
+0
-36
src/shrpx_https_upstream.cc
src/shrpx_https_upstream.cc
+2
-6
src/shrpx_spdy_upstream.cc
src/shrpx_spdy_upstream.cc
+2
-0
src/shrpx_ssl.cc
src/shrpx_ssl.cc
+1
-0
src/ssl.cc
src/ssl.cc
+5
-8
tests/main.c
tests/main.c
+8
-2
tests/nghttp2_session_test.c
tests/nghttp2_session_test.c
+378
-61
tests/nghttp2_session_test.h
tests/nghttp2_session_test.h
+4
-1
third-party/neverbleed
third-party/neverbleed
+1
-1
No files found.
COPYING
View file @
0caefe20
The MIT License
Copyright (c) 2012, 2014, 2015 Tatsuhiro Tsujikawa
Copyright (c) 2012, 2014, 2015
, 2016
Tatsuhiro Tsujikawa
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
...
...
LICENSE
0 → 100644
View file @
0caefe20
See COPYING
README.rst
View file @
0caefe20
...
...
@@ -274,7 +274,7 @@ for this 24 bytes byte string and updated API.
``NGHTTP2_CLIENT_MAGIC_LEN``.
* ``NGHTTP2_BAD_PREFACE`` was renamed as ``NGHTTP2_BAD_CLIENT_MAGIC``
The alreay deprecated ``NGHTTP2_CLIENT_CONNECTION_HEADER`` and
The alrea
d
y deprecated ``NGHTTP2_CLIENT_CONNECTION_HEADER`` and
``NGHTTP2_CLIENT_CONNECTION_HEADER_LEN`` were removed.
If application uses these macros, just replace old ones with new ones.
...
...
configure.ac
View file @
0caefe20
...
...
@@ -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.
5
.1-DEV], [t-tujikawa@users.sourceforge.net])
AC_INIT([nghttp2], [1.
6
.1-DEV], [t-tujikawa@users.sourceforge.net])
AC_CONFIG_AUX_DIR([.])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
...
...
@@ -46,9 +46,9 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 1
7
)
AC_SUBST(LT_CURRENT, 1
8
)
AC_SUBST(LT_REVISION, 0)
AC_SUBST(LT_AGE,
3
)
AC_SUBST(LT_AGE,
4
)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
minor=`echo $PACKAGE_VERSION |cut -d. -f2 | sed -e "s/[^0-9]//g"`
...
...
@@ -104,6 +104,11 @@ AC_ARG_ENABLE([failmalloc],
[Do not build failmalloc test program])],
[request_failmalloc=$enableval], [request_failmalloc=yes])
AC_ARG_ENABLE([lib-only],
[AS_HELP_STRING([--enable-lib-only],
[Build libnghttp2 only. This is a short hand for --disable-app --disable-examples --disable-hpack-tools --disable-python-bindings])],
[request_lib_only=$enableval], [request_lib_only=no])
AC_ARG_WITH([libxml2],
[AS_HELP_STRING([--with-libxml2],
[Use libxml2 [default=check]])],
...
...
@@ -150,6 +155,13 @@ PKG_PROG_PKG_CONFIG([0.20])
AM_PATH_PYTHON([2.7],, [:])
if [test "x$request_lib_only" = "xyes"]; then
request_app=no
request_hpack_tools=no
request_examples=no
request_python_bindings=no
fi
if [test "x$request_python_bindings" != "xno"]; then
AX_PYTHON_DEVEL([>= '2.7'])
fi
...
...
@@ -243,6 +255,11 @@ if test "x${have_zlib}" = "xno"; then
AC_MSG_NOTICE($ZLIB_PKG_ERRORS)
fi
# dl: openssl requires libdl when it is statically linked.
LIBS_OLD=$LIBS
AC_SEARCH_LIBS([dlopen], [dl], [APPLDFLAGS="-ldl $APPLDFLAGS"], [], [])
LIBS=$LIBS_OLD
# cunit
PKG_CHECK_MODULES([CUNIT], [cunit >= 2.1], [have_cunit=yes], [have_cunit=no])
# If pkg-config does not find cunit, check it using AC_CHECK_LIB. We
...
...
@@ -613,6 +630,10 @@ AC_CHECK_FUNCS([ \
AC_CHECK_FUNC([timerfd_create],
[have_timerfd_create=yes], [have_timerfd_create=no])
# 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>]])
# Checks for epoll availability, primarily for examples/tiny-nghttpd
AX_HAVE_EPOLL([have_epoll=yes], [have_epoll=no])
...
...
doc/conf.py.in
View file @
0caefe20
...
...
@@ -66,7 +66,7 @@ master_doc = 'index'
# General information about the project.
project = u'nghttp2'
copyright = u'2012, 2015, Tatsuhiro Tsujikawa'
copyright = u'2012, 2015,
2016,
Tatsuhiro Tsujikawa'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
...
...
doc/h2load.1
View file @
0caefe20
.\" Man page generated from reStructuredText.
.
.TH "H2LOAD" "1" "
November 29, 2015" "1.5.1-DEV
" "nghttp2"
.TH "H2LOAD" "1" "
December 23, 2015" "1.6.0
" "nghttp2"
.SH NAME
h2load \- HTTP/2 benchmarking tool
.
...
...
@@ -374,6 +374,28 @@ The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.TP
.B req/s
.INDENT 7.0
.TP
.B min
The minimum request per second among all clients.
.TP
.B max
The maximum request per second among all clients.
.TP
.B mean
The mean request per second among all clients.
.TP
.B sd
The standard deviation of request per second among all clients.
server.
.TP
.B +/\- sd
The fraction of the number of connections within standard
deviation range (mean +/\- sd) against total number of successful
connections.
.UNINDENT
.UNINDENT
.SH FLOW CONTROL
.sp
...
...
doc/h2load.1.rst
View file @
0caefe20
...
...
@@ -213,6 +213,8 @@ is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms
(hours, minutes, seconds and milliseconds, respectively). If a unit
is omitted, a second is used as unit.
.. _h2load-1-output:
OUTPUT
------
...
...
@@ -301,6 +303,21 @@ time for 1st byte (of (decrypted in case of TLS) application data)
deviation range (mean +/- sd) against total number of successful
connections.
req/s
min
The minimum request per second among all clients.
max
The maximum request per second among all clients.
mean
The mean request per second among all clients.
sd
The standard deviation of request per second among all clients.
server.
+/- sd
The fraction of the number of connections within standard
deviation range (mean +/- sd) against total number of successful
connections.
FLOW CONTROL
------------
...
...
doc/h2load.h2r
View file @
0caefe20
.. _h2load-1-output:
OUTPUT
------
...
...
@@ -86,7 +88,7 @@ time for 1st byte (of (decrypted in case of TLS) application data)
deviation range (mean +/- sd) against total number of successful
connections.
req/s
(client)
req/s
min
The minimum request per second among all clients.
max
...
...
doc/nghttp.1
View file @
0caefe20
.\" Man page generated from reStructuredText.
.
.TH "NGHTTP" "1" "
November 29, 2015" "1.5.1-DEV
" "nghttp2"
.TH "NGHTTP" "1" "
December 23, 2015" "1.6.0
" "nghttp2"
.SH NAME
nghttp \- HTTP/2 client
.
...
...
@@ -152,7 +152,8 @@ Default: \fB16\fP
.B \-M, \-\-peer\-max\-concurrent\-streams=<N>
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
.sp
Default: \fB100\fP
.UNINDENT
.INDENT 0.0
.TP
...
...
doc/nghttp.1.rst
View file @
0caefe20
...
...
@@ -116,7 +116,8 @@ OPTIONS
Use <N> as SETTINGS_MAX_CONCURRENT_STREAMS value of
remote endpoint as if it is received in SETTINGS frame.
The default is large enough as it is seen as unlimited.
Default: ``100``
.. option:: -c, --header-table-size=<SIZE>
...
...
doc/nghttpd.1
View file @
0caefe20
.\" Man page generated from reStructuredText.
.
.TH "NGHTTPD" "1" "
November 29, 2015" "1.5.1-DEV
" "nghttp2"
.TH "NGHTTPD" "1" "
December 23, 2015" "1.6.0
" "nghttp2"
.SH NAME
nghttpd \- HTTP/2 server
.
...
...
doc/nghttpx.1
View file @
0caefe20
.\
" Man page generated from reStructuredText.
.
.TH "
NGHTTPX
" "
1
" "
November
29
,
2015
" "
1.5.1
-
DEV
" "
nghttp2
"
.TH "
NGHTTPX
" "
1
" "
December
23
,
2015
" "
1.6.0
" "
nghttp2
"
.SH NAME
nghttpx \- HTTP/2 proxy
.
...
...
doc/sources/h2load-howto.rst
View file @
0caefe20
h2load - HTTP/2 benchmarking tool - HOW-TO
==========================================
h2load is benchmarking tool for HTTP/2. If built with
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
both
HTTP/2 and SPDY
.
supports SPDY protocol. It supports SSL/TLS and clear text for
all
supported protocols
.
Basic Usage
-----------
...
...
@@ -22,29 +22,37 @@ In order to set benchmark settings, specify following 3 options.
If ``auto`` is given, the number of given URIs is used.
Default: ``auto``
For SSL/TLS connection, the protocol will be negotiated via ALPN/NPN.
You can set specific protocols in ``--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.
Here is a command-line to perform benchmark to URI \https://localhost
using total 100000 requests, 100 concurrent clients and 10 max
concurrent streams::
concurrent streams:
.. code-block:: text
$ h2load -n100000 -c100 -m10 https://localhost
The benchmarking result looks like this:
:
The benchmarking result looks like this:
finished in 0 sec, 385 millisec and 851 microsec, 2591 req/s, 1689 kbytes/s
requests: 1000 total, 1000 started, 1000 done, 1000 succeeded, 0 failed, 0 errored
status codes: 1000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 667500 bytes total, 28700 bytes headers, 612000 bytes data
.. code-block:: text
The number of ``failed`` is the number of requests returned with non
2xx status. The number of ``error`` is the number of ``failed`` plus
the number of requests which failed with connection error.
finished in 7.08s, 141164.80 req/s, 555.33MB/s
requests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout
status codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx
traffic: 4125025824 bytes total, 11023424 bytes headers (space savings 93.07%), 4096000000 bytes data
min max mean sd +/- sd
time for request: 15.31ms 146.85ms 69.78ms 9.26ms 92.43%
time for connect: 1.08ms 25.04ms 10.71ms 9.80ms 64.00%
time to 1st byte: 25.36ms 184.96ms 79.11ms 53.97ms 78.00%
req/s (client) : 1412.04 1447.84 1426.52 10.57 63.00%
The number of ``total`` in ``traffic`` is the received application
data. If SSL/TLS is used, this number is calculated after decryption.
The number of ``headers`` is the sum of payload size of response
HEADERS (or SYN_REPLY for SPDY). This number comes before
decompressing header block. The number of ``data`` is the sum of
response body.
See the h2load manual page :ref:`h2load-1-output` section for the
explanation of the above numbers.
Flow Control
------------
...
...
lib/includes/nghttp2/nghttp2.h
View file @
0caefe20
...
...
@@ -3296,6 +3296,9 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
* :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
* No stream ID is available because maximum stream ID was
* reached.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* Trying to depend on itself (new stream ID equals
* ``pri_spec->stream_id``).
*
* .. warning::
*
...
...
@@ -3407,7 +3410,7 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* has already sent and if `nghttp2_submit_trailer()` is called before
* any response HEADERS submission (usually by
* `nghttp2_submit_response()`), the content of |nva| will be sent as
* reponse headers, which will result in error.
* re
s
ponse headers, which will result in error.
*
* This function has the same effect with `nghttp2_submit_headers()`,
* with flags = :enum:`NGHTTP2_FLAG_END_HEADERS` and both pri_spec and
...
...
@@ -3506,7 +3509,8 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* No stream ID is available because maximum stream ID was
* reached.
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
* The |stream_id| is 0; or trying to depend on itself (stream ID
* equals ``pri_spec->stream_id``).
* :enum:`NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. This happens if stream denoted by |stream_id|
...
...
@@ -3549,7 +3553,7 @@ nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
* :enum:`NGHTTP2_ERR_STREAM_CLOSED`
* The stream was alreay closed; or the |stream_id| is invalid.
* The stream was alrea
d
y closed; or the |stream_id| is invalid.
*
* .. note::
*
...
...
@@ -3718,7 +3722,7 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* The |stream_id| is 0; The |stream_id| does not designate stream
* that peer initiated.
* :enum:`NGHTTP2_ERR_STREAM_CLOSED`
* The stream was alreay closed; or the |stream_id| is invalid.
* The stream was alrea
d
y closed; or the |stream_id| is invalid.
*
* .. warning::
*
...
...
@@ -4336,7 +4340,7 @@ typedef enum {
* :enum:`NGHTTP2_ERR_HEADER_COMP`
* Inflation process has failed.
* :enum:`NGHTTP2_ERR_BUFFER_ERROR`
* The heder field name or value is too large.
* The he
a
der field name or value is too large.
*
* Example follows::
*
...
...
lib/nghttp2_outbound_item.h
View file @
0caefe20
...
...
@@ -43,9 +43,6 @@ typedef struct {
/* nonzero if request HEADERS is canceled. The error code is stored
in |error_code|. */
uint8_t
canceled
;
/* nonzero if this item should be attached to stream object to make
it under priority control */
uint8_t
attach_stream
;
}
nghttp2_headers_aux_data
;
/* struct used for DATA frame */
...
...
lib/nghttp2_pq.c
View file @
0caefe20
...
...
@@ -44,11 +44,13 @@ void nghttp2_pq_free(nghttp2_pq *pq) {
}
static
void
swap
(
nghttp2_pq
*
pq
,
size_t
i
,
size_t
j
)
{
nghttp2_pq_entry
*
t
=
pq
->
q
[
i
];
pq
->
q
[
i
]
=
pq
->
q
[
j
];
pq
->
q
[
i
]
->
index
=
i
;
pq
->
q
[
j
]
=
t
;
pq
->
q
[
j
]
->
index
=
j
;
nghttp2_pq_entry
*
a
=
pq
->
q
[
i
];
nghttp2_pq_entry
*
b
=
pq
->
q
[
j
];
pq
->
q
[
i
]
=
b
;
b
->
index
=
i
;
pq
->
q
[
j
]
=
a
;
a
->
index
=
j
;
}
static
void
bubble_up
(
nghttp2_pq
*
pq
,
size_t
index
)
{
...
...
lib/nghttp2_session.c
View file @
0caefe20
This diff is collapsed.
Click to expand it.
lib/nghttp2_session.h
View file @
0caefe20
...
...
@@ -73,6 +73,10 @@ typedef struct {
/* The default maximum number of incoming reserved streams */
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
#define NGHTTP2_MIN_IDLE_STREAMS 16
/* The maximum number of items in outbound queue, which is considered
as flooding caused by peer. All frames are not considered here.
We only consider PING + ACK and SETTINGS + ACK. This is because
...
...
@@ -450,6 +454,11 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
*
* This function returns a pointer to created new stream object, or
* NULL.
*
* This function adjusts neither the number of closed streams or idle
* streams. The caller should manually call
* nghttp2_session_adjust_closed_stream() or
* nghttp2_session_adjust_idle_stream() respectively.
*/
nghttp2_stream
*
nghttp2_session_open_stream
(
nghttp2_session
*
session
,
int32_t
stream_id
,
uint8_t
flags
,
...
...
@@ -498,29 +507,17 @@ int nghttp2_session_destroy_stream(nghttp2_session *session,
* limitation of maximum number of streams in memory, |stream| is not
* closed and just deleted from memory (see
* nghttp2_session_destroy_stream).
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int
nghttp2_session_keep_closed_stream
(
nghttp2_session
*
session
,
nghttp2_stream
*
stream
);
void
nghttp2_session_keep_closed_stream
(
nghttp2_session
*
session
,
nghttp2_stream
*
stream
);
/*
* Appends |stream| to linked list |session->idle_stream_head|. We
* apply fixed limit for list size. To fit into that limit, one or
* more oldest streams are removed from list as necessary.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
*
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int
nghttp2_session_keep_idle_stream
(
nghttp2_session
*
session
,
nghttp2_stream
*
stream
);
void
nghttp2_session_keep_idle_stream
(
nghttp2_session
*
session
,
nghttp2_stream
*
stream
);
/*
* Detaches |stream| from idle streams linked list.
...
...
@@ -531,9 +528,7 @@ void nghttp2_session_detach_idle_stream(nghttp2_session *session,
/*
* Deletes closed stream to ensure that number of incoming streams
* including active and closed is in the maximum number of allowed
* stream. If |offset| is nonzero, it is decreased from the maximum
* number of allowed stream when comparing number of active and closed
* stream and the maximum number.
* stream.
*
* This function returns 0 if it succeeds, or one the following
* negative error codes:
...
...
@@ -541,8 +536,7 @@ void nghttp2_session_detach_idle_stream(nghttp2_session *session,
* NGHTTP2_ERR_NOMEM
* Out of memory
*/
int
nghttp2_session_adjust_closed_stream
(
nghttp2_session
*
session
,
size_t
offset
);
int
nghttp2_session_adjust_closed_stream
(
nghttp2_session
*
session
);
/*
* Deletes idle stream to ensure that number of idle streams is in
...
...
@@ -814,6 +808,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
* pri_spec->stream_id.
*
* This function does not adjust the number of idle streams. The
* caller should call nghttp2_session_adjust_idle_stream() later.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
...
...
lib/nghttp2_stream.c
View file @
0caefe20
...
...
@@ -80,6 +80,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream
->
queued
=
0
;
stream
->
descendant_last_cycle
=
0
;
stream
->
cycle
=
0
;
stream
->
pending_penalty
=
0
;
stream
->
descendant_next_seq
=
0
;
stream
->
seq
=
0
;
stream
->
last_writelen
=
0
;
...
...
@@ -115,9 +116,14 @@ static int stream_subtree_active(nghttp2_stream *stream) {
/*
* Returns next cycle for |stream|.
*/
static
uint64_t
stream_next_cycle
(
nghttp2_stream
*
stream
,
uint64_t
last_cycle
)
{
return
last_cycle
+
stream
->
last_writelen
*
NGHTTP2_MAX_WEIGHT
/
(
uint32_t
)
stream
->
weight
;
static
void
stream_next_cycle
(
nghttp2_stream
*
stream
,
uint64_t
last_cycle
)
{
size_t
penalty
;
penalty
=
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
);
}
static
int
stream_obq_push
(
nghttp2_stream
*
dep_stream
,
nghttp2_stream
*
stream
)
{
...
...
@@ -125,8 +131,7 @@ static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
for
(;
dep_stream
&&
!
stream
->
queued
;
stream
=
dep_stream
,
dep_stream
=
dep_stream
->
dep_prev
)
{
stream
->
cycle
=
stream_next_cycle
(
stream
,
dep_stream
->
descendant_last_cycle
);
stream_next_cycle
(
stream
,
dep_stream
->
descendant_last_cycle
);
stream
->
seq
=
dep_stream
->
descendant_next_seq
++
;
DEBUGF
(
fprintf
(
stderr
,
"stream: stream=%d obq push cycle=%ld
\n
"
,
...
...
@@ -169,6 +174,7 @@ static void stream_obq_remove(nghttp2_stream *stream) {
stream
->
queued
=
0
;
stream
->
cycle
=
0
;
stream
->
pending_penalty
=
0
;
stream
->
descendant_last_cycle
=
0
;
stream
->
last_writelen
=
0
;
...
...
@@ -207,25 +213,12 @@ void nghttp2_stream_reschedule(nghttp2_stream *stream) {
dep_stream
=
stream
->
dep_prev
;
for
(;
dep_stream
;
stream
=
dep_stream
,
dep_stream
=
dep_stream
->
dep_prev
)
{
if
(
nghttp2_pq_size
(
&
dep_stream
->
obq
)
==
1
)
{
dep_stream
->
descendant_last_cycle
=
0
;
stream
->
cycle
=
0
;
}
else
{
/* We update descendant_last_cycle here, and we don't do it when
no data is written for stream. This effectively means that
we treat these streams as if they are not scheduled at all.
This does not cause disruption in scheduling machinery. It
just makes new streams scheduled a bit early. */
dep_stream
->
descendant_last_cycle
=
stream
->
cycle
;
nghttp2_pq_remove
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
nghttp2_pq_remove
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
stream
->
cycle
=
stream_next_cycle
(
stream
,
dep_stream
->
descendant_last_cycle
);
stream
->
seq
=
dep_stream
->
descendant_next_seq
++
;
stream_next_cycle
(
stream
,
dep_stream
->
descendant_last_cycle
);
stream
->
seq
=
dep_stream
->
descendant_next_seq
++
;
nghttp2_pq_push
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
}
nghttp2_pq_push
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
DEBUGF
(
fprintf
(
stderr
,
"stream: stream=%d obq resched cycle=%ld
\n
"
,
stream
->
stream_id
,
stream
->
cycle
));
...
...
@@ -234,6 +227,61 @@ 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
;
int32_t
old_weight
;
size_t
wlen_penalty
;
if
(
stream
->
weight
==
weight
)
{
return
;
}
old_weight
=
stream
->
weight
;
stream
->
weight
=
weight
;
dep_stream
=
stream
->
dep_prev
;
if
(
!
dep_stream
)
{
return
;
}
dep_stream
->
sum_dep_weight
+=
weight
-
old_weight
;
if
(
!
stream
->
queued
)
{
return
;
}
nghttp2_pq_remove
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
wlen_penalty
=
stream
->
last_writelen
*
NGHTTP2_MAX_WEIGHT
;
/* Compute old stream->pending_penalty we used to calculate
stream->cycle */
stream
->
pending_penalty
=
(
uint32_t
)((
stream
->
pending_penalty
+
(
uint32_t
)
old_weight
-
(
wlen_penalty
%
(
uint32_t
)
old_weight
))
%
(
uint32_t
)
old_weight
);
last_cycle
=
stream
->
cycle
-
(
wlen_penalty
+
stream
->
pending_penalty
)
/
(
uint32_t
)
old_weight
;
/* Now we have old stream->pending_penalty and new stream->weight in
place */
stream_next_cycle
(
stream
,
last_cycle
);
if
(
stream
->
cycle
<
dep_stream
->
descendant_last_cycle
)
{
stream
->
cycle
=
dep_stream
->
descendant_last_cycle
;
}
/* Continue to use same stream->seq */
nghttp2_pq_push
(
&
dep_stream
->
obq
,
&
stream
->
pq_entry
);
DEBUGF
(
fprintf
(
stderr
,
"stream: stream=%d obq resched cycle=%ld
\n
"
,
stream
->
stream_id
,
stream
->
cycle
));
}
static
nghttp2_stream
*
stream_last_sib
(
nghttp2_stream
*
stream
)
{
for
(;
stream
->
sib_next
;
stream
=
stream
->
sib_next
)
;
...
...
@@ -861,9 +909,15 @@ int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
nghttp2_outbound_item
*
nghttp2_stream_next_outbound_item
(
nghttp2_stream
*
stream
)
{
nghttp2_pq_entry
*
ent
;
nghttp2_stream
*
si
;
for
(;;)
{
if
(
stream_active
(
stream
))
{
/* Update ascendant's descendant_last_cycle here, so that we can
assure that new stream is scheduled based on it. */
for
(
si
=
stream
;
si
->
dep_prev
;
si
=
si
->
dep_prev
)
{
si
->
dep_prev
->
descendant_last_cycle
=
si
->
cycle
;
}
return
stream
->
item
;
}
ent
=
nghttp2_pq_top
(
&
stream
->
obq
);
...
...
lib/nghttp2_stream.h
View file @
0caefe20
...
...
@@ -197,6 +197,8 @@ struct nghttp2_stream {
int32_t
local_window_size
;
/* weight of this stream */
int32_t
weight
;
/* This is unpaid penalty (offset) when calculating cycle. */
uint32_t
pending_penalty
;
/* sum of weight of direct descendants */
int32_t
sum_dep_weight
;
nghttp2_stream_state
state
;
...
...
@@ -419,7 +421,14 @@ int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
void
nghttp2_stream_reschedule
(
nghttp2_stream
*
stream
);
/*
* Returns a stream which has highest priority.
* Changes |stream|'s weight to |weight|. If |stream| is queued, it
* will be rescheduled based on new weight.
*/
void
nghttp2_stream_change_weight
(
nghttp2_stream
*
stream
,
int32_t
weight
);
/*
* Returns a stream which has highest priority, updating
* descendant_last_cycle of selected stream's ancestors.
*/
nghttp2_outbound_item
*
nghttp2_stream_next_outbound_item
(
nghttp2_stream
*
stream
);
...
...
lib/nghttp2_submit.c
View file @
0caefe20
...
...
@@ -40,8 +40,7 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
const
nghttp2_priority_spec
*
pri_spec
,
nghttp2_nv
*
nva_copy
,
size_t
nvlen
,
const
nghttp2_data_provider
*
data_prd
,
void
*
stream_user_data
,
uint8_t
attach_stream
)
{
void
*
stream_user_data
)
{
int
rv
;
uint8_t
flags_copy
;
nghttp2_outbound_item
*
item
=
NULL
;
...
...
@@ -56,6 +55,16 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
goto
fail
;
}
if
(
stream_id
==
-
1
)
{
if
((
int32_t
)
session
->
next_stream_id
==
pri_spec
->
stream_id
)
{
rv
=
NGHTTP2_ERR_INVALID_ARGUMENT
;
goto
fail
;
}
}
else
if
(
stream_id
==
pri_spec
->
stream_id
)
{
rv
=
NGHTTP2_ERR_INVALID_ARGUMENT
;
goto
fail
;
}
item
=
nghttp2_mem_malloc
(
mem
,
sizeof
(
nghttp2_outbound_item
));
if
(
item
==
NULL
)
{
rv
=
NGHTTP2_ERR_NOMEM
;
...
...
@@ -69,7 +78,6 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
}
item
->
aux_data
.
headers
.
stream_user_data
=
stream_user_data
;
item
->
aux_data
.
headers
.
attach_stream
=
attach_stream
;
flags_copy
=
(
uint8_t
)((
flags
&
(
NGHTTP2_FLAG_END_STREAM
|
NGHTTP2_FLAG_PRIORITY
))
|
...
...
@@ -122,8 +130,7 @@ static int32_t submit_headers_shared_nva(nghttp2_session *session,
const
nghttp2_priority_spec
*
pri_spec
,
const
nghttp2_nv
*
nva
,
size_t
nvlen
,
const
nghttp2_data_provider
*
data_prd
,
void
*
stream_user_data
,
uint8_t
attach_stream
)
{
void
*
stream_user_data
)
{
int
rv
;
nghttp2_nv
*
nva_copy
;
nghttp2_priority_spec
copy_pri_spec
;
...
...
@@ -144,15 +151,14 @@ static int32_t submit_headers_shared_nva(nghttp2_session *session,
}
return
submit_headers_shared
(
session
,
flags
,
stream_id
,
&
copy_pri_spec
,
nva_copy
,
nvlen
,
data_prd
,
stream_user_data
,
attach_stream
);
nva_copy
,
nvlen
,
data_prd
,
stream_user_data
);
}
int
nghttp2_submit_trailer
(
nghttp2_session
*
session
,
int32_t
stream_id
,
const
nghttp2_nv
*
nva
,
size_t
nvlen
)
{
return
(
int
)
submit_headers_shared_nva
(
session
,
NGHTTP2_FLAG_END_STREAM
,
stream_id
,
NULL
,
nva
,
nvlen
,
NULL
,
NULL
,
0
);
stream_id
,
NULL
,
nva
,
nvlen
,
NULL
,
NULL
);
}
int32_t
nghttp2_submit_headers
(
nghttp2_session
*
session
,
uint8_t
flags
,
...
...
@@ -169,7 +175,7 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
}
return
submit_headers_shared_nva
(
session
,
flags
,
stream_id
,
pri_spec
,
nva
,
nvlen
,
NULL
,
stream_user_data
,
0
);
nvlen
,
NULL
,
stream_user_data
);
}
int
nghttp2_submit_ping
(
nghttp2_session
*
session
,
uint8_t
flags
_U_
,
...
...
@@ -398,7 +404,7 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
flags
=
set_request_flags
(
pri_spec
,
data_prd
);
return
submit_headers_shared_nva
(
session
,
flags
,
-
1
,
pri_spec
,
nva
,
nvlen
,
data_prd
,
stream_user_data
,
0
);
data_prd
,
stream_user_data
);
}
static
uint8_t
set_response_flags
(
const
nghttp2_data_provider
*
data_prd
)
{
...
...
@@ -414,7 +420,7 @@ int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
const
nghttp2_data_provider
*
data_prd
)
{
uint8_t
flags
=
set_response_flags
(
data_prd
);
return
submit_headers_shared_nva
(
session
,
flags
,
stream_id
,
NULL
,
nva
,
nvlen
,
data_prd
,
NULL
,
1
);
data_prd
,
NULL
);
}
int
nghttp2_submit_data
(
nghttp2_session
*
session
,
uint8_t
flags
,
...
...
src/HttpServer.cc
View file @
0caefe20
...
...
@@ -53,6 +53,7 @@
#include <deque>
#include <openssl/err.h>
#include <openssl/dh.h>
#include <zlib.h>
...
...
@@ -105,7 +106,7 @@ Config::Config()
max_concurrent_streams
(
100
),
header_table_size
(
-
1
),
port
(
0
),
verbose
(
false
),
daemon
(
false
),
verify_client
(
false
),
no_tls
(
false
),
error_gzip
(
false
),
early_response
(
false
),
hexdump
(
false
),
echo_upload
(
false
)
{}
echo_upload
(
false
)
,
no_content_length
(
false
)
{}
Config
::~
Config
()
{}
...
...
@@ -872,12 +873,14 @@ int Http2Handler::submit_file_response(const std::string &status,
std
::
string
last_modified_str
;
auto
nva
=
make_array
(
http2
::
make_nv_ls
(
":status"
,
status
),
http2
::
make_nv_ll
(
"server"
,
NGHTTPD_SERVER
),
http2
::
make_nv_ls
(
"content-length"
,
content_length
),
http2
::
make_nv_ll
(
"cache-control"
,
"max-age=3600"
),
http2
::
make_nv_ls
(
"date"
,
sessions_
->
get_cached_date
()),
http2
::
make_nv_ll
(
""
,
""
),
http2
::
make_nv_ll
(
""
,
""
),
http2
::
make_nv_ll
(
""
,
""
));
size_t
nvlen
=
5
;
http2
::
make_nv_ll
(
""
,
""
),
http2
::
make_nv_ll
(
""
,
""
));
size_t
nvlen
=
4
;
if
(
!
get_config
()
->
no_content_length
)
{
nva
[
nvlen
++
]
=
http2
::
make_nv_ls
(
"content-length"
,
content_length
);
}
if
(
last_modified
!=
0
)
{
last_modified_str
=
util
::
http_date
(
last_modified
);
nva
[
nvlen
++
]
=
http2
::
make_nv_ls
(
"last-modified"
,
last_modified_str
);
...
...
@@ -1087,7 +1090,9 @@ void prepare_echo_response(Stream *stream, Http2Handler *hd) {
Headers
headers
;
headers
.
emplace_back
(
"nghttpd-response"
,
"echo"
);
headers
.
emplace_back
(
"content-length"
,
util
::
utos
(
length
));
if
(
!
hd
->
get_config
()
->
no_content_length
)
{
headers
.
emplace_back
(
"content-length"
,
util
::
utos
(
length
));
}
hd
->
submit_response
(
"200"
,
stream
->
stream_id
,
headers
,
&
data_prd
);
}
...
...
src/HttpServer.h
View file @
0caefe20
...
...
@@ -76,6 +76,7 @@ struct Config {
bool
early_response
;
bool
hexdump
;
bool
echo_upload
;
bool
no_content_length
;
Config
();
~
Config
();
};
...
...
src/asio_client_session.cc
View file @
0caefe20
...
...
@@ -39,12 +39,16 @@ using boost::asio::ip::tcp;
session
::
session
(
boost
::
asio
::
io_service
&
io_service
,
const
std
::
string
&
host
,
const
std
::
string
&
service
)
:
impl_
(
make_unique
<
session_tcp_impl
>
(
io_service
,
host
,
service
))
{}
:
impl_
(
std
::
make_shared
<
session_tcp_impl
>
(
io_service
,
host
,
service
))
{
impl_
->
start_resolve
(
host
,
service
);
}
session
::
session
(
boost
::
asio
::
io_service
&
io_service
,
boost
::
asio
::
ssl
::
context
&
tls_ctx
,
const
std
::
string
&
host
,
const
std
::
string
&
service
)
:
impl_
(
make_unique
<
session_tls_impl
>
(
io_service
,
tls_ctx
,
host
,
service
))
{
:
impl_
(
std
::
make_shared
<
session_tls_impl
>
(
io_service
,
tls_ctx
,
host
,
service
))
{
impl_
->
start_resolve
(
host
,
service
);
}
session
::~
session
()
{}
...
...
@@ -93,6 +97,14 @@ const request *session::submit(boost::system::error_code &ec,
return
impl_
->
submit
(
ec
,
method
,
uri
,
std
::
move
(
cb
),
std
::
move
(
h
));
}
void
session
::
connect_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
impl_
->
connect_timeout
(
t
);
}
void
session
::
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
impl_
->
read_timeout
(
t
);
}
}
// namespace client
}
// namespace asio_http2
}
// nghttp2
src/asio_client_session_impl.cc
View file @
0caefe20
...
...
@@ -40,8 +40,10 @@ namespace client {
session_impl
::
session_impl
(
boost
::
asio
::
io_service
&
io_service
)
:
wblen_
(
0
),
io_service_
(
io_service
),
resolver_
(
io_service
),
session_
(
nullptr
),
data_pending_
(
nullptr
),
data_pendinglen_
(
0
),
writing_
(
false
),
inside_callback_
(
false
)
{}
deadline_
(
io_service
),
connect_timeout_
(
boost
::
posix_time
::
seconds
(
60
)),
read_timeout_
(
boost
::
posix_time
::
seconds
(
60
)),
session_
(
nullptr
),
data_pending_
(
nullptr
),
data_pendinglen_
(
0
),
writing_
(
false
),
inside_callback_
(
false
),
stopped_
(
false
)
{}
session_impl
::~
session_impl
()
{
// finish up all active stream
...
...
@@ -56,9 +58,13 @@ session_impl::~session_impl() {
void
session_impl
::
start_resolve
(
const
std
::
string
&
host
,
const
std
::
string
&
service
)
{
deadline_
.
expires_from_now
(
connect_timeout_
);
auto
self
=
this
->
shared_from_this
();
resolver_
.
async_resolve
({
host
,
service
},
[
this
](
const
boost
::
system
::
error_code
&
ec
,
tcp
::
resolver
::
iterator
endpoint_it
)
{
[
this
,
self
](
const
boost
::
system
::
error_code
&
ec
,
tcp
::
resolver
::
iterator
endpoint_it
)
{
if
(
ec
)
{
not_connected
(
ec
);
return
;
...
...
@@ -66,6 +72,25 @@ void session_impl::start_resolve(const std::string &host,
start_connect
(
endpoint_it
);
});
deadline_
.
async_wait
(
std
::
bind
(
&
session_impl
::
handle_deadline
,
self
));
}
void
session_impl
::
handle_deadline
()
{
if
(
stopped_
)
{
return
;
}
if
(
deadline_
.
expires_at
()
<=
boost
::
asio
::
deadline_timer
::
traits_type
::
now
())
{
call_error_cb
(
boost
::
asio
::
error
::
timed_out
);
stop
();
deadline_
.
expires_at
(
boost
::
posix_time
::
pos_infin
);
return
;
}
deadline_
.
async_wait
(
std
::
bind
(
&
session_impl
::
handle_deadline
,
this
->
shared_from_this
()));
}
void
session_impl
::
connected
(
tcp
::
resolver
::
iterator
endpoint_it
)
{
...
...
@@ -86,6 +111,7 @@ void session_impl::connected(tcp::resolver::iterator endpoint_it) {
void
session_impl
::
not_connected
(
const
boost
::
system
::
error_code
&
ec
)
{
call_error_cb
(
ec
);
stop
();
}
void
session_impl
::
on_connect
(
connect_cb
cb
)
{
connect_cb_
=
std
::
move
(
cb
);
}
...
...
@@ -97,6 +123,9 @@ const connect_cb &session_impl::on_connect() const { return connect_cb_; }
const
error_cb
&
session_impl
::
on_error
()
const
{
return
error_cb_
;
}
void
session_impl
::
call_error_cb
(
const
boost
::
system
::
error_code
&
ec
)
{
if
(
stopped_
)
{
return
;
}
auto
&
error_cb
=
on_error
();
if
(
!
error_cb
)
{
return
;
...
...
@@ -350,12 +379,20 @@ int session_impl::write_trailer(stream &strm, header_map h) {
}
void
session_impl
::
cancel
(
stream
&
strm
,
uint32_t
error_code
)
{
if
(
stopped_
)
{
return
;
}
nghttp2_submit_rst_stream
(
session_
,
NGHTTP2_FLAG_NONE
,
strm
.
stream_id
(),
error_code
);
signal_write
();
}
void
session_impl
::
resume
(
stream
&
strm
)
{
if
(
stopped_
)
{
return
;
}
nghttp2_session_resume_data
(
session_
,
strm
.
stream_id
());
signal_write
();
}
...
...
@@ -396,6 +433,11 @@ const request *session_impl::submit(boost::system::error_code &ec,
header_map
h
)
{
ec
.
clear
();
if
(
stopped_
)
{
ec
=
make_error_code
(
static_cast
<
nghttp2_error
>
(
NGHTTP2_INTERNAL_ERROR
));
return
nullptr
;
}
http_parser_url
u
{};
// TODO Handle CONNECT method
if
(
http_parser_parse_url
(
uri
.
c_str
(),
uri
.
size
(),
0
,
&
u
)
!=
0
)
{
...
...
@@ -485,6 +527,10 @@ const request *session_impl::submit(boost::system::error_code &ec,
}
void
session_impl
::
shutdown
()
{
if
(
stopped_
)
{
return
;
}
nghttp2_session_terminate_session
(
session_
,
NGHTTP2_NO_ERROR
);
signal_write
();
}
...
...
@@ -522,13 +568,21 @@ void session_impl::leave_callback() {
}
void
session_impl
::
do_read
()
{
read_socket
([
this
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
bytes_transferred
)
{
if
(
stopped_
)
{
return
;
}
deadline_
.
expires_from_now
(
read_timeout_
);
auto
self
=
this
->
shared_from_this
();
read_socket
([
this
,
self
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
bytes_transferred
)
{
if
(
ec
)
{
if
(
!
should_stop
())
{
call_error_cb
(
ec
);
shutdown_socket
();
}
stop
();
return
;
}
...
...
@@ -541,7 +595,7 @@ void session_impl::do_read() {
if
(
rv
!=
static_cast
<
ssize_t
>
(
bytes_transferred
))
{
call_error_cb
(
make_error_code
(
static_cast
<
nghttp2_error
>
(
rv
<
0
?
rv
:
NGHTTP2_ERR_PROTO
)));
s
hutdown_socket
();
s
top
();
return
;
}
}
...
...
@@ -549,7 +603,7 @@ void session_impl::do_read() {
do_write
();
if
(
should_stop
())
{
s
hutdown_socket
();
s
top
();
return
;
}
...
...
@@ -558,6 +612,10 @@ void session_impl::do_read() {
}
void
session_impl
::
do_write
()
{
if
(
stopped_
)
{
return
;
}
if
(
writing_
)
{
return
;
}
...
...
@@ -579,7 +637,7 @@ void session_impl::do_write() {
auto
n
=
nghttp2_session_mem_send
(
session_
,
&
data
);
if
(
n
<
0
)
{
call_error_cb
(
make_error_code
(
static_cast
<
nghttp2_error
>
(
n
)));
s
hutdown_socket
();
s
top
();
return
;
}
...
...
@@ -601,23 +659,51 @@ void session_impl::do_write() {
}
if
(
wblen_
==
0
)
{
if
(
should_stop
())
{
stop
();
}
return
;
}
writing_
=
true
;
write_socket
([
this
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
n
)
{
if
(
ec
)
{
call_error_cb
(
ec
);
shutdown_socket
();
return
;
}
// Reset read deadline here, because normally client is sending
// something, it does not expect timeout while doing it.
deadline_
.
expires_from_now
(
read_timeout_
);
wblen_
=
0
;
writing_
=
false
;
auto
self
=
this
->
shared_from_this
();
do_write
();
});
write_socket
(
[
this
,
self
](
const
boost
::
system
::
error_code
&
ec
,
std
::
size_t
n
)
{
if
(
ec
)
{
call_error_cb
(
ec
);
stop
();
return
;
}
wblen_
=
0
;
writing_
=
false
;
do_write
();
});
}
void
session_impl
::
stop
()
{
if
(
stopped_
)
{
return
;
}
shutdown_socket
();
deadline_
.
cancel
();
stopped_
=
true
;
}
void
session_impl
::
connect_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
connect_timeout_
=
t
;
}
void
session_impl
::
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
read_timeout_
=
t
;
}
}
// namespace client
...
...
src/asio_client_session_impl.h
View file @
0caefe20
...
...
@@ -41,7 +41,7 @@ class stream;
using
boost
::
asio
::
ip
::
tcp
;
class
session_impl
{
class
session_impl
:
public
std
::
enable_shared_from_this
<
session_impl
>
{
public:
session_impl
(
boost
::
asio
::
io_service
&
io_service
);
virtual
~
session_impl
();
...
...
@@ -91,6 +91,11 @@ public:
void
do_read
();
void
do_write
();
void
connect_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
void
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
void
stop
();
protected:
boost
::
array
<
uint8_t
,
8
_k
>
rb_
;
boost
::
array
<
uint8_t
,
64
_k
>
wb_
;
...
...
@@ -100,6 +105,7 @@ private:
bool
should_stop
()
const
;
bool
setup_session
();
void
call_error_cb
(
const
boost
::
system
::
error_code
&
ec
);
void
handle_deadline
();
boost
::
asio
::
io_service
&
io_service_
;
tcp
::
resolver
resolver_
;
...
...
@@ -109,6 +115,10 @@ private:
connect_cb
connect_cb_
;
error_cb
error_cb_
;
boost
::
asio
::
deadline_timer
deadline_
;
boost
::
posix_time
::
time_duration
connect_timeout_
;
boost
::
posix_time
::
time_duration
read_timeout_
;
nghttp2_session
*
session_
;
const
uint8_t
*
data_pending_
;
...
...
@@ -116,6 +126,7 @@ private:
bool
writing_
;
bool
inside_callback_
;
bool
stopped_
;
};
}
// namespace client
...
...
src/asio_client_session_tcp_impl.cc
View file @
0caefe20
...
...
@@ -31,9 +31,7 @@ namespace client {
session_tcp_impl
::
session_tcp_impl
(
boost
::
asio
::
io_service
&
io_service
,
const
std
::
string
&
host
,
const
std
::
string
&
service
)
:
session_impl
(
io_service
),
socket_
(
io_service
)
{
start_resolve
(
host
,
service
);
}
:
session_impl
(
io_service
),
socket_
(
io_service
)
{}
session_tcp_impl
::~
session_tcp_impl
()
{}
...
...
@@ -62,7 +60,10 @@ void session_tcp_impl::write_socket(
boost
::
asio
::
async_write
(
socket_
,
boost
::
asio
::
buffer
(
wb_
,
wblen_
),
h
);
}
void
session_tcp_impl
::
shutdown_socket
()
{
socket_
.
close
();
}
void
session_tcp_impl
::
shutdown_socket
()
{
boost
::
system
::
error_code
ignored_ec
;
socket_
.
close
(
ignored_ec
);
}
}
// namespace client
}
// namespace asio_http2
...
...
src/asio_client_session_tls_impl.cc
View file @
0caefe20
...
...
@@ -38,8 +38,6 @@ session_tls_impl::session_tls_impl(boost::asio::io_service &io_service,
// ssl::context::set_verify_mode(boost::asio::ssl::verify_peer) is
// not used, which is what we want.
socket_
.
set_verify_callback
(
boost
::
asio
::
ssl
::
rfc2818_verification
(
host
));
start_resolve
(
host
,
service
);
}
session_tls_impl
::~
session_tls_impl
()
{}
...
...
@@ -85,7 +83,8 @@ void session_tls_impl::write_socket(
}
void
session_tls_impl
::
shutdown_socket
()
{
socket_
.
async_shutdown
([](
const
boost
::
system
::
error_code
&
ec
)
{});
boost
::
system
::
error_code
ignored_ec
;
socket_
.
lowest_layer
().
close
(
ignored_ec
);
}
}
// namespace client
...
...
src/asio_io_service_pool.cc
View file @
0caefe20
...
...
@@ -92,6 +92,11 @@ boost::asio::io_service &io_service_pool::get_io_service() {
return
io_service
;
}
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
io_service_pool
::
io_services
()
const
{
return
io_services_
;
}
}
// namespace asio_http2
}
// namespace nghttp2
src/asio_io_service_pool.h
View file @
0caefe20
...
...
@@ -70,6 +70,10 @@ public:
/// Get an io_service to use.
boost
::
asio
::
io_service
&
get_io_service
();
/// Get access to all io_service objects.
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
io_services
()
const
;
private:
/// The pool of io_services.
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
io_services_
;
...
...
src/asio_server.cc
View file @
0caefe20
...
...
@@ -44,8 +44,12 @@ namespace nghttp2 {
namespace
asio_http2
{
namespace
server
{
server
::
server
(
std
::
size_t
io_service_pool_size
)
:
io_service_pool_
(
io_service_pool_size
)
{}
server
::
server
(
std
::
size_t
io_service_pool_size
,
const
boost
::
posix_time
::
time_duration
&
tls_handshake_timeout
,
const
boost
::
posix_time
::
time_duration
&
read_timeout
)
:
io_service_pool_
(
io_service_pool_size
),
tls_handshake_timeout_
(
tls_handshake_timeout
),
read_timeout_
(
read_timeout
)
{}
boost
::
system
::
error_code
server
::
listen_and_serve
(
boost
::
system
::
error_code
&
ec
,
...
...
@@ -121,7 +125,8 @@ boost::system::error_code server::bind_and_listen(boost::system::error_code &ec,
void
server
::
start_accept
(
boost
::
asio
::
ssl
::
context
&
tls_context
,
tcp
::
acceptor
&
acceptor
,
serve_mux
&
mux
)
{
auto
new_connection
=
std
::
make_shared
<
connection
<
ssl_socket
>>
(
mux
,
io_service_pool_
.
get_io_service
(),
tls_context
);
mux
,
tls_handshake_timeout_
,
read_timeout_
,
io_service_pool_
.
get_io_service
(),
tls_context
);
acceptor
.
async_accept
(
new_connection
->
socket
().
lowest_layer
(),
...
...
@@ -130,14 +135,17 @@ void server::start_accept(boost::asio::ssl::context &tls_context,
if
(
!
e
)
{
new_connection
->
socket
().
lowest_layer
().
set_option
(
tcp
::
no_delay
(
true
));
new_connection
->
start_tls_handshake_deadline
();
new_connection
->
socket
().
async_handshake
(
boost
::
asio
::
ssl
::
stream_base
::
server
,
[
new_connection
](
const
boost
::
system
::
error_code
&
e
)
{
if
(
e
)
{
new_connection
->
stop
();
return
;
}
if
(
!
tls_h2_negotiated
(
new_connection
->
socket
()))
{
new_connection
->
stop
();
return
;
}
...
...
@@ -151,13 +159,15 @@ void server::start_accept(boost::asio::ssl::context &tls_context,
void
server
::
start_accept
(
tcp
::
acceptor
&
acceptor
,
serve_mux
&
mux
)
{
auto
new_connection
=
std
::
make_shared
<
connection
<
tcp
::
socket
>>
(
mux
,
io_service_pool_
.
get_io_service
());
mux
,
tls_handshake_timeout_
,
read_timeout_
,
io_service_pool_
.
get_io_service
());
acceptor
.
async_accept
(
new_connection
->
socket
(),
[
this
,
&
acceptor
,
&
mux
,
new_connection
](
const
boost
::
system
::
error_code
&
e
)
{
if
(
!
e
)
{
new_connection
->
socket
().
set_option
(
tcp
::
no_delay
(
true
));
new_connection
->
start_read_deadline
();
new_connection
->
start
();
}
...
...
@@ -169,6 +179,11 @@ void server::stop() { io_service_pool_.stop(); }
void
server
::
join
()
{
io_service_pool_
.
join
();
}
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
server
::
io_services
()
const
{
return
io_service_pool_
.
io_services
();
}
}
// namespace server
}
// namespace asio_http2
}
// namespace nghttp2
src/asio_server.h
View file @
0caefe20
...
...
@@ -63,7 +63,9 @@ using ssl_socket = boost::asio::ssl::stream<tcp::socket>;
class
server
:
private
boost
::
noncopyable
{
public:
explicit
server
(
std
::
size_t
io_service_pool_size
);
explicit
server
(
std
::
size_t
io_service_pool_size
,
const
boost
::
posix_time
::
time_duration
&
tls_handshake_timeout
,
const
boost
::
posix_time
::
time_duration
&
read_timeout
);
boost
::
system
::
error_code
listen_and_serve
(
boost
::
system
::
error_code
&
ec
,
...
...
@@ -73,6 +75,10 @@ public:
void
join
();
void
stop
();
/// Get access to all io_service objects.
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
io_services
()
const
;
private:
/// Initiate an asynchronous accept operation.
void
start_accept
(
tcp
::
acceptor
&
acceptor
,
serve_mux
&
mux
);
...
...
@@ -94,6 +100,9 @@ private:
std
::
vector
<
tcp
::
acceptor
>
acceptors_
;
std
::
unique_ptr
<
boost
::
asio
::
ssl
::
context
>
ssl_ctx_
;
boost
::
posix_time
::
time_duration
tls_handshake_timeout_
;
boost
::
posix_time
::
time_duration
read_timeout_
;
};
}
// namespace server
...
...
src/asio_server_connection.h
View file @
0caefe20
...
...
@@ -64,15 +64,23 @@ class connection : public std::enable_shared_from_this<connection<socket_type>>,
public:
/// Construct a connection with the given io_service.
template
<
typename
...
SocketArgs
>
explicit
connection
(
serve_mux
&
mux
,
SocketArgs
&&
...
args
)
:
socket_
(
std
::
forward
<
SocketArgs
>
(
args
)...),
mux_
(
mux
),
writing_
(
false
)
{
}
explicit
connection
(
serve_mux
&
mux
,
const
boost
::
posix_time
::
time_duration
&
tls_handshake_timeout
,
const
boost
::
posix_time
::
time_duration
&
read_timeout
,
SocketArgs
&&
...
args
)
:
socket_
(
std
::
forward
<
SocketArgs
>
(
args
)...),
mux_
(
mux
),
deadline_
(
socket_
.
get_io_service
()),
tls_handshake_timeout_
(
tls_handshake_timeout
),
read_timeout_
(
read_timeout
),
writing_
(
false
),
stopped_
(
false
)
{}
/// Start the first asynchronous operation for the connection.
void
start
()
{
handler_
=
std
::
make_shared
<
http2_handler
>
(
socket_
.
get_io_service
(),
[
this
]()
{
do_write
();
},
mux_
);
handler_
=
std
::
make_shared
<
http2_handler
>
(
socket_
.
get_io_service
(),
socket_
.
lowest_layer
().
remote_endpoint
(),
[
this
]()
{
do_write
();
},
mux_
);
if
(
handler_
->
start
()
!=
0
)
{
stop
();
return
;
}
do_read
();
...
...
@@ -80,27 +88,62 @@ public:
socket_type
&
socket
()
{
return
socket_
;
}
void
start_tls_handshake_deadline
()
{
deadline_
.
expires_from_now
(
tls_handshake_timeout_
);
deadline_
.
async_wait
(
std
::
bind
(
&
connection
::
handle_deadline
,
this
->
shared_from_this
()));
}
void
start_read_deadline
()
{
deadline_
.
expires_from_now
(
read_timeout_
);
deadline_
.
async_wait
(
std
::
bind
(
&
connection
::
handle_deadline
,
this
->
shared_from_this
()));
}
void
handle_deadline
()
{
if
(
stopped_
)
{
return
;
}
if
(
deadline_
.
expires_at
()
<=
boost
::
asio
::
deadline_timer
::
traits_type
::
now
())
{
stop
();
deadline_
.
expires_at
(
boost
::
posix_time
::
pos_infin
);
return
;
}
deadline_
.
async_wait
(
std
::
bind
(
&
connection
::
handle_deadline
,
this
->
shared_from_this
()));
}
void
do_read
()
{
auto
self
=
this
->
shared_from_this
();
deadline_
.
expires_from_now
(
read_timeout_
);
socket_
.
async_read_some
(
boost
::
asio
::
buffer
(
buffer_
),
[
this
,
self
](
const
boost
::
system
::
error_code
&
e
,
std
::
size_t
bytes_transferred
)
{
if
(
!
e
)
{
if
(
handler_
->
on_read
(
buffer_
,
bytes_transferred
)
!=
0
)
{
return
;
}
if
(
e
)
{
stop
();
return
;
}
do_write
();
if
(
handler_
->
on_read
(
buffer_
,
bytes_transferred
)
!=
0
)
{
stop
();
return
;
}
if
(
!
writing_
&&
handler_
->
should_stop
())
{
return
;
}
do_write
();
do_read
();
if
(
!
writing_
&&
handler_
->
should_stop
())
{
stop
();
return
;
}
do_read
();
// If an error occurs then no new asynchronous operations are
// started. This means that all shared_ptr references to the
// connection object will disappear and the object will be
...
...
@@ -122,23 +165,34 @@ public:
rv
=
handler_
->
on_write
(
outbuf_
,
nwrite
);
if
(
rv
!=
0
)
{
stop
();
return
;
}
if
(
nwrite
==
0
)
{
if
(
handler_
->
should_stop
())
{
stop
();
}
return
;
}
writing_
=
true
;
// Reset read deadline here, because normally client is sending
// something, it does not expect timeout while doing it.
deadline_
.
expires_from_now
(
read_timeout_
);
boost
::
asio
::
async_write
(
socket_
,
boost
::
asio
::
buffer
(
outbuf_
,
nwrite
),
[
this
,
self
](
const
boost
::
system
::
error_code
&
e
,
std
::
size_t
)
{
if
(
!
e
)
{
writing_
=
false
;
do_write
();
if
(
e
)
{
stop
();
return
;
}
writing_
=
false
;
do_write
();
});
// No new asynchronous operations are started. This means that all
...
...
@@ -147,6 +201,17 @@ public:
// returns. The connection class's destructor closes the socket.
}
void
stop
()
{
if
(
stopped_
)
{
return
;
}
stopped_
=
true
;
boost
::
system
::
error_code
ignored_ec
;
socket_
.
lowest_layer
().
close
(
ignored_ec
);
deadline_
.
cancel
();
}
private:
socket_type
socket_
;
...
...
@@ -159,7 +224,12 @@ private:
boost
::
array
<
uint8_t
,
64
_k
>
outbuf_
;
boost
::
asio
::
deadline_timer
deadline_
;
boost
::
posix_time
::
time_duration
tls_handshake_timeout_
;
boost
::
posix_time
::
time_duration
read_timeout_
;
bool
writing_
;
bool
stopped_
;
};
}
// namespace server
...
...
src/asio_server_http2.cc
View file @
0caefe20
...
...
@@ -69,6 +69,14 @@ void http2::num_threads(size_t num_threads) { impl_->num_threads(num_threads); }
void
http2
::
backlog
(
int
backlog
)
{
impl_
->
backlog
(
backlog
);
}
void
http2
::
tls_handshake_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
impl_
->
tls_handshake_timeout
(
t
);
}
void
http2
::
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
impl_
->
read_timeout
(
t
);
}
bool
http2
::
handle
(
std
::
string
pattern
,
request_cb
cb
)
{
return
impl_
->
handle
(
std
::
move
(
pattern
),
std
::
move
(
cb
));
}
...
...
@@ -77,6 +85,11 @@ void http2::stop() { impl_->stop(); }
void
http2
::
join
()
{
return
impl_
->
join
();
}
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
http2
::
io_services
()
const
{
return
impl_
->
io_services
();
}
}
// namespace server
}
// namespace asio_http2
...
...
src/asio_server_http2_handler.cc
View file @
0caefe20
...
...
@@ -136,6 +136,9 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
break
;
}
auto
&
req
=
strm
->
request
().
impl
();
req
.
remote_endpoint
(
handler
->
remote_endpoint
());
handler
->
call_on_request
(
*
strm
);
if
(
frame
->
hd
.
flags
&
NGHTTP2_FLAG_END_STREAM
)
{
...
...
@@ -225,8 +228,9 @@ int on_frame_not_send_callback(nghttp2_session *session,
}
// namespace
http2_handler
::
http2_handler
(
boost
::
asio
::
io_service
&
io_service
,
boost
::
asio
::
ip
::
tcp
::
endpoint
ep
,
connection_write
writefun
,
serve_mux
&
mux
)
:
writefun_
(
writefun
),
mux_
(
mux
),
io_service_
(
io_service
),
:
writefun_
(
writefun
),
mux_
(
mux
),
io_service_
(
io_service
),
remote_ep_
(
ep
),
session_
(
nullptr
),
buf_
(
nullptr
),
buflen_
(
0
),
inside_callback_
(
false
),
tstamp_cached_
(
time
(
nullptr
)),
formatted_date_
(
util
::
http_date
(
tstamp_cached_
))
{}
...
...
@@ -449,6 +453,10 @@ response *http2_handler::push_promise(boost::system::error_code &ec,
boost
::
asio
::
io_service
&
http2_handler
::
io_service
()
{
return
io_service_
;
}
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
http2_handler
::
remote_endpoint
()
{
return
remote_ep_
;
}
callback_guard
::
callback_guard
(
http2_handler
&
h
)
:
handler
(
h
)
{
handler
.
enter_callback
();
}
...
...
src/asio_server_http2_handler.h
View file @
0caefe20
...
...
@@ -53,7 +53,8 @@ using connection_write = std::function<void(void)>;
class
http2_handler
:
public
std
::
enable_shared_from_this
<
http2_handler
>
{
public:
http2_handler
(
boost
::
asio
::
io_service
&
io_service
,
connection_write
writefun
,
http2_handler
(
boost
::
asio
::
io_service
&
io_service
,
boost
::
asio
::
ip
::
tcp
::
endpoint
ep
,
connection_write
writefun
,
serve_mux
&
mux
);
~
http2_handler
();
...
...
@@ -89,6 +90,8 @@ public:
boost
::
asio
::
io_service
&
io_service
();
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
remote_endpoint
();
const
std
::
string
&
http_date
();
template
<
size_t
N
>
...
...
@@ -152,6 +155,7 @@ private:
connection_write
writefun_
;
serve_mux
&
mux_
;
boost
::
asio
::
io_service
&
io_service_
;
boost
::
asio
::
ip
::
tcp
::
endpoint
remote_ep_
;
nghttp2_session
*
session_
;
const
uint8_t
*
buf_
;
std
::
size_t
buflen_
;
...
...
src/asio_server_http2_impl.cc
View file @
0caefe20
...
...
@@ -37,12 +37,16 @@ namespace asio_http2 {
namespace
server
{
http2_impl
::
http2_impl
()
:
num_threads_
(
1
),
backlog_
(
-
1
)
{}
http2_impl
::
http2_impl
()
:
num_threads_
(
1
),
backlog_
(
-
1
),
tls_handshake_timeout_
(
boost
::
posix_time
::
seconds
(
60
)),
read_timeout_
(
boost
::
posix_time
::
seconds
(
60
))
{}
boost
::
system
::
error_code
http2_impl
::
listen_and_serve
(
boost
::
system
::
error_code
&
ec
,
boost
::
asio
::
ssl
::
context
*
tls_context
,
const
std
::
string
&
address
,
const
std
::
string
&
port
,
bool
asynchronous
)
{
server_
.
reset
(
new
server
(
num_threads_
));
server_
.
reset
(
new
server
(
num_threads_
,
tls_handshake_timeout_
,
read_timeout_
));
return
server_
->
listen_and_serve
(
ec
,
tls_context
,
address
,
port
,
backlog_
,
mux_
,
asynchronous
);
}
...
...
@@ -51,6 +55,15 @@ void http2_impl::num_threads(size_t num_threads) { num_threads_ = num_threads; }
void
http2_impl
::
backlog
(
int
backlog
)
{
backlog_
=
backlog
;
}
void
http2_impl
::
tls_handshake_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
tls_handshake_timeout_
=
t
;
}
void
http2_impl
::
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
)
{
read_timeout_
=
t
;
}
bool
http2_impl
::
handle
(
std
::
string
pattern
,
request_cb
cb
)
{
return
mux_
.
handle
(
std
::
move
(
pattern
),
std
::
move
(
cb
));
}
...
...
@@ -59,6 +72,11 @@ void http2_impl::stop() { return server_->stop(); }
void
http2_impl
::
join
()
{
return
server_
->
join
();
}
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
http2_impl
::
io_services
()
const
{
return
server_
->
io_services
();
}
}
// namespace server
}
// namespace asio_http2
...
...
src/asio_server_http2_impl.h
View file @
0caefe20
...
...
@@ -47,15 +47,21 @@ public:
const
std
::
string
&
address
,
const
std
::
string
&
port
,
bool
asynchronous
);
void
num_threads
(
size_t
num_threads
);
void
backlog
(
int
backlog
);
void
tls_handshake_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
void
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
bool
handle
(
std
::
string
pattern
,
request_cb
cb
);
void
stop
();
void
join
();
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
io_services
()
const
;
private:
std
::
unique_ptr
<
server
>
server_
;
std
::
size_t
num_threads_
;
int
backlog_
;
serve_mux
mux_
;
boost
::
posix_time
::
time_duration
tls_handshake_timeout_
;
boost
::
posix_time
::
time_duration
read_timeout_
;
};
}
// namespace server
...
...
src/asio_server_request.cc
View file @
0caefe20
...
...
@@ -50,6 +50,10 @@ void request::on_data(data_cb cb) const {
request_impl
&
request
::
impl
()
const
{
return
*
impl_
;
}
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
request
::
remote_endpoint
()
const
{
return
impl_
->
remote_endpoint
();
}
}
// namespace server
}
// namespace asio_http2
}
// namespace nghttp2
src/asio_server_request_impl.cc
View file @
0caefe20
...
...
@@ -54,6 +54,14 @@ void request_impl::call_on_data(const uint8_t *data, std::size_t len) {
}
}
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
request_impl
::
remote_endpoint
()
const
{
return
remote_ep_
;
}
void
request_impl
::
remote_endpoint
(
boost
::
asio
::
ip
::
tcp
::
endpoint
ep
)
{
remote_ep_
=
std
::
move
(
ep
);
}
}
// namespace server
}
// namespace asio_http2
}
// namespace nghttp2
src/asio_server_request_impl.h
View file @
0caefe20
...
...
@@ -28,6 +28,7 @@
#include "nghttp2_config.h"
#include <nghttp2/asio_http2_server.h>
#include <boost/asio/ip/tcp.hpp>
namespace
nghttp2
{
namespace
asio_http2
{
...
...
@@ -54,12 +55,16 @@ public:
void
stream
(
class
stream
*
s
);
void
call_on_data
(
const
uint8_t
*
data
,
std
::
size_t
len
);
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
remote_endpoint
()
const
;
void
remote_endpoint
(
boost
::
asio
::
ip
::
tcp
::
endpoint
ep
);
private:
class
stream
*
strm_
;
header_map
header_
;
std
::
string
method_
;
uri_ref
uri_
;
data_cb
on_data_cb_
;
boost
::
asio
::
ip
::
tcp
::
endpoint
remote_ep_
;
};
}
// namespace server
...
...
src/h2load.cc
View file @
0caefe20
This diff is collapsed.
Click to expand it.
src/h2load.h
View file @
0caefe20
...
...
@@ -112,7 +112,6 @@ struct Config {
};
struct
RequestStat
{
RequestStat
();
// time point when request was sent
std
::
chrono
::
steady_clock
::
time_point
request_time
;
// time point when stream was closed
...
...
@@ -208,9 +207,21 @@ enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
struct
Client
;
// We use systematic sampling method
struct
Sampling
{
// sampling interval
double
interval
;
// cumulative value of interval, and the next point is the integer
// rounded up from this value.
double
point
;
// number of samples seen, including discarded samples.
size_t
n
;
};
struct
Worker
{
std
::
vector
<
std
::
unique_ptr
<
Client
>>
clients
;
Stats
stats
;
Sampling
request_times_smp
;
Sampling
client_smp
;
struct
ev_loop
*
loop
;
SSL_CTX
*
ssl_ctx
;
Config
*
config
;
...
...
@@ -226,24 +237,32 @@ struct Worker {
// at most nreqs_rem clients get an extra request
size_t
nreqs_rem
;
size_t
rate
;
// maximum number of samples in this worker thread
size_t
max_samples
;
ev_timer
timeout_watcher
;
// The next client ID this worker assigns
uint32_t
next_client_id
;
Worker
(
uint32_t
id
,
SSL_CTX
*
ssl_ctx
,
size_t
nreq_todo
,
size_t
nclients
,
size_t
rate
,
Config
*
config
);
size_t
rate
,
size_t
max_samples
,
Config
*
config
);
~
Worker
();
Worker
(
Worker
&&
o
)
=
default
;
void
run
();
void
sample_req_stat
(
RequestStat
*
req_stat
);
void
sample_client_stat
(
ClientStat
*
cstat
);
void
report_progress
();
void
report_rate_progress
();
};
struct
Stream
{
RequestStat
req_stat
;
int
status_success
;
Stream
();
};
struct
Client
{
std
::
unordered_map
<
int32_t
,
Stream
>
streams
;
ClientStat
cstat
;
std
::
unique_ptr
<
Session
>
session
;
ev_io
wev
;
ev_io
rev
;
...
...
@@ -288,7 +307,6 @@ struct Client {
void
process_request_failure
();
void
process_timedout_streams
();
void
process_abandoned_streams
();
void
report_progress
();
void
report_tls_info
();
void
report_app_info
();
void
terminate_session
();
...
...
@@ -318,8 +336,12 @@ struct Client {
// |success| == true means that the request/response was exchanged
// |successfully, but it does not mean response carried successful
// |HTTP status code.
void
on_stream_close
(
int32_t
stream_id
,
bool
success
,
RequestStat
*
req_stat
,
bool
final
=
false
);
void
on_stream_close
(
int32_t
stream_id
,
bool
success
,
bool
final
=
false
);
// Returns RequestStat for |stream_id|. This function must be
// called after on_request(stream_id), and before
// on_stream_close(stream_id, ...). Otherwise, this will return
// nullptr.
RequestStat
*
get_req_stat
(
int32_t
stream_id
);
void
record_request_time
(
RequestStat
*
req_stat
);
void
record_connect_start_time
();
...
...
src/h2load_http1_session.cc
View file @
0caefe20
...
...
@@ -80,9 +80,11 @@ int htp_msg_completecb(http_parser *htp) {
auto
client
=
session
->
get_client
();
auto
final
=
http_should_keep_alive
(
htp
)
==
0
;
client
->
on_stream_close
(
session
->
stream_resp_counter_
,
true
,
session
->
req_stats_
[
session
->
stream_resp_counter_
],
final
);
auto
req_stat
=
client
->
get_req_stat
(
session
->
stream_resp_counter_
);
assert
(
req_stat
);
client
->
on_stream_close
(
session
->
stream_resp_counter_
,
true
,
final
);
session
->
stream_resp_counter_
+=
2
;
...
...
@@ -150,7 +152,7 @@ http_parser_settings htp_hooks = {
void
Http1Session
::
on_connect
()
{
client_
->
signal_write
();
}
int
Http1Session
::
submit_request
(
RequestStat
*
req_stat
)
{
int
Http1Session
::
submit_request
()
{
auto
config
=
client_
->
worker
->
config
;
const
auto
&
req
=
config
->
h1reqs
[
client_
->
reqidx
];
client_
->
reqidx
++
;
...
...
@@ -159,13 +161,13 @@ int Http1Session::submit_request(RequestStat *req_stat) {
client_
->
reqidx
=
0
;
}
assert
(
req_stat
);
client_
->
on_request
(
stream_req_counter_
);
auto
req_stat
=
client_
->
get_req_stat
(
stream_req_counter_
);
client_
->
record_request_time
(
req_stat
);
client_
->
wb
.
write
(
req
.
c_str
(),
req
.
size
());
client_
->
on_request
(
stream_req_counter_
);
req_stats_
[
stream_req_counter_
]
=
req_stat
;
// increment for next request
stream_req_counter_
+=
2
;
...
...
src/h2load_http1_session.h
View file @
0caefe20
...
...
@@ -38,14 +38,13 @@ public:
Http1Session
(
Client
*
client
);
virtual
~
Http1Session
();
virtual
void
on_connect
();
virtual
int
submit_request
(
RequestStat
*
req_stat
);
virtual
int
submit_request
();
virtual
int
on_read
(
const
uint8_t
*
data
,
size_t
len
);
virtual
int
on_write
();
virtual
void
terminate
();
Client
*
get_client
();
int32_t
stream_req_counter_
;
int32_t
stream_resp_counter_
;
std
::
unordered_map
<
int32_t
,
RequestStat
*>
req_stats_
;
private:
Client
*
client_
;
...
...
src/h2load_http2_session.cc
View file @
0caefe20
...
...
@@ -89,12 +89,25 @@ namespace {
int
on_stream_close_callback
(
nghttp2_session
*
session
,
int32_t
stream_id
,
uint32_t
error_code
,
void
*
user_data
)
{
auto
client
=
static_cast
<
Client
*>
(
user_data
);
auto
req_stat
=
static_cast
<
RequestStat
*>
(
nghttp2_session_get_stream_user_data
(
session
,
stream_id
));
if
(
!
req_stat
)
{
client
->
on_stream_close
(
stream_id
,
error_code
==
NGHTTP2_NO_ERROR
);
return
0
;
}
}
// namespace
namespace
{
int
on_frame_not_send_callback
(
nghttp2_session
*
session
,
const
nghttp2_frame
*
frame
,
int
lib_error_code
,
void
*
user_data
)
{
if
(
frame
->
hd
.
type
!=
NGHTTP2_HEADERS
||
frame
->
headers
.
cat
!=
NGHTTP2_HCAT_REQUEST
)
{
return
0
;
}
client
->
on_stream_close
(
stream_id
,
error_code
==
NGHTTP2_NO_ERROR
,
req_stat
);
auto
client
=
static_cast
<
Client
*>
(
user_data
);
// request was not sent. Mark it as error.
client
->
on_stream_close
(
frame
->
hd
.
stream_id
,
false
);
return
0
;
}
}
// namespace
...
...
@@ -108,9 +121,7 @@ int before_frame_send_callback(nghttp2_session *session,
}
auto
client
=
static_cast
<
Client
*>
(
user_data
);
client
->
on_request
(
frame
->
hd
.
stream_id
);
auto
req_stat
=
static_cast
<
RequestStat
*>
(
nghttp2_session_get_stream_user_data
(
session
,
frame
->
hd
.
stream_id
));
auto
req_stat
=
client
->
get_req_stat
(
frame
->
hd
.
stream_id
);
assert
(
req_stat
);
client
->
record_request_time
(
req_stat
);
...
...
@@ -124,8 +135,7 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
nghttp2_data_source
*
source
,
void
*
user_data
)
{
auto
client
=
static_cast
<
Client
*>
(
user_data
);
auto
config
=
client
->
worker
->
config
;
auto
req_stat
=
static_cast
<
RequestStat
*>
(
nghttp2_session_get_stream_user_data
(
session
,
stream_id
));
auto
req_stat
=
client
->
get_req_stat
(
stream_id
);
assert
(
req_stat
);
ssize_t
nread
;
while
((
nread
=
pread
(
config
->
data_fd
,
buf
,
length
,
req_stat
->
data_offset
))
==
...
...
@@ -183,6 +193,9 @@ void Http2Session::on_connect() {
nghttp2_session_callbacks_set_on_header_callback
(
callbacks
,
on_header_callback
);
nghttp2_session_callbacks_set_on_frame_not_send_callback
(
callbacks
,
on_frame_not_send_callback
);
nghttp2_session_callbacks_set_before_frame_send_callback
(
callbacks
,
before_frame_send_callback
);
...
...
@@ -212,7 +225,7 @@ void Http2Session::on_connect() {
client_
->
signal_write
();
}
int
Http2Session
::
submit_request
(
RequestStat
*
req_stat
)
{
int
Http2Session
::
submit_request
()
{
if
(
nghttp2_session_check_request_allowed
(
session_
)
==
0
)
{
return
-
1
;
}
...
...
@@ -228,11 +241,13 @@ int Http2Session::submit_request(RequestStat *req_stat) {
auto
stream_id
=
nghttp2_submit_request
(
session_
,
nullptr
,
nva
.
data
(),
nva
.
size
(),
config
->
data_fd
==
-
1
?
nullptr
:
&
prd
,
req_stat
);
config
->
data_fd
==
-
1
?
nullptr
:
&
prd
,
nullptr
);
if
(
stream_id
<
0
)
{
return
-
1
;
}
client_
->
on_request
(
stream_id
);
return
0
;
}
...
...
src/h2load_http2_session.h
View file @
0caefe20
...
...
@@ -38,7 +38,7 @@ public:
Http2Session
(
Client
*
client
);
virtual
~
Http2Session
();
virtual
void
on_connect
();
virtual
int
submit_request
(
RequestStat
*
req_stat
);
virtual
int
submit_request
();
virtual
int
on_read
(
const
uint8_t
*
data
,
size_t
len
);
virtual
int
on_write
();
virtual
void
terminate
();
...
...
src/h2load_session.h
View file @
0caefe20
...
...
@@ -41,7 +41,7 @@ public:
// Called when the connection was made.
virtual
void
on_connect
()
=
0
;
// Called when one request must be issued.
virtual
int
submit_request
(
RequestStat
*
req_stat
)
=
0
;
virtual
int
submit_request
()
=
0
;
// Called when incoming bytes are available. The subclass has to
// return the number of bytes read.
virtual
int
on_read
(
const
uint8_t
*
data
,
size_t
len
)
=
0
;
...
...
src/h2load_spdy_session.cc
View file @
0caefe20
...
...
@@ -48,9 +48,7 @@ void before_ctrl_send_callback(spdylay_session *session,
return
;
}
client
->
on_request
(
frame
->
syn_stream
.
stream_id
);
auto
req_stat
=
static_cast
<
RequestStat
*>
(
spdylay_session_get_stream_user_data
(
session
,
frame
->
syn_stream
.
stream_id
));
auto
req_stat
=
client
->
get_req_stat
(
frame
->
syn_stream
.
stream_id
);
client
->
record_request_time
(
req_stat
);
}
}
// namespace
...
...
@@ -104,9 +102,7 @@ void on_stream_close_callback(spdylay_session *session, int32_t stream_id,
spdylay_status_code
status_code
,
void
*
user_data
)
{
auto
client
=
static_cast
<
Client
*>
(
user_data
);
auto
req_stat
=
static_cast
<
RequestStat
*>
(
spdylay_session_get_stream_user_data
(
session
,
stream_id
));
client
->
on_stream_close
(
stream_id
,
status_code
==
SPDYLAY_OK
,
req_stat
);
client
->
on_stream_close
(
stream_id
,
status_code
==
SPDYLAY_OK
);
}
}
// namespace
...
...
@@ -130,8 +126,7 @@ ssize_t file_read_callback(spdylay_session *session, int32_t stream_id,
spdylay_data_source
*
source
,
void
*
user_data
)
{
auto
client
=
static_cast
<
Client
*>
(
user_data
);
auto
config
=
client
->
worker
->
config
;
auto
req_stat
=
static_cast
<
RequestStat
*>
(
spdylay_session_get_stream_user_data
(
session
,
stream_id
));
auto
req_stat
=
client
->
get_req_stat
(
stream_id
);
ssize_t
nread
;
while
((
nread
=
pread
(
config
->
data_fd
,
buf
,
length
,
req_stat
->
data_offset
))
==
...
...
@@ -185,7 +180,7 @@ void SpdySession::on_connect() {
client_
->
signal_write
();
}
int
SpdySession
::
submit_request
(
RequestStat
*
req_stat
)
{
int
SpdySession
::
submit_request
()
{
int
rv
;
auto
config
=
client_
->
worker
->
config
;
auto
&
nv
=
config
->
nv
[
client_
->
reqidx
++
];
...
...
@@ -197,7 +192,7 @@ int SpdySession::submit_request(RequestStat *req_stat) {
spdylay_data_provider
prd
{{
0
},
file_read_callback
};
rv
=
spdylay_submit_request
(
session_
,
0
,
nv
.
data
(),
config
->
data_fd
==
-
1
?
nullptr
:
&
prd
,
req_stat
);
config
->
data_fd
==
-
1
?
nullptr
:
&
prd
,
nullptr
);
if
(
rv
!=
0
)
{
return
-
1
;
...
...
src/h2load_spdy_session.h
View file @
0caefe20
...
...
@@ -40,7 +40,7 @@ public:
SpdySession
(
Client
*
client
,
uint16_t
spdy_version
);
virtual
~
SpdySession
();
virtual
void
on_connect
();
virtual
int
submit_request
(
RequestStat
*
req_stat
);
virtual
int
submit_request
();
virtual
int
on_read
(
const
uint8_t
*
data
,
size_t
len
);
virtual
int
on_write
();
virtual
void
terminate
();
...
...
src/http2.cc
View file @
0caefe20
...
...
@@ -113,6 +113,8 @@ std::string get_status_string(unsigned int status_code) {
return
"429 Too Many Requests"
;
case
431
:
return
"431 Request Header Fields Too Large"
;
case
451
:
return
"451 Unavailable For Legal Reasons"
;
case
500
:
return
"500 Internal Server Error"
;
case
501
:
...
...
@@ -215,6 +217,8 @@ const char *stringify_status(unsigned int status_code) {
return
"429"
;
case
431
:
return
"431"
;
case
451
:
return
"451"
;
case
500
:
return
"500"
;
case
501
:
...
...
src/includes/nghttp2/asio_http2_client.h
View file @
0caefe20
...
...
@@ -144,6 +144,12 @@ public:
// and session is terminated.
void
on_error
(
error_cb
cb
)
const
;
// Sets connect timeout, which defaults to 60 seconds.
void
connect_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
// Sets read timeout, which defaults to 60 seconds.
void
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
// Shutdowns connection.
void
shutdown
()
const
;
...
...
@@ -177,7 +183,7 @@ public:
generator_cb
cb
,
header_map
h
=
header_map
{})
const
;
private:
std
::
unique
_ptr
<
session_impl
>
impl_
;
std
::
shared
_ptr
<
session_impl
>
impl_
;
};
// configure |tls_ctx| for client use. Currently, we just set NPN
...
...
src/includes/nghttp2/asio_http2_server.h
View file @
0caefe20
...
...
@@ -59,6 +59,9 @@ public:
// Application must not call this directly.
request_impl
&
impl
()
const
;
// Returns the remote endpoint of the request
const
boost
::
asio
::
ip
::
tcp
::
endpoint
&
remote_endpoint
()
const
;
private:
std
::
unique_ptr
<
request_impl
>
impl_
;
};
...
...
@@ -195,12 +198,22 @@ public:
// connections.
void
backlog
(
int
backlog
);
// Sets TLS handshake timeout, which defaults to 60 seconds.
void
tls_handshake_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
// Sets read timeout, which defaults to 60 seconds.
void
read_timeout
(
const
boost
::
posix_time
::
time_duration
&
t
);
// Gracefully stop http2 server
void
stop
();
// Join on http2 server and wait for it to fully stop
void
join
();
// Get access to the io_service objects.
const
std
::
vector
<
std
::
shared_ptr
<
boost
::
asio
::
io_service
>>
&
io_services
()
const
;
private:
std
::
unique_ptr
<
http2_impl
>
impl_
;
};
...
...
src/nghttpd.cc
View file @
0caefe20
...
...
@@ -164,6 +164,8 @@ Options:
Path to file that contains MIME media types and the
extensions that represent them.
Default: )"
<<
config
.
mime_types_file
<<
R"(
--no-content-length
Don't send content-length header field.
--version Display version information and exit.
-h, --help Display this help and exit.
...
...
@@ -209,6 +211,7 @@ int main(int argc, char **argv) {
{
"hexdump"
,
no_argument
,
&
flag
,
7
},
{
"echo-upload"
,
no_argument
,
&
flag
,
8
},
{
"mime-types-file"
,
required_argument
,
&
flag
,
9
},
{
"no-content-length"
,
no_argument
,
&
flag
,
10
},
{
nullptr
,
0
,
nullptr
,
0
}};
int
option_index
=
0
;
int
c
=
getopt_long
(
argc
,
argv
,
"DVb:c:d:ehm:n:p:va:"
,
long_options
,
...
...
@@ -340,6 +343,10 @@ int main(int argc, char **argv) {
mime_types_file_set_manually
=
true
;
config
.
mime_types_file
=
optarg
;
break
;
case
10
:
// no-content-length option
config
.
no_content_length
=
true
;
break
;
}
break
;
default:
...
...
src/shrpx.cc
View file @
0caefe20
...
...
@@ -1610,14 +1610,15 @@ HTTP:
used several times to specify multiple header fields.
Example: --add-response-header="foo: bar"
--header-field-buffer=<SIZE>
Set maximum
buffer size for incoming HTTP header field
list. This is the sum of header name and value
in
Set maximum
buffer size for incoming HTTP request header
field list. This is the sum of header name and value
in
bytes.
Default: )"
<<
util
::
utos_with_unit
(
get_config
()
->
header_field_buffer
)
<<
R"(
--max-header-fields=<N>
Set maximum number of incoming HTTP header fields, which
appear in one request or response header field list.
Set maximum number of incoming HTTP request header
fields, which appear in one request or response header
field list.
Default: )"
<<
get_config
()
->
max_header_fields
<<
R"(
Debug:
...
...
src/shrpx.h
View file @
0caefe20
...
...
@@ -44,4 +44,8 @@
#define DIE() _Exit(EXIT_FAILURE)
#if defined(HAVE_DECL_INITGROUPS) && !HAVE_DECL_INITGROUPS
inline
int
initgroups
(
const
char
*
user
,
gid_t
group
)
{
return
0
;
}
#endif // defined(HAVE_DECL_INITGROUPS) && !HAVE_DECL_INITGROUPS
#endif // SHRPX_H
src/shrpx_client_handler.cc
View file @
0caefe20
...
...
@@ -718,6 +718,34 @@ void ClientHandler::direct_http2_upgrade() {
int
ClientHandler
::
perform_http2_upgrade
(
HttpsUpstream
*
http
)
{
auto
upstream
=
make_unique
<
Http2Upstream
>
(
this
);
auto
output
=
upstream
->
get_response_buf
();
// We might have written non-final header in response_buf, in this
// case, response_state is still INITIAL. If this non-final header
// and upgrade header fit in output buffer, do upgrade. Otherwise,
// to avoid to send this non-final header as response body in HTTP/2
// upstream, fail upgrade.
auto
downstream
=
http
->
get_downstream
();
auto
input
=
downstream
->
get_response_buf
();
static
constexpr
char
res
[]
=
"HTTP/1.1 101 Switching Protocols
\r\n
"
"Connection: Upgrade
\r\n
"
"Upgrade: "
NGHTTP2_CLEARTEXT_PROTO_VERSION_ID
"
\r\n
"
"
\r\n
"
;
auto
required_size
=
str_size
(
res
)
+
input
->
rleft
();
if
(
output
->
wleft
()
<
required_size
)
{
if
(
LOG_ENABLED
(
INFO
))
{
CLOG
(
INFO
,
this
)
<<
"HTTP Upgrade failed because of insufficient buffer space: need "
<<
required_size
<<
", available "
<<
output
->
wleft
();
}
return
-
1
;
}
if
(
upstream
->
upgrade_upstream
(
http
)
!=
0
)
{
return
-
1
;
}
...
...
@@ -729,11 +757,11 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
on_read_
=
&
ClientHandler
::
upstream_http2_connhd_read
;
write_
=
&
ClientHandler
::
write_clear
;
static
char
res
[]
=
"HTTP/1.1 101 Switching Protocols
\r\n
"
"Connection: Upgrade
\r\n
"
"Upgrade: "
NGHTTP2_CLEARTEXT_PROTO_VERSION_ID
"
\r\n
"
"
\r\n
"
;
upstream
->
get_response_buf
()
->
write
(
res
,
sizeof
(
res
)
-
1
);
auto
nread
=
downstream
->
get_response_buf
()
->
remove
(
output
->
last
,
output
->
wleft
());
output
->
write
(
nread
);
output
->
write
(
res
,
str_size
(
res
)
);
upstream_
=
std
::
move
(
upstream
);
signal_write
();
...
...
src/shrpx_config.cc
View file @
0caefe20
...
...
@@ -276,11 +276,9 @@ std::string read_passwd_from_file(const char *filename) {
}
std
::
pair
<
std
::
string
,
std
::
string
>
parse_header
(
const
char
*
optarg
)
{
// We skip possible ":" at the start of optarg.
const
auto
*
colon
=
strchr
(
optarg
+
1
,
':'
);
const
auto
*
colon
=
strchr
(
optarg
,
':'
);
// name = ":" is not allowed
if
(
colon
==
nullptr
||
(
optarg
[
0
]
==
':'
&&
colon
==
optarg
+
1
))
{
if
(
colon
==
nullptr
||
colon
==
optarg
)
{
return
{
""
,
""
};
}
...
...
@@ -291,7 +289,14 @@ std::pair<std::string, std::string> parse_header(const char *optarg) {
auto
p
=
std
::
make_pair
(
std
::
string
(
optarg
,
colon
),
std
::
string
(
value
,
strlen
(
value
)));
util
::
inp_strlower
(
p
.
first
);
util
::
inp_strlower
(
p
.
second
);
if
(
!
nghttp2_check_header_name
(
reinterpret_cast
<
const
uint8_t
*>
(
p
.
first
.
c_str
()),
p
.
first
.
size
())
||
!
nghttp2_check_header_value
(
reinterpret_cast
<
const
uint8_t
*>
(
p
.
second
.
c_str
()),
p
.
second
.
size
()))
{
return
{
""
,
""
};
}
return
p
;
}
...
...
@@ -1800,7 +1805,7 @@ int parse_config(const char *opt, const char *optarg,
case
SHRPX_OPTID_ADD_RESPONSE_HEADER
:
{
auto
p
=
parse_header
(
optarg
);
if
(
p
.
first
.
empty
())
{
LOG
(
ERROR
)
<<
opt
<<
":
header field name is empty
: "
<<
optarg
;
LOG
(
ERROR
)
<<
opt
<<
":
invalid header field
: "
<<
optarg
;
return
-
1
;
}
if
(
optid
==
SHRPX_OPTID_ADD_REQUEST_HEADER
)
{
...
...
src/shrpx_config_test.cc
View file @
0caefe20
...
...
@@ -46,8 +46,7 @@ void test_shrpx_config_parse_header(void) {
CU_ASSERT
(
"b"
==
p
.
second
);
p
=
parse_header
(
":a: b"
);
CU_ASSERT
(
":a"
==
p
.
first
);
CU_ASSERT
(
"b"
==
p
.
second
);
CU_ASSERT
(
p
.
first
.
empty
());
p
=
parse_header
(
"a: :b"
);
CU_ASSERT
(
"a"
==
p
.
first
);
...
...
@@ -59,6 +58,12 @@ void test_shrpx_config_parse_header(void) {
p
=
parse_header
(
"alpha: bravo charlie"
);
CU_ASSERT
(
"alpha"
==
p
.
first
);
CU_ASSERT
(
"bravo charlie"
==
p
.
second
);
p
=
parse_header
(
"a,: b"
);
CU_ASSERT
(
p
.
first
.
empty
());
p
=
parse_header
(
"a: b
\x0a
"
);
CU_ASSERT
(
p
.
first
.
empty
());
}
void
test_shrpx_config_parse_log_format
(
void
)
{
...
...
src/shrpx_http2_session.cc
View file @
0caefe20
...
...
@@ -757,26 +757,6 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
auto
trailer
=
frame
->
headers
.
cat
==
NGHTTP2_HCAT_HEADERS
&&
!
downstream
->
get_expect_final_response
();
if
(
downstream
->
get_response_headers_sum
()
+
namelen
+
valuelen
>
get_config
()
->
header_field_buffer
||
downstream
->
get_response_headers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too large or many header field size="
<<
downstream
->
get_response_headers_sum
()
+
namelen
+
valuelen
<<
", num="
<<
downstream
->
get_response_headers
().
size
()
+
1
;
}
if
(
trailer
)
{
// we don't care trailer part exceeds header size limit; just
// discard it.
return
0
;
}
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
if
(
trailer
)
{
// just store header fields for trailer part
downstream
->
add_response_trailer
(
name
,
namelen
,
value
,
valuelen
,
...
...
@@ -803,21 +783,6 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
assert
(
promised_downstream
);
if
(
promised_downstream
->
get_request_headers_sum
()
+
namelen
+
valuelen
>
get_config
()
->
header_field_buffer
||
promised_downstream
->
get_request_headers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
promised_downstream
)
<<
"Too large or many header field size="
<<
promised_downstream
->
get_request_headers_sum
()
+
namelen
+
valuelen
<<
", num="
<<
promised_downstream
->
get_request_headers
().
size
()
+
1
;
}
return
NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
;
}
auto
token
=
http2
::
lookup_token
(
name
,
namelen
);
promised_downstream
->
add_request_header
(
name
,
namelen
,
value
,
valuelen
,
flags
&
NGHTTP2_NV_FLAG_NO_INDEX
,
...
...
src/shrpx_http2_upstream.cc
View file @
0caefe20
...
...
@@ -169,7 +169,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
if
(
downstream
->
get_request_headers_sum
()
+
namelen
+
valuelen
>
get_config
()
->
header_field_buffer
||
downstream
->
get_request_headers
().
size
()
>=
downstream
->
get_request_headers
().
size
()
+
downstream
->
get_request_trailers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
downstream
->
get_response_state
()
==
Downstream
::
MSG_COMPLETE
)
{
return
0
;
...
...
src/shrpx_http_downstream_connection.cc
View file @
0caefe20
...
...
@@ -562,29 +562,10 @@ int htp_hdrs_completecb(http_parser *htp) {
namespace
{
int
htp_hdr_keycb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
downstream
=
static_cast
<
Downstream
*>
(
htp
->
data
);
if
(
downstream
->
get_response_headers_sum
()
+
len
>
get_config
()
->
header_field_buffer
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too large header block size="
<<
downstream
->
get_response_headers_sum
()
+
len
;
}
return
-
1
;
}
if
(
downstream
->
get_response_state
()
==
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
append_last_response_header_key
(
data
,
len
);
}
else
{
if
(
downstream
->
get_response_headers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too many header field num="
<<
downstream
->
get_response_headers
().
size
()
+
1
;
}
return
-
1
;
}
downstream
->
add_response_header
(
std
::
string
(
data
,
len
),
""
);
}
}
else
{
...
...
@@ -592,15 +573,6 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
if
(
downstream
->
get_response_trailer_key_prev
())
{
downstream
->
append_last_response_trailer_key
(
data
,
len
);
}
else
{
if
(
downstream
->
get_response_headers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too many header field num="
<<
downstream
->
get_response_headers
().
size
()
+
1
;
}
return
-
1
;
}
downstream
->
add_response_trailer
(
std
::
string
(
data
,
len
),
""
);
}
}
...
...
@@ -611,14 +583,6 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
namespace
{
int
htp_hdr_valcb
(
http_parser
*
htp
,
const
char
*
data
,
size_t
len
)
{
auto
downstream
=
static_cast
<
Downstream
*>
(
htp
->
data
);
if
(
downstream
->
get_response_headers_sum
()
+
len
>
get_config
()
->
header_field_buffer
)
{
if
(
LOG_ENABLED
(
INFO
))
{
DLOG
(
INFO
,
downstream
)
<<
"Too large header block size="
<<
downstream
->
get_response_headers_sum
()
+
len
;
}
return
-
1
;
}
if
(
downstream
->
get_response_state
()
==
Downstream
::
INITIAL
)
{
if
(
downstream
->
get_response_header_key_prev
())
{
downstream
->
set_last_response_header_value
(
data
,
len
);
...
...
src/shrpx_https_upstream.cc
View file @
0caefe20
...
...
@@ -146,7 +146,8 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
if
(
downstream
->
get_request_trailer_key_prev
())
{
downstream
->
append_last_request_trailer_key
(
data
,
len
);
}
else
{
if
(
downstream
->
get_request_headers
().
size
()
>=
if
(
downstream
->
get_request_headers
().
size
()
+
downstream
->
get_request_trailers
().
size
()
>=
get_config
()
->
max_header_fields
)
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"Too many header field num="
...
...
@@ -409,11 +410,6 @@ int htp_msg_completecb(http_parser *htp) {
if
(
handler
->
get_http2_upgrade_allowed
()
&&
downstream
->
get_http2_upgrade_request
()
&&
// we may write non-final header in response_buf, in this case,
// response_state is still INITIAL. So don't upgrade in this
// case, otherwise we end up send this non-final header as
// response body in HTTP/2 upstream.
downstream
->
get_response_buf
()
->
rleft
()
==
0
&&
handler
->
perform_http2_upgrade
(
upstream
)
!=
0
)
{
if
(
LOG_ENABLED
(
INFO
))
{
ULOG
(
INFO
,
upstream
)
<<
"HTTP Upgrade to HTTP/2 failed"
;
...
...
src/shrpx_spdy_upstream.cc
View file @
0caefe20
...
...
@@ -169,6 +169,8 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
header_buffer
+=
strlen
(
nv
[
i
])
+
strlen
(
nv
[
i
+
1
]);
}
// spdy does not define usage of trailer fields, and we ignores
// them.
if
(
header_buffer
>
get_config
()
->
header_field_buffer
||
num_headers
>
get_config
()
->
max_header_fields
)
{
upstream
->
rst_stream
(
downstream
,
SPDYLAY_INTERNAL_ERROR
);
...
...
src/shrpx_ssl.cc
View file @
0caefe20
...
...
@@ -41,6 +41,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/dh.h>
#include <nghttp2/nghttp2.h>
...
...
src/ssl.cc
View file @
0caefe20
...
...
@@ -80,12 +80,7 @@ LibsslGlobalLock::LibsslGlobalLock() {
LibsslGlobalLock
::~
LibsslGlobalLock
()
{
ssl_global_locks
.
clear
();
}
const
char
*
get_tls_protocol
(
SSL
*
ssl
)
{
auto
session
=
SSL_get_session
(
ssl
);
if
(
!
session
)
{
return
"unknown"
;
}
switch
(
session
->
ssl_version
)
{
switch
(
SSL_version
(
ssl
))
{
case
SSL2_VERSION
:
return
"SSLv2"
;
case
SSL3_VERSION
:
...
...
@@ -113,10 +108,12 @@ TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) {
tls_info
->
cipher
=
SSL_get_cipher_name
(
ssl
);
tls_info
->
protocol
=
get_tls_protocol
(
ssl
);
tls_info
->
session_id
=
session
->
session_id
;
tls_info
->
session_id_length
=
session
->
session_id_length
;
tls_info
->
session_reused
=
SSL_session_reused
(
ssl
);
unsigned
int
session_id_length
;
tls_info
->
session_id
=
SSL_SESSION_get_id
(
session
,
&
session_id_length
);
tls_info
->
session_id_length
=
session_id_length
;
return
tls_info
;
}
...
...
tests/main.c
View file @
0caefe20
...
...
@@ -89,6 +89,8 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_recv_headers_with_priority
)
||
!
CU_add_test
(
pSuite
,
"session_recv_headers_early_response"
,
test_nghttp2_session_recv_headers_early_response
)
||
!
CU_add_test
(
pSuite
,
"session_server_recv_push_response"
,
test_nghttp2_session_server_recv_push_response
)
||
!
CU_add_test
(
pSuite
,
"session_recv_premature_headers"
,
test_nghttp2_session_recv_premature_headers
)
||
!
CU_add_test
(
pSuite
,
"session_recv_unknown_frame"
,
...
...
@@ -128,6 +130,8 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_on_window_update_received
)
||
!
CU_add_test
(
pSuite
,
"session_on_data_received"
,
test_nghttp2_session_on_data_received
)
||
!
CU_add_test
(
pSuite
,
"session_on_data_received_fail_fast"
,
test_nghttp2_session_on_data_received_fail_fast
)
||
!
CU_add_test
(
pSuite
,
"session_send_headers_start_stream"
,
test_nghttp2_session_send_headers_start_stream
)
||
!
CU_add_test
(
pSuite
,
"session_send_headers_reply"
,
...
...
@@ -205,8 +209,6 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_reply_fail
)
||
!
CU_add_test
(
pSuite
,
"session_max_concurrent_streams"
,
test_nghttp2_session_max_concurrent_streams
)
||
!
CU_add_test
(
pSuite
,
"session_stream_close_on_headers_push"
,
test_nghttp2_session_stream_close_on_headers_push
)
||
!
CU_add_test
(
pSuite
,
"session_stop_data_with_rst_stream"
,
test_nghttp2_session_stop_data_with_rst_stream
)
||
!
CU_add_test
(
pSuite
,
"session_defer_data"
,
...
...
@@ -291,6 +293,10 @@ int main(int argc _U_, char *argv[] _U_) {
!
CU_add_test
(
pSuite
,
"session_flooding"
,
test_nghttp2_session_flooding
)
||
!
CU_add_test
(
pSuite
,
"session_change_stream_priority"
,
test_nghttp2_session_change_stream_priority
)
||
!
CU_add_test
(
pSuite
,
"session_repeated_priority_change"
,
test_nghttp2_session_repeated_priority_change
)
||
!
CU_add_test
(
pSuite
,
"session_repeated_priority_submission"
,
test_nghttp2_session_repeated_priority_submission
)
||
!
CU_add_test
(
pSuite
,
"http_mandatory_headers"
,
test_nghttp2_http_mandatory_headers
)
||
!
CU_add_test
(
pSuite
,
"http_content_length"
,
...
...
tests/nghttp2_session_test.c
View file @
0caefe20
This diff is collapsed.
Click to expand it.
tests/nghttp2_session_test.h
View file @
0caefe20
...
...
@@ -34,6 +34,7 @@ void test_nghttp2_session_recv_data_no_auto_flow_control(void);
void
test_nghttp2_session_recv_continuation
(
void
);
void
test_nghttp2_session_recv_headers_with_priority
(
void
);
void
test_nghttp2_session_recv_headers_early_response
(
void
);
void
test_nghttp2_session_server_recv_push_response
(
void
);
void
test_nghttp2_session_recv_premature_headers
(
void
);
void
test_nghttp2_session_recv_unknown_frame
(
void
);
void
test_nghttp2_session_recv_unexpected_continuation
(
void
);
...
...
@@ -54,6 +55,7 @@ void test_nghttp2_session_on_ping_received(void);
void
test_nghttp2_session_on_goaway_received
(
void
);
void
test_nghttp2_session_on_window_update_received
(
void
);
void
test_nghttp2_session_on_data_received
(
void
);
void
test_nghttp2_session_on_data_received_fail_fast
(
void
);
void
test_nghttp2_session_send_headers_start_stream
(
void
);
void
test_nghttp2_session_send_headers_reply
(
void
);
void
test_nghttp2_session_send_headers_frame_size_error
(
void
);
...
...
@@ -95,7 +97,6 @@ void test_nghttp2_session_get_next_ob_item(void);
void
test_nghttp2_session_pop_next_ob_item
(
void
);
void
test_nghttp2_session_reply_fail
(
void
);
void
test_nghttp2_session_max_concurrent_streams
(
void
);
void
test_nghttp2_session_stream_close_on_headers_push
(
void
);
void
test_nghttp2_session_stop_data_with_rst_stream
(
void
);
void
test_nghttp2_session_defer_data
(
void
);
void
test_nghttp2_session_flow_control
(
void
);
...
...
@@ -139,6 +140,8 @@ void test_nghttp2_session_detach_item_from_closed_stream(void);
void
test_nghttp2_session_flooding
(
void
);
void
test_nghttp2_session_change_stream_priority
(
void
);
void
test_nghttp2_session_create_idle_stream
(
void
);
void
test_nghttp2_session_repeated_priority_change
(
void
);
void
test_nghttp2_session_repeated_priority_submission
(
void
);
void
test_nghttp2_http_mandatory_headers
(
void
);
void
test_nghttp2_http_content_length
(
void
);
void
test_nghttp2_http_content_length_mismatch
(
void
);
...
...
neverbleed
@
5c47587b
Subproject commit
81eff20bd84b4d0dce2cbbd1a5ad1384d086423b
Subproject commit
5c47587bc2855f2b9577a9bd369ed70088b77fec
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment