diff --git a/src/h2load.cc b/src/h2load.cc index cad1f30b..4d795528 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -92,6 +92,8 @@ Config::Config() conn_active_timeout(0.), conn_inactivity_timeout(0.), no_tls_proto(PROTO_HTTP2), + header_table_size(4_k), + encoder_header_table_size(4_k), data_fd(-1), port(0), default_port(0), @@ -1585,6 +1587,27 @@ std::unique_ptr create_worker(uint32_t id, SSL_CTX *ssl_ctx, } } // namespace +namespace { +int parse_header_table_size(uint32_t &dst, const char *opt, + const char *optarg) { + auto n = util::parse_uint_with_unit(optarg); + if (n == -1) { + std::cerr << "--" << opt << ": Bad option value: " << optarg << std::endl; + return -1; + } + if (n > std::numeric_limits::max()) { + std::cerr << "--" << opt + << ": Value too large. It should be less than or equal to " + << std::numeric_limits::max() << std::endl; + return -1; + } + + dst = n; + + return 0; +} +} // namespace + namespace { void print_version(std::ostream &out) { out << "h2load nghttp2/" NGHTTP2_VERSION << std::endl; @@ -1755,6 +1778,15 @@ Options: --h1 Short hand for --npn-list=http/1.1 --no-tls-proto=http/1.1, which effectively force http/1.1 for both http and https URI. + --header-table-size= + Specify decoder header table size. + Default: )" << config.header_table_size << R"( + --encoder-header-table-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. + Default: )" << config.encoder_header_table_size << R"( -v, --verbose Output debug information. --version Display version information and exit. @@ -1762,6 +1794,9 @@ Options: -- + The argument is an integer and an optional unit (e.g., 10K is + 10 * 1024). Units are K, M and G (powers of 1024). + The argument is an integer and an optional unit (e.g., 1s is 1 second and 500ms is 500 milliseconds). Units are h, m, s or ms (hours, minutes, seconds and milliseconds, respectively). If a unit @@ -1803,6 +1838,8 @@ int main(int argc, char **argv) { {"npn-list", required_argument, &flag, 4}, {"rate-period", required_argument, &flag, 5}, {"h1", no_argument, &flag, 6}, + {"header-table-size", required_argument, &flag, 7}, + {"encoder-header-table-size", required_argument, &flag, 8}, {nullptr, 0, nullptr, 0}}; int option_index = 0; auto c = getopt_long(argc, argv, "hvW:c:d:m:n:p:t:w:H:i:r:T:N:B:", @@ -2003,6 +2040,20 @@ int main(int argc, char **argv) { util::parse_config_str_list(StringRef::from_lit("http/1.1")); config.no_tls_proto = Config::PROTO_HTTP1_1; break; + case 7: + // --header-table-size + if (parse_header_table_size(config.header_table_size, + "header-table-size", optarg) != 0) { + exit(EXIT_FAILURE); + } + break; + case 8: + // --encoder-header-table-size + if (parse_header_table_size(config.encoder_header_table_size, + "encoder-header-table-size", optarg) != 0) { + exit(EXIT_FAILURE); + } + break; } break; default: diff --git a/src/h2load.h b/src/h2load.h index 39737805..0b84d2a6 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -96,6 +96,8 @@ struct Config { PROTO_SPDY3_1, PROTO_HTTP1_1 } no_tls_proto; + uint32_t header_table_size; + uint32_t encoder_header_table_size; // file descriptor for upload data int data_fd; uint16_t port; diff --git a/src/h2load_http2_session.cc b/src/h2load_http2_session.cc index 0b780128..f7f63f17 100644 --- a/src/h2load_http2_session.cc +++ b/src/h2load_http2_session.cc @@ -206,21 +206,40 @@ void Http2Session::on_connect() { nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); - nghttp2_session_client_new(&session_, callbacks, client_); + nghttp2_option *opt; - std::array iv; + rv = nghttp2_option_new(&opt); + assert(rv == 0); + + auto config = client_->worker->config; + + if (config->encoder_header_table_size != NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) { + nghttp2_option_set_max_deflate_dynamic_table_size( + opt, config->encoder_header_table_size); + } + + nghttp2_session_client_new2(&session_, callbacks, client_, opt); + + nghttp2_option_del(opt); + + std::array iv; + size_t niv = 2; iv[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; iv[0].value = 0; iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; - iv[1].value = (1 << client_->worker->config->window_bits) - 1; + iv[1].value = (1 << config->window_bits) - 1; - rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, iv.data(), - iv.size()); + if (config->header_table_size != NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) { + iv[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[niv].value = config->header_table_size; + ++niv; + } + + rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, iv.data(), niv); assert(rv == 0); - auto connection_window = - (1 << client_->worker->config->connection_window_bits) - 1; + auto connection_window = (1 << config->connection_window_bits) - 1; nghttp2_session_set_local_window_size(session_, NGHTTP2_FLAG_NONE, 0, connection_window);