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
|
* If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
|
||||||
* |frame| is the last frame from the remote peer in this stream.
|
* |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.
|
* The implementation of this function must return 0 if it succeeds.
|
||||||
* If nonzero value is returned, it is treated as fatal error and
|
* If nonzero value is returned, it is treated as fatal error and
|
||||||
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
* `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
|
||||||
|
@ -1440,6 +1443,31 @@ typedef ssize_t (*nghttp2_select_padding_callback)
|
||||||
size_t max_payloadlen,
|
size_t max_payloadlen,
|
||||||
void *user_data);
|
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;
|
struct nghttp2_session_callbacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1608,6 +1636,15 @@ void nghttp2_session_callbacks_set_data_source_read_length_callback
|
||||||
(nghttp2_session_callbacks *cbs,
|
(nghttp2_session_callbacks *cbs,
|
||||||
nghttp2_data_source_read_length_callback data_source_read_length_callback);
|
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;
|
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
|
* 1. :type:`nghttp2_recv_callback` is invoked one or more times to
|
||||||
* receive frame header.
|
* 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
|
* 1. :type:`nghttp2_recv_callback` is invoked to receive DATA
|
||||||
* payload. For each chunk of 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,
|
* reception of the frame triggers the closure of the stream,
|
||||||
* :type:`nghttp2_on_stream_close_callback` is invoked.
|
* :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
|
* 1. :type:`nghttp2_recv_callback` is invoked one or more times to
|
||||||
* receive whole frame.
|
* 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;
|
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_callback()`
|
||||||
*/
|
*/
|
||||||
nghttp2_data_source_read_length_callback read_length_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 */
|
#endif /* NGHTTP2_CALLBACKS_H */
|
||||||
|
|
|
@ -2453,6 +2453,24 @@ static ssize_t session_recv(nghttp2_session *session, uint8_t *buf, size_t len)
|
||||||
return rv;
|
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
|
static int session_call_on_frame_received
|
||||||
(nghttp2_session *session, nghttp2_frame *frame)
|
(nghttp2_session *session, nghttp2_frame *frame)
|
||||||
{
|
{
|
||||||
|
@ -4295,7 +4313,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
switch(iframe->state) {
|
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"));
|
DEBUGF(fprintf(stderr, "recv: [IB_READ_HEAD]\n"));
|
||||||
|
|
||||||
readlen = inbound_frame_buf_read(iframe, in, last);
|
readlen = inbound_frame_buf_read(iframe, in, last);
|
||||||
|
@ -4424,6 +4444,17 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
break;
|
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);
|
rv = session_process_headers_frame(session);
|
||||||
if(nghttp2_is_fatal(rv)) {
|
if(nghttp2_is_fatal(rv)) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -4632,7 +4663,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
|
|
||||||
break;
|
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;
|
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:
|
case NGHTTP2_IB_READ_NBYTE:
|
||||||
DEBUGF(fprintf(stderr, "recv: [IB_READ_NBYTE]\n"));
|
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) {
|
if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) {
|
||||||
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
|
iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK;
|
||||||
|
|
||||||
|
rv = session_call_on_begin_frame(session, &cont_hd);
|
||||||
|
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct {
|
||||||
nghttp2_nv nv;
|
nghttp2_nv nv;
|
||||||
size_t data_chunk_len;
|
size_t data_chunk_len;
|
||||||
size_t padlen;
|
size_t padlen;
|
||||||
|
int begin_frame_cb_called;
|
||||||
} my_user_data;
|
} my_user_data;
|
||||||
|
|
||||||
static void scripted_data_feed_init2(scripted_data_feed *df,
|
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;
|
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,
|
static int on_frame_recv_callback(nghttp2_session *session,
|
||||||
const nghttp2_frame *frame,
|
const nghttp2_frame *frame,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
|
@ -409,6 +419,7 @@ void test_nghttp2_session_recv(void)
|
||||||
callbacks.send_callback = null_send_callback;
|
callbacks.send_callback = null_send_callback;
|
||||||
callbacks.recv_callback = scripted_recv_callback;
|
callbacks.recv_callback = scripted_recv_callback;
|
||||||
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
callbacks.on_frame_recv_callback = on_frame_recv_callback;
|
||||||
|
callbacks.on_begin_frame_callback = on_begin_frame_callback;
|
||||||
|
|
||||||
user_data.df = &df;
|
user_data.df = &df;
|
||||||
|
|
||||||
|
@ -435,10 +446,13 @@ void test_nghttp2_session_recv(void)
|
||||||
nghttp2_frame_headers_free(&frame.headers);
|
nghttp2_frame_headers_free(&frame.headers);
|
||||||
|
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.frame_recv_cb_called = 0;
|
||||||
|
user_data.begin_frame_cb_called = 0;
|
||||||
|
|
||||||
while((ssize_t)df.seqidx < framelen) {
|
while((ssize_t)df.seqidx < framelen) {
|
||||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||||
}
|
}
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
||||||
|
CU_ASSERT(1 == user_data.begin_frame_cb_called);
|
||||||
|
|
||||||
nghttp2_bufs_reset(&bufs);
|
nghttp2_bufs_reset(&bufs);
|
||||||
|
|
||||||
|
@ -453,9 +467,33 @@ void test_nghttp2_session_recv(void)
|
||||||
|
|
||||||
scripted_data_feed_init2(&df, &bufs);
|
scripted_data_feed_init2(&df, &bufs);
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.frame_recv_cb_called = 0;
|
||||||
|
user_data.begin_frame_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||||
CU_ASSERT(1 == user_data.frame_recv_cb_called);
|
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_hd_deflate_free(&deflater);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
@ -463,8 +501,6 @@ void test_nghttp2_session_recv(void)
|
||||||
/* Some tests for frame too large */
|
/* Some tests for frame too large */
|
||||||
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
nghttp2_session_server_new(&session, &callbacks, &user_data);
|
||||||
|
|
||||||
nghttp2_bufs_reset(&bufs);
|
|
||||||
|
|
||||||
/* Receive PING with too large payload */
|
/* Receive PING with too large payload */
|
||||||
nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
|
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);
|
scripted_data_feed_init2(&df, &bufs);
|
||||||
user_data.frame_recv_cb_called = 0;
|
user_data.frame_recv_cb_called = 0;
|
||||||
|
user_data.begin_frame_cb_called = 0;
|
||||||
|
|
||||||
CU_ASSERT(0 == nghttp2_session_recv(session));
|
CU_ASSERT(0 == nghttp2_session_recv(session));
|
||||||
CU_ASSERT(0 == user_data.frame_recv_cb_called);
|
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);
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == OB_CTRL(item)->goaway.error_code);
|
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));
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
callbacks.on_header_callback = on_header_callback;
|
callbacks.on_header_callback = on_header_callback;
|
||||||
callbacks.on_begin_headers_callback = on_begin_headers_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);
|
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));
|
CU_ASSERT(0 == nghttp2_buf_len(buf));
|
||||||
|
|
||||||
ud.header_cb_called = 0;
|
ud.header_cb_called = 0;
|
||||||
|
ud.begin_frame_cb_called = 0;
|
||||||
|
|
||||||
rv = nghttp2_session_mem_recv(session, data, datalen);
|
rv = nghttp2_session_mem_recv(session, data, datalen);
|
||||||
CU_ASSERT((ssize_t)datalen == rv);
|
CU_ASSERT((ssize_t)datalen == rv);
|
||||||
CU_ASSERT(2 == ud.header_cb_called);
|
CU_ASSERT(2 == ud.header_cb_called);
|
||||||
|
CU_ASSERT(3 == ud.begin_frame_cb_called);
|
||||||
|
|
||||||
nghttp2_hd_deflate_free(&deflater);
|
nghttp2_hd_deflate_free(&deflater);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
Loading…
Reference in New Issue