From 45837a2cfad8303f179743dcf781c3606010faaa Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 9 Jan 2014 22:06:38 +0900 Subject: [PATCH] Ensure PRIORITY frame reception/transmission rule --- lib/nghttp2_session.c | 26 +++++++++++++++++++++- tests/nghttp2_session_test.c | 42 +++++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 708d3e45..9370a069 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -80,6 +80,22 @@ static int32_t nghttp2_pushed_stream_pri(nghttp2_stream *stream) (int32_t)NGHTTP2_PRI_LOWEST : stream->pri + 1; } +/* Returns nonzero if the |stream| is in reserved(remote) state */ +static int state_reserved_remote(nghttp2_session *session, + nghttp2_stream *stream) +{ + return stream->state == NGHTTP2_STREAM_RESERVED && + !nghttp2_session_is_my_stream_id(session, stream->stream_id); +} + +/* Returns nonzero if the |stream| is in reserved(local) state */ +static int state_reserved_local(nghttp2_session *session, + nghttp2_stream *stream) +{ + return stream->state == NGHTTP2_STREAM_RESERVED && + nghttp2_session_is_my_stream_id(session, stream->stream_id); +} + int nghttp2_session_terminate_session(nghttp2_session *session, nghttp2_error_code error_code) { @@ -883,7 +899,11 @@ static int nghttp2_session_predicate_priority_send if(stream->state == NGHTTP2_STREAM_CLOSING) { return NGHTTP2_ERR_STREAM_CLOSING; } - /* Sending PRIORITY to reserved state is OK */ + /* PRIORITY must not be sent in reserved(local) */ + if(state_reserved_local(session, stream)) { + return NGHTTP2_ERR_INVALID_STREAM_STATE; + } + /* Sending PRIORITY in reserved(remote) state is OK */ return 0; } @@ -2133,6 +2153,10 @@ int nghttp2_session_on_priority_received(nghttp2_session *session, if(!stream) { return 0; } + if(state_reserved_remote(session, stream)) { + return nghttp2_session_handle_invalid_connection(session, frame, + NGHTTP2_PROTOCOL_ERROR); + } /* Only update priority on server side for now */ if(session->server) { nghttp2_session_reprioritize_stream(session, stream, diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index f0e74e51..fedd11cc 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1010,6 +1010,9 @@ void test_nghttp2_session_on_priority_received(void) my_user_data user_data; nghttp2_frame frame; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + callbacks.on_frame_recv_callback = on_frame_recv_callback; + callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback; + nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE, NGHTTP2_PRI_DEFAULT, @@ -1022,6 +1025,23 @@ void test_nghttp2_session_on_priority_received(void) nghttp2_frame_priority_free(&frame.priority); nghttp2_session_del(session); + + /* Check that receiving PRIORITY in reserved(remote) is error */ + nghttp2_session_server_new(&session, &callbacks, &user_data); + nghttp2_session_open_stream(session, 3, NGHTTP2_FLAG_NONE, + NGHTTP2_PRI_DEFAULT, + NGHTTP2_STREAM_RESERVED, NULL); + + nghttp2_frame_priority_init(&frame.priority, 3, 123); + + user_data.frame_recv_cb_called = 0; + user_data.invalid_frame_recv_cb_called = 0; + CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame)); + CU_ASSERT(0 == user_data.frame_recv_cb_called); + CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); + + nghttp2_frame_priority_free(&frame.priority); + nghttp2_session_del(session); } void test_nghttp2_session_on_rst_stream_received(void) @@ -2197,11 +2217,14 @@ void test_nghttp2_submit_priority(void) nghttp2_session *session; nghttp2_session_callbacks callbacks; nghttp2_stream *stream; + my_user_data ud; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = null_send_callback; callbacks.on_frame_send_callback = on_frame_send_callback; - nghttp2_session_client_new(&session, &callbacks, NULL); + callbacks.on_frame_not_send_callback = on_frame_not_send_callback; + + nghttp2_session_client_new(&session, &callbacks, &ud); stream = nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_NONE, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, NULL); @@ -2214,6 +2237,23 @@ void test_nghttp2_submit_priority(void) CU_ASSERT(1000000007 == stream->pri); nghttp2_session_del(session); + + /* Check that transmission of PRIORITY in reserved(local) is + error */ + nghttp2_session_server_new(&session, &callbacks, &ud); + stream = nghttp2_session_open_stream(session, 2, NGHTTP2_FLAG_NONE, + NGHTTP2_PRI_DEFAULT, + NGHTTP2_STREAM_RESERVED, NULL); + + CU_ASSERT(0 == nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 2, 123)); + + ud.frame_send_cb_called = 0; + ud.frame_not_send_cb_called = 0; + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(0 == ud.frame_send_cb_called); + CU_ASSERT(1 == ud.frame_not_send_cb_called); + + nghttp2_session_del(session); } void test_nghttp2_submit_settings(void)