Add nghttp2_session_set_local_window_size() API function
This commit is contained in:
parent
f68dc02d6b
commit
204f9a3ec7
|
@ -4071,14 +4071,17 @@ nghttp2_session_check_server_session(nghttp2_session *session);
|
|||
* that value as window_size_increment is queued. If the
|
||||
* |window_size_increment| is larger than the received bytes from the
|
||||
* remote endpoint, the local window size is increased by that
|
||||
* difference.
|
||||
* difference. If the sole intention is to increase the local window
|
||||
* size, consider to use `nghttp2_session_set_local_window_size()`.
|
||||
*
|
||||
* If the |window_size_increment| is negative, the local window size
|
||||
* 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.
|
||||
* WINDOW_UPDATE is queued with the current received bytes count. If
|
||||
* the sole intention is to decrease the local window size, consider
|
||||
* to use `nghttp2_session_set_local_window_size()`.
|
||||
*
|
||||
* If the |window_size_increment| is 0, the function does nothing and
|
||||
* returns 0.
|
||||
|
@ -4096,6 +4099,44 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
|
|||
int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Set local window size (local endpoints's window size) to the given
|
||||
* |window_size| for the given stream denoted by |stream_id|. To
|
||||
* change connection level window size, specify 0 to |stream_id|. To
|
||||
* increase window size, this function may submit WINDOW_UPDATE frame
|
||||
* to transmission queue.
|
||||
*
|
||||
* The |flags| is currently ignored and should be
|
||||
* :enum:`NGHTTP2_FLAG_NONE`.
|
||||
*
|
||||
* This sounds similar to `nghttp2_submit_window_update()`, but there
|
||||
* are 2 differences. The first difference is that this function
|
||||
* takes the absolute value of window size to set, rather than the
|
||||
* delta. To change the window size, this may be easier to use since
|
||||
* the application just declares the intended window size, rather than
|
||||
* calculating delta. The second difference is that
|
||||
* `nghttp2_submit_window_update()` affects the received bytes count
|
||||
* which has not acked yet. By the specification of
|
||||
* `nghttp2_submit_window_update()`, to strictly increase the local
|
||||
* window size, we have to submit delta including all received bytes
|
||||
* count, which might not be desirable in some cases. On the other
|
||||
* hand, this function does not affect the received bytes count. It
|
||||
* just sets the local window size to the given value.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |stream_id| is negative.
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
*/
|
||||
NGHTTP2_EXTERN int
|
||||
nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, int32_t window_size);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
|
|
@ -213,6 +213,38 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr) {
|
||||
int32_t recv_reduction_delta;
|
||||
int32_t delta;
|
||||
|
||||
delta = *delta_ptr;
|
||||
|
||||
assert(delta >= 0);
|
||||
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference |delta|. */
|
||||
if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
|
||||
*local_window_size_ptr += delta;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
|
||||
*recv_reduction_ptr -= recv_reduction_delta;
|
||||
|
||||
*recv_window_size_ptr += recv_reduction_delta;
|
||||
|
||||
/* recv_reduction_delta must be paied from *delta_ptr, since it was
|
||||
added in window size reduction (see below). */
|
||||
*delta_ptr -= recv_reduction_delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size) {
|
||||
return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
|
||||
|
|
|
@ -89,6 +89,22 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
|||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* This function works like nghttp2_adjust_local_window_size(). The
|
||||
* difference is that this function assumes *delta_ptr >= 0, and
|
||||
* *recv_window_size_ptr is not decreased by *delta_ptr.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* local_window_size overflow or gets negative.
|
||||
*/
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* Returns non-zero if the function decided that WINDOW_UPDATE should
|
||||
* be sent.
|
||||
|
|
|
@ -410,6 +410,75 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size) {
|
||||
int32_t window_size_increment;
|
||||
nghttp2_stream *stream;
|
||||
int rv;
|
||||
|
||||
if (window_size < 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
|
||||
if (stream_id == 0) {
|
||||
window_size_increment = window_size - session->local_window_size;
|
||||
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (window_size_increment < 0) {
|
||||
return nghttp2_adjust_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
}
|
||||
|
||||
rv = nghttp2_increase_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
|
||||
if (stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
window_size_increment = window_size - stream->local_window_size;
|
||||
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (window_size_increment < 0) {
|
||||
return nghttp2_adjust_local_window_size(
|
||||
&stream->local_window_size, &stream->recv_window_size,
|
||||
&stream->recv_reduction, &window_size_increment);
|
||||
}
|
||||
|
||||
rv = nghttp2_increase_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) {
|
||||
return nghttp2_session_add_window_update(session, flags, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id, const uint8_t *origin,
|
||||
size_t origin_len, const uint8_t *field_value,
|
||||
|
|
|
@ -302,6 +302,8 @@ int main(int argc _U_, char *argv[] _U_) {
|
|||
test_nghttp2_session_repeated_priority_change) ||
|
||||
!CU_add_test(pSuite, "session_repeated_priority_submission",
|
||||
test_nghttp2_session_repeated_priority_submission) ||
|
||||
!CU_add_test(pSuite, "session_set_local_window_size",
|
||||
test_nghttp2_session_set_local_window_size) ||
|
||||
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||
test_nghttp2_http_mandatory_headers) ||
|
||||
!CU_add_test(pSuite, "http_content_length",
|
||||
|
|
|
@ -9405,6 +9405,104 @@ void test_nghttp2_session_repeated_priority_submission(void) {
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_set_local_window_size(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
nghttp2_session_client_new(&session, &callbacks, NULL);
|
||||
stream = open_sent_stream(session, 1);
|
||||
stream->recv_window_size = 4096;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 1, 65536));
|
||||
CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 1 ==
|
||||
stream->local_window_size);
|
||||
CU_ASSERT(4096 == stream->recv_window_size);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
|
||||
CU_ASSERT(1 == item->frame.window_update.hd.stream_id);
|
||||
CU_ASSERT(1 == item->frame.window_update.window_size_increment);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
/* Go decrement part */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 1, 32768));
|
||||
CU_ASSERT(32768 == stream->local_window_size);
|
||||
CU_ASSERT(-28672 == stream->recv_window_size);
|
||||
CU_ASSERT(32768 == stream->recv_reduction);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(item == NULL);
|
||||
|
||||
/* Increase local window size */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 1, 49152));
|
||||
CU_ASSERT(49152 == stream->local_window_size);
|
||||
CU_ASSERT(-12288 == stream->recv_window_size);
|
||||
CU_ASSERT(16384 == stream->recv_reduction);
|
||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||
|
||||
/* Increase local window again */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 1, 65537));
|
||||
CU_ASSERT(65537 == stream->local_window_size);
|
||||
CU_ASSERT(4096 == stream->recv_window_size);
|
||||
CU_ASSERT(0 == stream->recv_reduction);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(1 == item->frame.window_update.window_size_increment);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
/* Check connection-level flow control */
|
||||
session->recv_window_size = 4096;
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 0, 65536));
|
||||
CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 1 ==
|
||||
session->local_window_size);
|
||||
CU_ASSERT(4096 == session->recv_window_size);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
|
||||
CU_ASSERT(0 == item->frame.window_update.hd.stream_id);
|
||||
CU_ASSERT(1 == item->frame.window_update.window_size_increment);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
/* Go decrement part */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 0, 32768));
|
||||
CU_ASSERT(32768 == session->local_window_size);
|
||||
CU_ASSERT(-28672 == session->recv_window_size);
|
||||
CU_ASSERT(32768 == session->recv_reduction);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(item == NULL);
|
||||
|
||||
/* Increase local window size */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 0, 49152));
|
||||
CU_ASSERT(49152 == session->local_window_size);
|
||||
CU_ASSERT(-12288 == session->recv_window_size);
|
||||
CU_ASSERT(16384 == session->recv_reduction);
|
||||
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||
|
||||
/* Increase local window again */
|
||||
CU_ASSERT(0 == nghttp2_session_set_local_window_size(
|
||||
session, NGHTTP2_FLAG_NONE, 0, 65537));
|
||||
CU_ASSERT(65537 == session->local_window_size);
|
||||
CU_ASSERT(4096 == session->recv_window_size);
|
||||
CU_ASSERT(0 == session->recv_reduction);
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(1 == item->frame.window_update.window_size_increment);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
static void check_nghttp2_http_recv_headers_fail(
|
||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
||||
|
|
|
@ -149,6 +149,7 @@ void test_nghttp2_session_change_stream_priority(void);
|
|||
void test_nghttp2_session_create_idle_stream(void);
|
||||
void test_nghttp2_session_repeated_priority_change(void);
|
||||
void test_nghttp2_session_repeated_priority_submission(void);
|
||||
void test_nghttp2_session_set_local_window_size(void);
|
||||
void test_nghttp2_http_mandatory_headers(void);
|
||||
void test_nghttp2_http_content_length(void);
|
||||
void test_nghttp2_http_content_length_mismatch(void);
|
||||
|
|
Loading…
Reference in New Issue