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
|
* that value as window_size_increment is queued. If the
|
||||||
* |window_size_increment| is larger than the received bytes from the
|
* |window_size_increment| is larger than the received bytes from the
|
||||||
* remote endpoint, the local window size is increased by that
|
* 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
|
* If the |window_size_increment| is negative, the local window size
|
||||||
* is decreased by -|window_size_increment|. If automatic
|
* is decreased by -|window_size_increment|. If automatic
|
||||||
* WINDOW_UPDATE is enabled
|
* WINDOW_UPDATE is enabled
|
||||||
* (`nghttp2_option_set_no_auto_window_update()`), and the library
|
* (`nghttp2_option_set_no_auto_window_update()`), and the library
|
||||||
* decided that the WINDOW_UPDATE should be submitted, then
|
* 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
|
* If the |window_size_increment| is 0, the function does nothing and
|
||||||
* returns 0.
|
* returns 0.
|
||||||
|
@ -4096,6 +4099,44 @@ NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
int32_t window_size_increment);
|
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
|
* @function
|
||||||
*
|
*
|
||||||
|
|
|
@ -213,6 +213,38 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||||
return 0;
|
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,
|
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||||
int32_t recv_window_size) {
|
int32_t recv_window_size) {
|
||||||
return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
|
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 *recv_reduction_ptr,
|
||||||
int32_t *delta_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
|
* Returns non-zero if the function decided that WINDOW_UPDATE should
|
||||||
* be sent.
|
* be sent.
|
||||||
|
|
|
@ -410,6 +410,75 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||||
return 0;
|
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_,
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||||
int32_t stream_id, const uint8_t *origin,
|
int32_t stream_id, const uint8_t *origin,
|
||||||
size_t origin_len, const uint8_t *field_value,
|
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) ||
|
test_nghttp2_session_repeated_priority_change) ||
|
||||||
!CU_add_test(pSuite, "session_repeated_priority_submission",
|
!CU_add_test(pSuite, "session_repeated_priority_submission",
|
||||||
test_nghttp2_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",
|
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||||
test_nghttp2_http_mandatory_headers) ||
|
test_nghttp2_http_mandatory_headers) ||
|
||||||
!CU_add_test(pSuite, "http_content_length",
|
!CU_add_test(pSuite, "http_content_length",
|
||||||
|
|
|
@ -9405,6 +9405,104 @@ void test_nghttp2_session_repeated_priority_submission(void) {
|
||||||
nghttp2_session_del(session);
|
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(
|
static void check_nghttp2_http_recv_headers_fail(
|
||||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
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_create_idle_stream(void);
|
||||||
void test_nghttp2_session_repeated_priority_change(void);
|
void test_nghttp2_session_repeated_priority_change(void);
|
||||||
void test_nghttp2_session_repeated_priority_submission(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_mandatory_headers(void);
|
||||||
void test_nghttp2_http_content_length(void);
|
void test_nghttp2_http_content_length(void);
|
||||||
void test_nghttp2_http_content_length_mismatch(void);
|
void test_nghttp2_http_content_length_mismatch(void);
|
||||||
|
|
Loading…
Reference in New Issue