Add nghttp2_option_set_max_send_header_block_length API function
This function sets the maximum length of header block (a set of header fields per HEADERS frame) to send. The length of given set of header fields is calculated using nghttp2_hd_deflate_bound(). Previously, this is hard-coded, and is 64KiB.
This commit is contained in:
parent
47fa56fd0a
commit
c7b0e04498
|
@ -57,6 +57,7 @@ APIDOCS= \
|
|||
nghttp2_option_new.rst \
|
||||
nghttp2_option_set_builtin_recv_extension_type.rst \
|
||||
nghttp2_option_set_max_reserved_remote_streams.rst \
|
||||
nghttp2_option_set_max_send_header_block_length.rst \
|
||||
nghttp2_option_set_no_auto_ping_ack.rst \
|
||||
nghttp2_option_set_no_auto_window_update.rst \
|
||||
nghttp2_option_set_no_http_messaging.rst \
|
||||
|
|
|
@ -2412,6 +2412,21 @@ nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
|
|||
NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
|
||||
int val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* This option sets the maximum length of header block (a set of
|
||||
* header fields per one HEADERS frame) to send. The length of a
|
||||
* given set of header fields is calculated using
|
||||
* `nghttp2_hd_deflate_bound()`. The default value is 64KiB. If
|
||||
* application attempts to send header fields larger than this limit,
|
||||
* the transmission of the frame fails with error code
|
||||
* :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
|
||||
*/
|
||||
NGHTTP2_EXTERN void
|
||||
nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
|
||||
size_t val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
|
|
@ -52,14 +52,12 @@
|
|||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||
(NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
|
||||
|
||||
/* Number of inbound buffer */
|
||||
#define NGHTTP2_FRAMEBUF_MAX_NUM 5
|
||||
|
||||
/* The default length of DATA frame payload. */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
|
||||
|
||||
/* Maximum headers payload length, calculated in compressed form.
|
||||
This applies to transmission only. */
|
||||
/* Maximum headers block size to send, calculated using
|
||||
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
||||
overridden by nghttp2_option_set_max_send_header_block_size(). */
|
||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||
|
||||
/* The number of bytes for each SETTINGS entry */
|
||||
|
|
|
@ -95,3 +95,9 @@ void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) {
|
|||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK;
|
||||
option->no_auto_ping_ack = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
|
||||
size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH;
|
||||
option->max_send_header_block_length = val;
|
||||
}
|
||||
|
|
|
@ -62,13 +62,18 @@ typedef enum {
|
|||
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
|
||||
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
|
||||
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
|
||||
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7
|
||||
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
|
||||
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
* Struct to store option values for nghttp2_session.
|
||||
*/
|
||||
struct nghttp2_option {
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
|
||||
*/
|
||||
size_t max_send_header_block_length;
|
||||
/**
|
||||
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
||||
* are specified.
|
||||
|
|
|
@ -389,6 +389,7 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
void *user_data, int server,
|
||||
const nghttp2_option *option, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
size_t nbuffer;
|
||||
|
||||
if (mem == NULL) {
|
||||
mem = nghttp2_mem_default();
|
||||
|
@ -441,16 +442,6 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
(*session_ptr)->server = 1;
|
||||
}
|
||||
|
||||
/* 1 for Pad Field. */
|
||||
rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs,
|
||||
NGHTTP2_FRAMEBUF_CHUNKLEN, NGHTTP2_FRAMEBUF_MAX_NUM,
|
||||
1, NGHTTP2_FRAME_HDLEN + 1, mem);
|
||||
if (rv != 0) {
|
||||
goto fail_aob_framebuf;
|
||||
}
|
||||
|
||||
active_outbound_item_reset(&(*session_ptr)->aob, mem);
|
||||
|
||||
init_settings(&(*session_ptr)->remote_settings);
|
||||
init_settings(&(*session_ptr)->local_settings);
|
||||
|
||||
|
@ -460,6 +451,8 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
/* Limit max outgoing concurrent streams to sensible value */
|
||||
(*session_ptr)->remote_settings.max_concurrent_streams = 100;
|
||||
|
||||
(*session_ptr)->max_send_header_block_length = NGHTTP2_MAX_HEADERSLEN;
|
||||
|
||||
if (option) {
|
||||
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
||||
option->no_auto_window_update) {
|
||||
|
@ -504,8 +497,31 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
option->no_auto_ping_ack) {
|
||||
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_PING_ACK;
|
||||
}
|
||||
|
||||
if (option->opt_set_mask & NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH) {
|
||||
(*session_ptr)->max_send_header_block_length =
|
||||
option->max_send_header_block_length;
|
||||
}
|
||||
}
|
||||
|
||||
nbuffer = ((*session_ptr)->max_send_header_block_length +
|
||||
NGHTTP2_FRAMEBUF_CHUNKLEN - 1) /
|
||||
NGHTTP2_FRAMEBUF_CHUNKLEN;
|
||||
|
||||
if (nbuffer == 0) {
|
||||
nbuffer = 1;
|
||||
}
|
||||
|
||||
/* 1 for Pad Field. */
|
||||
rv = nghttp2_bufs_init3(&(*session_ptr)->aob.framebufs,
|
||||
NGHTTP2_FRAMEBUF_CHUNKLEN, nbuffer, 1,
|
||||
NGHTTP2_FRAME_HDLEN + 1, mem);
|
||||
if (rv != 0) {
|
||||
goto fail_aob_framebuf;
|
||||
}
|
||||
|
||||
active_outbound_item_reset(&(*session_ptr)->aob, mem);
|
||||
|
||||
(*session_ptr)->callbacks = *callbacks;
|
||||
(*session_ptr)->user_data = user_data;
|
||||
|
||||
|
@ -1951,7 +1967,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
session, frame->headers.nva, frame->headers.nvlen,
|
||||
NGHTTP2_PRIORITY_SPECLEN);
|
||||
|
||||
if (estimated_payloadlen > NGHTTP2_MAX_HEADERSLEN) {
|
||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1970,7 +1986,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
session, frame->headers.nva, frame->headers.nvlen,
|
||||
NGHTTP2_PRIORITY_SPECLEN);
|
||||
|
||||
if (estimated_payloadlen > NGHTTP2_MAX_HEADERSLEN) {
|
||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -2089,7 +2105,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
estimated_payloadlen = session_estimate_headers_payload(
|
||||
session, frame->push_promise.nva, frame->push_promise.nvlen, 0);
|
||||
|
||||
if (estimated_payloadlen > NGHTTP2_MAX_HEADERSLEN) {
|
||||
if (estimated_payloadlen > session->max_send_header_block_length) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -256,6 +256,9 @@ struct nghttp2_session {
|
|||
size_t nvbuflen;
|
||||
/* Counter for detecting flooding in outbound queue */
|
||||
size_t obq_flood_counter_;
|
||||
/* The maximum length of header block to send. Calculated by the
|
||||
same way as nghttp2_hd_deflate_bound() does. */
|
||||
size_t max_send_header_block_length;
|
||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||
uint32_t next_stream_id;
|
||||
/* The last stream ID this session initiated. For client session,
|
||||
|
|
|
@ -183,6 +183,8 @@ int main(int argc _U_, char *argv[] _U_) {
|
|||
!CU_add_test(pSuite, "submit_headers", test_nghttp2_submit_headers) ||
|
||||
!CU_add_test(pSuite, "submit_headers_continuation",
|
||||
test_nghttp2_submit_headers_continuation) ||
|
||||
!CU_add_test(pSuite, "submit_headers_continuation_extra_large",
|
||||
test_nghttp2_submit_headers_continuation_extra_large) ||
|
||||
!CU_add_test(pSuite, "submit_priority", test_nghttp2_submit_priority) ||
|
||||
!CU_add_test(pSuite, "session_submit_settings",
|
||||
test_nghttp2_submit_settings) ||
|
||||
|
|
|
@ -4842,6 +4842,51 @@ void test_nghttp2_submit_headers_continuation(void) {
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_submit_headers_continuation_extra_large(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_nv nv[] = {
|
||||
MAKE_NV("h1", ""), MAKE_NV("h1", ""), MAKE_NV("h1", ""),
|
||||
MAKE_NV("h1", ""), MAKE_NV("h1", ""), MAKE_NV("h1", ""),
|
||||
};
|
||||
nghttp2_outbound_item *item;
|
||||
uint8_t data[16384];
|
||||
size_t i;
|
||||
my_user_data ud;
|
||||
nghttp2_option *opt;
|
||||
|
||||
memset(data, '0', sizeof(data));
|
||||
for (i = 0; i < ARRLEN(nv); ++i) {
|
||||
nv[i].valuelen = sizeof(data);
|
||||
nv[i].value = data;
|
||||
}
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||
|
||||
/* The default size of max send header block length is too small to
|
||||
send these header fields. Expand it. */
|
||||
nghttp2_option_new(&opt);
|
||||
nghttp2_option_set_max_send_header_block_length(opt, 102400);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_client_new2(&session, &callbacks, &ud, opt));
|
||||
CU_ASSERT(1 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, -1,
|
||||
NULL, nv, ARRLEN(nv), NULL));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
|
||||
CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) ==
|
||||
item->frame.hd.flags);
|
||||
CU_ASSERT(0 == (item->frame.hd.flags & NGHTTP2_FLAG_PRIORITY));
|
||||
|
||||
ud.frame_send_cb_called = 0;
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(1 == ud.frame_send_cb_called);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_option_del(opt);
|
||||
}
|
||||
|
||||
void test_nghttp2_submit_priority(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
|
|
|
@ -87,6 +87,7 @@ void test_nghttp2_submit_headers_reply(void);
|
|||
void test_nghttp2_submit_headers_push_reply(void);
|
||||
void test_nghttp2_submit_headers(void);
|
||||
void test_nghttp2_submit_headers_continuation(void);
|
||||
void test_nghttp2_submit_headers_continuation_extra_large(void);
|
||||
void test_nghttp2_submit_priority(void);
|
||||
void test_nghttp2_submit_settings(void);
|
||||
void test_nghttp2_submit_settings_update_local_window_size(void);
|
||||
|
|
Loading…
Reference in New Issue