Compare commits

..

32 Commits

Author SHA1 Message Date
Tatsuhiro Tsujikawa
5a8d5e5dd9 Update man pages 2015-06-23 23:22:35 +09:00
Tatsuhiro Tsujikawa
9bcb0ffdef Bump up version number to 1.0.4, LT revision to 14:4:0 2015-06-23 23:20:13 +09:00
Tatsuhiro Tsujikawa
1945d0f02a Fix assertion failure in nghttp2_stream.c
This is regression introduced in
46b70c1db8.
2015-06-23 23:04:53 +09:00
Tatsuhiro Tsujikawa
4870edb33d Bump up version number to 1.0.4-DEV 2015-06-23 01:02:48 +09:00
Tatsuhiro Tsujikawa
3abb162969 Update man pages 2015-06-23 00:54:09 +09:00
Tatsuhiro Tsujikawa
4242478f39 Update nghttpx man page template 2015-06-23 00:53:51 +09:00
Tatsuhiro Tsujikawa
4fa2ffe292 Dump up version number to 1.0.3, LT revision to 14:3:0 2015-06-23 00:48:23 +09:00
Tatsuhiro Tsujikawa
301df2a856 src: Disable SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 2015-06-22 23:26:45 +09:00
Tatsuhiro Tsujikawa
f3b7f4140b nghttpx: Clarify origin host for --backend-http1-connection-per-host 2015-06-22 21:09:39 +09:00
Tatsuhiro Tsujikawa
878b873c69 src: Use using instead of typedef 2015-06-21 19:37:50 +09:00
Tatsuhiro Tsujikawa
2ca8cf36b7 util: Use constexpr for ALPN id 2015-06-21 19:34:43 +09:00
Tatsuhiro Tsujikawa
2224b98c9c Remove duplicated dependency validation in nghttp2_session_reprioritize_stream 2015-06-21 16:31:30 +09:00
Tatsuhiro Tsujikawa
a7031da364 Fix bug that idle self-depending PRIORITY is not handled gracefully
Previously, we did not handle PRIORITY frame which depends on itself
and for idle stream.  As a result, nghttp2_session_mem_recv (or
nghttp2_session_recv) returne NGHTTP2_ERR_NOMEM.  The error code was
still misleading.  It was not out of memory, and we failed to insert
hash map because of duplicated key, which was treated as out of
memory.  This commit fixes this issue, by explicitly checking
dependency for incoming PRIORITY for all cases.
2015-06-21 16:02:32 +09:00
Tatsuhiro Tsujikawa
cebfdacc5a src: Use user-defined literals for time (hours and minutes) 2015-06-21 14:51:32 +09:00
Tatsuhiro Tsujikawa
39f89f4a60 src: Use user-defined literals for k, m, and g. 2015-06-21 14:32:47 +09:00
Tatsuhiro Tsujikawa
46b70c1db8 Optimize dependency based priority code to Firefox style tree
While this commit optimizes dependency routine to Firefox style tree,
the other use cases (e.g., linear chain) are also improved
dramatically as well.
2015-06-20 22:11:24 +09:00
Tatsuhiro Tsujikawa
5537503172 Merge branch 'jfcalcerrada-patch-1' 2015-06-20 19:42:09 +09:00
José F. Calcerrada
81cc550eb9 Update README.rst
Typo
2015-06-20 11:02:33 +01:00
Tatsuhiro Tsujikawa
0a6de0d378 nghttp: Perform special handling of IPv6 literal with zone ID as per RFC 6874
This commit adds special handling of IPv6 literal with zone ID as per
RFC 6874.  Still IPv6 link local address does not work, since URI
parser from http-parser does not allow this syntax.
2015-06-18 20:00:02 +09:00
Tatsuhiro Tsujikawa
25d1de0278 nghttp: Print error if all connect() syscall faild 2015-06-18 18:03:25 +09:00
Tatsuhiro Tsujikawa
39eb8b8a6b nghttp: Print error when parsing URI failed 2015-06-18 18:00:24 +09:00
Tatsuhiro Tsujikawa
c050fca177 Merge branch 'vapier-master' 2015-06-18 17:55:50 +09:00
Mike Frysinger
19309823aa enable third-party for asio_lib too
Since this library uses the third-party subdir, make sure we auto-enable
it when that lib is turned on.
2015-06-17 13:29:37 -04:00
Tatsuhiro Tsujikawa
90bcdb0dda Merge branch 'libressl' 2015-06-17 18:27:54 +09:00
Tatsuhiro Tsujikawa
17ec30e45c Mention LibreSSL in README.rst 2015-06-17 18:27:27 +09:00
Tatsuhiro Tsujikawa
07f763be49 fetch-ocsp-response: Support LibreSSL, and include port in ocsp_host 2015-06-17 18:24:57 +09:00
Tatsuhiro Tsujikawa
69119f47c4 src: Support compile with LibreSSL 2015-06-17 18:24:51 +09:00
Tatsuhiro Tsujikawa
b0b792e735 integration: Add tests for x-forwarded-proto header field 2015-06-16 21:31:47 +09:00
Tatsuhiro Tsujikawa
8aab74ad36 nghttpx: Refactor a bit 2015-06-16 21:31:33 +09:00
Tatsuhiro Tsujikawa
f418d1239f nghttpx: Fix bug that XFP header always http on HTTP/2 backend
This commit fixes the bug that x-forwarded-proto header field sent on
HTTP/2 backend always "http", regardless of frontend scheme.
2015-06-16 21:29:47 +09:00
Tatsuhiro Tsujikawa
5b51320dc5 nghttpx: Validate :path on SPDY frontend
Unless method is CONNECT, we require that :path starts with "/",
except for OPTIONS method, which can take "*" as :path (server-wide
OPTIONS request).
2015-06-16 00:09:22 +09:00
Tatsuhiro Tsujikawa
d2e81da9e2 Bump up version number to 1.0.3-DEV 2015-06-12 22:58:14 +09:00
43 changed files with 922 additions and 424 deletions

View File

@@ -67,6 +67,8 @@ required:
* zlib >= 1.2.3 * zlib >= 1.2.3
ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015). ALPN support requires OpenSSL >= 1.0.2 (released 22 January 2015).
LibreSSL >= 2.2.0 can be used instead of OpenSSL, but OpenSSL has more
features than LibreSSL at the time of this writing.
To enable the SPDY protocol in the application program ``nghttpx`` and To enable the SPDY protocol in the application program ``nghttpx`` and
``h2load``, the following package is required: ``h2load``, the following package is required:

View File

@@ -25,7 +25,7 @@ dnl Do not change user variables!
dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html dnl http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT([nghttp2], [1.0.2], [t-tujikawa@users.sourceforge.net]) AC_INIT([nghttp2], [1.0.4], [t-tujikawa@users.sourceforge.net])
AC_USE_SYSTEM_EXTENSIONS AC_USE_SYSTEM_EXTENSIONS
LT_PREREQ([2.2.6]) LT_PREREQ([2.2.6])
@@ -48,7 +48,7 @@ AC_CONFIG_HEADERS([config.h])
dnl See versioning rule: dnl See versioning rule:
dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html dnl http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST(LT_CURRENT, 14) AC_SUBST(LT_CURRENT, 14)
AC_SUBST(LT_REVISION, 2) AC_SUBST(LT_REVISION, 4)
AC_SUBST(LT_AGE, 0) AC_SUBST(LT_AGE, 0)
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"` major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
@@ -464,11 +464,12 @@ fi
AM_CONDITIONAL([ENABLE_EXAMPLES], [ test "x${enable_examples}" = "xyes" ]) AM_CONDITIONAL([ENABLE_EXAMPLES], [ test "x${enable_examples}" = "xyes" ])
# third-party only be built if either enable_examples or enable_app is # third-party only be built when needed
# yes
enable_third_party=no enable_third_party=no
if test "x${enable_examples}" = "xyes" || test "x${enable_app}" = "xyes"; then if test "x${enable_examples}" = "xyes" ||
test "x${enable_app}" = "xyes" ||
test "x${enable_asio_lib}" = "xyes"; then
enable_third_party=yes enable_third_party=yes
fi fi

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "H2LOAD" "1" "June 12, 2015" "1.0.2" "nghttp2" .TH "H2LOAD" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME .SH NAME
h2load \- HTTP/2 benchmarking tool h2load \- HTTP/2 benchmarking tool
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTP" "1" "June 12, 2015" "1.0.2" "nghttp2" .TH "NGHTTP" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME .SH NAME
nghttp \- HTTP/2 experimental client nghttp \- HTTP/2 experimental client
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTPD" "1" "June 12, 2015" "1.0.2" "nghttp2" .TH "NGHTTPD" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME .SH NAME
nghttpd \- HTTP/2 experimental server nghttpd \- HTTP/2 experimental server
. .

View File

@@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText. .\" Man page generated from reStructuredText.
. .
.TH "NGHTTPX" "1" "June 12, 2015" "1.0.2" "nghttp2" .TH "NGHTTPX" "1" "June 23, 2015" "1.0.4" "nghttp2"
.SH NAME .SH NAME
nghttpx \- HTTP/2 experimental proxy nghttpx \- HTTP/2 experimental proxy
. .
@@ -203,9 +203,11 @@ backend addresses specified by \fI\%\-b\fP option.
.TP .TP
.B \-\-backend\-http1\-connections\-per\-host=<N> .B \-\-backend\-http1\-connections\-per\-host=<N>
Set maximum number of backend concurrent HTTP/1 Set maximum number of backend concurrent HTTP/1
connections per host. This option is meaningful when \fI\%\-s\fP connections per origin host. This option is meaningful
option is used. To limit the number of connections per when \fI\%\-s\fP option is used. The origin host is determined
frontend for default mode, use by authority portion of requset URI (or :authority
header field for HTTP/2). To limit the number of
connections per frontend for default mode, use
\fI\%\-\-backend\-http1\-connections\-per\-frontend\fP\&. \fI\%\-\-backend\-http1\-connections\-per\-frontend\fP\&.
.sp .sp
Default: \fB8\fP Default: \fB8\fP
@@ -890,9 +892,10 @@ both old and new configurations use same filename, new binary does not
delete the socket and continues to use it. delete the socket and continues to use it.
.SH OCSP STAPLING .SH OCSP STAPLING
.sp .sp
OCSP query is done using external perl script \fBfetch\-ocsp\-response\fP, OCSP query is done using external Python script
which has been developed as part of h2o project \fBfetch\-ocsp\-response\fP, which has been originally developed in Perl
(\fI\%https://github.com/h2o/h2o\fP). as part of h2o project (\fI\%https://github.com/h2o/h2o\fP), and was
translated into Python.
.sp .sp
The script file is usually installed under The script file is usually installed under
\fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can \fB$(prefix)/share/nghttp2/\fP directory. The actual path to script can

View File

@@ -172,9 +172,11 @@ Performance
.. option:: --backend-http1-connections-per-host=<N> .. option:: --backend-http1-connections-per-host=<N>
Set maximum number of backend concurrent HTTP/1 Set maximum number of backend concurrent HTTP/1
connections per host. This option is meaningful when :option:`-s` connections per origin host. This option is meaningful
option is used. To limit the number of connections per when :option:`-s` option is used. The origin host is determined
frontend for default mode, use by authority portion of requset URI (or :authority
header field for HTTP/2). To limit the number of
connections per frontend for default mode, use
:option:`--backend-http1-connections-per-frontend`\. :option:`--backend-http1-connections-per-frontend`\.
Default: ``8`` Default: ``8``
@@ -805,9 +807,10 @@ delete the socket and continues to use it.
OCSP STAPLING OCSP STAPLING
------------- -------------
OCSP query is done using external perl script ``fetch-ocsp-response``, OCSP query is done using external Python script
which has been developed as part of h2o project ``fetch-ocsp-response``, which has been originally developed in Perl
(https://github.com/h2o/h2o). as part of h2o project (https://github.com/h2o/h2o), and was
translated into Python.
The script file is usually installed under The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can ``$(prefix)/share/nghttp2/`` directory. The actual path to script can

View File

@@ -87,9 +87,10 @@ delete the socket and continues to use it.
OCSP STAPLING OCSP STAPLING
------------- -------------
OCSP query is done using external perl script ``fetch-ocsp-response``, OCSP query is done using external Python script
which has been developed as part of h2o project ``fetch-ocsp-response``, which has been originally developed in Perl
(https://github.com/h2o/h2o). as part of h2o project (https://github.com/h2o/h2o), and was
translated into Python.
The script file is usually installed under The script file is usually installed under
``$(prefix)/share/nghttp2/`` directory. The actual path to script can ``$(prefix)/share/nghttp2/`` directory. The actual path to script can

View File

@@ -510,6 +510,28 @@ func TestH2H1SNI(t *testing.T) {
} }
} }
// TestH2H1TLSXfp tests nghttpx sends x-forwarded-proto header field
// with http value since :scheme is http, even if the frontend
// connection is encrypted.
func TestH2H1TLSXfp(t *testing.T) {
st := newServerTesterTLS(nil, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H1TLSXfp",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}
// TestH2H1ServerPush tests server push using Link header field from // TestH2H1ServerPush tests server push using Link header field from
// backend server. // backend server.
func TestH2H1ServerPush(t *testing.T) { func TestH2H1ServerPush(t *testing.T) {
@@ -831,3 +853,25 @@ func TestH2H2NoHostRewrite(t *testing.T) {
t.Errorf("request-host: %v; want %v", got, want) t.Errorf("request-host: %v; want %v", got, want)
} }
} }
// TestH2H2TLSXfp tests nghttpx sends x-forwarded-proto header field
// with http value since :scheme is http, even if the frontend
// connection is encrypted.
func TestH2H2TLSXfp(t *testing.T) {
st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
}
})
defer st.Close()
res, err := st.http2(requestParam{
name: "TestH2H2TLSXfp",
})
if err != nil {
t.Fatalf("Error st.http2() = %v", err)
}
if got, want := res.status, 200; got != want {
t.Errorf("res.status: %v; want %v", got, want)
}
}

View File

@@ -601,15 +601,12 @@ nghttp2_session_reprioritize_stream(nghttp2_session *session,
nghttp2_priority_spec pri_spec_default; nghttp2_priority_spec pri_spec_default;
const nghttp2_priority_spec *pri_spec = pri_spec_in; const nghttp2_priority_spec *pri_spec = pri_spec_in;
assert(pri_spec->stream_id != stream->stream_id);
if (!nghttp2_stream_in_dep_tree(stream)) { if (!nghttp2_stream_in_dep_tree(stream)) {
return 0; return 0;
} }
if (pri_spec->stream_id == stream->stream_id) {
return nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, "depend on itself");
}
if (pri_spec->stream_id != 0) { if (pri_spec->stream_id != 0) {
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id); dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
@@ -3674,6 +3671,11 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
"PRIORITY: stream_id == 0"); "PRIORITY: stream_id == 0");
} }
if (frame->priority.pri_spec.stream_id == frame->hd.stream_id) {
return nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_PROTOCOL_ERROR, "depend on itself");
}
if (!session->server) { if (!session->server) {
/* Re-prioritization works only in server */ /* Re-prioritization works only in server */
return session_call_on_frame_received(session, frame); return session_call_on_frame_received(session, frame);
@@ -6306,8 +6308,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
return rv; return rv;
} }
session_outbound_item_schedule(session, stream->item, session_outbound_item_schedule(
stream->effective_weight); session, stream->item, nghttp2_stream_compute_effective_weight(stream));
return 0; return 0;
} }

View File

@@ -731,7 +731,8 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
/* /*
* Re-prioritize |stream|. The new priority specification is * Re-prioritize |stream|. The new priority specification is
* |pri_spec|. * |pri_spec|. Caller must ensure that stream->hd.stream_id !=
* pri_spec->stream_id.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:

View File

@@ -60,7 +60,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM; stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
stream->num_substreams = 1; stream->num_substreams = 1;
stream->weight = weight; stream->weight = weight;
stream->effective_weight = stream->weight;
stream->sum_dep_weight = 0; stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0; stream->sum_norest_weight = 0;
@@ -107,9 +106,9 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
weight. This will delay low priority stream, which is good. weight. This will delay low priority stream, which is good.
OTOH, this may incur delay for high priority item. Will OTOH, this may incur delay for high priority item. Will
see. */ see. */
item->cycle = item->cycle = session->last_cycle +
session->last_cycle + NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT /
NGHTTP2_DATA_PAYLOADLEN * NGHTTP2_MAX_WEIGHT / stream->effective_weight; nghttp2_stream_compute_effective_weight(stream);
rv = nghttp2_pq_push(&session->ob_da_pq, item); rv = nghttp2_pq_push(&session->ob_da_pq, item);
if (rv != 0) { if (rv != 0) {
@@ -133,13 +132,6 @@ static int stream_push_item(nghttp2_stream *stream, nghttp2_session *session) {
return 0; return 0;
} }
static nghttp2_stream *stream_first_sib(nghttp2_stream *stream) {
for (; stream->sib_prev; stream = stream->sib_prev)
;
return stream;
}
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) { static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
for (; stream->sib_next; stream = stream->sib_next) for (; stream->sib_next; stream = stream->sib_next)
; ;
@@ -147,17 +139,12 @@ static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
return stream; return stream;
} }
static nghttp2_stream *stream_update_dep_length(nghttp2_stream *stream, static void stream_update_dep_length(nghttp2_stream *stream, ssize_t delta) {
ssize_t delta) {
stream->num_substreams += delta; stream->num_substreams += delta;
stream = stream_first_sib(stream);
if (stream->dep_prev) { if (stream->dep_prev) {
return stream_update_dep_length(stream->dep_prev, delta); stream_update_dep_length(stream->dep_prev, delta);
} }
return stream;
} }
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
@@ -167,47 +154,6 @@ int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
return nghttp2_max(1, weight); return nghttp2_max(1, weight);
} }
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
int32_t weight) {
if (stream->sum_norest_weight == 0) {
return stream->effective_weight;
}
weight = stream->effective_weight * weight / stream->sum_norest_weight;
return nghttp2_max(1, weight);
}
static void stream_update_dep_set_rest(nghttp2_stream *stream);
/* Updates effective_weight of descendant streams in subtree of
|stream|. We assume that stream->effective_weight is already set
right. */
static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
nghttp2_stream *si;
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
"stream(%p)=%d, weight=%d, sum_norest_weight=%d\n",
stream, stream->stream_id, stream->weight,
stream->sum_norest_weight));
/* stream->sum_norest_weight == 0 means there is no
NGHTTP2_STREAM_DPRI_TOP under stream */
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM ||
stream->sum_norest_weight == 0) {
return;
}
for (si = stream->dep_next; si; si = si->sib_next) {
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
si->effective_weight =
nghttp2_stream_dep_distributed_effective_weight(stream, si->weight);
stream_update_dep_effective_weight(si);
}
}
}
static void stream_update_dep_set_rest(nghttp2_stream *stream) { static void stream_update_dep_set_rest(nghttp2_stream *stream) {
if (stream == NULL) { if (stream == NULL) {
return; return;
@@ -233,27 +179,41 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream) {
/* /*
* Performs dfs starting |stream|, search stream which can become * Performs dfs starting |stream|, search stream which can become
* NGHTTP2_STREAM_DPRI_TOP and set its dpri. * NGHTTP2_STREAM_DPRI_TOP and set its dpri. This function also
* updates sum_norest_weight if stream->dpri ==
* NGHTTP2_STREAM_DPRI_NO_ITEM. This function returns nonzero if
* stream's subtree contains at least one NGHTTP2_STRAEM_DPRI_TOP
* stream.
*/ */
static void stream_update_dep_set_top(nghttp2_stream *stream) { static int stream_update_dep_set_top(nghttp2_stream *stream) {
nghttp2_stream *si; nghttp2_stream *si;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) { if (!stream) {
return; return 0;
} }
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
}
stream->sum_norest_weight = 0;
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) { if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
DEBUGF( DEBUGF(
fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id)); fprintf(stderr, "stream: stream=%d item is top\n", stream->stream_id));
stream->dpri = NGHTTP2_STREAM_DPRI_TOP; stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
return; return 1;
} }
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
stream_update_dep_set_top(si); if (stream_update_dep_set_top(si)) {
stream->sum_norest_weight += si->weight;
} }
}
return stream->sum_norest_weight > 0;
} }
/* /*
@@ -288,6 +248,10 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
return 0; return 0;
} }
if (stream->sum_norest_weight == 0) {
return 0;
}
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
rv = stream_update_dep_queue_top(si, session); rv = stream_update_dep_queue_top(si, session);
@@ -300,72 +264,113 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
} }
/* /*
* Updates stream->sum_norest_weight recursively. We have to gather * Updates stream->sum_norest_weight recursively towards root.
* effective sum of weight of descendants. If stream->dpri == * |delta| must not be 0. We have to gather effective sum of weight
* NGHTTP2_STREAM_DPRI_NO_ITEM, we have to go deeper and check that * of descendants. |delta| is added to stream->sum_norest_weight. If
* any of its descendants has dpri value of NGHTTP2_STREAM_DPRI_TOP. * stream->sum_norest_weight becomes 0, we have to update parent
* If so, we have to add weight of its direct descendants to * stream, decreasing its sum_norest_weight by stream->weight. If
* stream->sum_norest_weight. To make this work, this function * stream->sum_norest_weight becomes from 0 to positive, then we have
* returns 1 if any of its descendants has dpri value of * to update parent stream, increasing its sum_norest_weight by
* NGHTTP2_STREAM_DPRI_TOP, otherwise 0. * stream->weight. Otherwise, we stop recursive call.
*/ */
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) { static void stream_update_dep_sum_norest_weight(nghttp2_stream *stream,
nghttp2_stream *si; int32_t delta) {
int32_t old;
stream->sum_norest_weight = 0; if (!stream) {
return;
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
return 1;
} }
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) { assert(delta != 0);
return 0; assert(stream->sum_norest_weight + delta >= 0);
old = stream->sum_norest_weight;
stream->sum_norest_weight += delta;
if (old == 0) {
assert(delta > 0);
stream_update_dep_sum_norest_weight(stream->dep_prev, stream->weight);
return;
} }
for (si = stream->dep_next; si; si = si->sib_next) { assert(old > 0);
if (stream_update_dep_sum_norest_weight(si)) { if (stream->sum_norest_weight == 0) {
stream->sum_norest_weight += si->weight; stream_update_dep_sum_norest_weight(stream->dep_prev, -stream->weight);
}
}
/*
* Returns stream whose dpri is NGHTTP2_STREAM_DPRI_NO_ITEM along the
* path following stream->dep_prev (stream's ancestors, including
* itself). In other words, find stream which blocks the descendant
* streams. If there is no such stream, returns NULL.
*/
static nghttp2_stream *stream_get_dep_blocking(nghttp2_stream *stream) {
for (; stream; stream = stream->dep_prev) {
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM) {
return stream;
} }
} }
return NULL;
return stream->sum_norest_weight > 0;
} }
static int stream_update_dep_on_attach_item(nghttp2_stream *stream, static int stream_update_dep_on_attach_item(nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
int rv;
stream->dpri = NGHTTP2_STREAM_DPRI_REST; stream->dpri = NGHTTP2_STREAM_DPRI_REST;
blocking_stream = stream_get_dep_blocking(stream->dep_prev);
/* If we found REST or TOP in ascendants, we don't have to update
any metadata. */
if (blocking_stream) {
return 0;
}
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
if (stream->sum_norest_weight == 0) {
stream_update_dep_sum_norest_weight(stream->dep_prev, stream->weight);
} else {
stream_update_dep_set_rest(stream->dep_next); stream_update_dep_set_rest(stream->dep_next);
}
root_stream = nghttp2_stream_get_dep_root(stream); if (!stream->item->queued) {
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id));
rv = stream_push_item(stream, session);
DEBUGF(fprintf(stderr, "root=%p, stream=%p\n", root_stream, stream)); if (rv != 0) {
return rv;
}
}
stream_update_dep_set_top(root_stream); return 0;
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return stream_update_dep_queue_top(root_stream, session);
} }
static int stream_update_dep_on_detach_item(nghttp2_stream *stream, static int stream_update_dep_on_detach_item(nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
return 0;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM) {
/* nghttp2_stream_defer_item() does not clear stream->item, but
set dpri = NGHTTP2_STREAM_DPRI_NO_ITEM. Catch this case
here. */
return 0;
}
stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM; stream->dpri = NGHTTP2_STREAM_DPRI_NO_ITEM;
root_stream = nghttp2_stream_get_dep_root(stream); if (stream_update_dep_set_top(stream) == 0) {
stream_update_dep_sum_norest_weight(stream->dep_prev, -stream->weight);
return 0;
}
stream_update_dep_set_top(root_stream); return stream_update_dep_queue_top(stream->dep_next, session);
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
return stream_update_dep_queue_top(root_stream, session);
} }
int nghttp2_stream_attach_item(nghttp2_stream *stream, int nghttp2_stream_attach_item(nghttp2_stream *stream,
@@ -465,22 +470,8 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
} }
nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) { nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) {
for (;;) { for (; stream->dep_prev; stream = stream->dep_prev)
if (stream->sib_prev) { ;
stream = stream->sib_prev;
continue;
}
if (stream->dep_prev) {
stream = stream->dep_prev;
continue;
}
break;
}
return stream; return stream;
} }
@@ -501,12 +492,25 @@ int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
return nghttp2_stream_dep_subtree_find(stream->dep_next, target); return nghttp2_stream_dep_subtree_find(stream->dep_next, target);
} }
int32_t nghttp2_stream_compute_effective_weight(nghttp2_stream *stream) {
int32_t weight;
if (!stream->dep_prev) {
return stream->weight;
}
weight = nghttp2_stream_compute_effective_weight(stream->dep_prev) *
stream->weight / stream->dep_prev->sum_norest_weight;
return nghttp2_max(1, weight);
}
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
nghttp2_stream *stream) { nghttp2_stream *stream) {
nghttp2_stream *si; nghttp2_stream *si;
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
assert(stream->item == NULL); assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
DEBUGF(fprintf(stderr, DEBUGF(fprintf(stderr,
"stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", "stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n",
@@ -515,34 +519,57 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
stream->sum_dep_weight = dep_stream->sum_dep_weight; stream->sum_dep_weight = dep_stream->sum_dep_weight;
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
blocking_stream = stream_get_dep_blocking(dep_stream);
stream->sum_norest_weight = 0;
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
assert(dep_stream->num_substreams >= 1);
/* num_substreams includes node itself */
stream->num_substreams = dep_stream->num_substreams;
for (si = dep_stream->dep_next; si; si = si->sib_next) { for (si = dep_stream->dep_next; si; si = si->sib_next) {
stream->num_substreams += si->num_substreams; si->dep_prev = stream;
if (!blocking_stream && (si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
si->sum_norest_weight))) {
stream->sum_norest_weight += si->weight;
}
} }
stream->dep_next = dep_stream->dep_next; stream->dep_next = dep_stream->dep_next;
stream->dep_next->dep_prev = stream;
} }
dep_stream->dep_next = stream; dep_stream->dep_next = stream;
stream->dep_prev = dep_stream; stream->dep_prev = dep_stream;
root_stream = stream_update_dep_length(dep_stream, 1); if (stream->sum_norest_weight) {
dep_stream->sum_norest_weight = stream->weight;
}
stream_update_dep_sum_norest_weight(root_stream); stream_update_dep_length(dep_stream, 1);
stream_update_dep_effective_weight(root_stream);
++stream->roots->num_streams; ++stream->roots->num_streams;
} }
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) { static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
dep_stream->dep_next = stream; for (; stream; stream = stream->sib_next) {
stream->dep_prev = dep_stream; stream->dep_prev = dep;
}
} }
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream) { static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
prev_stream->sib_next = stream; dep_stream->dep_next = stream;
stream->sib_prev = prev_stream; if (stream) {
stream->dep_prev = dep_stream;
}
}
static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
a->sib_next = b;
if (b) {
b->sib_prev = a;
}
} }
static void insert_link_dep(nghttp2_stream *dep_stream, static void insert_link_dep(nghttp2_stream *dep_stream,
@@ -555,8 +582,6 @@ static void insert_link_dep(nghttp2_stream *dep_stream,
link_sib(stream, sib_next); link_sib(stream, sib_next);
sib_next->dep_prev = NULL;
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
} }
@@ -574,10 +599,11 @@ static void unlink_sib(nghttp2_stream *stream) {
* | * |
* dep_next * dep_next
*/ */
dep_next->dep_prev = NULL;
link_sib(prev, dep_next); link_sib(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) { if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next); link_sib(stream_last_sib(dep_next), stream->sib_next);
} }
@@ -613,9 +639,12 @@ static void unlink_dep(nghttp2_stream *stream) {
*/ */
link_dep(prev, dep_next); link_dep(prev, dep_next);
set_dep_prev(dep_next, stream->dep_prev);
if (stream->sib_next) { if (stream->sib_next) {
link_sib(stream_last_sib(dep_next), stream->sib_next); link_sib(stream_last_sib(dep_next), stream->sib_next);
} }
} else if (stream->sib_next) { } else if (stream->sib_next) {
/* /*
* prev * prev
@@ -634,14 +663,12 @@ static void unlink_dep(nghttp2_stream *stream) {
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
nghttp2_stream *stream) { nghttp2_stream *stream) {
nghttp2_stream *root_stream; assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
assert(stream->item == NULL);
DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id)); dep_stream, dep_stream->stream_id, stream, stream->stream_id));
root_stream = stream_update_dep_length(dep_stream, 1); stream_update_dep_length(dep_stream, 1);
dep_stream->sum_dep_weight += stream->weight; dep_stream->sum_dep_weight += stream->weight;
@@ -651,38 +678,50 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
insert_link_dep(dep_stream, stream); insert_link_dep(dep_stream, stream);
} }
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
++stream->roots->num_streams; ++stream->roots->num_streams;
} }
void nghttp2_stream_dep_remove(nghttp2_stream *stream) { void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_prev, *si, *root_stream; nghttp2_stream *next, *dep_prev, *si, *blocking_stream;
int32_t sum_dep_weight_delta; int32_t sum_dep_weight_delta, sum_norest_weight_delta;
root_stream = NULL; assert(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM);
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream, DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream,
stream->stream_id)); stream->stream_id));
blocking_stream = stream_get_dep_blocking(stream->dep_prev);
/* Distribute weight of |stream| to direct descendants */ /* Distribute weight of |stream| to direct descendants */
sum_dep_weight_delta = -stream->weight; sum_dep_weight_delta = -stream->weight;
sum_norest_weight_delta = 0;
/* blocking_stream == NULL means that ascendants are all
NGHTTP2_STREAM_DPRI_NO_ITEM */
if (!blocking_stream && stream->sum_norest_weight) {
sum_norest_weight_delta -= stream->weight;
}
for (si = stream->dep_next; si; si = si->sib_next) { for (si = stream->dep_next; si; si = si->sib_next) {
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight); si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
sum_dep_weight_delta += si->weight; sum_dep_weight_delta += si->weight;
if (!blocking_stream &&
(si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM && si->sum_norest_weight))) {
sum_norest_weight_delta += si->weight;
}
} }
prev = stream_first_sib(stream); dep_prev = stream->dep_prev;
dep_prev = prev->dep_prev;
if (dep_prev) { if (dep_prev) {
root_stream = stream_update_dep_length(dep_prev, -1); stream_update_dep_length(dep_prev, -1);
dep_prev->sum_dep_weight += sum_dep_weight_delta; dep_prev->sum_dep_weight += sum_dep_weight_delta;
dep_prev->sum_norest_weight += sum_norest_weight_delta;
} }
if (stream->sib_prev) { if (stream->sib_prev) {
@@ -702,22 +741,15 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
si->sib_prev = NULL; si->sib_prev = NULL;
si->sib_next = NULL; si->sib_next = NULL;
/* We already distributed weight of |stream| to this. */
si->effective_weight = si->weight;
nghttp2_stream_roots_add(si->roots, si); nghttp2_stream_roots_add(si->roots, si);
si = next; si = next;
} }
} }
if (root_stream) {
stream_update_dep_sum_norest_weight(root_stream);
stream_update_dep_effective_weight(root_stream);
}
stream->num_substreams = 1; stream->num_substreams = 1;
stream->sum_dep_weight = 0; stream->sum_dep_weight = 0;
stream->sum_norest_weight = 0;
stream->dep_prev = NULL; stream->dep_prev = NULL;
stream->dep_next = NULL; stream->dep_next = NULL;
@@ -732,7 +764,8 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *last_sib; nghttp2_stream *last_sib;
nghttp2_stream *dep_next; nghttp2_stream *dep_next;
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
nghttp2_stream *si;
size_t delta_substreams; size_t delta_substreams;
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
@@ -741,7 +774,7 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
delta_substreams = stream->num_substreams; delta_substreams = stream->num_substreams;
stream_update_dep_set_rest(stream); blocking_stream = stream_get_dep_blocking(dep_stream);
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
/* dep_stream->num_substreams includes dep_stream itself */ /* dep_stream->num_substreams includes dep_stream itself */
@@ -752,7 +785,9 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
dep_next = dep_stream->dep_next; dep_next = dep_stream->dep_next;
if (!blocking_stream && dep_stream->sum_norest_weight) {
stream_update_dep_set_rest(dep_next); stream_update_dep_set_rest(dep_next);
}
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
@@ -760,11 +795,13 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
last_sib = stream_last_sib(stream->dep_next); last_sib = stream_last_sib(stream->dep_next);
link_sib(last_sib, dep_next); link_sib(last_sib, dep_next);
dep_next->dep_prev = NULL;
} else { } else {
link_dep(stream, dep_next); link_dep(stream, dep_next);
} }
for (si = dep_next; si; si = si->sib_next) {
si->dep_prev = stream;
}
} else { } else {
link_dep(dep_stream, stream); link_dep(dep_stream, stream);
@@ -772,27 +809,33 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, delta_substreams); stream_update_dep_length(dep_stream, delta_substreams);
stream_update_dep_set_top(root_stream); if (blocking_stream) {
stream_update_dep_set_rest(stream);
stream_update_dep_sum_norest_weight(root_stream); return 0;
stream_update_dep_effective_weight(root_stream); }
return stream_update_dep_queue_top(root_stream, session); if (stream_update_dep_set_top(stream) == 0) {
return 0;
}
dep_stream->sum_norest_weight = stream->weight;
stream_update_dep_sum_norest_weight(dep_stream->dep_prev, dep_stream->weight);
return stream_update_dep_queue_top(stream, session);
} }
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
nghttp2_stream *stream, nghttp2_stream *stream,
nghttp2_session *session) { nghttp2_session *session) {
nghttp2_stream *root_stream; nghttp2_stream *blocking_stream;
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d " DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
"stream(%p)=%d\n", "stream(%p)=%d\n",
dep_stream, dep_stream->stream_id, stream, stream->stream_id)); dep_stream, dep_stream->stream_id, stream, stream->stream_id));
stream_update_dep_set_rest(stream);
if (dep_stream->dep_next) { if (dep_stream->dep_next) {
dep_stream->sum_dep_weight += stream->weight; dep_stream->sum_dep_weight += stream->weight;
@@ -804,46 +847,52 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
dep_stream->sum_dep_weight = stream->weight; dep_stream->sum_dep_weight = stream->weight;
} }
root_stream = stream_update_dep_length(dep_stream, stream->num_substreams); stream_update_dep_length(dep_stream, stream->num_substreams);
stream_update_dep_set_top(root_stream); blocking_stream = stream_get_dep_blocking(dep_stream);
stream_update_dep_sum_norest_weight(root_stream); if (blocking_stream) {
stream_update_dep_effective_weight(root_stream); /* We cannot make any assumption for stream if its dpri is not
NGHTTP2_DPRI_TOP. Just dfs under stream here. */
stream_update_dep_set_rest(stream);
return stream_update_dep_queue_top(root_stream, session); return 0;
}
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
stream_update_dep_sum_norest_weight(dep_stream, stream->weight);
return 0;
}
if (stream_update_dep_set_top(stream) == 0) {
return 0;
}
/* Newly added subtree contributes to dep_stream's
sum_norest_weight */
stream_update_dep_sum_norest_weight(dep_stream, stream->weight);
return stream_update_dep_queue_top(stream, session);
} }
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) { void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
nghttp2_stream *prev, *next, *dep_prev, *root_stream; nghttp2_stream *next, *dep_prev, *blocking_stream;
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream, DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream,
stream->stream_id)); stream->stream_id));
if (stream->sib_prev) { if (stream->sib_prev) {
prev = stream->sib_prev; link_sib(stream->sib_prev, stream->sib_next);
dep_prev = stream->dep_prev;
prev->sib_next = stream->sib_next;
if (prev->sib_next) {
prev->sib_next->sib_prev = prev;
}
prev = stream_first_sib(prev);
dep_prev = prev->dep_prev;
} else if (stream->dep_prev) { } else if (stream->dep_prev) {
dep_prev = stream->dep_prev; dep_prev = stream->dep_prev;
next = stream->sib_next; next = stream->sib_next;
dep_prev->dep_next = next; link_dep(dep_prev, next);
if (next) { if (next) {
next->dep_prev = dep_prev;
next->sib_prev = NULL; next->sib_prev = NULL;
} }
} else { } else {
nghttp2_stream_roots_remove(stream->roots, stream); nghttp2_stream_roots_remove(stream->roots, stream);
@@ -853,10 +902,15 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
if (dep_prev) { if (dep_prev) {
dep_prev->sum_dep_weight -= stream->weight; dep_prev->sum_dep_weight -= stream->weight;
root_stream = stream_update_dep_length(dep_prev, -stream->num_substreams); stream_update_dep_length(dep_prev, -stream->num_substreams);
stream_update_dep_sum_norest_weight(root_stream); blocking_stream = stream_get_dep_blocking(dep_prev);
stream_update_dep_effective_weight(root_stream);
if (!blocking_stream && (stream->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(stream->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
stream->sum_norest_weight))) {
stream_update_dep_sum_norest_weight(dep_prev, -stream->weight);
}
} }
stream->sib_prev = NULL; stream->sib_prev = NULL;
@@ -871,14 +925,9 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
nghttp2_stream_roots_add(stream->roots, stream); nghttp2_stream_roots_add(stream->roots, stream);
stream_update_dep_set_rest(stream); if (stream_update_dep_set_top(stream) == 0) {
return 0;
stream->effective_weight = stream->weight; }
stream_update_dep_set_top(stream);
stream_update_dep_sum_norest_weight(stream);
stream_update_dep_effective_weight(stream);
return stream_update_dep_queue_top(stream, session); return stream_update_dep_queue_top(stream, session);
} }
@@ -908,6 +957,13 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
stream->sum_dep_weight += first->weight; stream->sum_dep_weight += first->weight;
stream->num_substreams += first->num_substreams; stream->num_substreams += first->num_substreams;
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM &&
(first->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(first->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
first->sum_norest_weight))) {
stream_update_dep_set_rest(first);
}
for (si = first->root_next; si; si = si->root_next) { for (si = first->root_next; si; si = si->root_next) {
assert(si != stream); assert(si != stream);
@@ -918,7 +974,15 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
stream->sum_dep_weight += si->weight; stream->sum_dep_weight += si->weight;
stream->num_substreams += si->num_substreams; stream->num_substreams += si->num_substreams;
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_ITEM &&
(si->dpri == NGHTTP2_STREAM_DPRI_TOP ||
(si->dpri == NGHTTP2_STREAM_DPRI_NO_ITEM &&
si->sum_norest_weight))) {
stream_update_dep_set_rest(si);
}
link_sib(prev, si); link_sib(prev, si);
si->dep_prev = stream;
prev = si; prev = si;
} }
@@ -928,8 +992,7 @@ nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
sib_next = stream->dep_next; sib_next = stream->dep_next;
sib_next->dep_prev = NULL; first->dep_prev = stream;
link_sib(first, sib_next); link_sib(first, sib_next);
link_dep(stream, prev); link_dep(stream, prev);
} else { } else {

View File

@@ -209,13 +209,14 @@ struct nghttp2_stream {
int32_t local_window_size; int32_t local_window_size;
/* weight of this stream */ /* weight of this stream */
int32_t weight; int32_t weight;
/* effective weight of this stream in belonging dependency tree */ /* sum of weight of direct descendants */
int32_t effective_weight;
/* sum of weight (not effective_weight) of direct descendants */
int32_t sum_dep_weight; int32_t sum_dep_weight;
/* sum of weight of direct descendants which have at least one /* sum of weight of direct descendants which have at least one
descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this descendant with dpri == NGHTTP2_STREAM_DPRI_TOP. We use this
value to calculate effective weight. */ value to calculate effective weight. This value is only
meaningful iff dpri == NGHTTP2_STREAM_DPRI_NO_ITEM and all
streams along the path to the root stream (follow dep_prev) have
NGHTTP2_STREAM_DPRI_NO_ITEM. */
int32_t sum_norest_weight; int32_t sum_norest_weight;
nghttp2_stream_state state; nghttp2_stream_state state;
/* status code from remote server */ /* status code from remote server */
@@ -325,21 +326,12 @@ int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
/* /*
* Computes distributed weight of a stream of the |weight| under the * Computes distributed weight of a stream of the |weight| under the
* |stream| if |stream| is removed from a dependency tree. The result * |stream| if |stream| is removed from a dependency tree.
* is computed using stream->weight rather than
* stream->effective_weight.
*/ */
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
int32_t weight); int32_t weight);
/* int32_t nghttp2_stream_compute_effective_weight(nghttp2_stream *stream);
* Computes effective weight of a stream of the |weight| under the
* |stream|. The result is computed using stream->effective_weight
* rather than stream->weight. This function is used to determine
* weight in dependency tree.
*/
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
int32_t weight);
/* /*
* Makes the |stream| depend on the |dep_stream|. This dependency is * Makes the |stream| depend on the |dep_stream|. This dependency is

View File

@@ -142,13 +142,13 @@ def send_and_receive_ocsp(respder_fn, cmd, cert_fn, issuer_fn, ocsp_uri,
# obtain response (without verification) # obtain response (without verification)
sys.stderr.write('sending OCSP request to {}\n'.format(ocsp_uri)) sys.stderr.write('sending OCSP request to {}\n'.format(ocsp_uri))
args = [ args = [
cmd, 'ocsp', '-issuer', issuer_fn, '-cert', cert_fn, '-url', ocsp_uri cmd, 'ocsp', '-issuer', issuer_fn, '-cert', cert_fn, '-url', ocsp_uri,
'-noverify', '-respout', respder_fn
] ]
if openssl_version.lower().startswith('openssl 1.'): ver = openssl_version.lower()
if ver.startswith('openssl 1.') or ver.startswith('libressl '):
args.extend(['-header', 'Host', ocsp_host]) args.extend(['-header', 'Host', ocsp_host])
args.extend(['-noverify', '-respout', respder_fn])
resp = run_openssl(args, allow_tempfail=True) resp = run_openssl(args, allow_tempfail=True)
return resp.decode('utf-8') return resp.decode('utf-8')
@@ -188,7 +188,7 @@ def fetch_ocsp_response(cmd, cert_fn, tempdir, issuer_fn=None):
'fetch-ocsp-response (using {})\n'.format(openssl_version)) 'fetch-ocsp-response (using {})\n'.format(openssl_version))
ocsp_uri = extract_ocsp_uri(cmd, cert_fn) ocsp_uri = extract_ocsp_uri(cmd, cert_fn)
ocsp_host = urlparse(ocsp_uri).hostname ocsp_host = urlparse(ocsp_uri).netloc
if not issuer_fn: if not issuer_fn:
issuer_fn = os.path.join(tempdir, 'issuer.crt') issuer_fn = os.path.join(tempdir, 'issuer.crt')

View File

@@ -100,8 +100,8 @@ template <typename Array> void append_nv(Stream *stream, const Array &nva) {
} // namespace } // namespace
Config::Config() Config::Config()
: stream_read_timeout(60.), stream_write_timeout(60.), data_ptr(nullptr), : stream_read_timeout(1_min), stream_write_timeout(1_min),
padding(0), num_worker(1), max_concurrent_streams(100), data_ptr(nullptr), padding(0), num_worker(1), max_concurrent_streams(100),
header_table_size(-1), port(0), verbose(false), daemon(false), header_table_size(-1), port(0), verbose(false), daemon(false),
verify_client(false), no_tls(false), error_gzip(false), verify_client(false), no_tls(false), error_gzip(false),
early_response(false), hexdump(false), echo_upload(false) {} early_response(false), hexdump(false), echo_upload(false) {}
@@ -453,7 +453,7 @@ int Http2Handler::fill_wb() {
int Http2Handler::read_clear() { int Http2Handler::read_clear() {
int rv; int rv;
std::array<uint8_t, 8192> buf; std::array<uint8_t, 8_k> buf;
for (;;) { for (;;) {
ssize_t nread; ssize_t nread;
@@ -570,7 +570,7 @@ int Http2Handler::tls_handshake() {
} }
int Http2Handler::read_tls() { int Http2Handler::read_tls() {
std::array<uint8_t, 8192> buf; std::array<uint8_t, 8_k> buf;
ERR_clear_error(); ERR_clear_error();
@@ -1768,12 +1768,13 @@ int HttpServer::run() {
return -1; return -1;
} }
SSL_CTX_set_options(ssl_ctx, auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_OP_CIPHER_SERVER_PREFERENCE;
SSL_CTX_set_options(ssl_ctx, ssl_opts);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);

View File

@@ -45,6 +45,7 @@
#include "http2.h" #include "http2.h"
#include "buffer.h" #include "buffer.h"
#include "template.h"
namespace nghttp2 { namespace nghttp2 {
@@ -155,7 +156,7 @@ public:
struct ev_loop *get_loop() const; struct ev_loop *get_loop() const;
using WriteBuf = Buffer<65536>; using WriteBuf = Buffer<64_k>;
WriteBuf *get_wb(); WriteBuf *get_wb();

View File

@@ -58,6 +58,7 @@
#include "app_helper.h" #include "app_helper.h"
#include "util.h" #include "util.h"
#include "http2.h" #include "http2.h"
#include "template.h"
namespace nghttp2 { namespace nghttp2 {
@@ -463,7 +464,7 @@ ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
size_t inlen) { size_t inlen) {
int rv; int rv;
z_stream zst; z_stream zst;
uint8_t temp_out[8192]; uint8_t temp_out[8_k];
auto temp_outlen = sizeof(temp_out); auto temp_outlen = sizeof(temp_out);
zst.next_in = Z_NULL; zst.next_in = Z_NULL;

View File

@@ -313,7 +313,7 @@ bool session_impl::setup_session() {
return false; return false;
} }
const uint32_t window_size = 256 * 1024 * 1024; const uint32_t window_size = 256_m;
std::array<nghttp2_settings_entry, 2> iv{ std::array<nghttp2_settings_entry, 2> iv{
{{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}, {{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100},

View File

@@ -31,6 +31,8 @@
#include <nghttp2/asio_http2_client.h> #include <nghttp2/asio_http2_client.h>
#include "template.h"
namespace nghttp2 { namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace client { namespace client {
@@ -90,8 +92,8 @@ public:
void do_write(); void do_write();
protected: protected:
boost::array<uint8_t, 8192> rb_; boost::array<uint8_t, 8_k> rb_;
boost::array<uint8_t, 65536> wb_; boost::array<uint8_t, 64_k> wb_;
std::size_t wblen_; std::size_t wblen_;
private: private:

View File

@@ -49,6 +49,7 @@
#include "asio_server_http2_handler.h" #include "asio_server_http2_handler.h"
#include "asio_server_serve_mux.h" #include "asio_server_serve_mux.h"
#include "util.h" #include "util.h"
#include "template.h"
namespace nghttp2 { namespace nghttp2 {
@@ -153,9 +154,9 @@ private:
std::shared_ptr<http2_handler> handler_; std::shared_ptr<http2_handler> handler_;
/// Buffer for incoming data. /// Buffer for incoming data.
boost::array<uint8_t, 8192> buffer_; boost::array<uint8_t, 8_k> buffer_;
boost::array<uint8_t, 65536> outbuf_; boost::array<uint8_t, 64_k> outbuf_;
bool writing_; bool writing_;
}; };

View File

@@ -49,11 +49,13 @@ configure_tls_context_easy(boost::system::error_code &ec,
auto ctx = tls_context.native_handle(); auto ctx = tls_context.native_handle();
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_NO_COMPRESSION | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET | SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_OP_CIPHER_SERVER_PREFERENCE;
SSL_CTX_set_options(ctx, ssl_opts);
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);

View File

@@ -49,6 +49,10 @@ extern "C" {
#include "comp_helper.h" #include "comp_helper.h"
} }
#include "template.h"
namespace nghttp2 {
typedef struct { typedef struct {
size_t table_size; size_t table_size;
size_t deflate_table_size; size_t deflate_table_size;
@@ -122,7 +126,7 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
ssize_t rv; ssize_t rv;
nghttp2_bufs bufs; nghttp2_bufs bufs;
nghttp2_bufs_init2(&bufs, 4096, 16, 0, nghttp2_mem_default()); nghttp2_bufs_init2(&bufs, 4_k, 16, 0, nghttp2_mem_default());
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, (nghttp2_nv *)nva.data(), rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, (nghttp2_nv *)nva.data(),
nva.size()); nva.size());
@@ -448,3 +452,7 @@ int main(int argc, char **argv) {
output_sum, comp_ratio); output_sum, comp_ratio);
return 0; return 0;
} }
} // namespace nghttp2
int main(int argc, char **argv) { return nghttp2::main(argc, argv); }

View File

@@ -292,7 +292,8 @@ const char *get_tls_protocol(SSL *ssl) {
namespace { namespace {
void print_server_tmp_key(SSL *ssl) { void print_server_tmp_key(SSL *ssl) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000L // libressl does not have SSL_get_server_tmp_key
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && defined(SSL_get_server_tmp_key)
EVP_PKEY *key; EVP_PKEY *key;
if (!SSL_get_server_tmp_key(ssl, &key)) { if (!SSL_get_server_tmp_key(ssl, &key)) {
@@ -505,7 +506,7 @@ int Client::on_write() {
} }
int Client::read_clear() { int Client::read_clear() {
uint8_t buf[8192]; uint8_t buf[8_k];
for (;;) { for (;;) {
ssize_t nread; ssize_t nread;
@@ -625,7 +626,7 @@ int Client::tls_handshake() {
} }
int Client::read_tls() { int Client::read_tls() {
uint8_t buf[8192]; uint8_t buf[8_k];
ERR_clear_error(); ERR_clear_error();
@@ -1276,10 +1277,11 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
SSL_CTX_set_options(ssl_ctx, auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_COMPRESSION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_options(ssl_ctx, ssl_opts);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);

View File

@@ -50,6 +50,7 @@
#include "http2.h" #include "http2.h"
#include "buffer.h" #include "buffer.h"
#include "template.h"
using namespace nghttp2; using namespace nghttp2;
@@ -200,7 +201,7 @@ struct Client {
// The number of requests this client has done so far. // The number of requests this client has done so far.
size_t req_done; size_t req_done;
int fd; int fd;
Buffer<65536> wb; Buffer<64_k> wb;
enum { ERR_CONNECT_FAIL = -100 }; enum { ERR_CONNECT_FAIL = -100 };

View File

@@ -61,7 +61,7 @@ struct Header {
bool no_index; bool no_index;
}; };
typedef std::vector<Header> Headers; using Headers = std::vector<Header>;
namespace http2 { namespace http2 {

View File

@@ -228,7 +228,7 @@ template <typename Memchunk> struct Memchunks {
size_t len; size_t len;
}; };
using Memchunk16K = Memchunk<16384>; using Memchunk16K = Memchunk<16_k>;
using MemchunkPool = Pool<Memchunk16K>; using MemchunkPool = Pool<Memchunk16K>;
using DefaultMemchunks = Memchunks<Memchunk16K>; using DefaultMemchunks = Memchunks<Memchunk16K>;

View File

@@ -95,7 +95,7 @@ constexpr auto anchors = std::array<Anchor, 5>{{
} // namespace } // namespace
Config::Config() Config::Config()
: output_upper_thres(1024 * 1024), padding(0), : padding(0),
peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS),
header_table_size(-1), weight(NGHTTP2_DEFAULT_WEIGHT), multiply(1), header_table_size(-1), weight(NGHTTP2_DEFAULT_WEIGHT), multiply(1),
timeout(0.), window_bits(-1), connection_window_bits(-1), verbose(0), timeout(0.), window_bits(-1), connection_window_bits(-1), verbose(0),
@@ -175,6 +175,37 @@ std::string Request::make_reqpath() const {
return path; return path;
} }
namespace {
// Perform special handling |host| if it is IPv6 literal and includes
// zone ID per RFC 6874.
std::string decode_host(std::string host) {
auto zone_start = std::find(std::begin(host), std::end(host), '%');
if (zone_start == std::end(host) ||
!util::ipv6_numeric_addr(
std::string(std::begin(host), zone_start).c_str())) {
return std::move(host);
}
// case: ::1%
if (zone_start + 1 == std::end(host)) {
host.pop_back();
return std::move(host);
}
// case: ::1%12 or ::1%1
if (zone_start + 3 >= std::end(host)) {
return std::move(host);
}
// If we see "%25", followed by more characters, then decode %25 as
// '%'.
auto zone_id_src = (*(zone_start + 1) == '2' && *(zone_start + 2) == '5')
? zone_start + 3
: zone_start + 1;
auto zone_id = util::percentDecode(zone_id_src, std::end(host));
host.erase(zone_start + 1, std::end(host));
host += zone_id;
return std::move(host);
}
} // namespace
namespace { namespace {
nghttp2_priority_spec resolve_dep(int res_type) { nghttp2_priority_spec resolve_dep(int res_type) {
nghttp2_priority_spec pri_spec; nghttp2_priority_spec pri_spec;
@@ -331,7 +362,7 @@ int submit_request(HttpClient *client, const Headers &headers, Request *req) {
if (config.continuation) { if (config.continuation) {
for (size_t i = 0; i < 6; ++i) { for (size_t i = 0; i < 6; ++i) {
build_headers.emplace_back("continuation-test-" + util::utos(i + 1), build_headers.emplace_back("continuation-test-" + util::utos(i + 1),
std::string(4096, '-')); std::string(4_k, '-'));
} }
} }
auto num_initial_headers = build_headers.size(); auto num_initial_headers = build_headers.size();
@@ -603,7 +634,7 @@ void HttpClient::disconnect() {
int HttpClient::read_clear() { int HttpClient::read_clear() {
ev_timer_again(loop, &rt); ev_timer_again(loop, &rt);
std::array<uint8_t, 8192> buf; std::array<uint8_t, 8_k> buf;
for (;;) { for (;;) {
ssize_t nread; ssize_t nread;
@@ -1118,7 +1149,7 @@ int HttpClient::read_tls() {
ERR_clear_error(); ERR_clear_error();
std::array<uint8_t, 8192> buf; std::array<uint8_t, 8_k> buf;
for (;;) { for (;;) {
auto rv = SSL_read(ssl, buf.data(), buf.size()); auto rv = SSL_read(ssl, buf.data(), buf.size());
@@ -1205,8 +1236,14 @@ void HttpClient::update_hostport() {
scheme = util::get_uri_field(reqvec[0]->uri.c_str(), reqvec[0]->u, UF_SCHEMA); scheme = util::get_uri_field(reqvec[0]->uri.c_str(), reqvec[0]->u, UF_SCHEMA);
std::stringstream ss; std::stringstream ss;
if (reqvec[0]->is_ipv6_literal_addr()) { if (reqvec[0]->is_ipv6_literal_addr()) {
// we may have zone ID, which must start with "%25", or "%". RFC
// 6874 defines "%25" only, and just "%" is allowed for just
// convenience to end-user input.
auto host =
util::get_uri_field(reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST);
auto end = std::find(std::begin(host), std::end(host), '%');
ss << "["; ss << "[";
util::write_uri_field(ss, reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST); ss.write(host.c_str(), end - std::begin(host));
ss << "]"; ss << "]";
} else { } else {
util::write_uri_field(ss, reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST); util::write_uri_field(ss, reqvec[0]->uri.c_str(), reqvec[0]->u, UF_HOST);
@@ -1488,7 +1525,7 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
if (req->inflater) { if (req->inflater) {
while (len > 0) { while (len > 0) {
const size_t MAX_OUTLEN = 4096; const size_t MAX_OUTLEN = 4_k;
std::array<uint8_t, MAX_OUTLEN> out; std::array<uint8_t, MAX_OUTLEN> out;
size_t outlen = MAX_OUTLEN; size_t outlen = MAX_OUTLEN;
size_t tlen = len; size_t tlen = len;
@@ -1968,10 +2005,12 @@ int communicate(
result = -1; result = -1;
goto fin; goto fin;
} }
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_NO_COMPRESSION | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
SSL_CTX_set_options(ssl_ctx, ssl_opts);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
if (SSL_CTX_set_cipher_list(ssl_ctx, CIPHER_LIST) == 0) { if (SSL_CTX_set_cipher_list(ssl_ctx, CIPHER_LIST) == 0) {
@@ -2036,6 +2075,8 @@ int communicate(
client.record_domain_lookup_end_time(); client.record_domain_lookup_end_time();
if (client.initiate_connection() != 0) { if (client.initiate_connection() != 0) {
std::cerr << "[ERROR] Could not connect to " << host << ", port " << port
<< std::endl;
goto fin; goto fin;
} }
ev_run(loop, 0); ev_run(loop, 0);
@@ -2205,7 +2246,7 @@ int run(char **uris, int n) {
<< std::endl; << std::endl;
} }
while (1) { while (1) {
std::array<char, 1024> buf; std::array<char, 1_k> buf;
ssize_t rret, wret; ssize_t rret, wret;
while ((rret = read(0, buf.data(), buf.size())) == -1 && while ((rret = read(0, buf.data(), buf.size())) == -1 &&
errno == EINTR) errno == EINTR)
@@ -2255,29 +2296,35 @@ int run(char **uris, int n) {
http_parser_url u; http_parser_url u;
memset(&u, 0, sizeof(u)); memset(&u, 0, sizeof(u));
auto uri = strip_fragment(uris[i]); auto uri = strip_fragment(uris[i]);
if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) == 0 && if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &u) != 0) {
util::has_uri_field(u, UF_SCHEMA)) { std::cerr << "[ERROR] Could not parse URI " << uri << std::endl;
uint16_t port = util::has_uri_field(u, UF_PORT) continue;
}
if (!util::has_uri_field(u, UF_SCHEMA)) {
std::cerr << "[ERROR] URI " << uri << " does not have scheme part"
<< std::endl;
continue;
}
auto port = util::has_uri_field(u, UF_PORT)
? u.port ? u.port
: util::get_default_port(uri.c_str(), u); : util::get_default_port(uri.c_str(), u);
auto host = decode_host(util::get_uri_field(uri.c_str(), u, UF_HOST));
if (!util::fieldeq(uri.c_str(), u, UF_SCHEMA, prev_scheme.c_str()) || if (!util::fieldeq(uri.c_str(), u, UF_SCHEMA, prev_scheme.c_str()) ||
!util::fieldeq(uri.c_str(), u, UF_HOST, prev_host.c_str()) || host != prev_host || port != prev_port) {
port != prev_port) {
if (!requests.empty()) { if (!requests.empty()) {
if (communicate(prev_scheme, prev_host, prev_port, if (communicate(prev_scheme, prev_host, prev_port, std::move(requests),
std::move(requests), callbacks) != 0) { callbacks) != 0) {
++failures; ++failures;
} }
requests.clear(); requests.clear();
} }
prev_scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA); prev_scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA);
prev_host = util::get_uri_field(uri.c_str(), u, UF_HOST); prev_host = std::move(host);
prev_port = port; prev_port = port;
} }
requests.emplace_back(uri, data_fd == -1 ? nullptr : &data_prd, requests.emplace_back(uri, data_fd == -1 ? nullptr : &data_prd,
data_stat.st_size); data_stat.st_size);
} }
}
if (!requests.empty()) { if (!requests.empty()) {
if (communicate(prev_scheme, prev_host, prev_port, std::move(requests), if (communicate(prev_scheme, prev_host, prev_port, std::move(requests),
callbacks) != 0) { callbacks) != 0) {

View File

@@ -52,6 +52,7 @@
#include "buffer.h" #include "buffer.h"
#include "http2.h" #include "http2.h"
#include "nghttp2_gzip.h" #include "nghttp2_gzip.h"
#include "template.h"
namespace nghttp2 { namespace nghttp2 {
@@ -68,7 +69,6 @@ struct Config {
std::string datafile; std::string datafile;
std::string harfile; std::string harfile;
nghttp2_option *http2_option; nghttp2_option *http2_option;
size_t output_upper_thres;
size_t padding; size_t padding;
ssize_t peer_max_concurrent_streams; ssize_t peer_max_concurrent_streams;
ssize_t header_table_size; ssize_t header_table_size;
@@ -260,7 +260,7 @@ struct HttpClient {
// true if the response message of HTTP Upgrade request is fully // true if the response message of HTTP Upgrade request is fully
// received. It is not relevant the upgrade succeeds, or not. // received. It is not relevant the upgrade succeeds, or not.
bool upgrade_response_complete; bool upgrade_response_complete;
Buffer<65536> wb; Buffer<64_k> wb;
// SETTINGS payload sent as token68 in HTTP Upgrade // SETTINGS payload sent as token68 in HTTP Upgrade
std::array<uint8_t, 128> settings_payload; std::array<uint8_t, 128> settings_payload;

View File

@@ -710,8 +710,7 @@ int event_loop() {
} }
if (auto_tls_ticket_key) { if (auto_tls_ticket_key) {
// Renew ticket key every 12hrs // Renew ticket key every 12hrs
ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 12_h);
12 * 3600.);
renew_ticket_key_timer.data = conn_handler.get(); renew_ticket_key_timer.data = conn_handler.get();
ev_timer_again(loop, &renew_ticket_key_timer); ev_timer_again(loop, &renew_ticket_key_timer);
@@ -831,16 +830,16 @@ void fill_default_config() {
mod_config()->cert_file = nullptr; mod_config()->cert_file = nullptr;
// Read timeout for HTTP2 upstream connection // Read timeout for HTTP2 upstream connection
mod_config()->http2_upstream_read_timeout = 180.; mod_config()->http2_upstream_read_timeout = 3_min;
// Read timeout for non-HTTP2 upstream connection // Read timeout for non-HTTP2 upstream connection
mod_config()->upstream_read_timeout = 180.; mod_config()->upstream_read_timeout = 3_min;
// Write timeout for HTTP2/non-HTTP2 upstream connection // Write timeout for HTTP2/non-HTTP2 upstream connection
mod_config()->upstream_write_timeout = 30.; mod_config()->upstream_write_timeout = 30.;
// Read/Write timeouts for downstream connection // Read/Write timeouts for downstream connection
mod_config()->downstream_read_timeout = 180.; mod_config()->downstream_read_timeout = 3_min;
mod_config()->downstream_write_timeout = 30.; mod_config()->downstream_write_timeout = 30.;
// Read timeout for HTTP/2 stream // Read timeout for HTTP/2 stream
@@ -945,17 +944,17 @@ void fill_default_config() {
mod_config()->downstream_connections_per_host = 8; mod_config()->downstream_connections_per_host = 8;
mod_config()->downstream_connections_per_frontend = 0; mod_config()->downstream_connections_per_frontend = 0;
mod_config()->listener_disable_timeout = 0.; mod_config()->listener_disable_timeout = 0.;
mod_config()->downstream_request_buffer_size = 16 * 1024; mod_config()->downstream_request_buffer_size = 16_k;
mod_config()->downstream_response_buffer_size = 16 * 1024; mod_config()->downstream_response_buffer_size = 16_k;
mod_config()->no_server_push = false; mod_config()->no_server_push = false;
mod_config()->host_unix = false; mod_config()->host_unix = false;
mod_config()->http2_downstream_connections_per_worker = 0; mod_config()->http2_downstream_connections_per_worker = 0;
// ocsp update interval = 14400 secs = 4 hours, borrowed from h2o // ocsp update interval = 14400 secs = 4 hours, borrowed from h2o
mod_config()->ocsp_update_interval = 14400.; mod_config()->ocsp_update_interval = 4_h;
mod_config()->fetch_ocsp_response_file = mod_config()->fetch_ocsp_response_file =
strcopy(PKGDATADIR "/fetch-ocsp-response"); strcopy(PKGDATADIR "/fetch-ocsp-response");
mod_config()->no_ocsp = false; mod_config()->no_ocsp = false;
mod_config()->header_field_buffer = 64 * 1024; mod_config()->header_field_buffer = 64_k;
mod_config()->max_header_fields = 100; mod_config()->max_header_fields = 100;
} }
} // namespace } // namespace
@@ -1075,9 +1074,11 @@ Performance:
backend addresses specified by -b option. backend addresses specified by -b option.
--backend-http1-connections-per-host=<N> --backend-http1-connections-per-host=<N>
Set maximum number of backend concurrent HTTP/1 Set maximum number of backend concurrent HTTP/1
connections per host. This option is meaningful when -s connections per origin host. This option is meaningful
option is used. To limit the number of connections per when -s option is used. The origin host is determined
frontend for default mode, use by authority portion of requset URI (or :authority
header field for HTTP/2). To limit the number of
connections per frontend for default mode, use
--backend-http1-connections-per-frontend. --backend-http1-connections-per-frontend.
Default: )" << get_config()->downstream_connections_per_host Default: )" << get_config()->downstream_connections_per_host
<< R"( << R"(

View File

@@ -119,7 +119,7 @@ public:
Worker *get_worker() const; Worker *get_worker() const;
using WriteBuf = Buffer<32768>; using WriteBuf = Buffer<32768>;
using ReadBuf = Buffer<8192>; using ReadBuf = Buffer<8_k>;
WriteBuf *get_wb(); WriteBuf *get_wb();
ReadBuf *get_rb(); ReadBuf *get_rb();

View File

@@ -455,7 +455,7 @@ int ConnectionHandler::start_ocsp_update(const char *cert_file) {
} }
void ConnectionHandler::read_ocsp_chunk() { void ConnectionHandler::read_ocsp_chunk() {
std::array<uint8_t, 4096> buf; std::array<uint8_t, 4_k> buf;
for (;;) { for (;;) {
ssize_t n; ssize_t n;
while ((n = read(ocsp_.fd, buf.data(), buf.size())) == -1 && errno == EINTR) while ((n = read(ocsp_.fd, buf.data(), buf.size())) == -1 && errno == EINTR)

View File

@@ -58,7 +58,7 @@ public:
HostEntry(); HostEntry();
}; };
typedef std::map<std::string, HostEntry> HostEntryMap; using HostEntryMap = std::map<std::string, HostEntry>;
// conn_max_per_host == 0 means no limit for downstream connection. // conn_max_per_host == 0 means no limit for downstream connection.
DownstreamQueue(size_t conn_max_per_host = 0, bool unified_host = true); DownstreamQueue(size_t conn_max_per_host = 0, bool unified_host = true);

View File

@@ -316,13 +316,11 @@ int Http2DownstreamConnection::push_request_headers() {
nva.reserve(nheader + 8 + cookies.size() + nva.reserve(nheader + 8 + cookies.size() +
get_config()->add_request_headers.size()); get_config()->add_request_headers.size());
std::string via_value;
std::string xff_value;
std::string scheme, uri_authority, path, query;
nva.push_back(http2::make_nv_lc( nva.push_back(http2::make_nv_lc(
":method", http2::to_method_string(downstream_->get_request_method()))); ":method", http2::to_method_string(downstream_->get_request_method())));
auto &scheme = downstream_->get_request_http2_scheme();
if (downstream_->get_request_method() == HTTP_CONNECT) { if (downstream_->get_request_method() == HTTP_CONNECT) {
if (authority) { if (authority) {
nva.push_back(http2::make_nv_lc(":authority", authority)); nva.push_back(http2::make_nv_lc(":authority", authority));
@@ -331,9 +329,8 @@ int Http2DownstreamConnection::push_request_headers() {
http2::make_nv_ls(":authority", downstream_->get_request_path())); http2::make_nv_ls(":authority", downstream_->get_request_path()));
} }
} else { } else {
assert(!downstream_->get_request_http2_scheme().empty()); assert(!scheme.empty());
nva.push_back( nva.push_back(http2::make_nv_ls(":scheme", scheme));
http2::make_nv_ls(":scheme", downstream_->get_request_http2_scheme()));
if (authority) { if (authority) {
nva.push_back(http2::make_nv_lc(":authority", authority)); nva.push_back(http2::make_nv_lc(":authority", authority));
@@ -362,6 +359,7 @@ int Http2DownstreamConnection::push_request_headers() {
nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index)); nva.push_back(http2::make_nv(nv.name, nv.value, nv.no_index));
} }
std::string xff_value;
auto xff = downstream_->get_request_header(http2::HD_X_FORWARDED_FOR); auto xff = downstream_->get_request_header(http2::HD_X_FORWARDED_FOR);
if (get_config()->add_x_forwarded_for) { if (get_config()->add_x_forwarded_for) {
if (xff && !get_config()->strip_incoming_x_forwarded_for) { if (xff && !get_config()->strip_incoming_x_forwarded_for) {
@@ -378,17 +376,10 @@ int Http2DownstreamConnection::push_request_headers() {
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !get_config()->client_proxy &&
downstream_->get_request_method() != HTTP_CONNECT) { downstream_->get_request_method() != HTTP_CONNECT) {
// We use same protocol with :scheme header field // We use same protocol with :scheme header field
if (scheme.empty()) {
if (client_handler_->get_ssl()) {
nva.push_back(http2::make_nv_ll("x-forwarded-proto", "https"));
} else {
nva.push_back(http2::make_nv_ll("x-forwarded-proto", "http"));
}
} else {
nva.push_back(http2::make_nv_ls("x-forwarded-proto", scheme)); nva.push_back(http2::make_nv_ls("x-forwarded-proto", scheme));
} }
}
std::string via_value;
auto via = downstream_->get_request_header(http2::HD_VIA); auto via = downstream_->get_request_header(http2::HD_VIA);
if (get_config()->no_via) { if (get_config()->no_via) {
if (via) { if (via) {

View File

@@ -177,7 +177,7 @@ public:
CONNECTION_CHECK_STARTED CONNECTION_CHECK_STARTED
}; };
using ReadBuf = Buffer<8192>; using ReadBuf = Buffer<8_k>;
using WriteBuf = Buffer<32768>; using WriteBuf = Buffer<32768>;
private: private:

View File

@@ -251,6 +251,9 @@ int HttpDownstreamConnection::push_request_headers() {
// Assume that method and request path do not contain \r\n. // Assume that method and request path do not contain \r\n.
std::string hdrs = http2::to_method_string(downstream_->get_request_method()); std::string hdrs = http2::to_method_string(downstream_->get_request_method());
hdrs += ' '; hdrs += ' ';
auto &scheme = downstream_->get_request_http2_scheme();
if (connect_method) { if (connect_method) {
if (authority) { if (authority) {
hdrs += authority; hdrs += authority;
@@ -260,8 +263,8 @@ int HttpDownstreamConnection::push_request_headers() {
} else if (get_config()->http2_proxy || get_config()->client_proxy) { } else if (get_config()->http2_proxy || get_config()->client_proxy) {
// Construct absolute-form request target because we are going to // Construct absolute-form request target because we are going to
// send a request to a HTTP/1 proxy. // send a request to a HTTP/1 proxy.
assert(!downstream_->get_request_http2_scheme().empty()); assert(!scheme.empty());
hdrs += downstream_->get_request_http2_scheme(); hdrs += scheme;
hdrs += "://"; hdrs += "://";
if (authority) { if (authority) {
@@ -344,8 +347,8 @@ int HttpDownstreamConnection::push_request_headers() {
if (!get_config()->http2_proxy && !get_config()->client_proxy && if (!get_config()->http2_proxy && !get_config()->client_proxy &&
!connect_method) { !connect_method) {
hdrs += "X-Forwarded-Proto: "; hdrs += "X-Forwarded-Proto: ";
assert(!downstream_->get_request_http2_scheme().empty()); assert(!scheme.empty());
hdrs += downstream_->get_request_http2_scheme(); hdrs += scheme;
hdrs += "\r\n"; hdrs += "\r\n";
} }
auto via = downstream_->get_request_header(http2::HD_VIA); auto via = downstream_->get_request_header(http2::HD_VIA);
@@ -726,7 +729,7 @@ int HttpDownstreamConnection::on_read() {
} }
ev_timer_again(conn_.loop, &conn_.rt); ev_timer_again(conn_.loop, &conn_.rt);
std::array<uint8_t, 8192> buf; std::array<uint8_t, 8_k> buf;
int rv; int rv;
if (downstream_->get_upgraded()) { if (downstream_->get_upgraded()) {

View File

@@ -125,7 +125,7 @@ Log::~Log() {
return; return;
} }
char buf[4096]; char buf[4_k];
auto tty = lgconf->errorlog_tty; auto tty = lgconf->errorlog_tty;
lgconf->update_tstamp(std::chrono::system_clock::now()); lgconf->update_tstamp(std::chrono::system_clock::now());
@@ -172,7 +172,7 @@ void upstream_accesslog(const std::vector<LogFragment> &lfv,
return; return;
} }
char buf[4096]; char buf[4_k];
auto downstream = lgsp.downstream; auto downstream = lgsp.downstream;

View File

@@ -215,6 +215,14 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
return; return;
} }
// For other than CONNECT method, path must start with "/", except
// for OPTIONS method, which can take "*" as path.
if (!is_connect && path->value[0] != '/' &&
(method_token != HTTP_OPTIONS || path->value != "*")) {
upstream->rst_stream(downstream, SPDYLAY_PROTOCOL_ERROR);
return;
}
downstream->set_request_method(method_token); downstream->set_request_method(method_token);
if (is_connect) { if (is_connect) {
downstream->set_request_http2_authority(path->value); downstream->set_request_http2_authority(path->value);
@@ -456,7 +464,7 @@ SpdyUpstream::SpdyUpstream(uint16_t version, ClientHandler *handler)
rv = spdylay_session_server_new(&session_, version, &callbacks, this); rv = spdylay_session_server_new(&session_, version, &callbacks, this);
assert(rv == 0); assert(rv == 0);
uint32_t max_buffer = 65536; uint32_t max_buffer = 64_k;
rv = spdylay_session_set_option(session_, rv = spdylay_session_set_option(session_,
SPDYLAY_OPT_MAX_RECV_CTRL_FRAME_BUFFER, SPDYLAY_OPT_MAX_RECV_CTRL_FRAME_BUFFER,
&max_buffer, sizeof(max_buffer)); &max_buffer, sizeof(max_buffer));

View File

@@ -338,12 +338,14 @@ SSL_CTX *create_ssl_context(const char *private_key_file,
DIE(); DIE();
} }
SSL_CTX_set_options( auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE |
SSL_OP_CIPHER_SERVER_PREFERENCE | get_config()->tls_proto_mask); SSL_OP_CIPHER_SERVER_PREFERENCE |
get_config()->tls_proto_mask;
SSL_CTX_set_options(ssl_ctx, ssl_opts);
const unsigned char sid_ctx[] = "shrpx"; const unsigned char sid_ctx[] = "shrpx";
SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1); SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1);
@@ -493,11 +495,13 @@ SSL_CTX *create_ssl_client_context() {
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr); LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
SSL_OP_NO_COMPRESSION | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
get_config()->tls_proto_mask); get_config()->tls_proto_mask;
SSL_CTX_set_options(ssl_ctx, ssl_opts);
const char *ciphers; const char *ciphers;
if (get_config()->ciphers) { if (get_config()->ciphers) {

View File

@@ -145,6 +145,26 @@ template <typename T> void dlist_delete_all(DList<T> &dl) {
} }
} }
// User-defined literals for K, M, and G (powers of 1024)
constexpr unsigned long long operator"" _k(unsigned long long k) {
return k * 1024;
}
constexpr unsigned long long operator"" _m(unsigned long long m) {
return m * 1024 * 1024;
}
constexpr unsigned long long operator"" _g(unsigned long long g) {
return g * 1024 * 1024 * 1024;
}
// User-defined literals for time, converted into double in seconds
constexpr double operator"" _h(unsigned long long h) { return h * 60 * 60; }
constexpr double operator"" _min(unsigned long long min) { return min * 60; }
} // namespace nghttp2 } // namespace nghttp2
#endif // TEMPLATE_H #endif // TEMPLATE_H

View File

@@ -52,11 +52,11 @@ namespace nghttp2 {
// The additional HTTP/2 protocol ALPN protocol identifier we also // The additional HTTP/2 protocol ALPN protocol identifier we also
// supports for our applications to make smooth migration into final // supports for our applications to make smooth migration into final
// h2 ALPN ID. // h2 ALPN ID.
#define NGHTTP2_H2_16_ALPN "\x5h2-16" constexpr const char NGHTTP2_H2_16_ALPN[] = "\x5h2-16";
#define NGHTTP2_H2_16 "h2-16" constexpr const char NGHTTP2_H2_16[] = "h2-16";
#define NGHTTP2_H2_14_ALPN "\x5h2-14" constexpr const char NGHTTP2_H2_14_ALPN[] = "\x5h2-14";
#define NGHTTP2_H2_14 "h2-14" constexpr const char NGHTTP2_H2_14[] = "h2-14";
namespace util { namespace util {

View File

@@ -266,6 +266,8 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_send_data_callback) || test_nghttp2_session_send_data_callback) ||
!CU_add_test(pSuite, "session_on_begin_headers_temporal_failure", !CU_add_test(pSuite, "session_on_begin_headers_temporal_failure",
test_nghttp2_session_on_begin_headers_temporal_failure) || test_nghttp2_session_on_begin_headers_temporal_failure) ||
!CU_add_test(pSuite, "session_defer_then_close",
test_nghttp2_session_defer_then_close) ||
!CU_add_test(pSuite, "http_mandatory_headers", !CU_add_test(pSuite, "http_mandatory_headers",
test_nghttp2_http_mandatory_headers) || test_nghttp2_http_mandatory_headers) ||
!CU_add_test(pSuite, "http_content_length", !CU_add_test(pSuite, "http_content_length",

View File

@@ -2163,6 +2163,22 @@ void test_nghttp2_session_on_priority_received(void) {
nghttp2_frame_priority_free(&frame.priority); nghttp2_frame_priority_free(&frame.priority);
nghttp2_session_del(session); nghttp2_session_del(session);
/* Check again dep_stream_id == stream_id, and stream_id is idle */
nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_priority_spec_init(&pri_spec, 1, 16, 0);
nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
nghttp2_frame_priority_free(&frame.priority);
nghttp2_session_del(session);
} }
void test_nghttp2_session_on_rst_stream_received(void) { void test_nghttp2_session_on_rst_stream_received(void) {
@@ -5526,7 +5542,7 @@ void test_nghttp2_session_stream_dep_add(void) {
check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, c); check_stream_dep_sib(b, a, NULL, NULL, c);
check_stream_dep_sib(c, NULL, d, b, NULL); check_stream_dep_sib(c, a, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(4 == session->roots.num_streams); CU_ASSERT(4 == session->roots.num_streams);
@@ -5559,7 +5575,7 @@ void test_nghttp2_session_stream_dep_add(void) {
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(e, a, b, NULL, NULL); check_stream_dep_sib(e, a, b, NULL, NULL);
check_stream_dep_sib(b, e, NULL, NULL, c); check_stream_dep_sib(b, e, NULL, NULL, c);
check_stream_dep_sib(c, NULL, d, b, NULL); check_stream_dep_sib(c, e, d, b, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
CU_ASSERT(5 == session->roots.num_streams); CU_ASSERT(5 == session->roots.num_streams);
@@ -5621,7 +5637,7 @@ void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_session_del(session); nghttp2_session_del(session);
/* Remove left most stream */ /* Remove right most stream */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
@@ -5667,19 +5683,20 @@ void test_nghttp2_session_stream_dep_remove(void) {
nghttp2_session_del(session); nghttp2_session_del(session);
/* Remove right most stream */ /* Remove left most stream */
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a); b = open_stream_with_dep(session, 3, a);
c = open_stream_with_dep(session, 5, a); c = open_stream_with_dep(session, 5, a);
d = open_stream_with_dep(session, 7, c); d = open_stream_with_dep(session, 7, c);
e = open_stream_with_dep(session, 9, c);
/* a /* a
* | * |
* c--b * c--b
* | * |
* d * e--d
*/ */
nghttp2_stream_dep_remove(c); nghttp2_stream_dep_remove(c);
@@ -5687,23 +5704,26 @@ void test_nghttp2_session_stream_dep_remove(void) {
/* becomes: /* becomes:
* a * a
* | * |
* d--b * e--d--b
*/ */
CU_ASSERT(3 == a->num_substreams); CU_ASSERT(4 == a->num_substreams);
CU_ASSERT(1 == b->num_substreams); CU_ASSERT(1 == b->num_substreams);
CU_ASSERT(1 == c->num_substreams); CU_ASSERT(1 == c->num_substreams);
CU_ASSERT(1 == d->num_substreams); CU_ASSERT(1 == d->num_substreams);
CU_ASSERT(1 == e->num_substreams);
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == d->sum_dep_weight); CU_ASSERT(0 == d->sum_dep_weight);
CU_ASSERT(0 == c->sum_dep_weight); CU_ASSERT(0 == c->sum_dep_weight);
CU_ASSERT(0 == e->sum_dep_weight);
check_stream_dep_sib(a, NULL, d, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, d, NULL); check_stream_dep_sib(b, a, NULL, d, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL); check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(d, a, NULL, NULL, b); check_stream_dep_sib(d, a, NULL, e, b);
check_stream_dep_sib(e, a, NULL, NULL, d);
nghttp2_session_del(session); nghttp2_session_del(session);
@@ -5763,10 +5783,10 @@ void test_nghttp2_session_stream_dep_remove(void) {
CU_ASSERT(0 == f->sum_dep_weight); CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, d, NULL, NULL); check_stream_dep_sib(a, NULL, d, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, e, NULL); check_stream_dep_sib(b, a, NULL, e, NULL);
check_stream_dep_sib(c, NULL, NULL, NULL, NULL); check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
check_stream_dep_sib(e, NULL, NULL, f, b); check_stream_dep_sib(e, a, NULL, f, b);
check_stream_dep_sib(f, NULL, NULL, d, e); check_stream_dep_sib(f, a, NULL, d, e);
check_stream_dep_sib(d, a, NULL, NULL, f); check_stream_dep_sib(d, a, NULL, NULL, f);
nghttp2_session_del(session); nghttp2_session_del(session);
@@ -5822,8 +5842,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
CU_ASSERT(0 == f->sum_dep_weight); CU_ASSERT(0 == f->sum_dep_weight);
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(b, NULL, NULL, c, NULL); check_stream_dep_sib(b, a, NULL, c, NULL);
check_stream_dep_sib(c, NULL, d, e, b); check_stream_dep_sib(c, a, d, e, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
check_stream_dep_sib(e, a, f, NULL, c); check_stream_dep_sib(e, a, f, NULL, c);
check_stream_dep_sib(f, e, NULL, NULL, NULL); check_stream_dep_sib(f, e, NULL, NULL, NULL);
@@ -5877,8 +5897,8 @@ void test_nghttp2_session_stream_dep_add_subtree(void) {
check_stream_dep_sib(a, NULL, e, NULL, NULL); check_stream_dep_sib(a, NULL, e, NULL, NULL);
check_stream_dep_sib(e, a, f, NULL, NULL); check_stream_dep_sib(e, a, f, NULL, NULL);
check_stream_dep_sib(f, e, NULL, NULL, c); check_stream_dep_sib(f, e, NULL, NULL, c);
check_stream_dep_sib(b, NULL, NULL, c, NULL); check_stream_dep_sib(b, e, NULL, c, NULL);
check_stream_dep_sib(c, NULL, d, f, b); check_stream_dep_sib(c, e, d, f, b);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
nghttp2_session_del(session); nghttp2_session_del(session);
@@ -6011,7 +6031,7 @@ void test_nghttp2_session_stream_dep_remove_subtree(void) {
check_stream_dep_sib(a, NULL, b, NULL, NULL); check_stream_dep_sib(a, NULL, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, e); check_stream_dep_sib(b, a, NULL, NULL, e);
check_stream_dep_sib(e, NULL, NULL, b, NULL); check_stream_dep_sib(e, a, NULL, b, NULL);
check_stream_dep_sib(c, NULL, d, NULL, NULL); check_stream_dep_sib(c, NULL, d, NULL, NULL);
check_stream_dep_sib(d, c, NULL, NULL, NULL); check_stream_dep_sib(d, c, NULL, NULL, NULL);
@@ -6022,6 +6042,10 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d; nghttp2_stream *a, *b, *c, *d;
nghttp2_outbound_item *db, *dc;
nghttp2_mem *mem;
mem = nghttp2_mem_default();
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
@@ -6057,6 +6081,10 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL); check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(a, c, b, NULL, NULL); check_stream_dep_sib(a, c, b, NULL, NULL);
check_stream_dep_sib(b, a, NULL, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, NULL);
@@ -6066,9 +6094,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
nghttp2_session_server_new(&session, &callbacks, NULL); nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1); a = open_stream(session, 1);
b = open_stream(session, 3); b = open_stream(session, 3);
c = open_stream(session, 5); c = open_stream(session, 5);
/* /*
@@ -6093,9 +6119,13 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_dep_weight); CU_ASSERT(0 == a->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
check_stream_dep_sib(c, NULL, b, NULL, NULL); check_stream_dep_sib(c, NULL, b, NULL, NULL);
check_stream_dep_sib(b, c, NULL, NULL, a); check_stream_dep_sib(b, c, NULL, NULL, a);
check_stream_dep_sib(a, NULL, NULL, b, NULL); check_stream_dep_sib(a, c, NULL, b, NULL);
nghttp2_session_del(session); nghttp2_session_del(session);
@@ -6134,8 +6164,100 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight); CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
CU_ASSERT(0 == b->sum_dep_weight); CU_ASSERT(0 == b->sum_dep_weight);
CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL); check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, NULL, NULL, a, NULL); check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream(session, 5);
d = open_stream_with_dep(session, 7, c);
/* a c
* | |
* b d
*/
db = create_data_ob_item(mem);
nghttp2_stream_attach_item(b, db, session);
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
/*
* c
* |
* a--d
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL);
nghttp2_session_del(session);
nghttp2_session_server_new(&session, &callbacks, NULL);
a = open_stream(session, 1);
b = open_stream_with_dep(session, 3, a);
c = open_stream(session, 5);
d = open_stream_with_dep(session, 7, c);
/* a c
* | |
* b d
*/
db = create_data_ob_item(mem);
dc = create_data_ob_item(mem);
nghttp2_stream_attach_item(b, db, session);
nghttp2_stream_attach_item(c, dc, session);
nghttp2_stream_dep_remove_subtree(c);
CU_ASSERT(0 ==
nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
/*
* c
* |
* a--d
* |
* b
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
check_stream_dep_sib(c, NULL, a, NULL, NULL);
check_stream_dep_sib(d, c, NULL, a, NULL);
check_stream_dep_sib(a, c, b, NULL, d); check_stream_dep_sib(a, c, b, NULL, d);
check_stream_dep_sib(b, a, NULL, NULL, NULL); check_stream_dep_sib(b, a, NULL, NULL, NULL);
@@ -6145,7 +6267,7 @@ void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
void test_nghttp2_session_stream_attach_item(void) { void test_nghttp2_session_stream_attach_item(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d; nghttp2_stream *a, *b, *c, *d, *e;
nghttp2_outbound_item *da, *db, *dc, *dd; nghttp2_outbound_item *da, *db, *dc, *dd;
nghttp2_mem *mem; nghttp2_mem *mem;
@@ -6176,7 +6298,7 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == a->sum_norest_weight); CU_ASSERT(16 == a->sum_norest_weight);
@@ -6191,8 +6313,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
CU_ASSERT(32 == a->sum_norest_weight); CU_ASSERT(32 == a->sum_norest_weight);
@@ -6207,7 +6329,7 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 == a->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(a));
CU_ASSERT(1 == da->queued); CU_ASSERT(1 == da->queued);
@@ -6218,8 +6340,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
dd = create_data_ob_item(mem); dd = create_data_ob_item(mem);
@@ -6230,8 +6352,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == c->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(c));
CU_ASSERT(0 == dd->queued); CU_ASSERT(0 == dd->queued);
@@ -6242,8 +6364,8 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 32 == b->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == d->effective_weight); CU_ASSERT(16 * 16 / 32 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(1 == dd->queued); CU_ASSERT(1 == dd->queued);
@@ -6254,10 +6376,58 @@ void test_nghttp2_session_stream_attach_item(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == d->effective_weight); CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(1 == dd->queued); CU_ASSERT(1 == dd->queued);
/* exercises insertion */
e = open_stream_with_dep_excl(session, 9, a);
/* a
* |
* e
* |
* c--b
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(16 == e->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* exercises deletion */
nghttp2_stream_dep_remove(e);
/* a
* |
* c--b
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(16 * 16 / 16 == nghttp2_stream_compute_effective_weight(d));
/* e's weight 16 is distributed equally among c and b, both now have
weight 8 each. */
CU_ASSERT(8 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@@ -6265,7 +6435,7 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_stream *a, *b, *c, *d, *e, *f; nghttp2_stream *a, *b, *c, *d, *e, *f;
nghttp2_outbound_item *db, *dd, *de; nghttp2_outbound_item *da, *db, *dd, *de;
nghttp2_mem *mem; nghttp2_mem *mem;
mem = nghttp2_mem_default(); mem = nghttp2_mem_default();
@@ -6281,6 +6451,8 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
e = open_stream(session, 9); e = open_stream(session, 9);
f = open_stream_with_dep(session, 11, e); f = open_stream_with_dep(session, 11, e);
e->weight = 32;
/* /*
* a e * a e
* | | * | |
@@ -6304,8 +6476,12 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(32 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
CU_ASSERT(0 == d->sum_norest_weight);
/* Insert subtree e under a */ /* Insert subtree e under a */
@@ -6329,7 +6505,9 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(32 == a->sum_norest_weight);
/* Remove subtree b */ /* Remove subtree b */
@@ -6354,8 +6532,8 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == e->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(e));
/* Remove subtree a */ /* Remove subtree a */
@@ -6391,10 +6569,15 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(32 == a->sum_norest_weight);
CU_ASSERT(0 == c->sum_norest_weight);
dd = create_data_ob_item(mem); dd = create_data_ob_item(mem);
nghttp2_stream_attach_item(d, dd, session); nghttp2_stream_attach_item(d, dd, session);
CU_ASSERT(16 == c->sum_norest_weight);
/* Add subtree c to a */ /* Add subtree c to a */
nghttp2_stream_dep_remove_subtree(c); nghttp2_stream_dep_remove_subtree(c);
@@ -6415,11 +6598,11 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 * 16 / 32 == e->effective_weight); CU_ASSERT(16 * 16 / 48 == nghttp2_stream_compute_effective_weight(d));
CU_ASSERT(16 * 16 / 32 == e->effective_weight); CU_ASSERT(16 * 32 / 48 == nghttp2_stream_compute_effective_weight(e));
CU_ASSERT(32 == a->sum_norest_weight); CU_ASSERT(48 == a->sum_norest_weight);
CU_ASSERT(16 == c->sum_norest_weight); CU_ASSERT(16 == c->sum_norest_weight);
/* Insert b under a */ /* Insert b under a */
@@ -6444,10 +6627,9 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(16 == b->effective_weight); CU_ASSERT(16 == nghttp2_stream_compute_effective_weight(b));
CU_ASSERT(16 == a->sum_norest_weight); CU_ASSERT(16 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* Remove subtree b */ /* Remove subtree b */
@@ -6470,7 +6652,76 @@ void test_nghttp2_session_stream_attach_item_subtree(void) {
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri); CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(0 == a->sum_norest_weight); CU_ASSERT(0 == a->sum_norest_weight);
CU_ASSERT(0 == b->sum_norest_weight);
/* Remove subtree c, and detach item from b, and then re-add
subtree c under b */
nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_detach_item(b, session);
nghttp2_stream_dep_add_subtree(b, c, session);
/*
* b a
* |
* e--c
* | |
* f d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(48 == b->sum_norest_weight);
/* Attach data to a, and add subtree a under b */
da = create_data_ob_item(mem);
nghttp2_stream_attach_item(a, da, session);
nghttp2_stream_dep_add_subtree(b, a, session);
/*
* b
* |
* a--e--c
* | |
* f d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(64 == b->sum_norest_weight);
/* Remove subtree c, and add under f */
nghttp2_stream_dep_remove_subtree(c);
nghttp2_stream_dep_insert_subtree(f, c, session);
/*
* b
* |
* a--e
* |
* f
* |
* c
* |
* d
*/
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
CU_ASSERT(48 == b->sum_norest_weight);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@@ -7218,6 +7469,45 @@ void test_nghttp2_session_on_begin_headers_temporal_failure(void) {
nghttp2_bufs_free(&bufs); nghttp2_bufs_free(&bufs);
} }
void test_nghttp2_session_defer_then_close(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_data_provider prd;
int rv;
const uint8_t *datap;
ssize_t datalen;
nghttp2_frame frame;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
nghttp2_session_client_new(&session, &callbacks, NULL);
prd.read_callback = defer_data_source_read_callback;
rv = nghttp2_submit_request(session, NULL, reqnv, ARRLEN(reqnv), &prd, NULL);
CU_ASSERT(rv > 0);
/* This sends HEADERS */
datalen = nghttp2_session_mem_send(session, &datap);
CU_ASSERT(datalen > 0);
/* This makes DATA item deferred */
datalen = nghttp2_session_mem_send(session, &datap);
CU_ASSERT(datalen == 0);
nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_CANCEL);
/* Assertion failure; GH-264 */
rv = nghttp2_session_on_rst_stream_received(session, &frame);
CU_ASSERT(rv == 0);
nghttp2_session_del(session);
}
static void check_nghttp2_http_recv_headers_fail( static void check_nghttp2_http_recv_headers_fail(
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id, nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
int stream_state, const nghttp2_nv *nva, size_t nvlen) { int stream_state, const nghttp2_nv *nva, size_t nvlen) {

View File

@@ -126,6 +126,7 @@ void test_nghttp2_session_cancel_reserved_remote(void);
void test_nghttp2_session_reset_pending_headers(void); void test_nghttp2_session_reset_pending_headers(void);
void test_nghttp2_session_send_data_callback(void); void test_nghttp2_session_send_data_callback(void);
void test_nghttp2_session_on_begin_headers_temporal_failure(void); void test_nghttp2_session_on_begin_headers_temporal_failure(void);
void test_nghttp2_session_defer_then_close(void);
void test_nghttp2_http_mandatory_headers(void); void test_nghttp2_http_mandatory_headers(void);
void test_nghttp2_http_content_length(void); void test_nghttp2_http_content_length(void);
void test_nghttp2_http_content_length_mismatch(void); void test_nghttp2_http_content_length_mismatch(void);