Fix bug that promised stream was not reset on decompression error

This commit is contained in:
Tatsuhiro Tsujikawa 2015-04-28 21:38:52 +09:00
parent 54bff91762
commit 9e1b068a4b
2 changed files with 46 additions and 22 deletions

View File

@ -3131,12 +3131,12 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
} }
if (proclen < 0) { if (proclen < 0) {
if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) { if (session->iframe.state == NGHTTP2_IB_READ_HEADER_BLOCK) {
if (stream && stream->state != NGHTTP2_STREAM_CLOSING) { if (subject_stream && subject_stream->state != NGHTTP2_STREAM_CLOSING) {
/* Adding RST_STREAM here is very important. It prevents /* Adding RST_STREAM here is very important. It prevents
from invoking subsequent callbacks for the same stream from invoking subsequent callbacks for the same stream
ID. */ ID. */
rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, rv = nghttp2_session_add_rst_stream(
NGHTTP2_COMPRESSION_ERROR); session, subject_stream->stream_id, NGHTTP2_COMPRESSION_ERROR);
if (nghttp2_is_fatal(rv)) { if (nghttp2_is_fatal(rv)) {
return rv; return rv;

View File

@ -1093,9 +1093,6 @@ void test_nghttp2_session_recv_headers_with_priority(void) {
void test_nghttp2_session_recv_premature_headers(void) { void test_nghttp2_session_recv_premature_headers(void) {
nghttp2_session *session; nghttp2_session *session;
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
nghttp2_nv *nva;
size_t nvlen;
nghttp2_frame frame;
nghttp2_bufs bufs; nghttp2_bufs bufs;
nghttp2_buf *buf; nghttp2_buf *buf;
ssize_t rv; ssize_t rv;
@ -1103,45 +1100,72 @@ void test_nghttp2_session_recv_premature_headers(void) {
nghttp2_hd_deflater deflater; nghttp2_hd_deflater deflater;
nghttp2_outbound_item *item; nghttp2_outbound_item *item;
nghttp2_mem *mem; nghttp2_mem *mem;
uint32_t payloadlen;
mem = nghttp2_mem_default(); mem = nghttp2_mem_default();
frame_pack_bufs_init(&bufs); frame_pack_bufs_init(&bufs);
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new(&session, &callbacks, &ud);
nghttp2_hd_deflate_init(&deflater, mem); nghttp2_hd_deflate_init(&deflater, mem);
nvlen = ARRLEN(reqnv); rv = pack_headers(&bufs, &deflater, 1, NGHTTP2_FLAG_END_HEADERS, reqnv,
nghttp2_nv_array_copy(&nva, reqnv, nvlen, mem); ARRLEN(reqnv), mem);
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
CU_ASSERT(0 == rv);
CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
nghttp2_frame_headers_free(&frame.headers, mem);
buf = &bufs.head->buf; buf = &bufs.head->buf;
assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
/* Intentionally feed payload cutting last 1 byte off */ /* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint32be(buf->pos, payloadlen = nghttp2_get_uint32(buf->pos) >> 8;
(uint32_t)(((frame.hd.length - 1) << 8) + buf->pos[3])); nghttp2_put_uint32be(buf->pos, ((payloadlen - 1) << 8) + buf->pos[3]);
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf) - 1); rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf) - 1);
CU_ASSERT((ssize_t)(nghttp2_buf_len(buf) - 1) == rv); CU_ASSERT(rv == nghttp2_buf_len(buf) - 1);
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item); CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type); CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == item->frame.rst_stream.error_code); CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == item->frame.rst_stream.error_code);
CU_ASSERT(1 == item->frame.hd.stream_id);
CU_ASSERT(0 == nghttp2_session_send(session));
nghttp2_bufs_free(&bufs); nghttp2_bufs_reset(&bufs);
nghttp2_hd_deflate_free(&deflater); nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session); nghttp2_session_del(session);
/* Test for PUSH_PROMISE */
nghttp2_session_client_new(&session, &callbacks, &ud);
nghttp2_hd_deflate_init(&deflater, mem);
nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
&pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
rv = pack_push_promise(&bufs, &deflater, 1, NGHTTP2_FLAG_END_HEADERS, 2,
reqnv, ARRLEN(reqnv), mem);
CU_ASSERT(0 == rv);
buf = &bufs.head->buf;
payloadlen = nghttp2_get_uint32(buf->pos) >> 8;
/* Intentionally feed payload cutting last 1 byte off */
nghttp2_put_uint32be(buf->pos, ((payloadlen - 1) << 8) + buf->pos[3]);
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf) - 1);
CU_ASSERT(rv == nghttp2_buf_len(buf) - 1);
item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL != item);
CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == item->frame.rst_stream.error_code);
CU_ASSERT(2 == item->frame.hd.stream_id);
CU_ASSERT(0 == nghttp2_session_send(session));
nghttp2_hd_deflate_free(&deflater);
nghttp2_session_del(session);
nghttp2_bufs_free(&bufs);
} }
void test_nghttp2_session_recv_unknown_frame(void) { void test_nghttp2_session_recv_unknown_frame(void) {