nghttp2_sesson_mem_recv: Process incoming data in streaming fashion

Now incoming data is processed in very small buffer (up to 8 bytes)
using state machine. GOAWAY debug data can get to 16K - 1, and we
don't have callback for it. Since we don't want to buffer that
amount of data just for debugging, we currently discard it.
This change also makes parse_error callback not function.
It probably be removed from API.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-26 15:44:43 +09:00
parent 8317559090
commit dba2406aba
6 changed files with 932 additions and 695 deletions

View File

@ -270,6 +270,25 @@ int nghttp2_frame_unpack_headers_without_nv(nghttp2_headers *frame,
return 0; return 0;
} }
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload,
size_t payloadlen)
{
/* TODO Return error if header continuation is used for now */
if((frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) {
return NGHTTP2_ERR_PROTO;
}
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
assert(payloadlen == 4);
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
} else {
frame->pri = NGHTTP2_PRI_DEFAULT;
}
frame->nva = NULL;
frame->nvlen = 0;
return 0;
}
ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_priority(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_priority *frame) nghttp2_priority *frame)
{ {
@ -295,7 +314,13 @@ int nghttp2_frame_unpack_priority(nghttp2_priority *frame,
nghttp2_frame_unpack_frame_hd(&frame->hd, head); nghttp2_frame_unpack_frame_hd(&frame->hd, head);
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK; frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
return 0; return 0;
}
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK;
} }
ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_rst_stream(uint8_t **buf_ptr, size_t *buflen_ptr,
@ -325,6 +350,13 @@ int nghttp2_frame_unpack_rst_stream(nghttp2_rst_stream *frame,
return 0; return 0;
} }
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->error_code = nghttp2_get_uint32(payload);
}
ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_settings *frame) nghttp2_settings *frame)
{ {
@ -371,6 +403,29 @@ int nghttp2_frame_unpack_settings(nghttp2_settings *frame,
return 0; return 0;
} }
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv)
{
size_t payloadlen = niv * sizeof(nghttp2_settings_entry);
frame->iv = malloc(payloadlen);
if(frame->iv == NULL) {
return NGHTTP2_ERR_NOMEM;
}
memcpy(frame->iv, iv, payloadlen);
frame->niv = niv;
return 0;
}
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload)
{
iv->settings_id = nghttp2_get_uint32(&payload[0]) &
NGHTTP2_SETTINGS_ID_MASK;
iv->value = nghttp2_get_uint32(&payload[4]);
}
int nghttp2_frame_unpack_settings_payload(nghttp2_settings_entry **iv_ptr, int nghttp2_frame_unpack_settings_payload(nghttp2_settings_entry **iv_ptr,
size_t *niv_ptr, size_t *niv_ptr,
const uint8_t *payload, const uint8_t *payload,
@ -384,9 +439,7 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings_entry **iv_ptr,
} }
for(i = 0; i < *niv_ptr; ++i) { for(i = 0; i < *niv_ptr; ++i) {
size_t off = i*8; size_t off = i*8;
(*iv_ptr)[i].settings_id = nghttp2_get_uint32(&payload[off]) & nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
NGHTTP2_SETTINGS_ID_MASK;
(*iv_ptr)[i].value = nghttp2_get_uint32(&payload[4+off]);
} }
return 0; return 0;
} }
@ -440,6 +493,21 @@ int nghttp2_frame_unpack_push_promise_without_nv(nghttp2_push_promise *frame,
return 0; return 0;
} }
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload,
size_t payloadlen)
{
/* TODO Return error if header continuation is used for now */
if((frame->hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) == 0) {
return NGHTTP2_ERR_PROTO;
}
frame->promised_stream_id = nghttp2_get_uint32(payload) &
NGHTTP2_STREAM_ID_MASK;
frame->nva = NULL;
frame->nvlen = 0;
return 0;
}
ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_ping(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_ping *frame) nghttp2_ping *frame)
{ {
@ -467,6 +535,12 @@ int nghttp2_frame_unpack_ping(nghttp2_ping *frame,
return 0; return 0;
} }
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
const uint8_t *payload,
size_t payloadlen)
{
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
}
ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_goaway(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_goaway *frame) nghttp2_goaway *frame)
@ -508,6 +582,17 @@ int nghttp2_frame_unpack_goaway(nghttp2_goaway *frame,
return 0; return 0;
} }
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
frame->error_code = nghttp2_get_uint32(payload+4);
/* TODO Currently we don't buffer debug data */
frame->opaque_data = NULL;
frame->opaque_data_len = 0;
}
ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr, ssize_t nghttp2_frame_pack_window_update(uint8_t **buf_ptr, size_t *buflen_ptr,
nghttp2_window_update *frame) nghttp2_window_update *frame)
{ {
@ -537,6 +622,14 @@ int nghttp2_frame_unpack_window_update(nghttp2_window_update *frame,
return 0; return 0;
} }
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen)
{
frame->window_size_increment = nghttp2_get_uint32(payload) &
NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
}
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
size_t niv) size_t niv)
{ {

View File

@ -161,6 +161,10 @@ int nghttp2_frame_unpack_headers_without_nv(nghttp2_headers *frame,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen); size_t payloadlen);
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs PRIORITY frame |frame| in wire format and store it in * Packs PRIORITY frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -189,6 +193,10 @@ int nghttp2_frame_unpack_priority(nghttp2_priority *frame,
const uint8_t *head, size_t headlen, const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen); const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs RST_STREAM frame |frame| in wire frame format and store it in * Packs RST_STREAM frame |frame| in wire frame format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -218,6 +226,10 @@ int nghttp2_frame_unpack_rst_stream(nghttp2_rst_stream *frame,
const uint8_t *head, size_t headlen, const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen); const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs SETTINGS frame |frame| in wire format and store it in * Packs SETTINGS frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -259,6 +271,13 @@ int nghttp2_frame_unpack_settings(nghttp2_settings *frame,
const uint8_t *payload, size_t payloadlen); const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload);
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings *frame,
nghttp2_settings_entry *iv,
size_t niv);
/* /*
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are * Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
* assigned to the |*niv_ptr|. This function allocates enough memory * assigned to the |*niv_ptr|. This function allocates enough memory
@ -347,6 +366,10 @@ int nghttp2_frame_unpack_push_promise_without_nv(nghttp2_push_promise *frame,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen); size_t payloadlen);
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs PING frame |frame| in wire format and store it in * Packs PING frame |frame| in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -375,6 +398,10 @@ int nghttp2_frame_unpack_ping(nghttp2_ping *frame,
const uint8_t *head, size_t headlen, const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen); const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs GOAWAY frame |frame | in wire format and store it in * Packs GOAWAY frame |frame | in wire format and store it in
* |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -405,6 +432,10 @@ int nghttp2_frame_unpack_goaway(nghttp2_goaway *frame,
const uint8_t *head, size_t headlen, const uint8_t *head, size_t headlen,
const uint8_t *payload, size_t payloadlen); const uint8_t *payload, size_t payloadlen);
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
* in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * in |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr|
@ -434,6 +465,10 @@ int nghttp2_frame_unpack_window_update(nghttp2_window_update *frame,
const uint8_t *payload, const uint8_t *payload,
size_t payloadlen); size_t payloadlen);
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
const uint8_t *payload,
size_t payloadlen);
/* /*
* Initializes HEADERS frame |frame| with given values. |frame| takes * Initializes HEADERS frame |frame| with given values. |frame| takes
* ownership of |nva|, so caller must not free it. If |stream_id| is * ownership of |nva|, so caller must not free it. If |stream_id| is

View File

@ -45,7 +45,9 @@ typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
inclusive. */ inclusive. */
typedef enum { typedef enum {
NGHTTP2_ERR_CREDENTIAL_PENDING = -101, NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
NGHTTP2_ERR_BUFFER_ERROR = - 102 NGHTTP2_ERR_BUFFER_ERROR = -102,
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
NGHTTP2_ERR_IGN_PAYLOAD = -104,
} nghttp2_internal_error; } nghttp2_internal_error;
#endif /* NGHTTP2_INT_H */ #endif /* NGHTTP2_INT_H */

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include "nghttp2_stream.h" #include "nghttp2_stream.h"
#include "nghttp2_buffer.h" #include "nghttp2_buffer.h"
#include "nghttp2_outbound_item.h" #include "nghttp2_outbound_item.h"
#include "nghttp2_int.h"
/* /*
* Option flags. * Option flags.
@ -72,39 +73,36 @@ typedef struct {
/* Internal state when receiving incoming frame */ /* Internal state when receiving incoming frame */
typedef enum { typedef enum {
/* Receiving frame header */ /* Receiving frame header */
NGHTTP2_RECV_HEAD, NGHTTP2_IB_READ_HEAD,
/* Receiving frame payload (comes after length field) */ NGHTTP2_IB_READ_NBYTE,
NGHTTP2_RECV_PAYLOAD, NGHTTP2_IB_READ_HEADER_BLOCK,
/* Receiving frame payload, but the received bytes are discarded. */ NGHTTP2_IB_IGN_HEADER_BLOCK,
NGHTTP2_RECV_PAYLOAD_IGN NGHTTP2_IB_IGN_PAYLOAD,
NGHTTP2_IB_FRAME_SIZE_ERROR,
NGHTTP2_IB_READ_SETTINGS,
NGHTTP2_IB_READ_GOAWAY_DEBUG,
NGHTTP2_IB_READ_DATA,
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state; } nghttp2_inbound_state;
typedef struct { typedef struct {
nghttp2_frame frame; nghttp2_frame frame;
/* Payload for non-DATA frames. */ /* The received SETTINGS entry. The protocol says that we only cares
uint8_t *buf; about the defined settings ID. If unknown ID is received, it is
/* How many bytes are filled in headbuf */ subject to connection error */
size_t headbufoff; nghttp2_settings_entry iv[5];
/* Capacity of buf */ /* The number of entry filled in |iv| */
size_t bufmax; size_t niv;
/* For frames without name/value header block, this is how many /* How many bytes we still need to receive in the |buf| */
bytes are going to filled in buf. For frames with the block, buf size_t left;
only contains bytes that come before ther block, but this value /* How many bytes we still need to receive for current frame */
includes the length of the block. buflen <= bufmax must be size_t payloadleft;
fulfilled. */
size_t buflen;
/* length in Length field */
size_t payloadlen;
/* How many bytes are received for this frame. off <= payloadlen
must be fulfilled. */
size_t off;
/* How many bytes are decompressed inside |buf|. This is used for
header decompression. */
size_t inflate_offset;
nghttp2_inbound_state state; nghttp2_inbound_state state;
/* Error code */ /* TODO, remove this. Error code */
int error_code; int error_code;
uint8_t headbuf[NGHTTP2_FRAME_HEAD_LENGTH]; uint8_t buf[8];
/* How many bytes have been written to |buf| */
uint8_t buflen;
} nghttp2_inbound_frame; } nghttp2_inbound_frame;
typedef enum { typedef enum {
@ -131,9 +129,6 @@ struct nghttp2_session {
/* Sequence number of outbound frame to maintain the order of /* Sequence number of outbound frame to maintain the order of
enqueue if priority is equal. */ enqueue if priority is equal. */
int64_t next_seq; int64_t next_seq;
/* Buffer used to store inflated name/value pairs in wire format
temporarily on pack/unpack. */
uint8_t *nvbuf;
void *user_data; void *user_data;
/* In-flight SETTINGS values. NULL does not necessarily mean there /* In-flight SETTINGS values. NULL does not necessarily mean there
is no in-flight SETTINGS. */ is no in-flight SETTINGS. */
@ -358,6 +353,15 @@ int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
nghttp2_stream *stream); nghttp2_stream *stream);
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_end_response_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_end_headers_received(nghttp2_session *session,
nghttp2_frame *frame);
int nghttp2_session_on_request_headers_received(nghttp2_session *session, int nghttp2_session_on_request_headers_received(nghttp2_session *session,
nghttp2_frame *frame); nghttp2_frame *frame);

View File

@ -565,8 +565,8 @@ void test_nghttp2_session_recv_data(void)
hd.stream_id = 1; hd.stream_id = 1;
nghttp2_frame_pack_frame_hd(data, &hd); nghttp2_frame_pack_frame_hd(data, &hd);
/* stream 1 is not opened, so it must be responded with RST_STREAM, /* stream 1 is not opened, so it must be responded with connection
well actually, this is not mandated by the spec */ error. This is not mandated by the spec */
ud.data_chunk_recv_cb_called = 0; ud.data_chunk_recv_cb_called = 0;
ud.data_recv_cb_called = 0; ud.data_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, data, 8+4096); rv = nghttp2_session_mem_recv(session, data, 8+4096);
@ -575,11 +575,7 @@ void test_nghttp2_session_recv_data(void)
CU_ASSERT(0 == ud.data_chunk_recv_cb_called); CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
CU_ASSERT(0 == ud.data_recv_cb_called); CU_ASSERT(0 == ud.data_recv_cb_called);
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
/* DATA against nonexistent stream is ignored for now */
CU_ASSERT(NULL == item); CU_ASSERT(NULL == item);
/* CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item)); */
/* CU_ASSERT(0 == nghttp2_session_send(session)); */
/* Create stream 1 with CLOSING state. DATA is ignored. */ /* Create stream 1 with CLOSING state. DATA is ignored. */
stream = nghttp2_session_open_stream(session, 1, stream = nghttp2_session_open_stream(session, 1,
@ -729,9 +725,9 @@ void test_nghttp2_session_continue(void)
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.end_headers_cb_called = 0; user_data.end_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session, bufp, buflen);
CU_ASSERT(rv == framelen1);
bufp += framelen1; bufp += rv;
buflen -= framelen1; buflen -= rv;
recv_frame = user_data.frame; recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type); CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
@ -746,7 +742,9 @@ void test_nghttp2_session_continue(void)
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.end_headers_cb_called = 0; user_data.end_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session, bufp, buflen);
CU_ASSERT(0 == rv);
bufp += rv;
buflen -= rv;
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
CU_ASSERT(0 == user_data.end_headers_cb_called); CU_ASSERT(0 == user_data.end_headers_cb_called);
@ -757,9 +755,9 @@ void test_nghttp2_session_continue(void)
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.end_headers_cb_called = 0; user_data.end_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session, bufp, buflen);
CU_ASSERT(rv == framelen2);
bufp += framelen2; bufp += rv;
buflen -= framelen2; buflen -= rv;
recv_frame = user_data.frame; recv_frame = user_data.frame;
CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type); CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
@ -774,7 +772,9 @@ void test_nghttp2_session_continue(void)
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.end_headers_cb_called = 0; user_data.end_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session, bufp, buflen);
CU_ASSERT(0 == rv);
bufp += rv;
buflen -= rv;
CU_ASSERT(1 == user_data.header_cb_called); CU_ASSERT(1 == user_data.header_cb_called);
CU_ASSERT(0 == user_data.end_headers_cb_called); CU_ASSERT(0 == user_data.end_headers_cb_called);
@ -785,7 +785,9 @@ void test_nghttp2_session_continue(void)
user_data.header_cb_called = 0; user_data.header_cb_called = 0;
user_data.end_headers_cb_called = 0; user_data.end_headers_cb_called = 0;
rv = nghttp2_session_mem_recv(session, bufp, buflen); rv = nghttp2_session_mem_recv(session, bufp, buflen);
CU_ASSERT(0 == rv);
bufp += rv;
buflen -= rv;
CU_ASSERT(0 == user_data.header_cb_called); CU_ASSERT(0 == user_data.header_cb_called);
CU_ASSERT(1 == user_data.end_headers_cb_called); CU_ASSERT(1 == user_data.end_headers_cb_called);
@ -906,7 +908,8 @@ void test_nghttp2_session_on_request_headers_received(void)
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
3, NGHTTP2_PRI_DEFAULT, NULL, 0); 3, NGHTTP2_PRI_DEFAULT, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND)); CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND));
@ -920,7 +923,8 @@ void test_nghttp2_session_on_request_headers_received(void)
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
3, NGHTTP2_PRI_DEFAULT, NULL, 0); 3, NGHTTP2_PRI_DEFAULT, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0; user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND); CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND);
@ -1008,7 +1012,6 @@ void test_nghttp2_session_on_headers_received(void)
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
CU_ASSERT(2 == user_data.frame_recv_cb_called); CU_ASSERT(2 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 1));
/* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is /* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is
discarded. */ discarded. */
@ -1017,7 +1020,8 @@ void test_nghttp2_session_on_headers_received(void)
NGHTTP2_STREAM_CLOSING, NULL); NGHTTP2_STREAM_CLOSING, NULL);
frame.hd.stream_id = 3; frame.hd.stream_id = 3;
frame.hd.flags = NGHTTP2_FLAG_END_HEADERS; frame.hd.flags = NGHTTP2_FLAG_END_HEADERS;
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_headers_received(session, &frame, stream));
/* See no counters are updated */ /* See no counters are updated */
CU_ASSERT(2 == user_data.frame_recv_cb_called); CU_ASSERT(2 == user_data.frame_recv_cb_called);
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
@ -1034,9 +1038,12 @@ void test_nghttp2_session_on_headers_received(void)
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
CU_ASSERT(3 == user_data.frame_recv_cb_called); CU_ASSERT(3 == user_data.frame_recv_cb_called);
CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state); CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
CU_ASSERT(stream->shut_flags & NGHTTP2_SHUT_RD);
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
/* Further reception of HEADERS is subject to stream error */ /* Further reception of HEADERS is subject to stream error */
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_headers_received(session, &frame, stream));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
@ -1080,7 +1087,8 @@ void test_nghttp2_session_on_push_response_headers_received(void)
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_RESERVED, NULL); NGHTTP2_STREAM_RESERVED, NULL);
frame.hd.stream_id = 4; frame.hd.stream_id = 4;
CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_response_headers_received
(session, &frame, stream)); (session, &frame, stream));
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item)); CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
@ -1320,7 +1328,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
@ -1339,7 +1348,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6)); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
@ -1355,7 +1365,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8)); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
@ -1370,7 +1381,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8)); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
@ -1384,7 +1396,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10)); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
@ -1406,7 +1419,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
@ -1430,7 +1444,8 @@ void test_nghttp2_session_on_push_promise_received(void)
user_data.frame_recv_cb_called = 0; user_data.frame_recv_cb_called = 0;
user_data.invalid_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(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_push_promise_received(session, &frame));
CU_ASSERT(0 == user_data.frame_recv_cb_called); CU_ASSERT(0 == user_data.frame_recv_cb_called);
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called); CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
@ -1619,17 +1634,6 @@ void test_nghttp2_session_on_data_received(void)
/* CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(top)); */ /* CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(top)); */
/* CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == OB_CTRL(top)->rst_stream.error_code); */ /* CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == OB_CTRL(top)->rst_stream.error_code); */
/* Receiving DATA against the reserved stream is subject to
connection error */
stream = nghttp2_session_open_stream(session, 6, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_RESERVED, NULL);
CU_ASSERT(0 == nghttp2_session_on_data_received(session, 4096,
NGHTTP2_FLAG_NONE, 6));
top = nghttp2_session_get_ob_pq_top(session);
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(top));
CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == OB_CTRL(top)->goaway.error_code);
nghttp2_session_del(session); nghttp2_session_del(session);
} }
@ -2990,7 +2994,8 @@ void test_nghttp2_session_max_concurrent_streams(void)
NGHTTP2_PRI_DEFAULT, NULL, 0); NGHTTP2_PRI_DEFAULT, NULL, 0);
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 1; session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
item = nghttp2_session_get_ob_pq_top(session); item = nghttp2_session_get_ob_pq_top(session);
CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item)); CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item));
@ -3466,7 +3471,6 @@ void test_nghttp2_session_on_request_recv_callback(void)
nghttp2_session_callbacks callbacks; nghttp2_session_callbacks callbacks;
my_user_data user_data; my_user_data user_data;
nghttp2_frame frame; nghttp2_frame frame;
nghttp2_stream *stream;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.on_request_recv_callback = on_request_recv_callback; callbacks.on_request_recv_callback = on_request_recv_callback;
@ -3475,31 +3479,35 @@ void test_nghttp2_session_on_request_recv_callback(void)
nghttp2_session_server_new(&session, &callbacks, &user_data); nghttp2_session_server_new(&session, &callbacks, &user_data);
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
1, NGHTTP2_PRI_DEFAULT, NULL, 0); 1, NGHTTP2_PRI_DEFAULT, NULL, 0);
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); CU_ASSERT(0 == nghttp2_session_end_request_headers_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id); CU_ASSERT(0 == user_data.stream_id);
/* nghttp2_session_end_* does not open stream, so we do it here */
nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL);
frame.hd.stream_id = 3; frame.hd.stream_id = 3;
frame.hd.flags |= NGHTTP2_FLAG_END_STREAM; frame.hd.flags |= NGHTTP2_FLAG_END_STREAM;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame)); CU_ASSERT(0 == nghttp2_session_end_request_headers_received(session, &frame));
CU_ASSERT(3 == user_data.stream_id); CU_ASSERT(3 == user_data.stream_id);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);
user_data.stream_id = 0; user_data.stream_id = 0;
stream = nghttp2_session_open_stream(session, 5, NGHTTP2_STREAM_FLAG_NONE, nghttp2_session_open_stream(session, 5, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_PRI_DEFAULT, NGHTTP2_PRI_DEFAULT,
NGHTTP2_STREAM_OPENING, NULL); NGHTTP2_STREAM_OPENING, NULL);
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
5, NGHTTP2_PRI_DEFAULT, NULL, 0); 5, NGHTTP2_PRI_DEFAULT, NULL, 0);
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame));
CU_ASSERT(0 == user_data.stream_id); CU_ASSERT(0 == user_data.stream_id);
frame.headers.hd.flags |= NGHTTP2_FLAG_END_STREAM; frame.headers.hd.flags |= NGHTTP2_FLAG_END_STREAM;
CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream)); CU_ASSERT(0 == nghttp2_session_end_headers_received(session, &frame));
CU_ASSERT(5 == user_data.stream_id); CU_ASSERT(5 == user_data.stream_id);
nghttp2_frame_headers_free(&frame.headers); nghttp2_frame_headers_free(&frame.headers);