diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 6ddea60d..5bce1a55 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1807,6 +1807,10 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, } } } + } else if(stream->state == NGHTTP2_STREAM_RESERVED) { + /* reserved (local) */ + return nghttp2_session_handle_invalid_connection(session, frame, + NGHTTP2_PROTOCOL_ERROR); } else { /* half closed (remote): from the spec: @@ -2162,6 +2166,10 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, session->last_recv_stream_id = frame->push_promise.promised_stream_id; stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if(stream) { + if(!nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) { + return nghttp2_session_handle_invalid_connection(session, frame, + NGHTTP2_PROTOCOL_ERROR); + } if((stream->shut_flags & NGHTTP2_SHUT_RD) == 0) { if(stream->state == NGHTTP2_STREAM_CLOSING) { return nghttp2_session_add_rst_stream @@ -2293,6 +2301,10 @@ int nghttp2_session_on_window_update_received(nghttp2_session *session, nghttp2_stream *stream; stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if(stream) { + if(stream->state == NGHTTP2_STREAM_RESERVED) { + return nghttp2_session_handle_invalid_connection + (session, frame, NGHTTP2_PROTOCOL_ERROR); + } if(stream->remote_flow_control == 0) { /* Same reason with connection-level flow control */ nghttp2_session_call_on_frame_received(session, frame); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index ab69a552..9fd6748a 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1043,7 +1043,7 @@ void test_nghttp2_session_on_push_promise_received(void) /* After GOAWAY, PUSH_PROMISE will be discarded */ frame.push_promise.promised_stream_id = 10; - user_data.frame_recv_cb_called = 0; + user_data.frame_recv_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0; CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame)); @@ -1053,6 +1053,25 @@ void test_nghttp2_session_on_push_promise_received(void) nghttp2_frame_push_promise_free(&frame.push_promise); nghttp2_session_del(session); + + nghttp2_session_client_new(&session, &callbacks, &user_data); + stream = nghttp2_session_open_stream(session, 2, NGHTTP2_FLAG_NONE, + NGHTTP2_PRI_DEFAULT, + NGHTTP2_STREAM_RESERVED, NULL); + nvlen = nghttp2_nv_array_from_cstr(&nva, nv); + /* Attempt to PUSH_PROMISE against reserved (remote) stream */ + nghttp2_frame_push_promise_init(&frame.push_promise, + NGHTTP2_FLAG_END_PUSH_PROMISE, 2, 4, + nva, nvlen); + + user_data.frame_recv_cb_called = 0; + user_data.invalid_frame_recv_cb_called = 0; + CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame)); + + CU_ASSERT(0 == user_data.frame_recv_cb_called); + CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); + + nghttp2_session_del(session); } void test_nghttp2_session_on_ping_received(void)