diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index 3eccb04a4d6..d24c22830d8 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -3952,7 +3952,17 @@ HTTP/2 Configuration .. ts:cv:: CONFIG proxy.config.http2.initial_window_size_in INT 65535 :reloadable: - The initial window size for inbound connections. + The initial window size for inbound connection streams. + +.. ts:cv:: CONFIG proxy.config.http2.session_initial_window_size_in INT 0 + :reloadable: + + The initial window size for inbound connection session. HTTP/2 provides both + a per stream window and a session wide window. Each data byte exchanged decrements + the window of the associated stream and the session window. To allow for multiple + active streams, the session window should be larger than the stream window. + |TS| verifies that the session initial window is always at least as large as the + stream initial window. .. ts:cv:: CONFIG proxy.config.http2.max_frame_size INT 16384 :reloadable: diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index ad29c08506a..cbd638d6fde 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1314,6 +1314,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.http2.initial_window_size_in", RECD_INT, "65535", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , + {RECT_CONFIG, "proxy.config.http2.session_initial_window_size_in", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} + , {RECT_CONFIG, "proxy.config.http2.max_frame_size", RECD_INT, "16384", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} , {RECT_CONFIG, "proxy.config.http2.header_table_size", RECD_INT, "4096", RECU_DYNAMIC, RR_NULL, RECC_STR, "^[0-9]+$", RECA_NULL} diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc index 648609cbb80..de16a0abe11 100644 --- a/proxy/http2/HTTP2.cc +++ b/proxy/http2/HTTP2.cc @@ -786,6 +786,7 @@ uint32_t Http2::max_active_streams_in = 0; bool Http2::throttling = false; uint32_t Http2::stream_priority_enabled = 0; uint32_t Http2::initial_window_size = 65535; +uint32_t Http2::session_initial_window_size = 65535; uint32_t Http2::max_frame_size = 16384; uint32_t Http2::header_table_size = 4096; uint32_t Http2::max_header_list_size = 4294967295; @@ -816,6 +817,13 @@ Http2::init() REC_EstablishStaticConfigInt32U(max_active_streams_in, "proxy.config.http2.max_active_streams_in"); REC_EstablishStaticConfigInt32U(stream_priority_enabled, "proxy.config.http2.stream_priority_enabled"); REC_EstablishStaticConfigInt32U(initial_window_size, "proxy.config.http2.initial_window_size_in"); + REC_EstablishStaticConfigInt32U(session_initial_window_size, "proxy.config.http2.session_initial_window_size_in"); + + // The session window must be at least as big as the stream window + if (session_initial_window_size < initial_window_size) { + session_initial_window_size = initial_window_size; + } + REC_EstablishStaticConfigInt32U(max_frame_size, "proxy.config.http2.max_frame_size"); REC_EstablishStaticConfigInt32U(header_table_size, "proxy.config.http2.header_table_size"); REC_EstablishStaticConfigInt32U(max_header_list_size, "proxy.config.http2.max_header_list_size"); diff --git a/proxy/http2/HTTP2.h b/proxy/http2/HTTP2.h index d2eed22ffe3..9e04423a0dd 100644 --- a/proxy/http2/HTTP2.h +++ b/proxy/http2/HTTP2.h @@ -385,6 +385,7 @@ class Http2 static bool throttling; static uint32_t stream_priority_enabled; static uint32_t initial_window_size; + static uint32_t session_initial_window_size; static uint32_t max_frame_size; static uint32_t header_table_size; static uint32_t max_header_list_size; diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc index 66855433729..63c935452a8 100644 --- a/proxy/http2/Http2ConnectionState.cc +++ b/proxy/http2/Http2ConnectionState.cc @@ -1043,7 +1043,7 @@ void Http2ConnectionState::init(Http2ClientSession *ssn) { ua_session = ssn; - this->_server_rwnd = Http2::initial_window_size; + this->_server_rwnd = Http2::session_initial_window_size; local_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE); remote_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE); @@ -1076,8 +1076,10 @@ Http2ConnectionState::send_connection_preface() send_settings_frame(configured_settings); - if (server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) > HTTP2_INITIAL_WINDOW_SIZE) { - send_window_update_frame(0, server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE) - HTTP2_INITIAL_WINDOW_SIZE); + // If the session window size is non-default, send a window update right away + + if (Http2::session_initial_window_size > HTTP2_INITIAL_WINDOW_SIZE) { + send_window_update_frame(0, Http2::session_initial_window_size - HTTP2_INITIAL_WINDOW_SIZE); } } @@ -1419,7 +1421,7 @@ Http2ConnectionState::restart_streams() void Http2ConnectionState::restart_receiving(Http2Stream *stream) { - uint32_t initial_rwnd = this->server_settings.get(HTTP2_SETTINGS_INITIAL_WINDOW_SIZE); + uint32_t initial_rwnd = Http2::session_initial_window_size; uint32_t min_rwnd = std::min(initial_rwnd, this->server_settings.get(HTTP2_SETTINGS_MAX_FRAME_SIZE)); // Connection level WINDOW UPDATE @@ -1440,6 +1442,8 @@ Http2ConnectionState::restart_receiving(Http2Stream *stream) return; } + // Update the window size for the stream + initial_rwnd = Http2::initial_window_size; Http2WindowSize diff_size = initial_rwnd - std::max(static_cast(stream->server_rwnd()), data_size); stream->increment_server_rwnd(diff_size); this->send_window_update_frame(stream->get_id(), diff_size);