diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 83311285..7bd255aa 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1063,12 +1063,19 @@ void nghttp2_session_del(nghttp2_session *session); */ typedef enum { /** - * This option prevents the library from sending WINDOW_UPDATE - * automatically. If this option is set, the application is + * This option prevents the library from sending WINDOW_UPDATE for a + * stream automatically. If this option is set, the application is * responsible for sending WINDOW_UPDATE using * `nghttp2_submit_window_update`. */ - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1, + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE = 1, + /** + * This option prevents the library from sending WINDOW_UPDATE for a + * connection automatically. If this option is set, the application + * is responsible for sending WINDOW_UPDATE with stream ID 0 using + * `nghttp2_submit_window_update`. + */ + NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 2 } nghttp2_opt; /** diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 39e4a56f..da932075 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1935,7 +1935,8 @@ static int nghttp2_update_local_initial_window_size_func return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, NGHTTP2_FLOW_CONTROL_ERROR); } - if(!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + if(!(arg->session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { if(nghttp2_should_send_window_update(stream->local_window_size, stream->recv_window_size)) { rv = nghttp2_session_add_window_update(arg->session, @@ -2651,8 +2652,8 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, /* * Accumulates received bytes |delta_size| for stream-level flow * control and decides whether to send WINDOW_UPDATE to that - * stream. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE - * will not be sent. + * stream. If NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE is set, + * WINDOW_UPDATE will not be sent. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2671,7 +2672,7 @@ static int nghttp2_session_update_recv_stream_window_size return nghttp2_session_add_rst_stream(session, stream->stream_id, NGHTTP2_ERR_FLOW_CONTROL); } - if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { /* We have to use local_settings here because it is the constraint the remote endpoint should honor. */ if(nghttp2_should_send_window_update(stream->local_window_size, @@ -2693,8 +2694,8 @@ static int nghttp2_session_update_recv_stream_window_size /* * Accumulates received bytes |delta_size| for connection-level flow * control and decides whether to send WINDOW_UPDATE to the - * connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, - * WINDOW_UPDATE will not be sent. + * connection. If NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE is + * set, WINDOW_UPDATE will not be sent. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2711,7 +2712,8 @@ static int nghttp2_session_update_recv_connection_window_size if(rv != 0) { return nghttp2_session_fail_session(session, NGHTTP2_ERR_FLOW_CONTROL); } - if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) { + if(!(session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE)) { if(nghttp2_should_send_window_update(session->local_window_size, session->recv_window_size)) { /* Use stream ID 0 to update connection-level flow control @@ -3094,18 +3096,26 @@ int nghttp2_session_set_option(nghttp2_session *session, int optname, void *optval, size_t optlen) { switch(optname) { - case NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE: + case NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE: + case NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE: { + int flag; + if(optname == NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE) { + flag = NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE; + } else { + flag = NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; + } if(optlen == sizeof(int)) { int intval = *(int*)optval; if(intval) { - session->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; + session->opt_flags |= flag; } else { - session->opt_flags &= ~NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; + session->opt_flags &= ~flag; } } else { return NGHTTP2_ERR_INVALID_ARGUMENT; } break; + } default: return NGHTTP2_ERR_INVALID_ARGUMENT; } diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 7eaf87a4..745f0c7f 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -42,7 +42,8 @@ * Option flags. */ typedef enum { - NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0 + NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0, + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1 } nghttp2_optmask; typedef struct { diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 343d68c1..574c0ba6 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -241,7 +241,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, if(rv != 0) { return rv; } - if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && + if(!(session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE) && window_size_increment < 0 && nghttp2_should_send_window_update(session->local_window_size, session->recv_window_size)) { @@ -260,7 +261,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, if(rv != 0) { return rv; } - if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) && + if(!(session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE) && window_size_increment < 0 && nghttp2_should_send_window_update(stream->local_window_size, stream->recv_window_size)) { diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index dbc250b4..692b9215 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -403,8 +403,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) flow_control_ = true; initial_window_size_ = (1 << get_config()->spdy_upstream_window_bits) - 1; rv = nghttp2_session_set_option(session_, - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, &val, - sizeof(val)); + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE, + &val, sizeof(val)); assert(rv == 0); // TODO Maybe call from outside? @@ -418,9 +418,10 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) rv = nghttp2_submit_settings (session_, entry, sizeof(entry)/sizeof(nghttp2_settings_entry)); assert(rv == 0); - // Disable connection-level flow control - rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_END_FLOW_CONTROL, - 0, 0); + // Set large connection-level window size to effectively disable + // connection-level flow control. + rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, + 0, 1000000007); assert(rv == 0); } diff --git a/src/shrpx_spdy_session.cc b/src/shrpx_spdy_session.cc index 7f8daaa2..453db1e1 100644 --- a/src/shrpx_spdy_session.cc +++ b/src/shrpx_spdy_session.cc @@ -1057,8 +1057,8 @@ int SpdySession::on_connect() int val = 1; flow_control_ = true; rv = nghttp2_session_set_option(session_, - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, &val, - sizeof(val)); + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE, + &val, sizeof(val)); assert(rv == 0); nghttp2_settings_entry entry[2]; @@ -1073,9 +1073,10 @@ int SpdySession::on_connect() if(rv != 0) { return -1; } - // Disable connection-level flow control - rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_END_FLOW_CONTROL, - 0, 0); + // Set large connection-level window size to effectively disable + // connection-level flow control. + rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, + 0, 1000000007); if(rv != 0) { return -1; } diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index ebe92ed5..bb18d6f6 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3091,17 +3091,20 @@ void test_nghttp2_session_set_option(void) intval = 1; CU_ASSERT(0 == - nghttp2_session_set_option(session, - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, - &intval, sizeof(intval))); - CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE); + nghttp2_session_set_option + (session, + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE, + &intval, sizeof(intval))); + CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE); intval = 0; CU_ASSERT(0 == - nghttp2_session_set_option(session, - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, - &intval, sizeof(intval))); - CU_ASSERT((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) == 0); + nghttp2_session_set_option + (session, + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE, + &intval, sizeof(intval))); + CU_ASSERT((session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE) == 0); CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == nghttp2_session_set_option(session, 0, /* 0 is invalid optname */ @@ -3109,9 +3112,19 @@ void test_nghttp2_session_set_option(void) charval = 1; CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == - nghttp2_session_set_option(session, - NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, - &charval, sizeof(charval))); + nghttp2_session_set_option + (session, + NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE, + &charval, sizeof(charval))); + + intval = 1; + CU_ASSERT(0 == + nghttp2_session_set_option + (session, + NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE, + &intval, sizeof(intval))); + CU_ASSERT(session->opt_flags & + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE); nghttp2_session_del(session); }