From f3a5a0a0ecc530cdfbe25838ba346b58d6caa733 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 13 Feb 2017 22:15:42 +0900 Subject: [PATCH] Add nghttp2_option_no_closed_streams nghttp2_option_no_closed_streams controls whether closed streams are retained or not. If nonzero is passed to that function's parameter val, a session does not retain closed streams. It may hurt the shape of priority tree, but can save memory. --- doc/Makefile.am | 1 + lib/includes/nghttp2/nghttp2.h | 10 ++++++++++ lib/nghttp2_option.c | 5 +++++ lib/nghttp2_option.h | 5 +++++ lib/nghttp2_session.c | 8 +++++++- lib/nghttp2_session.h | 3 ++- tests/main.c | 2 ++ tests/nghttp2_session_test.c | 22 ++++++++++++++++++++++ tests/nghttp2_session_test.h | 1 + 9 files changed, 55 insertions(+), 2 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 48817820..9511b492 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -62,6 +62,7 @@ APIDOCS= \ nghttp2_option_set_max_send_header_block_length.rst \ nghttp2_option_set_no_auto_ping_ack.rst \ nghttp2_option_set_no_auto_window_update.rst \ + nghttp2_option_set_no_closed_streams.rst \ nghttp2_option_set_no_http_messaging.rst \ nghttp2_option_set_no_recv_client_magic.rst \ nghttp2_option_set_peer_max_concurrent_streams.rst \ diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index be9b2ef5..15901004 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2551,6 +2551,16 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, size_t val); +/** + * @function + * + * This option prevents the library from retaining closed streams to + * maintain the priority tree. If this option is set to nonzero, + * applications can discard closed stream completely to save memory. + */ +NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option, + int val); + /** * @function * diff --git a/lib/nghttp2_option.c b/lib/nghttp2_option.c index 77e7db54..aec5dcfa 100644 --- a/lib/nghttp2_option.c +++ b/lib/nghttp2_option.c @@ -107,3 +107,8 @@ void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option, option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE; option->max_deflate_dynamic_table_size = val; } + +void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val) { + option->opt_set_mask |= NGHTTP2_OPT_NO_CLOSED_STREAMS; + option->no_closed_streams = val; +} diff --git a/lib/nghttp2_option.h b/lib/nghttp2_option.h index e750d1be..c743e33b 100644 --- a/lib/nghttp2_option.h +++ b/lib/nghttp2_option.h @@ -65,6 +65,7 @@ typedef enum { NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7, NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8, NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9, + NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10, } nghttp2_option_flag; /** @@ -112,6 +113,10 @@ struct nghttp2_option { * NGHTTP2_OPT_NO_AUTO_PING_ACK */ int no_auto_ping_ack; + /** + * NGHTTP2_OPT_NO_CLOSED_STREAMS + */ + int no_closed_streams; /** * NGHTTP2_OPT_USER_RECV_EXT_TYPES */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index bb822c88..0c6af535 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -494,6 +494,11 @@ static int session_new(nghttp2_session **session_ptr, if (option->opt_set_mask & NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE) { max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size; } + + if ((option->opt_set_mask & NGHTTP2_OPT_NO_CLOSED_STREAMS) && + option->no_closed_streams) { + (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_CLOSED_STREAMS; + } } rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, @@ -1186,7 +1191,8 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, /* Closes both directions just in case they are not closed yet */ stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED; - if (session->server && !is_my_stream_id && + if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 && + session->server && !is_my_stream_id && nghttp2_stream_in_dep_tree(stream)) { /* On server side, retain stream at most MAX_CONCURRENT_STREAMS combined with the current active incoming streams to make diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 348f89a9..3e4c1440 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -51,7 +51,8 @@ typedef enum { NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0, NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1, NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2, - NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3 + NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3, + NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4 } nghttp2_optmask; /* diff --git a/tests/main.c b/tests/main.c index 20ff40ae..b700b896 100644 --- a/tests/main.c +++ b/tests/main.c @@ -312,6 +312,8 @@ int main(int argc _U_, char *argv[] _U_) { test_nghttp2_session_removed_closed_stream) || !CU_add_test(pSuite, "session_pause_data", test_nghttp2_session_pause_data) || + !CU_add_test(pSuite, "session_no_closed_streams", + test_nghttp2_session_no_closed_streams) || !CU_add_test(pSuite, "http_mandatory_headers", test_nghttp2_http_mandatory_headers) || !CU_add_test(pSuite, "http_content_length", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 696ec394..928d1317 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -10098,6 +10098,28 @@ void test_nghttp2_session_pause_data(void) { nghttp2_session_del(session); } +void test_nghttp2_session_no_closed_streams(void) { + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + nghttp2_option *option; + + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + + nghttp2_option_new(&option); + nghttp2_option_set_no_closed_streams(option, 1); + + nghttp2_session_server_new2(&session, &callbacks, NULL, option); + + open_recv_stream(session, 1); + + nghttp2_session_close_stream(session, 1, NGHTTP2_NO_ERROR); + + CU_ASSERT(0 == session->num_closed_streams); + + nghttp2_session_del(session); + nghttp2_option_del(option); +} + static void check_nghttp2_http_recv_headers_fail( nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id, int stream_state, const nghttp2_nv *nva, size_t nvlen) { diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index b37713cb..470b274c 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -154,6 +154,7 @@ void test_nghttp2_session_set_local_window_size(void); void test_nghttp2_session_cancel_from_before_frame_send(void); void test_nghttp2_session_removed_closed_stream(void); void test_nghttp2_session_pause_data(void); +void test_nghttp2_session_no_closed_streams(void); void test_nghttp2_http_mandatory_headers(void); void test_nghttp2_http_content_length(void); void test_nghttp2_http_content_length_mismatch(void);