diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 27998498..2f72cb06 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -130,6 +130,8 @@ OPTIONS = [ "backend-connections-per-host", "error-page", "no-kqueue", + "frontend-http2-settings-timeout", + "backend-http2-settings-timeout", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 621e691f..e390af50 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1098,6 +1098,12 @@ void fill_default_config() { auto &http2conf = mod_config()->http2; { auto &upstreamconf = http2conf.upstream; + + { + auto &timeoutconf = upstreamconf.timeout; + timeoutconf.settings = 10_s; + } + // window bits for HTTP/2 and SPDY upstream connection per // stream. 2**16-1 = 64KiB-1, which is HTTP/2 default. Please note // that SPDY/3 default is 64KiB. @@ -1114,6 +1120,12 @@ void fill_default_config() { { auto &downstreamconf = http2conf.downstream; + + { + auto &timeoutconf = downstreamconf.timeout; + timeoutconf.settings = 10_s; + } + downstreamconf.window_bits = 16; downstreamconf.connection_window_bits = 30; downstreamconf.max_concurrent_streams = 100; @@ -1496,6 +1508,18 @@ Timeout: disables this feature. Default: )" << util::duration_str(get_config()->conn.listener.timeout.sleep) << R"( + --frontend-http2-setting-timeout= + Specify timeout before SETTINGS ACK is received from + client. + Default: )" + << util::duration_str(get_config()->http2.upstream.timeout.settings) + << R"( + --backend-http2-settings-timeout= + Specify timeout before SETTINGS ACK is received from + backend server. + Default: )" + << util::duration_str(get_config()->http2.downstream.timeout.settings) + << R"( SSL/TLS: --ciphers= @@ -2576,6 +2600,10 @@ int main(int argc, char **argv) { &flag, 121}, {SHRPX_OPT_ERROR_PAGE.c_str(), required_argument, &flag, 122}, {SHRPX_OPT_NO_KQUEUE.c_str(), no_argument, &flag, 123}, + {SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument, + &flag, 124}, + {SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument, + &flag, 125}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -3155,6 +3183,16 @@ int main(int argc, char **argv) { // --no-kqueue cmdcfgs.emplace_back(SHRPX_OPT_NO_KQUEUE, StringRef::from_lit("yes")); break; + case 124: + // --frontend-http2-settings-timeout + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT, + StringRef{optarg}); + break; + case 125: + // --backend-http2-settings-timeout + cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT, + StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index bcb0b50a..f8759918 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -937,6 +937,7 @@ enum { SHRPX_OPTID_BACKEND_HTTP2_CONNECTION_WINDOW_BITS, SHRPX_OPTID_BACKEND_HTTP2_CONNECTIONS_PER_WORKER, SHRPX_OPTID_BACKEND_HTTP2_MAX_CONCURRENT_STREAMS, + SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT, SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS, SHRPX_OPTID_BACKEND_IPV4, SHRPX_OPTID_BACKEND_IPV6, @@ -973,6 +974,7 @@ enum { SHRPX_OPTID_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER, SHRPX_OPTID_FRONTEND_HTTP2_MAX_CONCURRENT_STREAMS, SHRPX_OPTID_FRONTEND_HTTP2_READ_TIMEOUT, + SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT, SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS, SHRPX_OPTID_FRONTEND_NO_TLS, SHRPX_OPTID_FRONTEND_READ_TIMEOUT, @@ -1628,6 +1630,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_STRIP_INCOMING_X_FORWARDED_FOR; } break; + case 't': + if (util::strieq_l("backend-http2-settings-timeou", name, 29)) { + return SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT; + } + break; } break; case 31: @@ -1637,6 +1644,11 @@ int option_lookup_token(const char *name, size_t namelen) { return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS; } break; + case 't': + if (util::strieq_l("frontend-http2-settings-timeou", name, 30)) { + return SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT; + } + break; } break; case 32: @@ -2725,6 +2737,12 @@ int parse_config(const StringRef &opt, const StringRef &optarg, mod_config()->ev_loop_flags = ev_recommended_backends() & ~EVBACKEND_KQUEUE; return 0; + case SHRPX_OPTID_FRONTEND_HTTP2_SETTINGS_TIMEOUT: + return parse_duration(&mod_config()->http2.upstream.timeout.settings, opt, + optarg); + case SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT: + return parse_duration(&mod_config()->http2.downstream.timeout.settings, opt, + optarg); case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index f801a0ea..b16286f1 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -276,6 +276,10 @@ constexpr auto SHRPX_OPT_BACKEND_CONNECTIONS_PER_HOST = StringRef::from_lit("backend-connections-per-host"); constexpr auto SHRPX_OPT_ERROR_PAGE = StringRef::from_lit("error-page"); constexpr auto SHRPX_OPT_NO_KQUEUE = StringRef::from_lit("no-kqueue"); +constexpr auto SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT = + StringRef::from_lit("frontend-http2-settings-timeout"); +constexpr auto SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT = + StringRef::from_lit("backend-http2-settings-timeout"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -532,6 +536,9 @@ struct Http2Config { } dump; bool frame_debug; } debug; + struct { + ev_tstamp settings; + } timeout; nghttp2_option *option; nghttp2_session_callbacks *callbacks; size_t window_bits; @@ -539,6 +546,9 @@ struct Http2Config { size_t max_concurrent_streams; } upstream; struct { + struct { + ev_tstamp settings; + } timeout; nghttp2_option *option; nghttp2_session_callbacks *callbacks; size_t window_bits; diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 644e236e..ed311bca 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -755,7 +755,9 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, } // namespace void Http2Session::start_settings_timer() { - ev_timer_set(&settings_timer_, 10., 0.); + auto &downstreamconf = get_config()->http2.downstream; + + ev_timer_set(&settings_timer_, downstreamconf.timeout.settings, 0.); ev_timer_start(conn_.loop, &settings_timer_); } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 0021c1d3..f603bd04 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -895,7 +895,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) } // We wait for SETTINGS ACK at least 10 seconds. - ev_timer_init(&settings_timer_, settings_timeout_cb, 10., 0.); + ev_timer_init(&settings_timer_, settings_timeout_cb, + http2conf.upstream.timeout.settings, 0.); settings_timer_.data = this; diff --git a/src/shrpx_live_check.cc b/src/shrpx_live_check.cc index c700267e..fbfd7001 100644 --- a/src/shrpx_live_check.cc +++ b/src/shrpx_live_check.cc @@ -625,7 +625,9 @@ void LiveCheck::on_success() { int LiveCheck::noop() { return 0; } void LiveCheck::start_settings_timer() { - ev_timer_set(&settings_timer_, 10., 0.); + auto &downstreamconf = get_config()->http2.downstream; + + ev_timer_set(&settings_timer_, downstreamconf.timeout.settings, 0.); ev_timer_start(conn_.loop, &settings_timer_); }