From cbbecfeb41f37a36fbce08687a3fbfd0d2fc6876 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 15:35:44 +0900 Subject: [PATCH 1/2] Fix broken session_detect_idle_stream() --- lib/nghttp2_session.c | 4 ++-- tests/nghttp2_session_test.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 0df3c91d..9fd56a9b 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1898,7 +1898,7 @@ static int session_detect_idle_stream(nghttp2_session *session, { /* Assume that stream object with stream_id does not exist */ if(nghttp2_session_is_my_stream_id(session, stream_id)) { - if(session->next_stream_id >= (uint32_t)stream_id) { + if(session->next_stream_id <= (uint32_t)stream_id) { return 1; } return 0; @@ -2914,7 +2914,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, if(!stream || stream->state == NGHTTP2_STREAM_CLOSING) { if(!stream) { if(session_detect_idle_stream(session, frame->hd.stream_id)) { - return nghttp2_session_handle_invalid_connection + return nghttp2_session_inflate_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } } diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index cb21f8db..b675f3ed 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1480,11 +1480,17 @@ void test_nghttp2_session_on_push_promise_received(void) CU_ASSERT(0 == user_data.begin_headers_cb_called); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8)); item = nghttp2_session_get_next_ob_item(session); - CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item)); - CU_ASSERT(8 == OB_CTRL(item)->hd.stream_id); - CU_ASSERT(NGHTTP2_REFUSED_STREAM == OB_CTRL(item)->rst_stream.error_code); + CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item)); + CU_ASSERT(0 == OB_CTRL(item)->hd.stream_id); + CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == OB_CTRL(item)->goaway.error_code); CU_ASSERT(0 == nghttp2_session_send(session)); + nghttp2_session_del(session); + + nghttp2_session_client_new(&session, &callbacks, &user_data); + memset(session->iframe.buf, 0, 4); + session->iframe.buflen = 4; + /* Same ID twice */ stream->state = NGHTTP2_STREAM_OPENING; From cacf4ecf2657c5cc90b47f46a31602141a83e63b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:00:59 +0900 Subject: [PATCH 2/2] Fix premature header block is not treated as connection error --- lib/nghttp2_hd.c | 4 +++ tests/main.c | 2 ++ tests/nghttp2_session_test.c | 48 ++++++++++++++++++++++++++++++++++++ tests/nghttp2_session_test.h | 1 + 4 files changed, 55 insertions(+) diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index f04af0ea..71b2fe36 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -1642,6 +1642,10 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, } assert(in == last); if(in_final) { + if(inflater->state != NGHTTP2_HD_STATE_OPCODE) { + rv = NGHTTP2_ERR_HEADER_COMP; + goto fail; + } for(; inflater->end_headers_index < inflater->ctx.hd_table.len; ++inflater->end_headers_index) { nghttp2_hd_entry *ent; diff --git a/tests/main.c b/tests/main.c index 71e681cf..43f32f40 100644 --- a/tests/main.c +++ b/tests/main.c @@ -85,6 +85,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_recv_data) || !CU_add_test(pSuite, "session_recv_continuation", test_nghttp2_session_recv_continuation) || + !CU_add_test(pSuite, "session_recv_premature_headers", + test_nghttp2_session_recv_premature_headers) || !CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) || !CU_add_test(pSuite, "session_add_frame", test_nghttp2_session_add_frame) || diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index b675f3ed..036c14f9 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -760,6 +760,54 @@ void test_nghttp2_session_recv_continuation(void) nghttp2_session_del(session); } +void test_nghttp2_session_recv_premature_headers(void) +{ + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + const nghttp2_nv nv1[] = { + MAKE_NV("method", "GET"), + MAKE_NV("path", "/") + }; + nghttp2_nv *nva; + size_t nvlen; + nghttp2_frame frame; + uint8_t *framedata = NULL; + size_t framedatacap = 0; + size_t framedatalen; + ssize_t rv; + my_user_data ud; + nghttp2_hd_deflater deflater; + nghttp2_outbound_item *item; + + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + + nghttp2_session_server_new(&session, &callbacks, &ud); + + nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + + nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); + nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, + 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); + framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, + &frame.headers, + &deflater); + nghttp2_frame_headers_free(&frame.headers); + + /* Intentionally feed payload cutting last 1 byte off */ + nghttp2_put_uint16be(framedata, frame.hd.length - 1); + rv = nghttp2_session_mem_recv(session, framedata, framedatalen - 1); + CU_ASSERT((ssize_t)framedatalen - 1 == rv); + + item = nghttp2_session_get_next_ob_item(session); + CU_ASSERT(NULL != item); + CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item)); + CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == OB_CTRL(item)->goaway.error_code); + + free(framedata); + nghttp2_hd_deflate_free(&deflater); + nghttp2_session_del(session); +} + void test_nghttp2_session_continue(void) { nghttp2_session *session; diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 4b5bfcaf..1c877f0c 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -31,6 +31,7 @@ void test_nghttp2_session_recv_invalid_frame(void); void test_nghttp2_session_recv_eof(void); void test_nghttp2_session_recv_data(void); void test_nghttp2_session_recv_continuation(void); +void test_nghttp2_session_recv_premature_headers(void); void test_nghttp2_session_continue(void); void test_nghttp2_session_add_frame(void); void test_nghttp2_session_on_request_headers_received(void);