Merge branch 'set-max-deflate-dynamic-table-size'

This commit is contained in:
Tatsuhiro Tsujikawa 2016-09-18 22:13:56 +09:00
commit e464b10fc3
18 changed files with 367 additions and 64 deletions

View File

@ -142,6 +142,10 @@ OPTIONS = [
"frontend-http2-connection-window-size",
"backend-http2-window-size",
"backend-http2-connection-window-size",
"frontend-http2-encoder-dynamic-table-size",
"frontend-http2-decoder-dynamic-table-size",
"backend-http2-encoder-dynamic-table-size",
"backend-http2-decoder-dynamic-table-size",
]
LOGVARS = [

View File

@ -2532,6 +2532,19 @@ NGHTTP2_EXTERN void
nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
size_t val);
/**
* @function
*
* This option sets the maximum dynamic table size for deflating
* header fields. The default value is 4KiB. In HTTP/2, receiver of
* deflated header block can specify maximum dynamic table size. The
* actual maximum size is the minimum of the size receiver specified
* and this option value.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
size_t val);
/**
* @function
*
@ -4583,7 +4596,7 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
*
* Initializes |*deflater_ptr| for deflating name/values pairs.
*
* The |deflate_hd_table_bufsize_max| is the upper bound of header
* The |max_deflate_dynamic_table_size| is the upper bound of header
* table size the deflater will use.
*
* If this function fails, |*deflater_ptr| is left untouched.
@ -4594,8 +4607,9 @@ typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
* :enum:`NGHTTP2_ERR_NOMEM`
* Out of memory.
*/
NGHTTP2_EXTERN int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
size_t deflate_hd_table_bufsize_max);
NGHTTP2_EXTERN int
nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
size_t max_deflate_dynamic_table_size);
/**
* @function
@ -4612,9 +4626,10 @@ NGHTTP2_EXTERN int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
* The library code does not refer to |mem| pointer after this
* function returns, so the application can safely free it.
*/
NGHTTP2_EXTERN int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
size_t deflate_hd_table_bufsize_max,
nghttp2_mem *mem);
NGHTTP2_EXTERN int
nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
size_t max_deflate_dynamic_table_size,
nghttp2_mem *mem);
/**
* @function
@ -4627,18 +4642,18 @@ NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
* @function
*
* Changes header table size of the |deflater| to
* |settings_hd_table_bufsize_max| bytes. This may trigger eviction
* |settings_max_dynamic_table_size| bytes. This may trigger eviction
* in the dynamic table.
*
* The |settings_hd_table_bufsize_max| should be the value received in
* SETTINGS_HEADER_TABLE_SIZE.
* The |settings_max_dynamic_table_size| should be the value received
* in SETTINGS_HEADER_TABLE_SIZE.
*
* The deflater never uses more memory than
* ``deflate_hd_table_bufsize_max`` bytes specified in
* ``max_deflate_dynamic_table_size`` bytes specified in
* `nghttp2_hd_deflate_new()`. Therefore, if
* |settings_hd_table_bufsize_max| > ``deflate_hd_table_bufsize_max``,
* resulting maximum table size becomes
* ``deflate_hd_table_bufsize_max``.
* |settings_max_dynamic_table_size| >
* ``max_deflate_dynamic_table_size``, resulting maximum table size
* becomes ``max_deflate_dynamic_table_size``.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@ -4648,7 +4663,7 @@ NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
*/
NGHTTP2_EXTERN int
nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t settings_hd_table_bufsize_max);
size_t settings_max_dynamic_table_size);
/**
* @function
@ -4819,8 +4834,8 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
* Changes header table size in the |inflater|. This may trigger
* eviction in the dynamic table.
*
* The |settings_hd_table_bufsize_max| should be the value transmitted
* in SETTINGS_HEADER_TABLE_SIZE.
* The |settings_max_dynamic_table_size| should be the value
* transmitted in SETTINGS_HEADER_TABLE_SIZE.
*
* This function must not be called while header block is being
* inflated. In other words, this function must be called after
@ -4841,7 +4856,7 @@ NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
*/
NGHTTP2_EXTERN int
nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t settings_hd_table_bufsize_max);
size_t settings_max_dynamic_table_size);
/**
* @enum

View File

@ -684,7 +684,7 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) {
}
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
size_t deflate_hd_table_bufsize_max,
size_t max_deflate_dynamic_table_size,
nghttp2_mem *mem) {
int rv;
rv = hd_context_init(&deflater->ctx, mem);
@ -694,14 +694,14 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
hd_map_init(&deflater->map);
if (deflate_hd_table_bufsize_max < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) {
if (max_deflate_dynamic_table_size < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) {
deflater->notify_table_size_change = 1;
deflater->ctx.hd_table_bufsize_max = deflate_hd_table_bufsize_max;
deflater->ctx.hd_table_bufsize_max = max_deflate_dynamic_table_size;
} else {
deflater->notify_table_size_change = 0;
}
deflater->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max;
deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size;
deflater->min_hd_table_bufsize_max = UINT32_MAX;
return 0;
@ -1225,9 +1225,9 @@ static void hd_context_shrink_table_size(nghttp2_hd_context *context,
}
}
int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
size_t settings_hd_table_bufsize_max) {
size_t next_bufsize = nghttp2_min(settings_hd_table_bufsize_max,
int nghttp2_hd_deflate_change_table_size(
nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) {
size_t next_bufsize = nghttp2_min(settings_max_dynamic_table_size,
deflater->deflate_hd_table_bufsize_max);
deflater->ctx.hd_table_bufsize_max = next_bufsize;
@ -1241,8 +1241,8 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
return 0;
}
int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
size_t settings_hd_table_bufsize_max) {
int nghttp2_hd_inflate_change_table_size(
nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) {
switch (inflater->state) {
case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
case NGHTTP2_HD_STATE_INFLATE_START:
@ -1258,16 +1258,16 @@ int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
strictly smaller than the current negotiated maximum size,
encoder must send dynamic table size update. In other cases, we
cannot expect it to do so. */
if (inflater->ctx.hd_table_bufsize_max > settings_hd_table_bufsize_max) {
if (inflater->ctx.hd_table_bufsize_max > settings_max_dynamic_table_size) {
inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE;
/* Remember minimum value, and validate that encoder sends the
value less than or equal to this. */
inflater->min_hd_table_bufsize_max = settings_hd_table_bufsize_max;
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
}
inflater->settings_hd_table_bufsize_max = settings_hd_table_bufsize_max;
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
inflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max;
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
hd_context_shrink_table_size(&inflater->ctx, NULL);
return 0;

View File

@ -288,7 +288,7 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
/*
* Initializes |deflater| for deflating name/values pairs.
*
* The encoder only uses up to |deflate_hd_table_bufsize_max| bytes
* The encoder only uses up to |max_deflate_dynamic_table_size| bytes
* for header table even if the larger value is specified later in
* nghttp2_hd_change_table_size().
*
@ -299,7 +299,7 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
* Out of memory.
*/
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
size_t deflate_hd_table_bufsize_max,
size_t max_deflate_dynamic_table_size,
nghttp2_mem *mem);
/*

View File

@ -101,3 +101,9 @@ void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH;
option->max_send_header_block_length = val;
}
void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE;
option->max_deflate_dynamic_table_size = val;
}

View File

@ -64,6 +64,7 @@ typedef enum {
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
} nghttp2_option_flag;
/**
@ -74,6 +75,10 @@ struct nghttp2_option {
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
*/
size_t max_send_header_block_length;
/**
* NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE
*/
size_t max_deflate_dynamic_table_size;
/**
* Bitwise OR of nghttp2_option_flag to determine that which fields
* are specified.

View File

@ -390,6 +390,8 @@ static int session_new(nghttp2_session **session_ptr,
const nghttp2_option *option, nghttp2_mem *mem) {
int rv;
size_t nbuffer;
size_t max_deflate_dynamic_table_size =
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
if (mem == NULL) {
mem = nghttp2_mem_default();
@ -407,19 +409,6 @@ static int session_new(nghttp2_session **session_ptr,
/* next_stream_id is initialized in either
nghttp2_session_client_new2 or nghttp2_session_server_new2 */
rv = nghttp2_hd_deflate_init(&(*session_ptr)->hd_deflater, mem);
if (rv != 0) {
goto fail_hd_deflater;
}
rv = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, mem);
if (rv != 0) {
goto fail_hd_inflater;
}
rv = nghttp2_map_init(&(*session_ptr)->streams, mem);
if (rv != 0) {
goto fail_map;
}
nghttp2_stream_init(&(*session_ptr)->root, 0, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_STREAM_IDLE, NGHTTP2_DEFAULT_WEIGHT, 0, 0, NULL,
mem);
@ -502,6 +491,24 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->max_send_header_block_length =
option->max_send_header_block_length;
}
if (option->opt_set_mask & NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE) {
max_deflate_dynamic_table_size = option->max_deflate_dynamic_table_size;
}
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
max_deflate_dynamic_table_size, mem);
if (rv != 0) {
goto fail_hd_deflater;
}
rv = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, mem);
if (rv != 0) {
goto fail_hd_inflater;
}
rv = nghttp2_map_init(&(*session_ptr)->streams, mem);
if (rv != 0) {
goto fail_map;
}
nbuffer = ((*session_ptr)->max_send_header_block_length +

View File

@ -96,6 +96,7 @@ Config::Config()
num_worker(1),
max_concurrent_streams(100),
header_table_size(-1),
encoder_header_table_size(-1),
window_bits(-1),
connection_window_bits(-1),
port(0),
@ -231,6 +232,7 @@ public:
config_(config),
ssl_ctx_(ssl_ctx),
callbacks_(nullptr),
option_(nullptr),
next_session_id_(1),
tstamp_cached_(ev_now(loop)),
cached_date_(util::http_date(tstamp_cached_)) {
@ -238,6 +240,13 @@ public:
fill_callback(callbacks_, config_);
nghttp2_option_new(&option_);
if (config_->encoder_header_table_size != -1) {
nghttp2_option_set_max_deflate_dynamic_table_size(
option_, config_->encoder_header_table_size);
}
ev_timer_init(&release_fd_timer_, release_fd_cb, 0., RELEASE_FD_TIMEOUT);
release_fd_timer_.data = this;
}
@ -246,6 +255,7 @@ public:
for (auto handler : handlers_) {
delete handler;
}
nghttp2_option_del(option_);
nghttp2_session_callbacks_del(callbacks_);
}
void add_handler(Http2Handler *handler) { handlers_.insert(handler); }
@ -283,6 +293,7 @@ public:
return session_id;
}
const nghttp2_session_callbacks *get_callbacks() const { return callbacks_; }
const nghttp2_option *get_option() const { return option_; }
void accept_connection(int fd) {
util::make_socket_nodelay(fd);
SSL *ssl = nullptr;
@ -408,6 +419,7 @@ private:
const Config *config_;
SSL_CTX *ssl_ctx_;
nghttp2_session_callbacks *callbacks_;
nghttp2_option *option_;
ev_timer release_fd_timer_;
int64_t next_session_id_;
ev_tstamp tstamp_cached_;
@ -825,7 +837,8 @@ int Http2Handler::on_write() { return write_(*this); }
int Http2Handler::connection_made() {
int r;
r = nghttp2_session_server_new(&session_, sessions_->get_callbacks(), this);
r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
sessions_->get_option());
if (r != 0) {
return r;

View File

@ -69,6 +69,7 @@ struct Config {
size_t num_worker;
size_t max_concurrent_streams;
ssize_t header_table_size;
ssize_t encoder_header_table_size;
int window_bits;
int connection_window_bits;
uint16_t port;

View File

@ -95,6 +95,7 @@ constexpr auto anchors = std::array<Anchor, 5>{{
Config::Config()
: header_table_size(-1),
min_header_table_size(std::numeric_limits<uint32_t>::max()),
encoder_header_table_size(-1),
padding(0),
max_concurrent_streams(100),
peer_max_concurrent_streams(100),
@ -2619,6 +2620,11 @@ Options:
the last value, that minimum value is set in SETTINGS
frame payload before the last value, to simulate
multiple header table size change.
--encoder-header-table-size=<SIZE>
Specify encoder header table size. The decoder (server)
specifies the maximum dynamic table size it accepts.
Then the negotiated dynamic table size is the minimum of
this option value and the value which server specified.
-b, --padding=<N>
Add at most <N> bytes to a frame payload as padding.
Specify 0 to disable padding.
@ -2695,6 +2701,7 @@ int main(int argc, char **argv) {
{"no-push", no_argument, &flag, 11},
{"max-concurrent-streams", required_argument, &flag, 12},
{"expect-continue", no_argument, &flag, 13},
{"encoder-header-table-size", required_argument, &flag, 14},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "M:Oab:c:d:gm:np:r:hH:vst:uw:W:",
@ -2813,16 +2820,21 @@ int main(int argc, char **argv) {
case 'm':
config.multiply = strtoul(optarg, nullptr, 10);
break;
case 'c':
errno = 0;
config.header_table_size = util::parse_uint_with_unit(optarg);
if (config.header_table_size == -1) {
case 'c': {
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
std::cerr << "-c: Bad option value: " << optarg << std::endl;
exit(EXIT_FAILURE);
}
config.min_header_table_size =
std::min(config.min_header_table_size, config.header_table_size);
if (n > std::numeric_limits<uint32_t>::max()) {
std::cerr << "-c: Value too large. It should be less than or equal to "
<< std::numeric_limits<uint32_t>::max() << std::endl;
exit(EXIT_FAILURE);
}
config.header_table_size = n;
config.min_header_table_size = std::min(config.min_header_table_size, n);
break;
}
case '?':
util::show_candidates(argv[optind - 1], long_options);
exit(EXIT_FAILURE);
@ -2896,6 +2908,23 @@ int main(int argc, char **argv) {
// expect-continue option
config.expect_continue = true;
break;
case 14: {
// encoder-header-table-size option
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
std::cerr << "--encoder-header-table-size: Bad option value: "
<< optarg << std::endl;
exit(EXIT_FAILURE);
}
if (n > std::numeric_limits<uint32_t>::max()) {
std::cerr << "--encoder-header-table-size: Value too large. It "
"should be less than or equal to "
<< std::numeric_limits<uint32_t>::max() << std::endl;
exit(EXIT_FAILURE);
}
config.encoder_header_table_size = n;
break;
}
}
break;
default:
@ -2916,6 +2945,11 @@ int main(int argc, char **argv) {
nghttp2_option_set_peer_max_concurrent_streams(
config.http2_option, config.peer_max_concurrent_streams);
if (config.encoder_header_table_size != -1) {
nghttp2_option_set_max_deflate_dynamic_table_size(
config.http2_option, config.encoder_header_table_size);
}
struct sigaction act {};
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);

View File

@ -72,6 +72,7 @@ struct Config {
nghttp2_option *http2_option;
int64_t header_table_size;
int64_t min_header_table_size;
int64_t encoder_header_table_size;
size_t padding;
size_t max_concurrent_streams;
ssize_t peer_max_concurrent_streams;

View File

@ -124,6 +124,11 @@ Options:
--no-tls Disable SSL/TLS.
-c, --header-table-size=<SIZE>
Specify decoder header table size.
--encoder-header-table-size=<SIZE>
Specify encoder header table size. The decoder (client)
specifies the maximum dynamic table size it accepts.
Then the negotiated dynamic table size is the minimum of
this option value and the value which client specified.
--color Force colored log output.
-p, --push=<PATH>=<PUSH_PATH,...>
Push resources <PUSH_PATH>s when <PATH> is requested.
@ -219,6 +224,7 @@ int main(int argc, char **argv) {
{"echo-upload", no_argument, &flag, 8},
{"mime-types-file", required_argument, &flag, 9},
{"no-content-length", no_argument, &flag, 10},
{"encoder-header-table-size", required_argument, &flag, 11},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:w:W:", long_options,
@ -276,14 +282,20 @@ int main(int argc, char **argv) {
case 'v':
config.verbose = true;
break;
case 'c':
errno = 0;
config.header_table_size = util::parse_uint_with_unit(optarg);
if (config.header_table_size == -1) {
case 'c': {
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
std::cerr << "-c: Bad option value: " << optarg << std::endl;
exit(EXIT_FAILURE);
}
if (n > std::numeric_limits<uint32_t>::max()) {
std::cerr << "-c: Value too large. It should be less than or equal to "
<< std::numeric_limits<uint32_t>::max() << std::endl;
exit(EXIT_FAILURE);
}
config.header_table_size = n;
break;
}
case 'p':
if (parse_push_config(config, optarg) != 0) {
std::cerr << "-p: Bad option value: " << optarg << std::endl;
@ -375,6 +387,23 @@ int main(int argc, char **argv) {
// no-content-length option
config.no_content_length = true;
break;
case 11: {
// encoder-header-table-size option
auto n = util::parse_uint_with_unit(optarg);
if (n == -1) {
std::cerr << "--encoder-header-table-size: Bad option value: "
<< optarg << std::endl;
exit(EXIT_FAILURE);
}
if (n > std::numeric_limits<uint32_t>::max()) {
std::cerr << "--encoder-header-table-size: Value too large. It "
"should be less than or equal to "
<< std::numeric_limits<uint32_t>::max() << std::endl;
exit(EXIT_FAILURE);
}
config.encoder_header_table_size = n;
break;
}
}
break;
default:

View File

@ -1345,14 +1345,21 @@ void fill_default_config(Config *config) {
upstreamconf.connection_window_size = 64_k - 1;
upstreamconf.max_concurrent_streams = 100;
upstreamconf.encoder_dynamic_table_size = 4_k;
upstreamconf.decoder_dynamic_table_size = 4_k;
nghttp2_option_new(&upstreamconf.option);
nghttp2_option_set_no_auto_window_update(upstreamconf.option, 1);
nghttp2_option_set_no_recv_client_magic(upstreamconf.option, 1);
nghttp2_option_set_max_deflate_dynamic_table_size(
upstreamconf.option, upstreamconf.encoder_dynamic_table_size);
// For API endpoint, we enable automatic window update. This is
// because we are a sink.
nghttp2_option_new(&upstreamconf.alt_mode_option);
nghttp2_option_set_no_recv_client_magic(upstreamconf.alt_mode_option, 1);
nghttp2_option_set_max_deflate_dynamic_table_size(
upstreamconf.alt_mode_option, upstreamconf.encoder_dynamic_table_size);
}
{
@ -1367,9 +1374,14 @@ void fill_default_config(Config *config) {
downstreamconf.connection_window_size = (1u << 31) - 1;
downstreamconf.max_concurrent_streams = 100;
downstreamconf.encoder_dynamic_table_size = 4_k;
downstreamconf.decoder_dynamic_table_size = 4_k;
nghttp2_option_new(&downstreamconf.option);
nghttp2_option_set_no_auto_window_update(downstreamconf.option, 1);
nghttp2_option_set_peer_max_concurrent_streams(downstreamconf.option, 100);
nghttp2_option_set_max_deflate_dynamic_table_size(
downstreamconf.option, downstreamconf.encoder_dynamic_table_size);
}
auto &loggingconf = config->logging;
@ -2053,6 +2065,36 @@ HTTP/2 and SPDY:
be adjusted using --frontend-http2-window-size option as
well. This option is only effective on recent Linux
platform.
--frontend-http2-encoder-dynamic-table-size=<SIZE>
Specify the maximum dynamic table size of HPACK encoder
in the frontend HTTP/2 connection. The decoder (client)
specifies the maximum dynamic table size it accepts.
Then the negotiated dynamic table size is the minimum of
this option value and the value which client specified.
Default: )"
<< util::utos_unit(
get_config()->http2.upstream.encoder_dynamic_table_size) << R"(
--frontend-http2-decoder-dynamic-table-size=<SIZE>
Specify the maximum dynamic table size of HPACK decoder
in the frontend HTTP/2 connection.
Default: )"
<< util::utos_unit(
get_config()->http2.upstream.decoder_dynamic_table_size) << R"(
--backend-http2-encoder-dynamic-table-size=<SIZE>
Specify the maximum dynamic table size of HPACK encoder
in the backend HTTP/2 connection. The decoder (backend)
specifies the maximum dynamic table size it accepts.
Then the negotiated dynamic table size is the minimum of
this option value and the value which backend specified.
Default: )"
<< util::utos_unit(
get_config()->http2.downstream.encoder_dynamic_table_size) << R"(
--backend-http2-decoder-dynamic-table-size=<SIZE>
Specify the maximum dynamic table size of HPACK decoder
in the backend HTTP/2 connection.
Default: )"
<< util::utos_unit(
get_config()->http2.downstream.decoder_dynamic_table_size) << R"(
Mode:
(default mode)
@ -2875,6 +2917,14 @@ int main(int argc, char **argv) {
134},
{SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE.c_str(),
required_argument, &flag, 135},
{SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
required_argument, &flag, 136},
{SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
required_argument, &flag, 137},
{SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE.c_str(),
required_argument, &flag, 138},
{SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE.c_str(),
required_argument, &flag, 139},
{nullptr, 0, nullptr, 0}};
int option_index = 0;
@ -3512,6 +3562,28 @@ int main(int argc, char **argv) {
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE,
StringRef{optarg});
break;
case 136:
// --frontend-http2-encoder-dynamic-table-size
cmdcfgs.emplace_back(
SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
StringRef{optarg});
break;
case 137:
// --frontend-http2-decoder-dynamic-table-size
cmdcfgs.emplace_back(
SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
StringRef{optarg});
break;
case 138:
// --backend-http2-encoder-dynamic-table-size
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
StringRef{optarg});
break;
case 139:
// --backend-http2-decoder-dynamic-table-size
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
StringRef{optarg});
break;
default:
break;
}

View File

@ -1733,9 +1733,29 @@ int option_lookup_token(const char *name, size_t namelen) {
break;
}
break;
case 40:
switch (name[39]) {
case 'e':
if (util::strieq_l("backend-http2-decoder-dynamic-table-siz", name, 39)) {
return SHRPX_OPTID_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE;
}
if (util::strieq_l("backend-http2-encoder-dynamic-table-siz", name, 39)) {
return SHRPX_OPTID_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE;
}
break;
}
break;
case 41:
switch (name[40]) {
case 'e':
if (util::strieq_l("frontend-http2-decoder-dynamic-table-siz", name,
40)) {
return SHRPX_OPTID_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE;
}
if (util::strieq_l("frontend-http2-encoder-dynamic-table-siz", name,
40)) {
return SHRPX_OPTID_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE;
}
if (util::strieq_l("frontend-http2-optimize-write-buffer-siz", name,
40)) {
return SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE;
@ -2773,6 +2793,38 @@ int parse_config(Config *config, int optid, const StringRef &opt,
}
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE:
if (parse_uint_with_unit(&config->http2.upstream.encoder_dynamic_table_size,
opt, optarg) != 0) {
return -1;
}
nghttp2_option_set_max_deflate_dynamic_table_size(
config->http2.upstream.option,
config->http2.upstream.encoder_dynamic_table_size);
nghttp2_option_set_max_deflate_dynamic_table_size(
config->http2.upstream.alt_mode_option,
config->http2.upstream.encoder_dynamic_table_size);
return 0;
case SHRPX_OPTID_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE:
return parse_uint_with_unit(
&config->http2.upstream.decoder_dynamic_table_size, opt, optarg);
case SHRPX_OPTID_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE:
if (parse_uint_with_unit(
&config->http2.downstream.encoder_dynamic_table_size, opt,
optarg) != 0) {
return -1;
}
nghttp2_option_set_max_deflate_dynamic_table_size(
config->http2.downstream.option,
config->http2.downstream.encoder_dynamic_table_size);
return 0;
case SHRPX_OPTID_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE:
return parse_uint_with_unit(
&config->http2.downstream.decoder_dynamic_table_size, opt, optarg);
case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored";

View File

@ -299,6 +299,14 @@ constexpr auto SHRPX_OPT_BACKEND_HTTP2_WINDOW_SIZE =
StringRef::from_lit("backend-http2-window-size");
constexpr auto SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE =
StringRef::from_lit("backend-http2-connection-window-size");
constexpr auto SHRPX_OPT_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE =
StringRef::from_lit("frontend-http2-encoder-dynamic-table-size");
constexpr auto SHRPX_OPT_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE =
StringRef::from_lit("frontend-http2-decoder-dynamic-table-size");
constexpr auto SHRPX_OPT_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE =
StringRef::from_lit("backend-http2-encoder-dynamic-table-size");
constexpr auto SHRPX_OPT_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE =
StringRef::from_lit("backend-http2-decoder-dynamic-table-size");
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
@ -595,9 +603,11 @@ struct Http2Config {
nghttp2_option *option;
nghttp2_option *alt_mode_option;
nghttp2_session_callbacks *callbacks;
size_t max_concurrent_streams;
size_t encoder_dynamic_table_size;
size_t decoder_dynamic_table_size;
int32_t window_size;
int32_t connection_window_size;
size_t max_concurrent_streams;
bool optimize_write_buffer_size;
bool optimize_window_size;
} upstream;
@ -607,6 +617,8 @@ struct Http2Config {
} timeout;
nghttp2_option *option;
nghttp2_session_callbacks *callbacks;
size_t encoder_dynamic_table_size;
size_t decoder_dynamic_table_size;
int32_t window_size;
int32_t connection_window_size;
size_t max_concurrent_streams;
@ -795,6 +807,8 @@ enum {
SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_SIZE,
SHRPX_OPTID_BACKEND_HTTP2_CONNECTIONS_PER_WORKER,
SHRPX_OPTID_BACKEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
SHRPX_OPTID_BACKEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
SHRPX_OPTID_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS,
SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT,
SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS,
@ -832,8 +846,10 @@ enum {
SHRPX_OPTID_FRONTEND_FRAME_DEBUG,
SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
SHRPX_OPTID_FRONTEND_HTTP2_CONNECTION_WINDOW_SIZE,
SHRPX_OPTID_FRONTEND_HTTP2_DECODER_DYNAMIC_TABLE_SIZE,
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_REQUEST_HEADER,
SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER,
SHRPX_OPTID_FRONTEND_HTTP2_ENCODER_DYNAMIC_TABLE_SIZE,
SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS,
SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WINDOW_SIZE,
SHRPX_OPTID_FRONTEND_HTTP2_OPTIMIZE_WRITE_BUFFER_SIZE,

View File

@ -1569,7 +1569,7 @@ int Http2Session::connection_made() {
return -1;
}
std::array<nghttp2_settings_entry, 3> entry;
std::array<nghttp2_settings_entry, 4> entry;
size_t nentry = 2;
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
entry[0].value = http2conf.downstream.max_concurrent_streams;
@ -1583,6 +1583,13 @@ int Http2Session::connection_made() {
++nentry;
}
if (http2conf.downstream.decoder_dynamic_table_size !=
NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) {
entry[nentry].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
entry[nentry].value = http2conf.downstream.decoder_dynamic_table_size;
++nentry;
}
rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
nentry);
if (rv != 0) {

View File

@ -939,7 +939,9 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
flow_control_ = true;
// TODO Maybe call from outside?
std::array<nghttp2_settings_entry, 2> entry;
std::array<nghttp2_settings_entry, 3> entry;
size_t nentry = 2;
entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
entry[0].value = http2conf.upstream.max_concurrent_streams;
@ -950,8 +952,15 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
entry[1].value = http2conf.upstream.window_size;
}
if (http2conf.upstream.decoder_dynamic_table_size !=
NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) {
entry[nentry].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
entry[nentry].value = http2conf.upstream.decoder_dynamic_table_size;
++nentry;
}
rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
entry.size());
nentry);
if (rv != 0) {
ULOG(ERROR, this) << "nghttp2_submit_settings() returned error: "
<< nghttp2_strerror(rv);

View File

@ -6666,33 +6666,45 @@ void test_nghttp2_session_set_option(void) {
nghttp2_session *session;
nghttp2_session_callbacks callbacks;
nghttp2_option *option;
nghttp2_option_new(&option);
nghttp2_option_set_no_auto_window_update(option, 1);
nghttp2_hd_deflater *deflater;
int rv;
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
callbacks.send_callback = null_send_callback;
/* Test for nghttp2_option_set_no_auto_window_update */
nghttp2_option_new(&option);
nghttp2_option_set_no_auto_window_update(option, 1);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE);
nghttp2_session_del(session);
nghttp2_option_del(option);
/* Test for nghttp2_option_set_peer_max_concurrent_streams */
nghttp2_option_new(&option);
nghttp2_option_set_peer_max_concurrent_streams(option, 100);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
CU_ASSERT(100 == session->remote_settings.max_concurrent_streams);
nghttp2_session_del(session);
nghttp2_option_del(option);
/* Test for nghttp2_option_set_max_reserved_remote_streams */
nghttp2_option_new(&option);
nghttp2_option_set_max_reserved_remote_streams(option, 99);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
CU_ASSERT(99 == session->max_incoming_reserved_streams);
nghttp2_session_del(session);
nghttp2_option_del(option);
/* Test for nghttp2_option_set_no_auto_ping_ack */
nghttp2_option_new(&option);
nghttp2_option_set_no_auto_ping_ack(option, 1);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
@ -6700,7 +6712,27 @@ void test_nghttp2_session_set_option(void) {
CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_PING_ACK);
nghttp2_session_del(session);
nghttp2_option_del(option);
/* Test for nghttp2_option_set_max_deflate_dynamic_table_size */
nghttp2_option_new(&option);
nghttp2_option_set_max_deflate_dynamic_table_size(option, 0);
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
deflater = &session->hd_deflater;
rv = nghttp2_submit_request(session, NULL, reqnv, ARRLEN(reqnv), NULL, NULL);
CU_ASSERT(1 == rv);
rv = nghttp2_session_send(session);
CU_ASSERT(0 == rv);
CU_ASSERT(0 == deflater->deflate_hd_table_bufsize_max);
CU_ASSERT(0 == deflater->ctx.hd_table_bufsize);
nghttp2_session_del(session);
nghttp2_option_del(option);
}