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 {
/**
* 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;
/**

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,
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;
}

View File

@ -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 {

View File

@ -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)) {

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}