Merge branch 'master' into simple-extensions
This commit is contained in:
commit
e14da859b6
13
doc/h2load.1
13
doc/h2load.1
|
@ -1,6 +1,6 @@
|
||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "H2LOAD" "1" "December 23, 2015" "1.6.0" "nghttp2"
|
.TH "H2LOAD" "1" "January 11, 2016" "1.6.1-DEV" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
h2load \- HTTP/2 benchmarking tool
|
h2load \- HTTP/2 benchmarking tool
|
||||||
.
|
.
|
||||||
|
@ -88,11 +88,12 @@ scheme, host or port values.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-m, \-\-max\-concurrent\-streams=(auto|<N>)
|
.B \-m, \-\-max\-concurrent\-streams=<N>
|
||||||
Max concurrent streams to issue per session. If "auto"
|
Max concurrent streams to issue per session. When
|
||||||
is given, the number of given URIs is used.
|
http/1.1 is used, this specifies the number of HTTP
|
||||||
|
pipelining requests in\-flight.
|
||||||
.sp
|
.sp
|
||||||
Default: \fBauto\fP
|
Default: \fB1\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
@ -410,6 +411,6 @@ window size described in HTTP/2 and SPDY protocol specification.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Tatsuhiro Tsujikawa
|
Tatsuhiro Tsujikawa
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
2012, 2015, Tatsuhiro Tsujikawa
|
2012, 2015, 2016, Tatsuhiro Tsujikawa
|
||||||
.\" Generated by docutils manpage writer.
|
.\" Generated by docutils manpage writer.
|
||||||
.
|
.
|
||||||
|
|
|
@ -63,12 +63,13 @@ OPTIONS
|
||||||
are used solely. Definition of a base URI overrides all
|
are used solely. Definition of a base URI overrides all
|
||||||
scheme, host or port values.
|
scheme, host or port values.
|
||||||
|
|
||||||
.. option:: -m, --max-concurrent-streams=(auto|<N>)
|
.. option:: -m, --max-concurrent-streams=<N>
|
||||||
|
|
||||||
Max concurrent streams to issue per session. If "auto"
|
Max concurrent streams to issue per session. When
|
||||||
is given, the number of given URIs is used.
|
http/1.1 is used, this specifies the number of HTTP
|
||||||
|
pipelining requests in-flight.
|
||||||
|
|
||||||
Default: ``auto``
|
Default: ``1``
|
||||||
|
|
||||||
.. option:: -w, --window-bits=<N>
|
.. option:: -w, --window-bits=<N>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTP" "1" "December 23, 2015" "1.6.0" "nghttp2"
|
.TH "NGHTTP" "1" "January 11, 2016" "1.6.1-DEV" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttp \- HTTP/2 client
|
nghttp \- HTTP/2 client
|
||||||
.
|
.
|
||||||
|
@ -296,6 +296,6 @@ on stream 11 with the weight 2.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Tatsuhiro Tsujikawa
|
Tatsuhiro Tsujikawa
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
2012, 2015, Tatsuhiro Tsujikawa
|
2012, 2015, 2016, Tatsuhiro Tsujikawa
|
||||||
.\" Generated by docutils manpage writer.
|
.\" Generated by docutils manpage writer.
|
||||||
.
|
.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPD" "1" "December 23, 2015" "1.6.0" "nghttp2"
|
.TH "NGHTTPD" "1" "January 11, 2016" "1.6.1-DEV" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpd \- HTTP/2 server
|
nghttpd \- HTTP/2 server
|
||||||
.
|
.
|
||||||
|
@ -180,6 +180,11 @@ Default: \fB/etc/mime.types\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
|
.B \-\-no\-content\-length
|
||||||
|
Don\(aqt send content\-length header field.
|
||||||
|
.UNINDENT
|
||||||
|
.INDENT 0.0
|
||||||
|
.TP
|
||||||
.B \-\-version
|
.B \-\-version
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
@ -197,6 +202,6 @@ The <SIZE> argument is an integer and an optional unit (e.g., 10K is
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Tatsuhiro Tsujikawa
|
Tatsuhiro Tsujikawa
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
2012, 2015, Tatsuhiro Tsujikawa
|
2012, 2015, 2016, Tatsuhiro Tsujikawa
|
||||||
.\" Generated by docutils manpage writer.
|
.\" Generated by docutils manpage writer.
|
||||||
.
|
.
|
||||||
|
|
|
@ -139,6 +139,10 @@ OPTIONS
|
||||||
|
|
||||||
Default: ``/etc/mime.types``
|
Default: ``/etc/mime.types``
|
||||||
|
|
||||||
|
.. option:: --no-content-length
|
||||||
|
|
||||||
|
Don't send content-length header field.
|
||||||
|
|
||||||
.. option:: --version
|
.. option:: --version
|
||||||
|
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.\" Man page generated from reStructuredText.
|
.\" Man page generated from reStructuredText.
|
||||||
.
|
.
|
||||||
.TH "NGHTTPX" "1" "December 23, 2015" "1.6.0" "nghttp2"
|
.TH "NGHTTPX" "1" "January 11, 2016" "1.6.1-DEV" "nghttp2"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
nghttpx \- HTTP/2 proxy
|
nghttpx \- HTTP/2 proxy
|
||||||
.
|
.
|
||||||
|
@ -896,8 +896,8 @@ Example: \fI\%\-\-add\-response\-header\fP="foo: bar"
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-header\-field\-buffer=<SIZE>
|
.B \-\-header\-field\-buffer=<SIZE>
|
||||||
Set maximum buffer size for incoming HTTP header field
|
Set maximum buffer size for incoming HTTP request header
|
||||||
list. This is the sum of header name and value in
|
field list. This is the sum of header name and value in
|
||||||
bytes.
|
bytes.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB64K\fP
|
Default: \fB64K\fP
|
||||||
|
@ -905,8 +905,9 @@ Default: \fB64K\fP
|
||||||
.INDENT 0.0
|
.INDENT 0.0
|
||||||
.TP
|
.TP
|
||||||
.B \-\-max\-header\-fields=<N>
|
.B \-\-max\-header\-fields=<N>
|
||||||
Set maximum number of incoming HTTP header fields, which
|
Set maximum number of incoming HTTP request header
|
||||||
appear in one request or response header field list.
|
fields, which appear in one request or response header
|
||||||
|
field list.
|
||||||
.sp
|
.sp
|
||||||
Default: \fB100\fP
|
Default: \fB100\fP
|
||||||
.UNINDENT
|
.UNINDENT
|
||||||
|
@ -1458,6 +1459,6 @@ App.new
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Tatsuhiro Tsujikawa
|
Tatsuhiro Tsujikawa
|
||||||
.SH COPYRIGHT
|
.SH COPYRIGHT
|
||||||
2012, 2015, Tatsuhiro Tsujikawa
|
2012, 2015, 2016, Tatsuhiro Tsujikawa
|
||||||
.\" Generated by docutils manpage writer.
|
.\" Generated by docutils manpage writer.
|
||||||
.
|
.
|
||||||
|
|
|
@ -797,16 +797,17 @@ HTTP
|
||||||
|
|
||||||
.. option:: --header-field-buffer=<SIZE>
|
.. option:: --header-field-buffer=<SIZE>
|
||||||
|
|
||||||
Set maximum buffer size for incoming HTTP header field
|
Set maximum buffer size for incoming HTTP request header
|
||||||
list. This is the sum of header name and value in
|
field list. This is the sum of header name and value in
|
||||||
bytes.
|
bytes.
|
||||||
|
|
||||||
Default: ``64K``
|
Default: ``64K``
|
||||||
|
|
||||||
.. option:: --max-header-fields=<N>
|
.. option:: --max-header-fields=<N>
|
||||||
|
|
||||||
Set maximum number of incoming HTTP header fields, which
|
Set maximum number of incoming HTTP request header
|
||||||
appear in one request or response header field list.
|
fields, which appear in one request or response header
|
||||||
|
field list.
|
||||||
|
|
||||||
Default: ``100``
|
Default: ``100``
|
||||||
|
|
||||||
|
|
|
@ -3299,6 +3299,8 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
|
||||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||||
* Trying to depend on itself (new stream ID equals
|
* Trying to depend on itself (new stream ID equals
|
||||||
* ``pri_spec->stream_id``).
|
* ``pri_spec->stream_id``).
|
||||||
|
* :enum:`NGHTTP2_ERR_PROTO`
|
||||||
|
* The |session| is server session.
|
||||||
*
|
*
|
||||||
* .. warning::
|
* .. warning::
|
||||||
*
|
*
|
||||||
|
@ -3371,6 +3373,8 @@ nghttp2_submit_request(nghttp2_session *session,
|
||||||
* processed yet. Normally, this does not happen, but when
|
* processed yet. Normally, this does not happen, but when
|
||||||
* application wrongly calls `nghttp2_submit_response()` twice,
|
* application wrongly calls `nghttp2_submit_response()` twice,
|
||||||
* this may happen.
|
* this may happen.
|
||||||
|
* :enum:`NGHTTP2_ERR_PROTO`
|
||||||
|
* The |session| is client session.
|
||||||
*
|
*
|
||||||
* .. warning::
|
* .. warning::
|
||||||
*
|
*
|
||||||
|
@ -3515,6 +3519,8 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
|
||||||
* DATA or HEADERS has been already submitted and not fully
|
* DATA or HEADERS has been already submitted and not fully
|
||||||
* processed yet. This happens if stream denoted by |stream_id|
|
* processed yet. This happens if stream denoted by |stream_id|
|
||||||
* is in reserved state.
|
* is in reserved state.
|
||||||
|
* :enum:`NGHTTP2_ERR_PROTO`
|
||||||
|
* The |stream_id| is -1, and |session| is server session.
|
||||||
*
|
*
|
||||||
* .. warning::
|
* .. warning::
|
||||||
*
|
*
|
||||||
|
|
|
@ -130,7 +130,7 @@ static int session_detect_idle_stream(nghttp2_session *session,
|
||||||
int32_t stream_id) {
|
int32_t stream_id) {
|
||||||
/* Assume that stream object with stream_id does not exist */
|
/* Assume that stream object with stream_id does not exist */
|
||||||
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||||
if (session->next_stream_id <= (uint32_t)stream_id) {
|
if (session->sent_stream_id < stream_id) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1379,7 +1379,9 @@ static int session_predicate_request_headers_send(nghttp2_session *session,
|
||||||
* NGHTTP2_ERR_INVALID_STREAM_STATE
|
* NGHTTP2_ERR_INVALID_STREAM_STATE
|
||||||
* The state of the stream is not valid.
|
* The state of the stream is not valid.
|
||||||
* NGHTTP2_ERR_SESSION_CLOSING
|
* NGHTTP2_ERR_SESSION_CLOSING
|
||||||
* This session is closing.
|
* This session is closing.
|
||||||
|
* NGHTTP2_ERR_PROTO
|
||||||
|
* Client side attempted to send response.
|
||||||
*/
|
*/
|
||||||
static int session_predicate_response_headers_send(nghttp2_session *session,
|
static int session_predicate_response_headers_send(nghttp2_session *session,
|
||||||
nghttp2_stream *stream) {
|
nghttp2_stream *stream) {
|
||||||
|
@ -1389,6 +1391,9 @@ static int session_predicate_response_headers_send(nghttp2_session *session,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
assert(stream);
|
assert(stream);
|
||||||
|
if (!session->server) {
|
||||||
|
return NGHTTP2_ERR_PROTO;
|
||||||
|
}
|
||||||
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
||||||
return NGHTTP2_ERR_INVALID_STREAM_ID;
|
return NGHTTP2_ERR_INVALID_STREAM_ID;
|
||||||
}
|
}
|
||||||
|
@ -1422,6 +1427,8 @@ static int session_predicate_response_headers_send(nghttp2_session *session,
|
||||||
* NGHTTP2_ERR_START_STREAM_NOT_ALLOWED
|
* NGHTTP2_ERR_START_STREAM_NOT_ALLOWED
|
||||||
* New stream cannot be created because GOAWAY is already sent or
|
* New stream cannot be created because GOAWAY is already sent or
|
||||||
* received.
|
* received.
|
||||||
|
* NGHTTP2_ERR_PROTO
|
||||||
|
* Client side attempted to send push response.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
session_predicate_push_response_headers_send(nghttp2_session *session,
|
session_predicate_push_response_headers_send(nghttp2_session *session,
|
||||||
|
@ -1433,6 +1440,9 @@ session_predicate_push_response_headers_send(nghttp2_session *session,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
assert(stream);
|
assert(stream);
|
||||||
|
if (!session->server) {
|
||||||
|
return NGHTTP2_ERR_PROTO;
|
||||||
|
}
|
||||||
if (stream->state != NGHTTP2_STREAM_RESERVED) {
|
if (stream->state != NGHTTP2_STREAM_RESERVED) {
|
||||||
return NGHTTP2_ERR_PROTO;
|
return NGHTTP2_ERR_PROTO;
|
||||||
}
|
}
|
||||||
|
@ -1901,6 +1911,11 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n",
|
DEBUGF(fprintf(stderr, "send: HEADERS finally serialized in %zd bytes\n",
|
||||||
nghttp2_bufs_len(&session->aob.framebufs)));
|
nghttp2_bufs_len(&session->aob.framebufs)));
|
||||||
|
|
||||||
|
if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
|
||||||
|
assert(session->sent_stream_id < frame->hd.stream_id);
|
||||||
|
session->sent_stream_id = frame->hd.stream_id;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NGHTTP2_PRIORITY: {
|
case NGHTTP2_PRIORITY: {
|
||||||
|
@ -1970,6 +1985,10 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(session->sent_stream_id + 2 <=
|
||||||
|
frame->push_promise.promised_stream_id);
|
||||||
|
session->sent_stream_id = frame->push_promise.promised_stream_id;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NGHTTP2_PING:
|
case NGHTTP2_PING:
|
||||||
|
@ -3805,13 +3824,14 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||||
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
|
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
|
||||||
"RST_STREAM: stream_id == 0");
|
"RST_STREAM: stream_id == 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
||||||
|
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
|
||||||
|
"RST_STREAM: stream in idle");
|
||||||
|
}
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
if (!stream) {
|
if (stream) {
|
||||||
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
|
||||||
return session_handle_invalid_connection(
|
|
||||||
session, frame, NGHTTP2_ERR_PROTO, "RST_STREAM: stream in idle");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* We may use stream->shut_flags for strict error checking. */
|
/* We may use stream->shut_flags for strict error checking. */
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
}
|
}
|
||||||
|
@ -4249,21 +4269,20 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
session, frame, NGHTTP2_ERR_PROTO,
|
session, frame, NGHTTP2_ERR_PROTO,
|
||||||
"PUSH_PROMISE: invalid promised_stream_id");
|
"PUSH_PROMISE: invalid promised_stream_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
||||||
|
return session_inflate_handle_invalid_connection(
|
||||||
|
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle");
|
||||||
|
}
|
||||||
|
|
||||||
session->last_recv_stream_id = frame->push_promise.promised_stream_id;
|
session->last_recv_stream_id = frame->push_promise.promised_stream_id;
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
if (!stream || stream->state == NGHTTP2_STREAM_CLOSING ||
|
if (!stream || stream->state == NGHTTP2_STREAM_CLOSING ||
|
||||||
!session->pending_enable_push ||
|
!session->pending_enable_push ||
|
||||||
session->num_incoming_reserved_streams >=
|
session->num_incoming_reserved_streams >=
|
||||||
session->max_incoming_reserved_streams) {
|
session->max_incoming_reserved_streams) {
|
||||||
if (!stream) {
|
/* Currently, client does not retain closed stream, so we don't
|
||||||
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
check NGHTTP2_SHUT_RD condition here. */
|
||||||
return session_inflate_handle_invalid_connection(
|
|
||||||
session, frame, NGHTTP2_ERR_PROTO, "PUSH_PROMISE: stream in idle");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Currently, client does not retain closed stream, so we don't
|
|
||||||
check NGHTTP2_SHUT_RD condition here. */
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = nghttp2_session_add_rst_stream(
|
rv = nghttp2_session_add_rst_stream(
|
||||||
session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL);
|
session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL);
|
||||||
|
@ -4415,12 +4434,14 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame) {
|
nghttp2_frame *frame) {
|
||||||
int rv;
|
int rv;
|
||||||
nghttp2_stream *stream;
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
||||||
|
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
|
||||||
|
"WINDOW_UPDATE to idle stream");
|
||||||
|
}
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
|
||||||
return session_handle_invalid_connection(
|
|
||||||
session, frame, NGHTTP2_ERR_PROTO, "WINDOW_UPDATE to idle stream");
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (state_reserved_remote(session, stream)) {
|
if (state_reserved_remote(session, stream)) {
|
||||||
|
@ -4736,14 +4757,15 @@ static int session_on_data_received_fail_fast(nghttp2_session *session) {
|
||||||
failure_reason = "DATA: stream_id == 0";
|
failure_reason = "DATA: stream_id == 0";
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session_detect_idle_stream(session, stream_id)) {
|
||||||
|
failure_reason = "DATA: stream in idle";
|
||||||
|
error_code = NGHTTP2_PROTOCOL_ERROR;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream(session, stream_id);
|
stream = nghttp2_session_get_stream(session, stream_id);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
if (session_detect_idle_stream(session, stream_id)) {
|
|
||||||
failure_reason = "DATA: stream in idle";
|
|
||||||
error_code = NGHTTP2_PROTOCOL_ERROR;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
||||||
if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) {
|
if (stream && (stream->shut_flags & NGHTTP2_SHUT_RD)) {
|
||||||
failure_reason = "DATA: stream closed";
|
failure_reason = "DATA: stream closed";
|
||||||
|
|
|
@ -247,6 +247,10 @@ struct nghttp2_session {
|
||||||
size_t obq_flood_counter_;
|
size_t obq_flood_counter_;
|
||||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||||
uint32_t next_stream_id;
|
uint32_t next_stream_id;
|
||||||
|
/* The last stream ID this session initiated. For client session,
|
||||||
|
this is the last stream ID it has sent. For server session, it
|
||||||
|
is the last promised stream ID sent in PUSH_PROMISE. */
|
||||||
|
int32_t sent_stream_id;
|
||||||
/* The largest stream ID received so far */
|
/* The largest stream ID received so far */
|
||||||
int32_t last_recv_stream_id;
|
int32_t last_recv_stream_id;
|
||||||
/* The largest stream ID which has been processed in some way. This
|
/* The largest stream ID which has been processed in some way. This
|
||||||
|
|
|
@ -32,6 +32,35 @@
|
||||||
#include "nghttp2_helper.h"
|
#include "nghttp2_helper.h"
|
||||||
#include "nghttp2_priority_spec.h"
|
#include "nghttp2_priority_spec.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detects the dependency error, that is stream attempted to depend on
|
||||||
|
* itself. If |stream_id| is -1, we use session->next_stream_id as
|
||||||
|
* stream ID.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||||
|
* Stream attempted to depend on itself.
|
||||||
|
*/
|
||||||
|
static int detect_self_dependency(nghttp2_session *session, int32_t stream_id,
|
||||||
|
const nghttp2_priority_spec *pri_spec) {
|
||||||
|
assert(pri_spec);
|
||||||
|
|
||||||
|
if (stream_id == -1) {
|
||||||
|
if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream_id == pri_spec->stream_id) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function takes ownership of |nva_copy|. Regardless of the
|
/* This function takes ownership of |nva_copy|. Regardless of the
|
||||||
return value, the caller must not free |nva_copy| after this
|
return value, the caller must not free |nva_copy| after this
|
||||||
function returns. */
|
function returns. */
|
||||||
|
@ -50,21 +79,6 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
|
||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
if (stream_id == 0) {
|
|
||||||
rv = NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream_id == -1) {
|
|
||||||
if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
|
|
||||||
rv = NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
} else if (stream_id == pri_spec->stream_id) {
|
|
||||||
rv = NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||||
if (item == NULL) {
|
if (item == NULL) {
|
||||||
rv = NGHTTP2_ERR_NOMEM;
|
rv = NGHTTP2_ERR_NOMEM;
|
||||||
|
@ -156,6 +170,10 @@ static int32_t submit_headers_shared_nva(nghttp2_session *session,
|
||||||
|
|
||||||
int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
|
int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
|
||||||
const nghttp2_nv *nva, size_t nvlen) {
|
const nghttp2_nv *nva, size_t nvlen) {
|
||||||
|
if (stream_id <= 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
|
return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
|
||||||
stream_id, NULL, nva, nvlen, NULL,
|
stream_id, NULL, nva, nvlen, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -166,9 +184,24 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
||||||
const nghttp2_priority_spec *pri_spec,
|
const nghttp2_priority_spec *pri_spec,
|
||||||
const nghttp2_nv *nva, size_t nvlen,
|
const nghttp2_nv *nva, size_t nvlen,
|
||||||
void *stream_user_data) {
|
void *stream_user_data) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (stream_id == -1) {
|
||||||
|
if (session->server) {
|
||||||
|
return NGHTTP2_ERR_PROTO;
|
||||||
|
}
|
||||||
|
} else if (stream_id <= 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||||
|
|
||||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||||
|
rv = detect_self_dependency(session, stream_id, pri_spec);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||||
} else {
|
} else {
|
||||||
pri_spec = NULL;
|
pri_spec = NULL;
|
||||||
|
@ -281,7 +314,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
if (stream_id == 0 || nghttp2_session_is_my_stream_id(session, stream_id)) {
|
if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,8 +429,18 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
|
||||||
const nghttp2_data_provider *data_prd,
|
const nghttp2_data_provider *data_prd,
|
||||||
void *stream_user_data) {
|
void *stream_user_data) {
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
|
int rv;
|
||||||
|
|
||||||
if (pri_spec && nghttp2_priority_spec_check_default(pri_spec)) {
|
if (session->server) {
|
||||||
|
return NGHTTP2_ERR_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||||
|
rv = detect_self_dependency(session, -1, pri_spec);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
pri_spec = NULL;
|
pri_spec = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +461,17 @@ static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
|
||||||
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
||||||
const nghttp2_nv *nva, size_t nvlen,
|
const nghttp2_nv *nva, size_t nvlen,
|
||||||
const nghttp2_data_provider *data_prd) {
|
const nghttp2_data_provider *data_prd) {
|
||||||
uint8_t flags = set_response_flags(data_prd);
|
uint8_t flags;
|
||||||
|
|
||||||
|
if (stream_id <= 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session->server) {
|
||||||
|
return NGHTTP2_ERR_PROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = set_response_flags(data_prd);
|
||||||
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
|
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
|
||||||
data_prd, NULL);
|
data_prd, NULL);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -306,3 +306,119 @@ nghttp2_outbound_item *create_data_ob_item(nghttp2_mem *mem) {
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream(nghttp2_session *session, int32_t stream_id) {
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
|
||||||
|
return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
|
||||||
|
NGHTTP2_STREAM_OPENED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream2(nghttp2_session *session, int32_t stream_id,
|
||||||
|
nghttp2_stream_state initial_state) {
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
|
||||||
|
return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
|
||||||
|
initial_state, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream3(nghttp2_session *session, int32_t stream_id,
|
||||||
|
uint8_t flags,
|
||||||
|
nghttp2_priority_spec *pri_spec_in,
|
||||||
|
nghttp2_stream_state initial_state,
|
||||||
|
void *stream_user_data) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
assert(nghttp2_session_is_my_stream_id(session, stream_id));
|
||||||
|
|
||||||
|
stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
|
||||||
|
initial_state, stream_user_data);
|
||||||
|
session->sent_stream_id = nghttp2_max(session->sent_stream_id, stream_id);
|
||||||
|
session->next_stream_id =
|
||||||
|
nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream_with_dep(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
nghttp2_stream *dep_stream) {
|
||||||
|
return open_sent_stream_with_dep_weight(session, stream_id,
|
||||||
|
NGHTTP2_DEFAULT_WEIGHT, dep_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream_with_dep_weight(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
int32_t weight,
|
||||||
|
nghttp2_stream *dep_stream) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
assert(nghttp2_session_is_my_stream_id(session, stream_id));
|
||||||
|
|
||||||
|
stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
|
||||||
|
|
||||||
|
session->sent_stream_id = nghttp2_max(session->sent_stream_id, stream_id);
|
||||||
|
session->next_stream_id =
|
||||||
|
nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream(nghttp2_session *session, int32_t stream_id) {
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
|
||||||
|
return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
|
||||||
|
NGHTTP2_STREAM_OPENED, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream2(nghttp2_session *session, int32_t stream_id,
|
||||||
|
nghttp2_stream_state initial_state) {
|
||||||
|
nghttp2_priority_spec pri_spec;
|
||||||
|
|
||||||
|
nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
|
||||||
|
return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
|
||||||
|
initial_state, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream3(nghttp2_session *session, int32_t stream_id,
|
||||||
|
uint8_t flags,
|
||||||
|
nghttp2_priority_spec *pri_spec_in,
|
||||||
|
nghttp2_stream_state initial_state,
|
||||||
|
void *stream_user_data) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
assert(!nghttp2_session_is_my_stream_id(session, stream_id));
|
||||||
|
|
||||||
|
stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
|
||||||
|
initial_state, stream_user_data);
|
||||||
|
session->last_recv_stream_id =
|
||||||
|
nghttp2_max(session->last_recv_stream_id, stream_id);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream_with_dep(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
nghttp2_stream *dep_stream) {
|
||||||
|
return open_recv_stream_with_dep_weight(session, stream_id,
|
||||||
|
NGHTTP2_DEFAULT_WEIGHT, dep_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream_with_dep_weight(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
int32_t weight,
|
||||||
|
nghttp2_stream *dep_stream) {
|
||||||
|
nghttp2_stream *stream;
|
||||||
|
|
||||||
|
assert(!nghttp2_session_is_my_stream_id(session, stream_id));
|
||||||
|
|
||||||
|
stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
|
||||||
|
|
||||||
|
session->last_recv_stream_id =
|
||||||
|
nghttp2_max(session->last_recv_stream_id, stream_id);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
|
@ -110,4 +110,49 @@ nghttp2_stream *open_stream_with_dep_excl(nghttp2_session *session,
|
||||||
|
|
||||||
nghttp2_outbound_item *create_data_ob_item(nghttp2_mem *mem);
|
nghttp2_outbound_item *create_data_ob_item(nghttp2_mem *mem);
|
||||||
|
|
||||||
|
/* Opens stream. This stream is assumed to be sent from |session|,
|
||||||
|
and session->sent_stream_id and session->next_stream_id will be
|
||||||
|
adjusted accordingly. */
|
||||||
|
nghttp2_stream *open_sent_stream(nghttp2_session *session, int32_t stream_id);
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream2(nghttp2_session *session, int32_t stream_id,
|
||||||
|
nghttp2_stream_state initial_state);
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream3(nghttp2_session *session, int32_t stream_id,
|
||||||
|
uint8_t flags,
|
||||||
|
nghttp2_priority_spec *pri_spec_in,
|
||||||
|
nghttp2_stream_state initial_state,
|
||||||
|
void *stream_user_data);
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream_with_dep(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
nghttp2_stream *dep_stream);
|
||||||
|
|
||||||
|
nghttp2_stream *open_sent_stream_with_dep_weight(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
int32_t weight,
|
||||||
|
nghttp2_stream *dep_stream);
|
||||||
|
|
||||||
|
/* Opens stream. This stream is assumed to be received by |session|,
|
||||||
|
and session->last_recv_stream_id will be adjusted accordingly. */
|
||||||
|
nghttp2_stream *open_recv_stream(nghttp2_session *session, int32_t stream_id);
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream2(nghttp2_session *session, int32_t stream_id,
|
||||||
|
nghttp2_stream_state initial_state);
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream3(nghttp2_session *session, int32_t stream_id,
|
||||||
|
uint8_t flags,
|
||||||
|
nghttp2_priority_spec *pri_spec_in,
|
||||||
|
nghttp2_stream_state initial_state,
|
||||||
|
void *stream_user_data);
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream_with_dep(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
nghttp2_stream *dep_stream);
|
||||||
|
|
||||||
|
nghttp2_stream *open_recv_stream_with_dep_weight(nghttp2_session *session,
|
||||||
|
int32_t stream_id,
|
||||||
|
int32_t weight,
|
||||||
|
nghttp2_stream *dep_stream);
|
||||||
|
|
||||||
#endif /* NGHTTP2_TEST_HELPER_H */
|
#endif /* NGHTTP2_TEST_HELPER_H */
|
||||||
|
|
Loading…
Reference in New Issue