Limit the number of incoming reserved (remote) streams
RFC 7540 does not enforce any limit on the number of incoming reserved streams (in RFC 7540 terms, streams in reserved (remote) state). This only affects client side, since only server can push streams. Malicious server can push arbitrary number of streams, and make client's memory exhausted. The new option, nghttp2_set_max_reserved_remote_streams, can set the maximum number of such incoming streams to avoid possible memory exhaustion. If this option is set, and pushed streams are automatically closed on reception, without calling user provided callback, if they exceed the given limit. The default value is 200. If session is configured as server side, this option has no effect. Server can control the number of streams to push.
This commit is contained in:
parent
647e30619f
commit
928a81885c
|
@ -2031,6 +2031,25 @@ nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
|
||||||
NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
|
NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
|
||||||
int val);
|
int val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
*
|
||||||
|
* RFC 7540 does not enforce any limit on the number of incoming
|
||||||
|
* reserved streams (in RFC 7540 terms, streams in reserved (remote)
|
||||||
|
* state). This only affects client side, since only server can push
|
||||||
|
* streams. Malicious server can push arbitrary number of streams,
|
||||||
|
* and make client's memory exhausted. This option can set the
|
||||||
|
* maximum number of such incoming streams to avoid possible memory
|
||||||
|
* exhaustion. If this option is set, and pushed streams are
|
||||||
|
* automatically closed on reception, without calling user provided
|
||||||
|
* callback, if they exceed the given limit. The default value is
|
||||||
|
* 200. If session is configured as server side, this option has no
|
||||||
|
* effect. Server can control the number of streams to push.
|
||||||
|
*/
|
||||||
|
NGHTTP2_EXTERN void
|
||||||
|
nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
||||||
|
uint32_t val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -56,3 +56,9 @@ void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) {
|
||||||
option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING;
|
option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING;
|
||||||
option->no_http_messaging = val;
|
option->no_http_messaging = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
||||||
|
uint32_t val) {
|
||||||
|
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
|
||||||
|
option->max_reserved_remote_streams = val;
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,8 @@ typedef enum {
|
||||||
*/
|
*/
|
||||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||||
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
|
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
|
||||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3
|
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
||||||
|
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4
|
||||||
} nghttp2_option_flag;
|
} nghttp2_option_flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,6 +75,10 @@ struct nghttp2_option {
|
||||||
* NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
|
* NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
|
||||||
*/
|
*/
|
||||||
uint32_t peer_max_concurrent_streams;
|
uint32_t peer_max_concurrent_streams;
|
||||||
|
/**
|
||||||
|
* NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
|
||||||
|
*/
|
||||||
|
uint32_t max_reserved_remote_streams;
|
||||||
/**
|
/**
|
||||||
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -372,6 +372,9 @@ static int session_new(nghttp2_session **session_ptr,
|
||||||
init_settings(&(*session_ptr)->remote_settings);
|
init_settings(&(*session_ptr)->remote_settings);
|
||||||
init_settings(&(*session_ptr)->local_settings);
|
init_settings(&(*session_ptr)->local_settings);
|
||||||
|
|
||||||
|
(*session_ptr)->max_incoming_reserved_streams =
|
||||||
|
NGHTTP2_MAX_INCOMING_RESERVED_STREAMS;
|
||||||
|
|
||||||
if (option) {
|
if (option) {
|
||||||
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
||||||
option->no_auto_window_update) {
|
option->no_auto_window_update) {
|
||||||
|
@ -385,6 +388,12 @@ static int session_new(nghttp2_session **session_ptr,
|
||||||
option->peer_max_concurrent_streams;
|
option->peer_max_concurrent_streams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option->opt_set_mask & NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS) {
|
||||||
|
|
||||||
|
(*session_ptr)->max_incoming_reserved_streams =
|
||||||
|
option->max_reserved_remote_streams;
|
||||||
|
}
|
||||||
|
|
||||||
if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) &&
|
if ((option->opt_set_mask & NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC) &&
|
||||||
option->no_recv_client_magic) {
|
option->no_recv_client_magic) {
|
||||||
|
|
||||||
|
@ -910,11 +919,12 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
||||||
switch (initial_state) {
|
switch (initial_state) {
|
||||||
case NGHTTP2_STREAM_RESERVED:
|
case NGHTTP2_STREAM_RESERVED:
|
||||||
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||||
/* half closed (remote) */
|
/* reserved (local) */
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
|
||||||
} else {
|
} else {
|
||||||
/* half closed (local) */
|
/* reserved (remote) */
|
||||||
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR);
|
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR);
|
||||||
|
++session->num_incoming_reserved_streams;
|
||||||
}
|
}
|
||||||
/* Reserved stream does not count in the concurrent streams
|
/* Reserved stream does not count in the concurrent streams
|
||||||
limit. That is one of the DOS vector. */
|
limit. That is one of the DOS vector. */
|
||||||
|
@ -1017,7 +1027,11 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||||
|
|
||||||
/* pushed streams which is not opened yet is not counted toward max
|
/* pushed streams which is not opened yet is not counted toward max
|
||||||
concurrent limits */
|
concurrent limits */
|
||||||
if ((stream->flags & NGHTTP2_STREAM_FLAG_PUSH) == 0) {
|
if ((stream->flags & NGHTTP2_STREAM_FLAG_PUSH)) {
|
||||||
|
if (!nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||||
|
--session->num_incoming_reserved_streams;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
if (nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||||
--session->num_outgoing_streams;
|
--session->num_outgoing_streams;
|
||||||
} else {
|
} else {
|
||||||
|
@ -3458,6 +3472,9 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_stream_promise_fulfilled(stream);
|
nghttp2_stream_promise_fulfilled(stream);
|
||||||
|
if (!nghttp2_session_is_my_stream_id(session, stream->stream_id)) {
|
||||||
|
--session->num_incoming_reserved_streams;
|
||||||
|
}
|
||||||
++session->num_incoming_streams;
|
++session->num_incoming_streams;
|
||||||
rv = session_call_on_begin_headers(session, frame);
|
rv = session_call_on_begin_headers(session, frame);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
|
@ -4057,7 +4074,9 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
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->max_incoming_reserved_streams) {
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
if (session_detect_idle_stream(session, frame->hd.stream_id)) {
|
||||||
return session_inflate_handle_invalid_connection(
|
return session_inflate_handle_invalid_connection(
|
||||||
|
|
|
@ -66,6 +66,9 @@ typedef struct {
|
||||||
nghttp2_session_recv(). */
|
nghttp2_session_recv(). */
|
||||||
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
|
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
|
||||||
|
|
||||||
|
/* The default maximum number of incoming reserved streams */
|
||||||
|
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
|
||||||
|
|
||||||
/* Internal state when receiving incoming frame */
|
/* Internal state when receiving incoming frame */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* Receiving frame header */
|
/* Receiving frame header */
|
||||||
|
@ -194,6 +197,19 @@ struct nghttp2_session {
|
||||||
/* The number of incoming streams. This will be capped by
|
/* The number of incoming streams. This will be capped by
|
||||||
local_settings.max_concurrent_streams. */
|
local_settings.max_concurrent_streams. */
|
||||||
size_t num_incoming_streams;
|
size_t num_incoming_streams;
|
||||||
|
/* The number of incoming reserved streams. This is the number of
|
||||||
|
streams in reserved (remote) state. RFC 7540 does not limit this
|
||||||
|
number. nghttp2 offers
|
||||||
|
nghttp2_option_set_max_reserved_remote_streams() to achieve this.
|
||||||
|
If it is used, num_incoming_streams is capped by
|
||||||
|
max_incoming_reserved_streams. Client application should
|
||||||
|
consider to set this because without that server can send
|
||||||
|
arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
|
||||||
|
size_t num_incoming_reserved_streams;
|
||||||
|
/* The maximum number of incoming reserved streams (reserved
|
||||||
|
(remote) state). RST_STREAM will be sent for the pushed stream
|
||||||
|
which exceeds this limit. */
|
||||||
|
size_t max_incoming_reserved_streams;
|
||||||
/* The number of closed streams still kept in |streams| hash. The
|
/* The number of closed streams still kept in |streams| hash. The
|
||||||
closed streams can be accessed through single linked list
|
closed streams can be accessed through single linked list
|
||||||
|closed_stream_head|. The current implementation only keeps
|
|closed_stream_head|. The current implementation only keeps
|
||||||
|
|
|
@ -2065,9 +2065,11 @@ void test_nghttp2_session_on_push_response_headers_received(void) {
|
||||||
user_data.begin_headers_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received(
|
CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received(
|
||||||
session, &frame, stream));
|
session, &frame, stream));
|
||||||
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(0 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
|
||||||
CU_ASSERT(1 == session->num_incoming_streams);
|
CU_ASSERT(1 == session->num_incoming_streams);
|
||||||
CU_ASSERT(0 == (stream->flags & NGHTTP2_STREAM_FLAG_PUSH));
|
CU_ASSERT(0 == (stream->flags & NGHTTP2_STREAM_FLAG_PUSH));
|
||||||
|
@ -2086,6 +2088,7 @@ void test_nghttp2_session_on_push_response_headers_received(void) {
|
||||||
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
||||||
CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
|
CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
|
||||||
CU_ASSERT(1 == session->num_incoming_streams);
|
CU_ASSERT(1 == session->num_incoming_streams);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
CU_ASSERT(1 == session->num_incoming_streams);
|
CU_ASSERT(1 == session->num_incoming_streams);
|
||||||
|
@ -2106,6 +2109,7 @@ void test_nghttp2_session_on_push_response_headers_received(void) {
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||||
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
|
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
|
||||||
CU_ASSERT(1 == session->num_incoming_streams);
|
CU_ASSERT(1 == session->num_incoming_streams);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
@ -2401,6 +2405,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
promised_stream = nghttp2_session_get_stream(session, 2);
|
promised_stream = nghttp2_session_get_stream(session, 2);
|
||||||
CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
|
CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
|
||||||
CU_ASSERT(2 == session->last_recv_stream_id);
|
CU_ASSERT(2 == session->last_recv_stream_id);
|
||||||
|
@ -2416,6 +2421,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 4));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 4));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
||||||
|
@ -2435,6 +2441,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
||||||
|
@ -2452,6 +2459,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||||
|
@ -2468,7 +2476,16 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
NGHTTP2_STREAM_OPENING, NULL);
|
NGHTTP2_STREAM_OPENING, NULL);
|
||||||
|
|
||||||
/* Same ID twice */
|
/* Same ID twice */
|
||||||
stream->state = NGHTTP2_STREAM_OPENING;
|
frame.hd.stream_id = 1;
|
||||||
|
frame.push_promise.promised_stream_id = 2;
|
||||||
|
|
||||||
|
user_data.begin_headers_cb_called = 0;
|
||||||
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
|
CU_ASSERT(1 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
CU_ASSERT(NULL != nghttp2_session_get_stream(session, 2));
|
||||||
|
|
||||||
user_data.begin_headers_cb_called = 0;
|
user_data.begin_headers_cb_called = 0;
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
|
@ -2476,6 +2493,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
|
||||||
item = nghttp2_session_get_next_ob_item(session);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||||
|
@ -2491,6 +2509,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
|
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
|
||||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
@ -2512,6 +2531,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
@ -2534,6 +2554,7 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
|
|
||||||
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
CU_ASSERT(0 == user_data.begin_headers_cb_called);
|
||||||
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
|
||||||
|
CU_ASSERT(0 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
@ -2572,6 +2593,35 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
nghttp2_session_on_push_promise_received(session, &frame));
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
|
CU_ASSERT(0 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
|
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
/* Check max_incoming_reserved_streams */
|
||||||
|
nghttp2_session_client_new(&session, &callbacks, &user_data);
|
||||||
|
session->max_incoming_reserved_streams = 1;
|
||||||
|
|
||||||
|
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
&pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
|
||||||
|
nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
|
||||||
|
&pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL);
|
||||||
|
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
|
nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS,
|
||||||
|
1, 4, NULL, 0);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||||
|
nghttp2_session_on_push_promise_received(session, &frame));
|
||||||
|
|
||||||
|
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
|
||||||
|
CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
|
||||||
|
|
||||||
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
nghttp2_frame_push_promise_free(&frame.push_promise, mem);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
@ -5398,6 +5448,13 @@ void test_nghttp2_session_set_option(void) {
|
||||||
CU_ASSERT(100 == session->remote_settings.max_concurrent_streams);
|
CU_ASSERT(100 == session->remote_settings.max_concurrent_streams);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
nghttp2_option_set_max_reserved_remote_streams(option, 99);
|
||||||
|
|
||||||
|
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
|
||||||
|
|
||||||
|
CU_ASSERT(99 == session->max_incoming_reserved_streams);
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
nghttp2_option_del(option);
|
nghttp2_option_del(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue