Add nghttp2_on_begin_frame_callback
nghttp2_on_begin_frame_callback will be invoked when a frame header is received.
This commit is contained in:
parent
3daa6f2c30
commit
a36c4c6f5f
|
@ -1163,6 +1163,9 @@ typedef ssize_t (*nghttp2_recv_callback)
|
|||
* If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
|
||||
* |frame| is the last frame from the remote peer in this stream.
|
||||
*
|
||||
* This callback won't be called for CONTINUATION frames.
|
||||
* HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
|
||||
*
|
||||
* The implementation of this function must return 0 if it succeeds.
|
||||
* If nonzero value is returned, it is treated as fatal error and
|
||||
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
||||
|
@ -1440,6 +1443,31 @@ typedef ssize_t (*nghttp2_select_padding_callback)
|
|||
size_t max_payloadlen,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
*
|
||||
* Callback function invoked when a frame header is received. The
|
||||
* |hd| points to received frame header.
|
||||
*
|
||||
* Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will
|
||||
* also be called when frame header of CONTINUATION frame is received.
|
||||
*
|
||||
* If both :type:`nghttp2_on_begin_frame_callback` and
|
||||
* :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or
|
||||
* PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback`
|
||||
* will be called first.
|
||||
*
|
||||
* The implementation of this function must return 0 if it succeeds.
|
||||
* If nonzero value is returned, it is treated as fatal error and
|
||||
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
||||
* immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
|
||||
*
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_begin_frame_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame_hd *hd, void *user_data);
|
||||
|
||||
struct nghttp2_session_callbacks;
|
||||
|
||||
/**
|
||||
|
@ -1608,6 +1636,15 @@ void nghttp2_session_callbacks_set_data_source_read_length_callback
|
|||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback);
|
||||
|
||||
struct nghttp2_option;
|
||||
|
||||
/**
|
||||
|
@ -1879,7 +1916,10 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
|
|||
* 1. :type:`nghttp2_recv_callback` is invoked one or more times to
|
||||
* receive frame header.
|
||||
*
|
||||
* 2. If the frame is DATA frame:
|
||||
* 2. When frame header is received,
|
||||
* :type:`nghttp2_on_begin_frame_callback` is invoked.
|
||||
*
|
||||
* 3. If the frame is DATA frame:
|
||||
*
|
||||
* 1. :type:`nghttp2_recv_callback` is invoked to receive DATA
|
||||
* payload. For each chunk of data,
|
||||
|
@ -1890,7 +1930,7 @@ ssize_t nghttp2_session_mem_send(nghttp2_session *session,
|
|||
* reception of the frame triggers the closure of the stream,
|
||||
* :type:`nghttp2_on_stream_close_callback` is invoked.
|
||||
*
|
||||
* 3. If the frame is the control frame:
|
||||
* 4. If the frame is the control frame:
|
||||
*
|
||||
* 1. :type:`nghttp2_recv_callback` is invoked one or more times to
|
||||
* receive whole frame.
|
||||
|
|
|
@ -130,3 +130,10 @@ void nghttp2_session_callbacks_set_data_source_read_length_callback
|
|||
{
|
||||
cbs->read_length_callback = data_source_read_length_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback)
|
||||
{
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,10 @@ struct nghttp2_session_callbacks {
|
|||
* `nghttp2_data_source_read_callback()`
|
||||
*/
|
||||
nghttp2_data_source_read_length_callback read_length_callback;
|
||||
/**
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
|
|
|
@ -2453,6 +2453,24 @@ static ssize_t session_recv(nghttp2_session *session, uint8_t *buf, size_t len)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static int session_call_on_begin_frame
|
||||
(nghttp2_session *session, const nghttp2_frame_hd *hd)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if(session->callbacks.on_begin_frame_callback) {
|
||||
|
||||
rv = session->callbacks.on_begin_frame_callback
|
||||
(session, hd, session->user_data);
|
||||
|
||||
if(rv != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_call_on_frame_received
|
||||
(nghttp2_session *session, nghttp2_frame *frame)
|
||||
{
|
||||
|
@ -4295,7 +4313,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
|||
|
||||
for(;;) {
|
||||
switch(iframe->state) {
|
||||
case NGHTTP2_IB_READ_HEAD:
|
||||
case NGHTTP2_IB_READ_HEAD: {
|
||||
int on_begin_frame_called = 0;
|
||||
|
||||
DEBUGF(fprintf(stderr, "recv: [IB_READ_HEAD]\n"));
|
||||
|
||||
readlen = inbound_frame_buf_read(iframe, in, last);
|
||||
|
@ -4424,6 +4444,17 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
|||
break;
|
||||
}
|
||||
|
||||
/* Call on_begin_frame_callback here because
|
||||
session_process_headers_frame() may call
|
||||
on_begin_headers_callback */
|
||||
rv = session_call_on_begin_frame(session, &iframe->frame.hd);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
on_begin_frame_called = 1;
|
||||
|
||||
rv = session_process_headers_frame(session);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -4632,7 +4663,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
if(!on_begin_frame_called) {
|
||||
switch(iframe->state) {
|
||||
case NGHTTP2_IB_IGN_HEADER_BLOCK:
|
||||
case NGHTTP2_IB_IGN_PAYLOAD:
|
||||
case NGHTTP2_IB_FRAME_SIZE_ERROR:
|
||||
case NGHTTP2_IB_IGN_DATA:
|
||||
break;
|
||||
default:
|
||||
rv = session_call_on_begin_frame(session, &iframe->frame.hd);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_IB_READ_NBYTE:
|
||||
DEBUGF(fprintf(stderr, "recv: [IB_READ_NBYTE]\n"));
|
||||
|
||||
|
@ -5105,6 +5154,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
|||
|
||||
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
|
||||
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
|
||||
|
||||
rv = session_call_on_begin_frame(session, &cont_hd);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ typedef struct {
|
|||
nghttp2_nv nv;
|
||||
size_t data_chunk_len;
|
||||
size_t padlen;
|
||||
int begin_frame_cb_called;
|
||||
} my_user_data;
|
||||
|
||||
static void scripted_data_feed_init2(scripted_data_feed *df,
|
||||
|
@ -156,6 +157,15 @@ static ssize_t accumulator_send_callback(nghttp2_session *session,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int on_begin_frame_callback(nghttp2_session *session,
|
||||
const nghttp2_frame_hd *hd,
|
||||
void *user_data)
|
||||
{
|
||||
my_user_data *ud = (my_user_data*)user_data;
|
||||
++ud->begin_frame_cb_called;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
|
@ -409,6 +419,7 @@ void test_nghttp2_session_recv(void)
|
|||
callbacks.send_callback = null_send_callback;
|
||||
callbacks.recv_callback = scripted_recv_callback;
|
||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||
callbacks.on_begin_frame_callback = on_begin_frame_callback;
|
||||
|
||||
user_data.df = &df;
|
||||
|
||||
|
@ -435,10 +446,13 @@ void test_nghttp2_session_recv(void)
|
|||
nghttp2_frame_headers_free(&frame.headers);
|
||||
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
user_data.begin_frame_cb_called = 0;
|
||||
|
||||
while((ssize_t)df.seqidx < framelen) {
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
}
|
||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||
CU_ASSERT(1 == user_data.begin_frame_cb_called);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
|
@ -453,9 +467,33 @@ void test_nghttp2_session_recv(void)
|
|||
|
||||
scripted_data_feed_init2(&df, &bufs);
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
user_data.begin_frame_cb_called = 0;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||
CU_ASSERT(1 == user_data.begin_frame_cb_called);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
/* Receive PRIORITY */
|
||||
nghttp2_frame_priority_init(&frame.priority, 5, &pri_spec_default);
|
||||
|
||||
rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
nghttp2_frame_priority_free(&frame.priority);
|
||||
|
||||
scripted_data_feed_init2(&df, &bufs);
|
||||
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
user_data.begin_frame_cb_called = 0;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||
CU_ASSERT(1 == user_data.begin_frame_cb_called);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_session_del(session);
|
||||
|
@ -463,8 +501,6 @@ void test_nghttp2_session_recv(void)
|
|||
/* Some tests for frame too large */
|
||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
|
||||
/* Receive PING with too large payload */
|
||||
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
|
||||
|
||||
|
@ -485,8 +521,12 @@ void test_nghttp2_session_recv(void)
|
|||
|
||||
scripted_data_feed_init2(&df, &bufs);
|
||||
user_data.frame_recv_cb_called = 0;
|
||||
user_data.begin_frame_cb_called = 0;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
||||
CU_ASSERT(0 == user_data.begin_frame_cb_called);
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||
CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == OB_CTRL(item)->goaway.error_code);
|
||||
|
@ -760,6 +800,7 @@ void test_nghttp2_session_recv_continuation(void)
|
|||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.on_header_callback = on_header_callback;
|
||||
callbacks.on_begin_headers_callback = on_begin_headers_callback;
|
||||
callbacks.on_begin_frame_callback = on_begin_frame_callback;
|
||||
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
|
@ -816,9 +857,12 @@ void test_nghttp2_session_recv_continuation(void)
|
|||
CU_ASSERT(0 == nghttp2_buf_len(buf));
|
||||
|
||||
ud.header_cb_called = 0;
|
||||
ud.begin_frame_cb_called = 0;
|
||||
|
||||
rv = nghttp2_session_mem_recv(session, data, datalen);
|
||||
CU_ASSERT((ssize_t)datalen == rv);
|
||||
CU_ASSERT(2 == ud.header_cb_called);
|
||||
CU_ASSERT(3 == ud.begin_frame_cb_called);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_session_del(session);
|
||||
|
|
Loading…
Reference in New Issue