mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-07 10:38:53 +08:00
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:
@@ -2065,9 +2065,11 @@ void test_nghttp2_session_on_push_response_headers_received(void) {
|
||||
user_data.begin_headers_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(
|
||||
session, &frame, stream));
|
||||
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(1 == session->num_incoming_streams);
|
||||
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_REFUSED_STREAM == item->frame.rst_stream.error_code);
|
||||
CU_ASSERT(1 == session->num_incoming_streams);
|
||||
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
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_PROTOCOL_ERROR == item->frame.goaway.error_code);
|
||||
CU_ASSERT(1 == session->num_incoming_streams);
|
||||
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||
|
||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||
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(1 == user_data.begin_headers_cb_called);
|
||||
CU_ASSERT(1 == session->num_incoming_reserved_streams);
|
||||
promised_stream = nghttp2_session_get_stream(session, 2);
|
||||
CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
|
||||
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(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));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
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));
|
||||
|
||||
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));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
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));
|
||||
|
||||
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));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
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);
|
||||
|
||||
/* 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.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));
|
||||
|
||||
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));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
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));
|
||||
|
||||
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_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(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_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(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_session_del(session);
|
||||
@@ -2572,6 +2593,35 @@ void test_nghttp2_session_on_push_promise_received(void) {
|
||||
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
|
||||
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_session_del(session);
|
||||
}
|
||||
@@ -5398,6 +5448,13 @@ void test_nghttp2_session_set_option(void) {
|
||||
CU_ASSERT(100 == session->remote_settings.max_concurrent_streams);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user