mirror of
https://github.com/nghttp2/nghttp2.git
synced 2025-12-08 02:58:53 +08:00
Add nghttp2_session_consume() API
Reworked no automatic WINDOW_UPDATE feature. We added new API nghttp2_session_consume() which tells the library how many bytes are consumed by the application. Instead of submitting WINDOW_UPDATE by the application, the library is now responsible to submit WINDOW_UPDATE based on consumed bytes. This is more reliable method, since it enables us to properly send WINDOW_UPDATE for stream and connection individually. The previous implementation of nghttpx had broken connection window management.
This commit is contained in:
@@ -1505,31 +1505,17 @@ int nghttp2_option_new(nghttp2_option **option_ptr);
|
||||
*/
|
||||
void nghttp2_option_del(nghttp2_option *option);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* stream automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a stream and the application
|
||||
* is responsible for sending WINDOW_UPDATE using
|
||||
* `nghttp2_submit_window_update`. By default, this option is set to
|
||||
* zero.
|
||||
*/
|
||||
void nghttp2_option_set_no_auto_stream_window_update(nghttp2_option *option,
|
||||
int val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a connection and the
|
||||
* application is responsible for sending WINDOW_UPDATE with stream ID
|
||||
* 0 using `nghttp2_submit_window_update`. By default, this option is
|
||||
* set to zero.
|
||||
* library won't send WINDOW_UPDATE for DATA until application calls
|
||||
* `nghttp2_session_consume()` to indicate the consumed amount of
|
||||
* data. Don't use `nghttp2_submit_window_update()` for this purpose.
|
||||
* By default, this option is set to zero.
|
||||
*/
|
||||
void nghttp2_option_set_no_auto_connection_window_update
|
||||
(nghttp2_option *option, int val);
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@@ -2067,6 +2053,28 @@ int nghttp2_session_terminate_session2(nghttp2_session *session,
|
||||
uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
|
||||
nghttp2_settings_id id);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Tells the |session| that |size| bytes for a stream denoted by
|
||||
* |stream_id| were consumed by application and are ready to
|
||||
* WINDOW_UPDATE. This function is intended to be used without
|
||||
* automatic window update (see
|
||||
* `nghttp2_option_set_no_auto_window_update()`).
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |stream_id| is 0.
|
||||
* :enum:`NGHTTP2_ERR_INVALID_STATE`
|
||||
* Automatic WINDOW_UPDATE is not disabled.
|
||||
*/
|
||||
int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
@@ -2609,12 +2617,11 @@ int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||
* difference.
|
||||
*
|
||||
* If the |window_size_increment| is negative, the local window size
|
||||
* is decreased by -|window_size_increment|. If
|
||||
* :enum:`NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE` (or
|
||||
* :enum:`NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE` if |stream_id|
|
||||
* is 0) is not set and the library decided that the WINDOW_UPDATE
|
||||
* should be submitted, then WINDOW_UPDATE is queued with the current
|
||||
* received bytes count.
|
||||
* is decreased by -|window_size_increment|. If automatic
|
||||
* WINDOW_UPDATE is enabled
|
||||
* (`nghttp2_option_set_no_auto_window_update()`), and the library
|
||||
* decided that the WINDOW_UPDATE should be submitted, then
|
||||
* WINDOW_UPDATE is queued with the current received bytes count.
|
||||
*
|
||||
* If the |window_size_increment| is 0, the function does nothing and
|
||||
* returns 0.
|
||||
|
||||
@@ -40,18 +40,10 @@ void nghttp2_option_del(nghttp2_option *option)
|
||||
free(option);
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_stream_window_update(nghttp2_option *option,
|
||||
int val)
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val)
|
||||
{
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE;
|
||||
option->no_auto_stream_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_connection_window_update
|
||||
(nghttp2_option *option, int val)
|
||||
{
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE;
|
||||
option->no_auto_connection_window_update = val;
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
|
||||
option->no_auto_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
|
||||
@@ -37,22 +37,12 @@
|
||||
typedef enum {
|
||||
/**
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* stream automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a stream and the application
|
||||
* is responsible for sending WINDOW_UPDATE using
|
||||
* `nghttp2_submit_window_update`. By default, this option is set to
|
||||
* zero.
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for DATA until application calls
|
||||
* nghttp2_session_consume() to indicate the amount of consumed
|
||||
* DATA. By default, this option is set to zero.
|
||||
*/
|
||||
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 to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for a connection and the
|
||||
* application is responsible for sending WINDOW_UPDATE with stream
|
||||
* ID 0 using `nghttp2_submit_window_update`. By default, this
|
||||
* option is set to zero.
|
||||
*/
|
||||
NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1,
|
||||
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
|
||||
/**
|
||||
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
|
||||
* remote endpoint as if it is received in SETTINGS frame. Without
|
||||
@@ -66,7 +56,7 @@ typedef enum {
|
||||
* will be overwritten if the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
|
||||
*/
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
@@ -83,13 +73,9 @@ struct nghttp2_option {
|
||||
*/
|
||||
uint32_t peer_max_concurrent_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE
|
||||
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
||||
*/
|
||||
uint8_t no_auto_stream_window_update;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE
|
||||
*/
|
||||
uint8_t no_auto_connection_window_update;
|
||||
uint8_t no_auto_window_update;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_OPTION_H */
|
||||
|
||||
@@ -352,6 +352,7 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
|
||||
(*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||
(*session_ptr)->recv_window_size = 0;
|
||||
(*session_ptr)->consumed_size = 0;
|
||||
(*session_ptr)->recv_reduction = 0;
|
||||
(*session_ptr)->local_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||
|
||||
@@ -383,19 +384,10 @@ static int session_new(nghttp2_session **session_ptr,
|
||||
|
||||
|
||||
if(option) {
|
||||
if((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_STREAM_WINDOW_UPDATE) &&
|
||||
option->no_auto_stream_window_update) {
|
||||
if((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
|
||||
option->no_auto_window_update) {
|
||||
|
||||
(*session_ptr)->opt_flags |=
|
||||
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE;
|
||||
|
||||
}
|
||||
|
||||
if((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE) &&
|
||||
option->no_auto_connection_window_update) {
|
||||
|
||||
(*session_ptr)->opt_flags |=
|
||||
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE;
|
||||
(*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE;
|
||||
|
||||
}
|
||||
|
||||
@@ -3175,10 +3167,11 @@ static int update_local_initial_window_size_func
|
||||
return nghttp2_session_terminate_session(arg->session,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
}
|
||||
if(!(arg->session->opt_flags &
|
||||
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) {
|
||||
if(!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) {
|
||||
|
||||
if(nghttp2_should_send_window_update(stream->local_window_size,
|
||||
stream->recv_window_size)) {
|
||||
|
||||
rv = nghttp2_session_add_window_update(arg->session,
|
||||
NGHTTP2_FLAG_NONE,
|
||||
stream->stream_id,
|
||||
@@ -3876,9 +3869,9 @@ 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_STREAM_WINDOW_UPDATE is set,
|
||||
* WINDOW_UPDATE will not be sent.
|
||||
* 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.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
@@ -3902,7 +3895,7 @@ static int session_update_recv_stream_window_size
|
||||
/* We don't have to send WINDOW_UPDATE if the data received is the
|
||||
last chunk in the incoming stream. */
|
||||
if(send_window_update &&
|
||||
!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) {
|
||||
!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_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,
|
||||
@@ -3924,8 +3917,8 @@ static int 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_CONNECTION_WINDOW_UPDATE is
|
||||
* set, WINDOW_UPDATE will not be sent.
|
||||
* connection. If NGHTTP2_OPT_NO_AUTO_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:
|
||||
@@ -3944,30 +3937,92 @@ static int session_update_recv_connection_window_size
|
||||
return nghttp2_session_terminate_session(session,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
}
|
||||
if(!(session->opt_flags &
|
||||
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE)) {
|
||||
if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_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
|
||||
window */
|
||||
rv = nghttp2_session_add_window_update(session,
|
||||
NGHTTP2_FLAG_NONE,
|
||||
0,
|
||||
session->recv_window_size);
|
||||
if(rv == 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 {
|
||||
rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 0,
|
||||
session->recv_window_size);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
session->recv_window_size = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_update_stream_consumed_size
|
||||
(nghttp2_session *session, nghttp2_stream *stream, size_t delta_size)
|
||||
{
|
||||
int32_t recv_size;
|
||||
int rv;
|
||||
|
||||
if((size_t)stream->consumed_size > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
|
||||
return nghttp2_session_terminate_session(session,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
}
|
||||
|
||||
stream->consumed_size += delta_size;
|
||||
|
||||
/* recv_window_size may be smaller than consumed_size, because it
|
||||
may be decreased by negative value with
|
||||
nghttp2_submit_window_update(). */
|
||||
recv_size = nghttp2_min(stream->consumed_size, stream->recv_window_size);
|
||||
|
||||
if(nghttp2_should_send_window_update(stream->local_window_size, recv_size)) {
|
||||
rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE,
|
||||
stream->stream_id, recv_size);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->recv_window_size -= recv_size;
|
||||
stream->consumed_size -= recv_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_update_connection_consumed_size
|
||||
(nghttp2_session *session, size_t delta_size)
|
||||
{
|
||||
int32_t recv_size;
|
||||
int rv;
|
||||
|
||||
if((size_t)session->consumed_size > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
|
||||
return nghttp2_session_terminate_session(session,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
}
|
||||
|
||||
session->consumed_size += delta_size;
|
||||
|
||||
/* recv_window_size may be smaller than consumed_size, because it
|
||||
may be decreased by negative value with
|
||||
nghttp2_submit_window_update(). */
|
||||
recv_size = nghttp2_min(session->consumed_size, session->recv_window_size);
|
||||
|
||||
if(nghttp2_should_send_window_update(session->local_window_size,
|
||||
recv_size)) {
|
||||
|
||||
rv = nghttp2_session_add_window_update(session, NGHTTP2_FLAG_NONE, 0,
|
||||
recv_size);
|
||||
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
session->recv_window_size -= recv_size;
|
||||
session->consumed_size -= recv_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that we can receive the DATA frame for stream, which is
|
||||
* indicated by |session->iframe.frame.hd.stream_id|. If it is a
|
||||
@@ -5033,6 +5088,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Pad Length field is consumed immediately */
|
||||
rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id,
|
||||
readlen);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream = nghttp2_session_get_stream(session,
|
||||
iframe->frame.hd.stream_id);
|
||||
if(stream) {
|
||||
@@ -5098,6 +5161,18 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
data_readlen = inbound_frame_effective_readlen
|
||||
(iframe, iframe->payloadleft, readlen);
|
||||
|
||||
padlen = readlen - data_readlen;
|
||||
|
||||
if(padlen > 0) {
|
||||
/* Padding is considered as "consumed" immediately */
|
||||
rv = nghttp2_session_consume(session, iframe->frame.hd.stream_id,
|
||||
padlen);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGF(fprintf(stderr, "recv: data_readlen=%zu\n", data_readlen));
|
||||
|
||||
if(stream && data_readlen > 0 &&
|
||||
@@ -5142,8 +5217,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
readlen, iframe->payloadleft));
|
||||
|
||||
if(readlen > 0) {
|
||||
session->recv_ign_window_size += readlen;
|
||||
|
||||
/* Update connection-level flow control window for ignored
|
||||
DATA frame too */
|
||||
rv = session_update_recv_connection_window_size(session, readlen);
|
||||
@@ -5151,20 +5224,14 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
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)) {
|
||||
if(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
|
||||
|
||||
rv = nghttp2_session_add_window_update
|
||||
(session, NGHTTP2_FLAG_NONE, 0, session->recv_ign_window_size);
|
||||
/* Ignored DATA is considered as "consumed" immediately. */
|
||||
rv = session_update_connection_consumed_size(session, readlen);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
session->recv_window_size -= session->recv_ign_window_size;
|
||||
session->recv_ign_window_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5737,3 +5804,36 @@ int nghttp2_session_get_stream_remote_close(nghttp2_session* session,
|
||||
|
||||
return (stream->shut_flags & NGHTTP2_SHUT_RD) != 0;
|
||||
}
|
||||
|
||||
int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id,
|
||||
size_t size)
|
||||
{
|
||||
int rv;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
if(stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE)) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
rv = session_update_connection_consumed_size(session, size);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
|
||||
if(stream) {
|
||||
rv = session_update_stream_consumed_size(session, stream, size);
|
||||
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@
|
||||
* Option flags.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1
|
||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||
} nghttp2_optmask;
|
||||
|
||||
typedef enum {
|
||||
@@ -206,15 +205,10 @@ struct nghttp2_session {
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE. */
|
||||
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 number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
|
||||
@@ -48,6 +48,7 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
stream->remote_window_size = remote_initial_window_size;
|
||||
stream->local_window_size = local_initial_window_size;
|
||||
stream->recv_window_size = 0;
|
||||
stream->consumed_size = 0;
|
||||
stream->recv_reduction = 0;
|
||||
stream->blocked_sent = 0;
|
||||
|
||||
|
||||
@@ -151,6 +151,10 @@ struct nghttp2_stream {
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
|
||||
@@ -348,27 +348,30 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
if(rv != 0) {
|
||||
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 {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
if(stream) {
|
||||
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
|
||||
&stream->recv_window_size,
|
||||
&stream->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
if(!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
|
||||
&stream->recv_window_size,
|
||||
&stream->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if(window_size_increment > 0) {
|
||||
if(stream_id == 0) {
|
||||
session->consumed_size =
|
||||
nghttp2_max(0, session->consumed_size - window_size_increment);
|
||||
} else {
|
||||
stream->consumed_size =
|
||||
nghttp2_max(0, stream->consumed_size - window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_add_window_update(session, flags, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user