Allow disabling auto WINDOW_UPDATE for connection and stream individually

Now NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is split into 2 options:
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE and
NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE.
This is preparation for the upcoming removal of END_FLOW_CONTROL
flag. For nghttpx, instead of using END_FLOW_CONTROL to disable
connection-level flow control, increase window size by large
enough value, which is friendly way to current chromium
implementation.
This commit is contained in:
Tatsuhiro Tsujikawa 2013-08-09 01:23:39 +09:00
parent b979d2e8d2
commit 19377fb3cd
7 changed files with 72 additions and 37 deletions

View File

@ -1063,12 +1063,19 @@ void nghttp2_session_del(nghttp2_session *session);
*/ */
typedef enum { typedef enum {
/** /**
* This option prevents the library from sending WINDOW_UPDATE * This option prevents the library from sending WINDOW_UPDATE for a
* automatically. If this option is set, the application is * stream automatically. If this option is set, the application is
* responsible for sending WINDOW_UPDATE using * responsible for sending WINDOW_UPDATE using
* `nghttp2_submit_window_update`. * `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; } nghttp2_opt;
/** /**

View File

@ -1935,7 +1935,8 @@ static int nghttp2_update_local_initial_window_size_func
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
NGHTTP2_FLOW_CONTROL_ERROR); 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, if(nghttp2_should_send_window_update(stream->local_window_size,
stream->recv_window_size)) { stream->recv_window_size)) {
rv = nghttp2_session_add_window_update(arg->session, 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 * Accumulates received bytes |delta_size| for stream-level flow
* control and decides whether to send WINDOW_UPDATE to that * control and decides whether to send WINDOW_UPDATE to that
* stream. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE * stream. If NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE is set,
* will not be sent. * WINDOW_UPDATE will not be sent.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * 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, return nghttp2_session_add_rst_stream(session, stream->stream_id,
NGHTTP2_ERR_FLOW_CONTROL); 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 /* We have to use local_settings here because it is the constraint
the remote endpoint should honor. */ the remote endpoint should honor. */
if(nghttp2_should_send_window_update(stream->local_window_size, 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 * Accumulates received bytes |delta_size| for connection-level flow
* control and decides whether to send WINDOW_UPDATE to the * control and decides whether to send WINDOW_UPDATE to the
* connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, * connection. If NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE is
* WINDOW_UPDATE will not be sent. * set, WINDOW_UPDATE will not be sent.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
@ -2711,7 +2712,8 @@ static int nghttp2_session_update_recv_connection_window_size
if(rv != 0) { if(rv != 0) {
return nghttp2_session_fail_session(session, NGHTTP2_ERR_FLOW_CONTROL); 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, if(nghttp2_should_send_window_update(session->local_window_size,
session->recv_window_size)) { session->recv_window_size)) {
/* Use stream ID 0 to update connection-level flow control /* 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) int optname, void *optval, size_t optlen)
{ {
switch(optname) { 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)) { if(optlen == sizeof(int)) {
int intval = *(int*)optval; int intval = *(int*)optval;
if(intval) { if(intval) {
session->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; session->opt_flags |= flag;
} else { } else {
session->opt_flags &= ~NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE; session->opt_flags &= ~flag;
} }
} else { } else {
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }
break; break;
}
default: default:
return NGHTTP2_ERR_INVALID_ARGUMENT; return NGHTTP2_ERR_INVALID_ARGUMENT;
} }

View File

@ -42,7 +42,8 @@
* Option flags. * Option flags.
*/ */
typedef enum { 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; } nghttp2_optmask;
typedef struct { typedef struct {

View File

@ -241,7 +241,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
if(rv != 0) { if(rv != 0) {
return rv; 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 && window_size_increment < 0 &&
nghttp2_should_send_window_update(session->local_window_size, nghttp2_should_send_window_update(session->local_window_size,
session->recv_window_size)) { session->recv_window_size)) {
@ -260,7 +261,8 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
if(rv != 0) { if(rv != 0) {
return rv; 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 && window_size_increment < 0 &&
nghttp2_should_send_window_update(stream->local_window_size, nghttp2_should_send_window_update(stream->local_window_size,
stream->recv_window_size)) { stream->recv_window_size)) {

View File

@ -403,8 +403,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
flow_control_ = true; flow_control_ = true;
initial_window_size_ = (1 << get_config()->spdy_upstream_window_bits) - 1; initial_window_size_ = (1 << get_config()->spdy_upstream_window_bits) - 1;
rv = nghttp2_session_set_option(session_, rv = nghttp2_session_set_option(session_,
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, &val, NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE,
sizeof(val)); &val, sizeof(val));
assert(rv == 0); assert(rv == 0);
// TODO Maybe call from outside? // TODO Maybe call from outside?
@ -418,9 +418,10 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
rv = nghttp2_submit_settings rv = nghttp2_submit_settings
(session_, entry, sizeof(entry)/sizeof(nghttp2_settings_entry)); (session_, entry, sizeof(entry)/sizeof(nghttp2_settings_entry));
assert(rv == 0); assert(rv == 0);
// Disable connection-level flow control // Set large connection-level window size to effectively disable
rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_END_FLOW_CONTROL, // connection-level flow control.
0, 0); rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE,
0, 1000000007);
assert(rv == 0); assert(rv == 0);
} }

View File

@ -1057,8 +1057,8 @@ int SpdySession::on_connect()
int val = 1; int val = 1;
flow_control_ = true; flow_control_ = true;
rv = nghttp2_session_set_option(session_, rv = nghttp2_session_set_option(session_,
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, &val, NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE,
sizeof(val)); &val, sizeof(val));
assert(rv == 0); assert(rv == 0);
nghttp2_settings_entry entry[2]; nghttp2_settings_entry entry[2];
@ -1073,9 +1073,10 @@ int SpdySession::on_connect()
if(rv != 0) { if(rv != 0) {
return -1; return -1;
} }
// Disable connection-level flow control // Set large connection-level window size to effectively disable
rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_END_FLOW_CONTROL, // connection-level flow control.
0, 0); rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE,
0, 1000000007);
if(rv != 0) { if(rv != 0) {
return -1; return -1;
} }

View File

@ -3091,17 +3091,20 @@ void test_nghttp2_session_set_option(void)
intval = 1; intval = 1;
CU_ASSERT(0 == CU_ASSERT(0 ==
nghttp2_session_set_option(session, nghttp2_session_set_option
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, (session,
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE,
&intval, sizeof(intval))); &intval, sizeof(intval)));
CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE); CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE);
intval = 0; intval = 0;
CU_ASSERT(0 == CU_ASSERT(0 ==
nghttp2_session_set_option(session, nghttp2_session_set_option
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, (session,
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE,
&intval, sizeof(intval))); &intval, sizeof(intval)));
CU_ASSERT((session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) == 0); CU_ASSERT((session->opt_flags &
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE) == 0);
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
nghttp2_session_set_option(session, 0, /* 0 is invalid optname */ nghttp2_session_set_option(session, 0, /* 0 is invalid optname */
@ -3109,10 +3112,20 @@ void test_nghttp2_session_set_option(void)
charval = 1; charval = 1;
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
nghttp2_session_set_option(session, nghttp2_session_set_option
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE, (session,
NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE,
&charval, sizeof(charval))); &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); nghttp2_session_del(session);
} }