Send WINDOW_UPDATE for ignored DATA bytes when manual flow control is enabled

Since we do not call on_data_chunk_recv_callback for ignored DATA
chunk, if nghttp2_option_set_no_auto_connection_window_update is used,
application may not have a chance to send connection WINDOW_UPDATE.
To fix this, we accumulate those received bytes, and if it exceeds
certain number, we automatically send connection-level WINDOW_UPDATE.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-07-02 21:20:40 +09:00
parent ed38dbf67a
commit 6da044cbb5
3 changed files with 37 additions and 0 deletions

View File

@ -3889,6 +3889,10 @@ static int session_update_recv_connection_window_size
session->recv_window_size); session->recv_window_size);
if(rv == 0) { if(rv == 0) {
session->recv_window_size = 0; session->recv_window_size = 0;
/* recv_ign_window_size keeps track of ignored DATA bytes
before any connection-level WINDOW_UPDATE therefore, we can
reset it here. */
session->recv_ign_window_size = 0;
} else { } else {
return rv; return rv;
} }
@ -5027,12 +5031,30 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
readlen, iframe->payloadleft)); readlen, iframe->payloadleft));
if(readlen > 0) { if(readlen > 0) {
session->recv_ign_window_size += readlen;
/* Update connection-level flow control window for ignored /* Update connection-level flow control window for ignored
DATA frame too */ DATA frame too */
rv = session_update_recv_connection_window_size(session, readlen); rv = session_update_recv_connection_window_size(session, readlen);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
if((session->opt_flags &
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE) &&
nghttp2_should_send_window_update
(session->local_window_size, session->recv_ign_window_size)) {
rv = nghttp2_session_add_window_update
(session, NGHTTP2_FLAG_NONE, 0, session->recv_ign_window_size);
if(nghttp2_is_fatal(rv)) {
return rv;
}
session->recv_window_size -= session->recv_ign_window_size;
session->recv_ign_window_size = 0;
}
} }
if(iframe->payloadleft) { if(iframe->payloadleft) {

View File

@ -200,6 +200,15 @@ struct nghttp2_session {
WINDOW_UPDATE. This could be negative after submitting negative WINDOW_UPDATE. This could be negative after submitting negative
value to WINDOW_UPDATE. */ value to WINDOW_UPDATE. */
int32_t recv_window_size; int32_t recv_window_size;
/* The number of bytes in ignored DATA frame received without
connection-level WINDOW_UPDATE. Since we do not call
on_data_chunk_recv_callback for ignored DATA chunk, if
nghttp2_option_set_no_auto_connection_window_update is used,
application may not have a chance to send connection
WINDOW_UPDATE. To fix this, we accumulate those received bytes,
and if it exceeds certain number, we automatically send
connection-level WINDOW_UPDATE. */
int32_t recv_ign_window_size;
/* The amount of recv_window_size cut using submitting negative /* The amount of recv_window_size cut using submitting negative
value to WINDOW_UPDATE */ value to WINDOW_UPDATE */
int32_t recv_reduction; int32_t recv_reduction;

View File

@ -348,6 +348,11 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
if(rv != 0) { if(rv != 0) {
return rv; return rv;
} }
/* recv_ign_window_size keeps track of ignored DATA bytes before
any connection-level WINDOW_UPDATE therefore, we can reset it
here. */
session->recv_ign_window_size = 0;
} else { } else {
stream = nghttp2_session_get_stream(session, stream_id); stream = nghttp2_session_get_stream(session, stream_id);
if(stream) { if(stream) {
@ -362,6 +367,7 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
return 0; return 0;
} }
} }
if(window_size_increment > 0) { if(window_size_increment > 0) {
return nghttp2_session_add_window_update(session, flags, stream_id, return nghttp2_session_add_window_update(session, flags, stream_id,
window_size_increment); window_size_increment);