Fix crash if response or data is submitted to closing stream

This commit is contained in:
Tatsuhiro Tsujikawa 2015-07-31 21:11:16 +09:00
parent a152c6346d
commit e66bd490a4
4 changed files with 60 additions and 0 deletions

View File

@ -1780,6 +1780,12 @@ static int session_prep_frame(nghttp2_session *session,
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;
@ -1938,6 +1944,10 @@ static int session_prep_frame(nghttp2_session *session,
rv = nghttp2_session_predicate_data_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) {
int rv2;

View File

@ -270,6 +270,8 @@ int main(int argc _U_, char *argv[] _U_) {
test_nghttp2_session_on_begin_headers_temporal_failure) ||
!CU_add_test(pSuite, "session_defer_then_close",
test_nghttp2_session_defer_then_close) ||
!CU_add_test(pSuite, "session_detach_item_from_closed_stream",
test_nghttp2_session_detach_item_from_closed_stream) ||
!CU_add_test(pSuite, "http_mandatory_headers",
test_nghttp2_http_mandatory_headers) ||
!CU_add_test(pSuite, "http_content_length",

View File

@ -7640,6 +7640,53 @@ void test_nghttp2_session_defer_then_close(void) {
nghttp2_session_del(session);
}
static int submit_response_on_stream_close(nghttp2_session *session,
int32_t stream_id,
uint32_t error_code _U_,
void *user_data _U_) {
nghttp2_data_provider data_prd;
data_prd.read_callback = temporal_failure_data_source_read_callback;
// Attempt to submit response or data to the stream being closed
switch (stream_id) {
case 1:
CU_ASSERT(0 == nghttp2_submit_response(session, stream_id, resnv,
ARRLEN(resnv), &data_prd));
break;
case 3:
CU_ASSERT(0 == nghttp2_submit_data(session, NGHTTP2_FLAG_NONE, stream_id,
&data_prd));
break;
}
return 0;
}
void test_nghttp2_session_detach_item_from_closed_stream(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_data_provider data_prd;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = null_send_callback;
callbacks.on_stream_close_callback = submit_response_on_stream_close;
data_prd.read_callback = temporal_failure_data_source_read_callback;
nghttp2_session_server_new(&session, &callbacks, NULL);
open_stream(session, 1);
open_stream(session, 3);
nghttp2_session_close_stream(session, 1, NGHTTP2_NO_ERROR);
nghttp2_session_close_stream(session, 3, NGHTTP2_NO_ERROR);
CU_ASSERT(0 == nghttp2_session_send(session));
nghttp2_session_del(session);
}
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) {

View File

@ -128,6 +128,7 @@ void test_nghttp2_session_reset_pending_headers(void);
void test_nghttp2_session_send_data_callback(void);
void test_nghttp2_session_on_begin_headers_temporal_failure(void);
void test_nghttp2_session_defer_then_close(void);
void test_nghttp2_session_detach_item_from_closed_stream(void);
void test_nghttp2_http_mandatory_headers(void);
void test_nghttp2_http_content_length(void);
void test_nghttp2_http_content_length_mismatch(void);