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);