diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 8674ce26..e06a850b 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1550,6 +1550,38 @@ void* nghttp2_session_get_stream_user_data(nghttp2_session *session, */ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session); +/** + * @function + * + * Returns the number of DATA payload in bytes received without + * WINDOW_UPDATE transmission for the stream |stream_id|. The local + * (receive) window size can be adjusted by + * `nghttp2_submit_window_update()`. This function takes into account + * that and returns effective data length. In particular, if the + * local window size is reduced by submitting negative + * window_size_increment with `nghttp2_submit_window_update()`, this + * function returns the number of bytes less than actually received. + * + * If flow control is disabled for that stream, this function returns + * 0. + * + * This function returns -1 if it fails. + */ +int32_t nghttp2_session_get_stream_effective_recv_data_length +(nghttp2_session *session, int32_t stream_id); + +/** + * @function + * + * Returns the local (receive) window size. The local window size can + * be adjusted by `nghttp2_submit_window_update()`. This function + * takes into account that and returns effective window size. + * + * This function returns -1 if it fails. + */ +int32_t nghttp2_session_get_stream_effective_local_window_size +(nghttp2_session *session, int32_t stream_id); + /** * @function * diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index a6b5b843..9e1dc262 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3571,6 +3571,31 @@ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session) return nghttp2_pq_size(&session->ob_pq)+nghttp2_pq_size(&session->ob_ss_pq); } +int32_t nghttp2_session_get_stream_effective_recv_data_length +(nghttp2_session *session, int32_t stream_id) +{ + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if(stream == NULL) { + return -1; + } + if(stream->local_flow_control == 0) { + return 0; + } + return stream->recv_window_size; +} + +int32_t nghttp2_session_get_stream_effective_local_window_size +(nghttp2_session *session, int32_t stream_id) +{ + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, stream_id); + if(stream == NULL) { + return -1; + } + return stream->local_window_size; +} + int nghttp2_session_set_option(nghttp2_session *session, int optname, void *optval, size_t optlen) { diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 14dd3b14..513c0e21 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -723,12 +723,13 @@ int Http2Upstream::rst_stream(Downstream *downstream, return 0; } -int Http2Upstream::window_update(Downstream *downstream) +int Http2Upstream::window_update(Downstream *downstream, + int32_t window_size_increment) { int rv; rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, downstream->get_stream_id(), - downstream->get_recv_window_size()); + window_size_increment); downstream->set_recv_window_size(0); if(rv < NGHTTP2_ERR_FATAL) { ULOG(FATAL, this) << "nghttp2_submit_window_update() failed: " @@ -962,8 +963,15 @@ void Http2Upstream::pause_read(IOCtrlReason reason) int Http2Upstream::resume_read(IOCtrlReason reason, Downstream *downstream) { if(get_flow_control()) { - if(downstream->get_recv_window_size() >= get_initial_window_size()/2) { - window_update(downstream); + int32_t recv_length, window_size; + recv_length = nghttp2_session_get_stream_effective_recv_data_length + (session_, downstream->get_stream_id()); + window_size = nghttp2_session_get_stream_effective_local_window_size + (session_, downstream->get_stream_id()); + if(recv_length != -1 && window_size != -1) { + if(recv_length >= window_size / 2) { + window_update(downstream, recv_length); + } } } return send(); diff --git a/src/shrpx_http2_upstream.h b/src/shrpx_http2_upstream.h index e63dc27a..1d0c02a1 100644 --- a/src/shrpx_http2_upstream.h +++ b/src/shrpx_http2_upstream.h @@ -58,7 +58,7 @@ public: nghttp2_session* get_spdy_session(); int rst_stream(Downstream *downstream, nghttp2_error_code error_code); - int window_update(Downstream *downstream); + int window_update(Downstream *downstream, int32_t window_size_increment); int error_reply(Downstream *downstream, unsigned int status_code); virtual void pause_read(IOCtrlReason reason); diff --git a/src/shrpx_spdy_downstream_connection.cc b/src/shrpx_spdy_downstream_connection.cc index f79e8724..a9b76379 100644 --- a/src/shrpx_spdy_downstream_connection.cc +++ b/src/shrpx_spdy_downstream_connection.cc @@ -442,14 +442,20 @@ int SpdyDownstreamConnection::resume_read(IOCtrlReason reason) int rv; if(spdy_->get_state() == SpdySession::CONNECTED && spdy_->get_flow_control() && - downstream_ && downstream_->get_downstream_stream_id() != -1 && - recv_window_size_ >= spdy_->get_initial_window_size()/2) { - rv = spdy_->submit_window_update(this, recv_window_size_); - if(rv == -1) { - return -1; + downstream_ && downstream_->get_downstream_stream_id() != -1) { + int32_t recv_length, window_size; + recv_length = spdy_->get_stream_effective_recv_data_length + (downstream_->get_stream_id()); + window_size = spdy_->get_stream_effective_local_window_size + (downstream_->get_stream_id()); + if(recv_length >= window_size / 2) { + rv = spdy_->submit_window_update(this, recv_length); + if(rv == -1) { + return -1; + } + spdy_->notify(); + recv_window_size_ = 0; } - spdy_->notify(); - recv_window_size_ = 0; } return 0; } diff --git a/src/shrpx_spdy_session.cc b/src/shrpx_spdy_session.cc index a71a740a..5e2c73a4 100644 --- a/src/shrpx_spdy_session.cc +++ b/src/shrpx_spdy_session.cc @@ -618,6 +618,18 @@ int32_t SpdySession::get_initial_window_size() const return (1 << get_config()->spdy_downstream_window_bits) - 1; } +int32_t SpdySession::get_stream_effective_recv_data_length(int32_t stream_id) +{ + return nghttp2_session_get_stream_effective_recv_data_length + (session_, stream_id); +} + +int32_t SpdySession::get_stream_effective_local_window_size(int32_t stream_id) +{ + return nghttp2_session_get_stream_effective_local_window_size + (session_, stream_id); +} + bool SpdySession::get_flow_control() const { return flow_control_; diff --git a/src/shrpx_spdy_session.h b/src/shrpx_spdy_session.h index c1eb80ab..4e6d93b4 100644 --- a/src/shrpx_spdy_session.h +++ b/src/shrpx_spdy_session.h @@ -74,6 +74,9 @@ public: int32_t get_initial_window_size() const; + int32_t get_stream_effective_recv_data_length(int32_t stream_id); + int32_t get_stream_effective_local_window_size(int32_t stream_id); + bool get_flow_control() const; int resume_data(SpdyDownstreamConnection *dconn);