Add nghttp2_option_set_user_recv_extension_type to opt-in incoming extension type

This commit is contained in:
Tatsuhiro Tsujikawa 2015-10-15 00:17:07 +09:00
parent d9893d014c
commit 061a557839
6 changed files with 54 additions and 5 deletions

View File

@ -2186,6 +2186,21 @@ NGHTTP2_EXTERN void
nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option, nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
uint32_t val); uint32_t val);
/**
* @function
*
* Set extension frame type the application is willing to handle with
* user defined callbacks (see
* :type:`nghttp2_on_extension_chunk_recv_callback` and
* :type:`nghttp2_unpack_extension_callback`). The |type| is
* extension frame type, and must be strictly greater than 0x9.
* Otherwise, this function does nothing. The application does not
* have to call this function if it just sends extension frames.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
uint8_t type);
/** /**
* @function * @function
* *

View File

@ -62,3 +62,13 @@ void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS; option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
option->max_reserved_remote_streams = val; option->max_reserved_remote_streams = val;
} }
void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
uint8_t type) {
if (type < 10) {
return;
}
option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES;
option->user_recv_ext_types[type / 8] |= 1 << (7 - (type & 0x7));
}

View File

@ -59,7 +59,8 @@ typedef enum {
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1, NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2, NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3, NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4 NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5
} nghttp2_option_flag; } nghttp2_option_flag;
/** /**
@ -91,6 +92,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_NO_HTTP_MESSAGING * NGHTTP2_OPT_NO_HTTP_MESSAGING
*/ */
int no_http_messaging; int no_http_messaging;
/**
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
*/
uint8_t user_recv_ext_types[32];
}; };
#endif /* NGHTTP2_OPTION_H */ #endif /* NGHTTP2_OPTION_H */

View File

@ -402,6 +402,11 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING; (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_HTTP_MESSAGING;
} }
if (option->opt_set_mask & NGHTTP2_OPT_USER_RECV_EXT_TYPES) {
memcpy((*session_ptr)->user_recv_ext_types, option->user_recv_ext_types,
sizeof((*session_ptr)->user_recv_ext_types));
}
} }
(*session_ptr)->callbacks = *callbacks; (*session_ptr)->callbacks = *callbacks;
@ -5291,7 +5296,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
default: default:
DEBUGF(fprintf(stderr, "recv: unknown frame\n")); DEBUGF(fprintf(stderr, "recv: unknown frame\n"));
if (!session->callbacks.unpack_extension_callback) { if (!session->callbacks.unpack_extension_callback ||
(session->user_recv_ext_types[iframe->frame.hd.type / 8] &
(1 << (7 - (iframe->frame.hd.type & 0x7)))) == 0) {
/* Silently ignore unknown frame type. */ /* Silently ignore unknown frame type. */
busy = 1; busy = 1;

View File

@ -296,6 +296,12 @@ struct nghttp2_session {
this session. The nonzero does not necessarily mean this session. The nonzero does not necessarily mean
WINDOW_UPDATE is not queued. */ WINDOW_UPDATE is not queued. */
uint8_t window_update_queued; uint8_t window_update_queued;
/* Bitfield of extension frame types that application is willing to
receive. First most significant 10 bits are standard frame types
and not used. If bit is set, it indicates that incoming frame
with that type is passed to user defined callbacks, otherwise
they are ignored. */
uint8_t user_recv_ext_types[32];
}; };
/* Struct used when updating initial window size of each active /* Struct used when updating initial window size of each active

View File

@ -1769,6 +1769,7 @@ void test_nghttp2_session_recv_extension(void) {
nghttp2_mem *mem; nghttp2_mem *mem;
const char data[] = "Hello World!"; const char data[] = "Hello World!";
ssize_t rv; ssize_t rv;
nghttp2_option *option;
mem = nghttp2_mem_default(); mem = nghttp2_mem_default();
@ -1778,6 +1779,9 @@ void test_nghttp2_session_recv_extension(void) {
callbacks.unpack_extension_callback = unpack_extension_callback; callbacks.unpack_extension_callback = unpack_extension_callback;
callbacks.on_frame_recv_callback = on_frame_recv_callback; callbacks.on_frame_recv_callback = on_frame_recv_callback;
nghttp2_option_new(&option);
nghttp2_option_set_user_recv_extension_type(option, 111);
nghttp2_buf_init2(&ud.scratchbuf, 4096, mem); nghttp2_buf_init2(&ud.scratchbuf, 4096, mem);
nghttp2_buf_init2(&buf, 4096, mem); nghttp2_buf_init2(&buf, 4096, mem);
@ -1786,7 +1790,7 @@ void test_nghttp2_session_recv_extension(void) {
buf.last += NGHTTP2_FRAME_HDLEN; buf.last += NGHTTP2_FRAME_HDLEN;
buf.last = nghttp2_cpymem(buf.last, data, sizeof(data)); buf.last = nghttp2_cpymem(buf.last, data, sizeof(data));
nghttp2_session_client_new(&session, &callbacks, &ud); nghttp2_session_client_new2(&session, &callbacks, &ud, option);
nghttp2_frame_hd_init(&ud.recv_frame_hd, 0, 0, 0, 0); nghttp2_frame_hd_init(&ud.recv_frame_hd, 0, 0, 0, 0);
rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf)); rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf));
@ -1805,7 +1809,7 @@ void test_nghttp2_session_recv_extension(void) {
callbacks.on_extension_chunk_recv_callback = callbacks.on_extension_chunk_recv_callback =
cancel_on_extension_chunk_recv_callback; cancel_on_extension_chunk_recv_callback;
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new2(&session, &callbacks, &ud, option);
ud.frame_recv_cb_called = 0; ud.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf)); rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf));
@ -1821,7 +1825,7 @@ void test_nghttp2_session_recv_extension(void) {
callbacks.on_extension_chunk_recv_callback = on_extension_chunk_recv_callback; callbacks.on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
callbacks.unpack_extension_callback = cancel_unpack_extension_callback; callbacks.unpack_extension_callback = cancel_unpack_extension_callback;
nghttp2_session_server_new(&session, &callbacks, &ud); nghttp2_session_server_new2(&session, &callbacks, &ud, option);
ud.frame_recv_cb_called = 0; ud.frame_recv_cb_called = 0;
rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf)); rv = nghttp2_session_mem_recv(session, buf.pos, nghttp2_buf_len(&buf));
@ -1833,6 +1837,8 @@ void test_nghttp2_session_recv_extension(void) {
nghttp2_buf_free(&buf, mem); nghttp2_buf_free(&buf, mem);
nghttp2_buf_free(&ud.scratchbuf, mem); nghttp2_buf_free(&ud.scratchbuf, mem);
nghttp2_option_del(option);
} }
void test_nghttp2_session_continue(void) { void test_nghttp2_session_continue(void) {