diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 278a8fe3..e83265f6 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2152,14 +2152,28 @@ int32_t nghttp2_session_get_effective_local_window_size * @function * * Returns the remote window size for a given stream |stream_id|. + * * This is the amount of flow-controlled payload (e.g., DATA) that the - * local endpoint can send without WINDOW_UPDATE. + * local endpoint can send without stream level WINDOW_UPDATE. There + * is also connection level flow control, so the effective size of + * payload that the local endpoint can actually send is + * min(`nghttp2_session_get_stream_remote_window_size()`, + * `nghttp2_session_get_remote_window_size()`). * * This function returns -1 if it fails. */ int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session* session, int32_t stream_id); +/** + * @function + * + * Returns the remote window size for a connection. + * + * This function always succeeds. + */ +int32_t nghttp2_session_get_remote_window_size(nghttp2_session* session); + /** * @function * diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 20fe0a0a..d4320acd 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -5812,8 +5812,8 @@ int32_t nghttp2_session_get_effective_local_window_size return session->local_window_size; } -int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session* session, - int32_t stream_id) +int32_t nghttp2_session_get_stream_remote_window_size +(nghttp2_session *session, int32_t stream_id) { nghttp2_stream *stream; @@ -5822,7 +5822,14 @@ int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session* session, return -1; } - return (int32_t)nghttp2_session_next_data_read(session, stream); + /* stream->remote_window_size can be negative when + SETTINGS_INITIAL_WINDOW_SIZE is changed. */ + return nghttp2_max(0, stream->remote_window_size); +} + +int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session) +{ + return session->remote_window_size; } uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, diff --git a/src/HttpServer.cc b/src/HttpServer.cc index dba97f52..e992b44a 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -1359,8 +1359,9 @@ int hd_on_frame_send_callback if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { remove_stream_write_timeout(stream); - } else if(nghttp2_session_get_stream_remote_window_size - (session, frame->hd.stream_id) == 0) { + } else if(std::min(nghttp2_session_get_stream_remote_window_size + (session, frame->hd.stream_id), + nghttp2_session_get_remote_window_size(session)) <= 0) { // If stream is blocked by flow control, enable write timeout. add_stream_read_timeout_if_pending(stream); add_stream_write_timeout(stream); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index c256bf12..d6894d79 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2201,6 +2201,13 @@ void test_nghttp2_session_on_settings_received(void) CU_ASSERT(16*1024 == stream1->remote_window_size); CU_ASSERT(-48*1024 == stream2->remote_window_size); + CU_ASSERT(16*1024 == + nghttp2_session_get_stream_remote_window_size(session, + stream1->stream_id)); + CU_ASSERT(0 == + nghttp2_session_get_stream_remote_window_size(session, + stream2->stream_id)); + nghttp2_frame_settings_free(&frame.settings); nghttp2_session_del(session);