Merge pull request #1734 from nghttp2/server-change-extpri
Allow server to override RFC 9218 stream priority
This commit is contained in:
commit
41aaa47fd0
|
@ -107,6 +107,7 @@ APIDOCS= \
|
|||
nghttp2_session_callbacks_set_send_callback.rst \
|
||||
nghttp2_session_callbacks_set_send_data_callback.rst \
|
||||
nghttp2_session_callbacks_set_unpack_extension_callback.rst \
|
||||
nghttp2_session_change_extpri_stream_priority.rst \
|
||||
nghttp2_session_change_stream_priority.rst \
|
||||
nghttp2_session_check_request_allowed.rst \
|
||||
nghttp2_session_check_server_session.rst \
|
||||
|
|
|
@ -4901,6 +4901,40 @@ NGHTTP2_EXTERN int nghttp2_submit_priority_update(nghttp2_session *session,
|
|||
const uint8_t *field_value,
|
||||
size_t field_value_len);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Changes the priority of the existing stream denoted by |stream_id|.
|
||||
* The new priority is |extpri|. This function is meant to be used by
|
||||
* server for :rfc:`9218` extensible prioritization scheme.
|
||||
*
|
||||
* If |session| is initialized as client, this function returns
|
||||
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`. For client, use
|
||||
* `nghttp2_submit_priority_update()` instead.
|
||||
*
|
||||
* If :member:`extpri->urgency <nghttp2_extpri.urgency>` is out of
|
||||
* bound, it is set to :macro:`NGHTTP2_EXTPRI_URGENCY_LOW`.
|
||||
*
|
||||
* If |ignore_client_signal| is nonzero, server starts to ignore
|
||||
* client priority signals for this stream.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is not submitted via `nghttp2_submit_settings()`,
|
||||
* this function does nothing and returns 0.
|
||||
*
|
||||
* :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_STATE`
|
||||
* The |session| is initialized as client.
|
||||
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* |stream_id| is zero; or a stream denoted by |stream_id| is not
|
||||
* found.
|
||||
*/
|
||||
NGHTTP2_EXTERN int nghttp2_session_change_extpri_stream_priority(
|
||||
nghttp2_session *session, int32_t stream_id, const nghttp2_extpri *extpri,
|
||||
int ignore_client_signal);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
|
|
|
@ -4084,6 +4084,7 @@ static int session_end_stream_headers_received(nghttp2_session *session,
|
|||
if (session->server && session_enforce_http_messaging(session) &&
|
||||
frame->headers.cat == NGHTTP2_HCAT_REQUEST &&
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
|
||||
!(stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PRIORITY)) {
|
||||
rv = session_update_stream_priority(session, stream, stream->http_extpri);
|
||||
if (rv != 0) {
|
||||
|
@ -5333,6 +5334,9 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session,
|
|||
stream = nghttp2_session_get_stream_raw(session, priority_update->stream_id);
|
||||
if (stream) {
|
||||
/* Stream already exists. */
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES) {
|
||||
return session_call_on_frame_received(session, frame);
|
||||
}
|
||||
} else if (session_detect_idle_stream(session, priority_update->stream_id)) {
|
||||
if (session->num_idle_streams + session->num_incoming_streams >=
|
||||
session->local_settings.max_concurrent_streams) {
|
||||
|
@ -8375,3 +8379,38 @@ nghttp2_session_get_hd_deflate_dynamic_table_size(nghttp2_session *session) {
|
|||
void nghttp2_session_set_user_data(nghttp2_session *session, void *user_data) {
|
||||
session->user_data = user_data;
|
||||
}
|
||||
|
||||
int nghttp2_session_change_extpri_stream_priority(
|
||||
nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_extpri *extpri_in, int ignore_client_signal) {
|
||||
nghttp2_stream *stream;
|
||||
nghttp2_extpri extpri = *extpri_in;
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (session->pending_no_rfc7540_priorities != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
stream = nghttp2_session_get_stream_raw(session, stream_id);
|
||||
if (!stream) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (extpri.urgency > NGHTTP2_EXTPRI_URGENCY_LOW) {
|
||||
extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW;
|
||||
}
|
||||
|
||||
if (ignore_client_signal) {
|
||||
stream->flags |= NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES;
|
||||
}
|
||||
|
||||
return session_update_stream_priority(session, stream,
|
||||
nghttp2_extpri_to_uint8(&extpri));
|
||||
}
|
||||
|
|
|
@ -94,6 +94,8 @@ typedef enum {
|
|||
/* Indicates that this stream is not subject to RFC7540
|
||||
priorities scheme. */
|
||||
NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
|
||||
/* Ignore client RFC 9218 priority signal. */
|
||||
NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
/* HTTP related flags to enforce HTTP semantics */
|
||||
|
|
|
@ -317,6 +317,8 @@ int main(void) {
|
|||
!CU_add_test(pSuite, "session_flooding", test_nghttp2_session_flooding) ||
|
||||
!CU_add_test(pSuite, "session_change_stream_priority",
|
||||
test_nghttp2_session_change_stream_priority) ||
|
||||
!CU_add_test(pSuite, "session_change_extpri_stream_priority",
|
||||
test_nghttp2_session_change_extpri_stream_priority) ||
|
||||
!CU_add_test(pSuite, "session_create_idle_stream",
|
||||
test_nghttp2_session_create_idle_stream) ||
|
||||
!CU_add_test(pSuite, "session_repeated_priority_change",
|
||||
|
|
|
@ -10698,6 +10698,84 @@ void test_nghttp2_session_change_stream_priority(void) {
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_change_extpri_stream_priority(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_buf *buf;
|
||||
ssize_t rv;
|
||||
nghttp2_option *option;
|
||||
nghttp2_extension frame;
|
||||
nghttp2_ext_priority_update priority_update;
|
||||
nghttp2_extpri extpri;
|
||||
nghttp2_stream *stream;
|
||||
static const uint8_t field_value[] = "u=2";
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
nghttp2_option_new(&option);
|
||||
nghttp2_option_set_builtin_recv_extension_type(option,
|
||||
NGHTTP2_PRIORITY_UPDATE);
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
session->pending_no_rfc7540_priorities = 1;
|
||||
|
||||
open_recv_stream(session, 1);
|
||||
|
||||
extpri.urgency = NGHTTP2_EXTPRI_URGENCY_LOW + 1;
|
||||
extpri.inc = 1;
|
||||
|
||||
rv = nghttp2_session_change_extpri_stream_priority(
|
||||
session, 1, &extpri, /* ignore_client_signal = */ 0);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
stream = nghttp2_session_get_stream(session, 1);
|
||||
|
||||
CU_ASSERT(NGHTTP2_EXTPRI_URGENCY_LOW ==
|
||||
nghttp2_extpri_uint8_urgency(stream->extpri));
|
||||
CU_ASSERT(1 == nghttp2_extpri_uint8_inc(stream->extpri));
|
||||
|
||||
/* Client can still update stream priority. */
|
||||
frame.payload = &priority_update;
|
||||
nghttp2_frame_priority_update_init(&frame, 1, (uint8_t *)field_value,
|
||||
sizeof(field_value) - 1);
|
||||
nghttp2_frame_pack_priority_update(&bufs, &frame);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||
|
||||
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
|
||||
CU_ASSERT(2 == stream->extpri);
|
||||
|
||||
/* Start to ignore client priority signal for this stream. */
|
||||
rv = nghttp2_session_change_extpri_stream_priority(
|
||||
session, 1, &extpri, /* ignore_client_signal = */ 1);
|
||||
|
||||
CU_ASSERT(0 == rv);
|
||||
|
||||
stream = nghttp2_session_get_stream(session, 1);
|
||||
|
||||
CU_ASSERT(NGHTTP2_EXTPRI_URGENCY_LOW ==
|
||||
nghttp2_extpri_uint8_urgency(stream->extpri));
|
||||
CU_ASSERT(1 == nghttp2_extpri_uint8_inc(stream->extpri));
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
|
||||
|
||||
CU_ASSERT((ssize_t)nghttp2_buf_len(buf) == rv);
|
||||
CU_ASSERT(NGHTTP2_EXTPRI_URGENCY_LOW ==
|
||||
nghttp2_extpri_uint8_urgency(stream->extpri));
|
||||
CU_ASSERT(1 == nghttp2_extpri_uint8_inc(stream->extpri));
|
||||
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_option_del(option);
|
||||
nghttp2_bufs_free(&bufs);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_create_idle_stream(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
|
|
|
@ -155,6 +155,7 @@ void test_nghttp2_session_defer_then_close(void);
|
|||
void test_nghttp2_session_detach_item_from_closed_stream(void);
|
||||
void test_nghttp2_session_flooding(void);
|
||||
void test_nghttp2_session_change_stream_priority(void);
|
||||
void test_nghttp2_session_change_extpri_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);
|
||||
|
|
Loading…
Reference in New Issue