diff --git a/gennghttpxfun.py b/gennghttpxfun.py index fc161ad3..d2f04143 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -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 = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 8d70f630..5b10ea72 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -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= + 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 client specified. + Default: )" + << util::utos_unit( + get_config()->http2.upstream.encoder_dynamic_table_size) << R"( + --frontend-http2-decoder-dynamic-table-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= + 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 backend specified. + Default: )" + << util::utos_unit( + get_config()->http2.downstream.encoder_dynamic_table_size) << R"( + --backend-http2-decoder-dynamic-table-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; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 98c81d21..6196e6bf 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -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"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 1eeb9a36..a36210c0 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -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, diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 99179aad..e8650c02 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -1584,7 +1584,7 @@ int Http2Session::connection_made() { return -1; } - std::array entry; + std::array entry; size_t nentry = 2; entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; entry[0].value = http2conf.downstream.max_concurrent_streams; @@ -1598,6 +1598,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) { diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 565deced..34881254 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -939,7 +939,9 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) flow_control_ = true; // TODO Maybe call from outside? - std::array entry; + std::array 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);