From b918f9650a7382132563a30b7f614963c3f1caf0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 16 Nov 2015 22:47:12 +0900 Subject: [PATCH] Don't send push response if GOAWAY has been received --- lib/nghttp2_session.c | 47 +++++++++++++++++++++--------------- tests/main.c | 2 ++ tests/nghttp2_session_test.c | 27 +++++++++++++++++++++ tests/nghttp2_session_test.h | 1 + 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 3b180865..366a8007 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1415,6 +1415,9 @@ static int session_predicate_response_headers_send(nghttp2_session *session, * RST_STREAM was queued for this stream. * NGHTTP2_ERR_SESSION_CLOSING * This session is closing. + * NGHTTP2_ERR_START_STREAM_NOT_ALLOWED + * New stream cannot be created because GOAWAY is already sent or + * received. */ static int session_predicate_push_response_headers_send(nghttp2_session *session, @@ -1432,6 +1435,9 @@ session_predicate_push_response_headers_send(nghttp2_session *session, if (stream->state == NGHTTP2_STREAM_CLOSING) { return NGHTTP2_ERR_STREAM_CLOSING; } + if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { + return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; + } return 0; } @@ -1795,40 +1801,41 @@ static int session_prep_frame(nghttp2_session *session, stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if (session_predicate_push_response_headers_send(session, stream) == - 0) { - frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; + if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { + rv = session_predicate_push_response_headers_send(session, stream); + if (rv == 0) { + frame->headers.cat = NGHTTP2_HCAT_PUSH_RESPONSE; - if (aux_data->stream_user_data) { - stream->stream_user_data = aux_data->stream_user_data; + if (aux_data->stream_user_data) { + stream->stream_user_data = aux_data->stream_user_data; + } } } else if (session_predicate_response_headers_send(session, stream) == 0) { frame->headers.cat = NGHTTP2_HCAT_RESPONSE; + rv = 0; } else { frame->headers.cat = NGHTTP2_HCAT_HEADERS; rv = session_predicate_headers_send(session, stream); + } - if (rv != 0) { - // If stream was alreay closed, - // nghttp2_session_get_stream() returns NULL, but item is - // still attached to the stream. Search stream including - // closed again. - stream = - nghttp2_session_get_stream_raw(session, frame->hd.stream_id); - if (stream && stream->item == item) { - int rv2; + if (rv != 0) { + // If stream was alreay closed, nghttp2_session_get_stream() + // returns NULL, but item is still attached to the stream. + // Search stream including closed again. + stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); + if (stream && stream->item == item) { + int rv2; - rv2 = nghttp2_stream_detach_item(stream); + rv2 = nghttp2_stream_detach_item(stream); - if (nghttp2_is_fatal(rv2)) { - return rv2; - } + if (nghttp2_is_fatal(rv2)) { + return rv2; } - - return rv; } + + return rv; } } diff --git a/tests/main.c b/tests/main.c index cc3896c0..14b43dbf 100644 --- a/tests/main.c +++ b/tests/main.c @@ -159,6 +159,8 @@ int main(int argc _U_, char *argv[] _U_) { test_nghttp2_submit_response_with_data) || !CU_add_test(pSuite, "submit_response_without_data", test_nghttp2_submit_response_without_data) || + !CU_add_test(pSuite, "Submit_response_push_response", + test_nghttp2_submit_response_push_response) || !CU_add_test(pSuite, "submit_trailer", test_nghttp2_submit_trailer) || !CU_add_test(pSuite, "submit_headers_start_stream", test_nghttp2_submit_headers_start_stream) || diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 21ee5798..149dd81b 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3879,6 +3879,33 @@ void test_nghttp2_submit_response_without_data(void) { nghttp2_session_del(session); } +void test_nghttp2_submit_response_push_response(void) { + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + my_user_data ud; + + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + callbacks.send_callback = null_send_callback; + callbacks.on_frame_not_send_callback = on_frame_not_send_callback; + + nghttp2_session_server_new(&session, &callbacks, &ud); + + nghttp2_session_open_stream(session, 2, NGHTTP2_FLAG_NONE, &pri_spec_default, + NGHTTP2_STREAM_RESERVED, NULL); + + session->goaway_flags |= NGHTTP2_GOAWAY_RECV; + + CU_ASSERT(0 == + nghttp2_submit_response(session, 2, resnv, ARRLEN(resnv), NULL)); + + ud.frame_not_send_cb_called = 0; + + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(1 == ud.frame_not_send_cb_called); + + nghttp2_session_del(session); +} + void test_nghttp2_submit_trailer(void) { nghttp2_session *session; nghttp2_session_callbacks callbacks; diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 80aa8edd..ce3954b3 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -70,6 +70,7 @@ void test_nghttp2_submit_request_with_data(void); void test_nghttp2_submit_request_without_data(void); void test_nghttp2_submit_response_with_data(void); void test_nghttp2_submit_response_without_data(void); +void test_nghttp2_submit_response_push_response(void); void test_nghttp2_submit_trailer(void); void test_nghttp2_submit_headers_start_stream(void); void test_nghttp2_submit_headers_reply(void);