Add SETTINGS_NO_RFC7540_PRIORITIES
Add SETTINGS_NO_RFC7540_PRIORITIES to disable RFC7540 priorities. If disabled, streams are served in FIFO.
This commit is contained in:
parent
8d48686cec
commit
9812a0bc81
|
@ -703,7 +703,12 @@ typedef enum {
|
|||
* SETTINGS_ENABLE_CONNECT_PROTOCOL
|
||||
* (`RFC 8441 <https://tools.ietf.org/html/rfc8441>`_)
|
||||
*/
|
||||
NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08
|
||||
NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08,
|
||||
/**
|
||||
* SETTINGS_NO_RFC7540_PRIORITIES (`RFC 9218
|
||||
* <https://datatracker.ietf.org/doc/html/rfc9218>`_)
|
||||
*/
|
||||
NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES = 0x09
|
||||
} nghttp2_settings_id;
|
||||
/* Note: If we add SETTINGS, update the capacity of
|
||||
NGHTTP2_INBOUND_NUM_IV as well */
|
||||
|
@ -2693,6 +2698,11 @@ nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
|
|||
* This option prevents the library from retaining closed streams to
|
||||
* maintain the priority tree. If this option is set to nonzero,
|
||||
* applications can discard closed stream completely to save memory.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is submitted via `nghttp2_submit_settings()`, any
|
||||
* closed streams are not retained regardless of this option.
|
||||
*/
|
||||
NGHTTP2_EXTERN void nghttp2_option_set_no_closed_streams(nghttp2_option *option,
|
||||
int val);
|
||||
|
@ -3589,6 +3599,11 @@ NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
|
|||
* found, we use default priority instead of given |pri_spec|. That
|
||||
* is make stream depend on root stream with weight 16.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is submitted via `nghttp2_submit_settings()`, this
|
||||
* function does nothing and returns 0.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
|
@ -3632,6 +3647,11 @@ nghttp2_session_change_stream_priority(nghttp2_session *session,
|
|||
* found, we use default priority instead of given |pri_spec|. That
|
||||
* is make stream depend on root stream with weight 16.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is submitted via `nghttp2_submit_settings()`, this
|
||||
* function does nothing and returns 0.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
|
@ -3837,6 +3857,11 @@ nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
|
|||
* :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
|
||||
* :macro:`NGHTTP2_MAX_WEIGHT`.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is received by a remote endpoint, |pri_spec| is
|
||||
* ignored, and treated as if ``NULL`` is specified.
|
||||
*
|
||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||
* |nvlen| elements. The application is responsible to include
|
||||
* required pseudo-header fields (header field whose name starts with
|
||||
|
@ -4057,6 +4082,11 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
|
|||
* :macro:`NGHTTP2_MIN_WEIGHT`. If it is strictly greater than
|
||||
* :macro:`NGHTTP2_MAX_WEIGHT`, it becomes :macro:`NGHTTP2_MAX_WEIGHT`.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is received by a remote endpoint, |pri_spec| is
|
||||
* ignored, and treated as if ``NULL`` is specified.
|
||||
*
|
||||
* The |nva| is an array of name/value pair :type:`nghttp2_nv` with
|
||||
* |nvlen| elements. The application is responsible to include
|
||||
* required pseudo-header fields (header field whose name starts with
|
||||
|
@ -4184,6 +4214,11 @@ NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
|||
* :macro:`NGHTTP2_MAX_WEIGHT`, it becomes
|
||||
* :macro:`NGHTTP2_MAX_WEIGHT`.
|
||||
*
|
||||
* If
|
||||
* :enum:`nghttp2_settings_id.NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES`
|
||||
* of value of 1 is received by a remote endpoint, this function does
|
||||
* nothing and returns 0.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
|
|
|
@ -1071,6 +1071,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
if (iv[i].value != 0 && iv[i].value != 1) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
|
|
@ -385,6 +385,7 @@ static void init_settings(nghttp2_settings_storage *settings) {
|
|||
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
|
||||
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
|
||||
settings->max_header_list_size = UINT32_MAX;
|
||||
settings->no_rfc7540_priorities = UINT32_MAX;
|
||||
}
|
||||
|
||||
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
|
||||
|
@ -398,6 +399,15 @@ static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
|
|||
aob->state = NGHTTP2_OB_POP_ITEM;
|
||||
}
|
||||
|
||||
static int stream_less(const void *lhsx, const void *rhsx) {
|
||||
const nghttp2_stream *lhs, *rhs;
|
||||
|
||||
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
|
||||
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
|
||||
|
||||
return lhs->seq < rhs->seq;
|
||||
}
|
||||
|
||||
int nghttp2_enable_strict_preface = 1;
|
||||
|
||||
static int session_new(nghttp2_session **session_ptr,
|
||||
|
@ -442,6 +452,7 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
(*session_ptr)->pending_local_max_concurrent_stream =
|
||||
NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
|
||||
(*session_ptr)->pending_enable_push = 1;
|
||||
(*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX;
|
||||
|
||||
if (server) {
|
||||
(*session_ptr)->server = 1;
|
||||
|
@ -584,6 +595,12 @@ static int session_new(nghttp2_session **session_ptr,
|
|||
}
|
||||
}
|
||||
|
||||
rv = nghttp2_pq_init(&(*session_ptr)->ob_data, stream_less, mem);
|
||||
if (rv != 0) {
|
||||
assert(0);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_aob_framebuf:
|
||||
|
@ -748,6 +765,7 @@ void nghttp2_session_del(nghttp2_session *session) {
|
|||
settings = next;
|
||||
}
|
||||
|
||||
nghttp2_pq_free(&session->ob_data);
|
||||
nghttp2_stream_free(&session->root);
|
||||
|
||||
/* Have to free streams first, so that we can check
|
||||
|
@ -775,6 +793,7 @@ int nghttp2_session_reprioritize_stream(
|
|||
nghttp2_priority_spec pri_spec_default;
|
||||
const nghttp2_priority_spec *pri_spec = pri_spec_in;
|
||||
|
||||
assert(session->pending_no_rfc7540_priorities != 1);
|
||||
assert(pri_spec->stream_id != stream->stream_id);
|
||||
|
||||
if (!nghttp2_stream_in_dep_tree(stream)) {
|
||||
|
@ -842,6 +861,104 @@ int nghttp2_session_reprioritize_stream(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int session_ob_data_push(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
||||
assert(stream->queued == 0);
|
||||
|
||||
rv = nghttp2_pq_push(&session->ob_data, &stream->pq_entry);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
stream->queued = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_ob_data_remove(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES);
|
||||
assert(stream->queued == 1);
|
||||
|
||||
nghttp2_pq_remove(&session->ob_data, &stream->pq_entry);
|
||||
|
||||
stream->queued = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int session_attach_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *item) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_attach_item(stream, item);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_ob_data_push(session, stream);
|
||||
}
|
||||
|
||||
static int session_detach_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
!stream->queued) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_ob_data_remove(session, stream);
|
||||
}
|
||||
|
||||
static int session_defer_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream, uint8_t flags) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_defer_item(stream, flags);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
!stream->queued) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_ob_data_remove(session, stream);
|
||||
}
|
||||
|
||||
static int session_resume_deferred_stream_item(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
uint8_t flags) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_stream_resume_deferred_item(stream, flags);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return session_ob_data_push(session, stream);
|
||||
}
|
||||
|
||||
int nghttp2_session_add_item(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item) {
|
||||
/* TODO Return error if stream is not found for the frame requiring
|
||||
|
@ -863,7 +980,7 @@ int nghttp2_session_add_item(nghttp2_session *session,
|
|||
return NGHTTP2_ERR_DATA_EXIST;
|
||||
}
|
||||
|
||||
rv = nghttp2_stream_attach_item(stream, item);
|
||||
rv = session_attach_stream_item(session, stream, item);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
|
@ -1041,11 +1158,20 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
|||
|
||||
if (stream) {
|
||||
assert(stream->state == NGHTTP2_STREAM_IDLE);
|
||||
assert(nghttp2_stream_in_dep_tree(stream));
|
||||
nghttp2_session_detach_idle_stream(session, stream);
|
||||
rv = nghttp2_stream_dep_remove(stream);
|
||||
if (rv != 0) {
|
||||
return NULL;
|
||||
assert((stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) ||
|
||||
nghttp2_stream_in_dep_tree(stream));
|
||||
|
||||
if (nghttp2_stream_in_dep_tree(stream)) {
|
||||
assert(!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES));
|
||||
nghttp2_session_detach_idle_stream(session, stream);
|
||||
rv = nghttp2_stream_dep_remove(stream);
|
||||
if (rv != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
stream->flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stream = nghttp2_mem_malloc(mem, sizeof(nghttp2_stream));
|
||||
|
@ -1056,7 +1182,21 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
|||
stream_alloc = 1;
|
||||
}
|
||||
|
||||
if (pri_spec->stream_id != 0) {
|
||||
if (session->pending_no_rfc7540_priorities == 1 ||
|
||||
session->remote_settings.no_rfc7540_priorities == 1) {
|
||||
/* For client which has not received server
|
||||
SETTINGS_NO_RFC7540_PRIORITIES = 1, send a priority signal
|
||||
opportunistically. */
|
||||
if (session->server ||
|
||||
session->remote_settings.no_rfc7540_priorities == 1) {
|
||||
nghttp2_priority_spec_default_init(&pri_spec_default);
|
||||
pri_spec = &pri_spec_default;
|
||||
}
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
flags |= NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES;
|
||||
}
|
||||
} else if (pri_spec->stream_id != 0) {
|
||||
dep_stream = nghttp2_session_get_stream_raw(session, pri_spec->stream_id);
|
||||
|
||||
if (!dep_stream &&
|
||||
|
@ -1102,6 +1242,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
|||
(int32_t)session->local_settings.initial_window_size,
|
||||
stream_user_data, mem);
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
stream->seq = session->stream_seq++;
|
||||
}
|
||||
|
||||
rv = nghttp2_map_insert(&session->streams, stream_id, stream);
|
||||
if (rv != 0) {
|
||||
nghttp2_stream_free(stream);
|
||||
|
@ -1141,6 +1285,10 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
|||
}
|
||||
}
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
if (pri_spec->stream_id == 0) {
|
||||
dep_stream = &session->root;
|
||||
}
|
||||
|
@ -1180,7 +1328,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
|||
|
||||
item = stream->item;
|
||||
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
|
@ -1230,6 +1378,10 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
|||
/* Closes both directions just in case they are not closed yet */
|
||||
stream->flags |= NGHTTP2_STREAM_FLAG_CLOSED;
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
return nghttp2_session_destroy_stream(session, stream);
|
||||
}
|
||||
|
||||
if ((session->opt_flags & NGHTTP2_OPTMASK_NO_CLOSED_STREAMS) == 0 &&
|
||||
session->server && !is_my_stream_id &&
|
||||
nghttp2_stream_in_dep_tree(stream)) {
|
||||
|
@ -2013,7 +2165,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
if (stream) {
|
||||
int rv2;
|
||||
|
||||
rv2 = nghttp2_stream_detach_item(stream);
|
||||
rv2 = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
|
@ -2032,7 +2184,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
queue when session->remote_window_size > 0 */
|
||||
assert(session->remote_window_size > 0);
|
||||
|
||||
rv = nghttp2_stream_defer_item(stream,
|
||||
rv = session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
|
@ -2051,7 +2203,8 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
return rv;
|
||||
}
|
||||
if (rv == NGHTTP2_ERR_DEFERRED) {
|
||||
rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||
rv = session_defer_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -2062,7 +2215,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
return NGHTTP2_ERR_DEFERRED;
|
||||
}
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -2078,7 +2231,7 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
if (rv != 0) {
|
||||
int rv2;
|
||||
|
||||
rv2 = nghttp2_stream_detach_item(stream);
|
||||
rv2 = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv2)) {
|
||||
return rv2;
|
||||
|
@ -2339,6 +2492,10 @@ static int session_prep_frame(nghttp2_session *session,
|
|||
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_pq_entry *ent;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
if (nghttp2_outbound_queue_top(&session->ob_urgent)) {
|
||||
return nghttp2_outbound_queue_top(&session->ob_urgent);
|
||||
}
|
||||
|
@ -2354,7 +2511,18 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
|||
}
|
||||
|
||||
if (session->remote_window_size > 0) {
|
||||
return nghttp2_stream_next_outbound_item(&session->root);
|
||||
item = nghttp2_stream_next_outbound_item(&session->root);
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
ent = nghttp2_pq_top(&session->ob_data);
|
||||
if (!ent) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
||||
return stream->item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -2363,6 +2531,8 @@ nghttp2_session_get_next_ob_item(nghttp2_session *session) {
|
|||
nghttp2_outbound_item *
|
||||
nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_pq_entry *ent;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
item = nghttp2_outbound_queue_top(&session->ob_urgent);
|
||||
if (item) {
|
||||
|
@ -2388,7 +2558,18 @@ nghttp2_session_pop_next_ob_item(nghttp2_session *session) {
|
|||
}
|
||||
|
||||
if (session->remote_window_size > 0) {
|
||||
return nghttp2_stream_next_outbound_item(&session->root);
|
||||
item = nghttp2_stream_next_outbound_item(&session->root);
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
ent = nghttp2_pq_top(&session->ob_data);
|
||||
if (!ent) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
||||
return stream->item;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -2550,7 +2731,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
|
|||
}
|
||||
|
||||
if (stream && aux_data->eof) {
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -2675,9 +2856,8 @@ static int session_after_frame_sent1(nghttp2_session *session) {
|
|||
}
|
||||
}
|
||||
case NGHTTP2_PRIORITY:
|
||||
if (session->server) {
|
||||
if (session->server || session->pending_no_rfc7540_priorities == 1) {
|
||||
return 0;
|
||||
;
|
||||
}
|
||||
|
||||
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
|
||||
|
@ -2852,7 +3032,7 @@ static int session_after_frame_sent2(nghttp2_session *session) {
|
|||
further data. */
|
||||
if (nghttp2_session_predicate_data_send(session, stream) != 0) {
|
||||
if (stream) {
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -3150,7 +3330,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
|||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = nghttp2_stream_detach_item(stream);
|
||||
rv = session_detach_stream_item(session, stream);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -4091,6 +4271,8 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
|
|||
int rv;
|
||||
nghttp2_stream *stream;
|
||||
|
||||
assert(session->pending_no_rfc7540_priorities != 1);
|
||||
|
||||
if (frame->hd.stream_id == 0) {
|
||||
return session_handle_invalid_connection(session, frame, NGHTTP2_ERR_PROTO,
|
||||
"PRIORITY: stream_id == 0");
|
||||
|
@ -4148,6 +4330,8 @@ static int session_process_priority_frame(nghttp2_session *session) {
|
|||
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||
nghttp2_frame *frame = &iframe->frame;
|
||||
|
||||
assert(session->pending_no_rfc7540_priorities != 1);
|
||||
|
||||
nghttp2_frame_unpack_priority_payload(&frame->priority, iframe->sbuf.pos);
|
||||
|
||||
return nghttp2_session_on_priority_received(session, frame);
|
||||
|
@ -4214,8 +4398,8 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) {
|
|||
if (stream->remote_window_size > 0 &&
|
||||
nghttp2_stream_check_deferred_by_flow_control(stream)) {
|
||||
|
||||
rv = nghttp2_stream_resume_deferred_item(
|
||||
stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
rv = session_resume_deferred_stream_item(
|
||||
arg->session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -4389,6 +4573,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
|||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
session->local_settings.enable_connect_protocol = iv[i].value;
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
session->local_settings.no_rfc7540_priorities = iv[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4547,10 +4734,32 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
|||
|
||||
session->remote_settings.enable_connect_protocol = entry->value;
|
||||
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
|
||||
if (entry->value != 0 && entry->value != 1) {
|
||||
return session_handle_invalid_connection(
|
||||
session, frame, NGHTTP2_ERR_PROTO,
|
||||
"SETTINGS: invalid SETTINGS_NO_RFC7540_PRIORITIES");
|
||||
}
|
||||
|
||||
if (session->remote_settings.no_rfc7540_priorities != UINT32_MAX &&
|
||||
session->remote_settings.no_rfc7540_priorities != entry->value) {
|
||||
return session_handle_invalid_connection(
|
||||
session, frame, NGHTTP2_ERR_PROTO,
|
||||
"SETTINGS: SETTINGS_NO_RFC7540_PRIORITIES cannot be changed");
|
||||
}
|
||||
|
||||
session->remote_settings.no_rfc7540_priorities = entry->value;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (session->remote_settings.no_rfc7540_priorities == UINT32_MAX) {
|
||||
session->remote_settings.no_rfc7540_priorities = 0;
|
||||
}
|
||||
|
||||
if (!noack && !session_is_closing(session)) {
|
||||
rv = nghttp2_session_add_settings(session, NGHTTP2_FLAG_ACK, NULL, 0);
|
||||
|
||||
|
@ -4833,8 +5042,8 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
|
|||
if (stream->remote_window_size > 0 &&
|
||||
nghttp2_stream_check_deferred_by_flow_control(stream)) {
|
||||
|
||||
rv = nghttp2_stream_resume_deferred_item(
|
||||
stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
rv = session_resume_deferred_stream_item(
|
||||
session, stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
|
@ -5276,6 +5485,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
|
|||
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
|
||||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
break;
|
||||
default:
|
||||
DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id);
|
||||
|
@ -5995,13 +6205,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
|||
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
rv = session_process_priority_frame(session);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (session->pending_no_rfc7540_priorities != 1 &&
|
||||
session->remote_settings.no_rfc7540_priorities != 1) {
|
||||
rv = session_process_priority_frame(session);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (ssize_t)inlen;
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (ssize_t)inlen;
|
||||
}
|
||||
}
|
||||
|
||||
session_inbound_frame_reset(session);
|
||||
|
@ -6870,7 +7083,8 @@ int nghttp2_session_want_write(nghttp2_session *session) {
|
|||
*/
|
||||
return session->aob.item || nghttp2_outbound_queue_top(&session->ob_urgent) ||
|
||||
nghttp2_outbound_queue_top(&session->ob_reg) ||
|
||||
(!nghttp2_pq_empty(&session->root.obq) &&
|
||||
((!nghttp2_pq_empty(&session->root.obq) ||
|
||||
!nghttp2_pq_empty(&session->ob_data)) &&
|
||||
session->remote_window_size > 0) ||
|
||||
(nghttp2_outbound_queue_top(&session->ob_syn) &&
|
||||
!session_is_outgoing_concurrent_streams_max(session));
|
||||
|
@ -7023,6 +7237,7 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
|||
int rv;
|
||||
nghttp2_mem *mem;
|
||||
nghttp2_inflight_settings *inflight_settings = NULL;
|
||||
uint8_t no_rfc7540_pri = session->pending_no_rfc7540_priorities;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
|
@ -7040,6 +7255,21 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
|||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
for (i = 0; i < niv; ++i) {
|
||||
if (iv[i].settings_id != NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (no_rfc7540_pri == UINT8_MAX) {
|
||||
no_rfc7540_pri = (uint8_t)iv[i].value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iv[i].value != (uint32_t)no_rfc7540_pri) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
|
@ -7114,6 +7344,12 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
|||
}
|
||||
}
|
||||
|
||||
if (no_rfc7540_pri == UINT8_MAX) {
|
||||
session->pending_no_rfc7540_priorities = 0;
|
||||
} else {
|
||||
session->pending_no_rfc7540_priorities = no_rfc7540_pri;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -7242,7 +7478,9 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
|||
return rv;
|
||||
}
|
||||
|
||||
reschedule_stream(stream);
|
||||
if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES)) {
|
||||
reschedule_stream(stream);
|
||||
}
|
||||
|
||||
if (frame->hd.length == 0 && (data_flags & NGHTTP2_DATA_FLAG_EOF) &&
|
||||
(data_flags & NGHTTP2_DATA_FLAG_NO_END_STREAM)) {
|
||||
|
@ -7316,7 +7554,7 @@ int nghttp2_session_resume_data(nghttp2_session *session, int32_t stream_id) {
|
|||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = nghttp2_stream_resume_deferred_item(stream,
|
||||
rv = session_resume_deferred_stream_item(session, stream,
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
|
@ -7424,6 +7662,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
|
|||
return session->remote_settings.max_header_list_size;
|
||||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
return session->remote_settings.enable_connect_protocol;
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
return session->remote_settings.no_rfc7540_priorities;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
|
@ -7447,6 +7687,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session,
|
|||
return session->local_settings.max_header_list_size;
|
||||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
return session->local_settings.enable_connect_protocol;
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
return session->local_settings.no_rfc7540_priorities;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
|
@ -7730,6 +7972,10 @@ int nghttp2_session_change_stream_priority(
|
|||
nghttp2_stream *stream;
|
||||
nghttp2_priority_spec pri_spec_copy;
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_id == 0 || stream_id == pri_spec->stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
@ -7762,6 +8008,10 @@ int nghttp2_session_create_idle_stream(nghttp2_session *session,
|
|||
nghttp2_stream *stream;
|
||||
nghttp2_priority_spec pri_spec_copy;
|
||||
|
||||
if (session->pending_no_rfc7540_priorities == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_id == 0 || stream_id == pri_spec->stream_id ||
|
||||
!session_detect_idle_stream(session, stream_id)) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
|
|
|
@ -165,6 +165,7 @@ typedef struct {
|
|||
uint32_t max_frame_size;
|
||||
uint32_t max_header_list_size;
|
||||
uint32_t enable_connect_protocol;
|
||||
uint32_t no_rfc7540_priorities;
|
||||
} nghttp2_settings_storage;
|
||||
|
||||
typedef enum {
|
||||
|
@ -202,6 +203,9 @@ struct nghttp2_session {
|
|||
response) frame, which are subject to
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||
nghttp2_outbound_queue ob_syn;
|
||||
/* Queue for DATA frames which is used when
|
||||
SETTINGS_NO_RFC7540_PRIORITIES is enabled. */
|
||||
nghttp2_pq ob_data;
|
||||
nghttp2_active_outbound_item aob;
|
||||
nghttp2_inbound_frame iframe;
|
||||
nghttp2_hd_deflater hd_deflater;
|
||||
|
@ -227,6 +231,9 @@ struct nghttp2_session {
|
|||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||
considered as in-flight. */
|
||||
nghttp2_inflight_settings *inflight_settings_head;
|
||||
/* Sequential number across all streams to process streams in
|
||||
FIFO. */
|
||||
uint64_t stream_seq;
|
||||
/* The number of outgoing streams. This will be capped by
|
||||
remote_settings.max_concurrent_streams. */
|
||||
size_t num_outgoing_streams;
|
||||
|
@ -328,6 +335,9 @@ struct nghttp2_session {
|
|||
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
|
||||
accept :protocol header field before SETTINGS_ACK is received. */
|
||||
uint8_t pending_enable_connect_protocol;
|
||||
/* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
|
||||
effective before it is acknowledged. */
|
||||
uint8_t pending_no_rfc7540_priorities;
|
||||
/* Nonzero if the session is server side. */
|
||||
uint8_t server;
|
||||
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
||||
|
|
|
@ -484,6 +484,10 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
|||
|
||||
stream->item = item;
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = stream_update_dep_on_attach_item(stream);
|
||||
if (rv != 0) {
|
||||
/* This may relave stream->queued == 1, but stream->item == NULL.
|
||||
|
@ -503,6 +507,10 @@ int nghttp2_stream_detach_item(nghttp2_stream *stream) {
|
|||
stream->item = NULL;
|
||||
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
|
@ -514,6 +522,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
|||
|
||||
stream->flags |= flags;
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
|
@ -529,6 +541,10 @@ int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_attach_item(stream);
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,10 @@ typedef enum {
|
|||
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
||||
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
||||
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
|
||||
/* Indicates that this stream is not subject to RFC7540
|
||||
priorities scheme. */
|
||||
NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
/* HTTP related flags to enforce HTTP semantics */
|
||||
|
|
|
@ -196,7 +196,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
|||
|
||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
|
||||
session->remote_settings.no_rfc7540_priorities != 1) {
|
||||
rv = detect_self_dependency(session, stream_id, pri_spec);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
|
@ -229,6 +230,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
|||
|
||||
mem = &session->mem;
|
||||
|
||||
if (session->remote_settings.no_rfc7540_priorities == 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_id == 0 || pri_spec == NULL) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
@ -688,7 +693,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
|
|||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
|
||||
session->remote_settings.no_rfc7540_priorities != 1) {
|
||||
rv = detect_self_dependency(session, -1, pri_spec);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
|
|
|
@ -114,7 +114,8 @@ Config::Config()
|
|||
hexdump(false),
|
||||
echo_upload(false),
|
||||
no_content_length(false),
|
||||
ktls(false) {}
|
||||
ktls(false),
|
||||
no_rfc7540_pri(false) {}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
|
@ -864,6 +865,12 @@ int Http2Handler::connection_made() {
|
|||
++niv;
|
||||
}
|
||||
|
||||
if (config->no_rfc7540_pri) {
|
||||
entry[niv].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
entry[niv].value = 1;
|
||||
++niv;
|
||||
}
|
||||
|
||||
r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
|
||||
if (r != 0) {
|
||||
return r;
|
||||
|
|
|
@ -83,6 +83,7 @@ struct Config {
|
|||
bool echo_upload;
|
||||
bool no_content_length;
|
||||
bool ktls;
|
||||
bool no_rfc7540_pri;
|
||||
Config();
|
||||
~Config();
|
||||
};
|
||||
|
|
|
@ -79,6 +79,8 @@ const char *strsettingsid(int32_t id) {
|
|||
return "SETTINGS_MAX_HEADER_LIST_SIZE";
|
||||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
return "SETTINGS_ENABLE_CONNECT_PROTOCOL";
|
||||
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||
return "SETTINGS_NO_RFC7540_PRIORITIES";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
|
|
@ -123,7 +123,8 @@ Config::Config()
|
|||
no_push(false),
|
||||
expect_continue(false),
|
||||
verify_peer(true),
|
||||
ktls(false) {
|
||||
ktls(false),
|
||||
no_rfc7540_pri(false) {
|
||||
nghttp2_option_new(&http2_option);
|
||||
nghttp2_option_set_peer_max_concurrent_streams(http2_option,
|
||||
peer_max_concurrent_streams);
|
||||
|
@ -935,6 +936,12 @@ size_t populate_settings(nghttp2_settings_entry *iv) {
|
|||
++niv;
|
||||
}
|
||||
|
||||
if (config.no_rfc7540_pri) {
|
||||
iv[niv].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[niv].value = 1;
|
||||
++niv;
|
||||
}
|
||||
|
||||
return niv;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -2757,6 +2764,8 @@ Options:
|
|||
Suppress warning on server certificate verification
|
||||
failure.
|
||||
--ktls Enable ktls.
|
||||
--no-rfc7540-pri
|
||||
Disable RFC7540 priorities.
|
||||
--version Display version information and exit.
|
||||
-h, --help Display this help and exit.
|
||||
|
||||
|
@ -2813,6 +2822,7 @@ int main(int argc, char **argv) {
|
|||
{"expect-continue", no_argument, &flag, 13},
|
||||
{"encoder-header-table-size", required_argument, &flag, 14},
|
||||
{"ktls", no_argument, &flag, 15},
|
||||
{"no-rfc7540-pri", no_argument, &flag, 16},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
int option_index = 0;
|
||||
int c =
|
||||
|
@ -3044,6 +3054,10 @@ int main(int argc, char **argv) {
|
|||
// ktls option
|
||||
config.ktls = true;
|
||||
break;
|
||||
case 16:
|
||||
// no-rfc7540-pri option
|
||||
config.no_rfc7540_pri = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -98,6 +98,7 @@ struct Config {
|
|||
bool expect_continue;
|
||||
bool verify_peer;
|
||||
bool ktls;
|
||||
bool no_rfc7540_pri;
|
||||
};
|
||||
|
||||
enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE };
|
||||
|
|
|
@ -179,6 +179,8 @@ Options:
|
|||
--no-content-length
|
||||
Don't send content-length header field.
|
||||
--ktls Enable ktls.
|
||||
--no-rfc7540-pri
|
||||
Disable RFC7540 priorities.
|
||||
--version Display version information and exit.
|
||||
-h, --help Display this help and exit.
|
||||
|
||||
|
@ -230,6 +232,7 @@ int main(int argc, char **argv) {
|
|||
{"no-content-length", no_argument, &flag, 10},
|
||||
{"encoder-header-table-size", required_argument, &flag, 11},
|
||||
{"ktls", no_argument, &flag, 12},
|
||||
{"no-rfc7540-pri", no_argument, &flag, 13},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "DVb:c:d:ehm:n:p:va:w:W:", long_options,
|
||||
|
@ -413,6 +416,10 @@ int main(int argc, char **argv) {
|
|||
// tls option
|
||||
config.ktls = true;
|
||||
break;
|
||||
case 13:
|
||||
// no-rfc7540-pri option
|
||||
config.no_rfc7540_pri = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -329,6 +329,8 @@ int main(void) {
|
|||
test_nghttp2_session_no_closed_streams) ||
|
||||
!CU_add_test(pSuite, "session_set_stream_user_data",
|
||||
test_nghttp2_session_set_stream_user_data) ||
|
||||
!CU_add_test(pSuite, "session_no_rfc7540_priorities",
|
||||
test_nghttp2_session_no_rfc7540_priorities) ||
|
||||
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||
test_nghttp2_http_mandatory_headers) ||
|
||||
!CU_add_test(pSuite, "http_content_length",
|
||||
|
|
|
@ -3651,6 +3651,29 @@ void test_nghttp2_session_on_settings_received(void) {
|
|||
|
||||
nghttp2_session_del(session);
|
||||
nghttp2_option_del(option);
|
||||
|
||||
/* It is invalid to change SETTINGS_NO_RFC7540_PRIORITIES in the
|
||||
following SETTINGS. */
|
||||
nghttp2_session_client_new(&session, &callbacks, NULL);
|
||||
|
||||
session->remote_settings.no_rfc7540_priorities = 1;
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[0].value = 0;
|
||||
|
||||
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 1),
|
||||
1);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||
|
||||
nghttp2_frame_settings_free(&frame.settings, mem);
|
||||
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
|
||||
CU_ASSERT(NULL != item);
|
||||
CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_on_push_promise_received(void) {
|
||||
|
@ -5796,6 +5819,37 @@ void test_nghttp2_submit_settings(void) {
|
|||
CU_ASSERT(50 == session->pending_local_max_concurrent_stream);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Bail out if there are contradicting
|
||||
SETTINGS_NO_RFC7540_PRIORITIES in one SETTINGS. */
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[0].value = 1;
|
||||
iv[1].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[1].value = 0;
|
||||
|
||||
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
|
||||
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2));
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Attempt to change SETTINGS_NO_RFC7540_PRIORITIES in the 2nd
|
||||
SETTINGS. */
|
||||
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[0].value = 1;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
||||
|
||||
iv[0].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv[0].value = 0;
|
||||
|
||||
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
|
||||
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
|
||||
|
||||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_submit_settings_update_local_window_size(void) {
|
||||
|
@ -11118,6 +11172,101 @@ void test_nghttp2_session_set_stream_user_data(void) {
|
|||
nghttp2_session_del(session);
|
||||
}
|
||||
|
||||
void test_nghttp2_session_no_rfc7540_priorities(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_data_provider data_prd;
|
||||
my_user_data ud;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_mem *mem;
|
||||
nghttp2_settings_entry iv;
|
||||
nghttp2_priority_spec pri_spec;
|
||||
|
||||
mem = nghttp2_mem_default();
|
||||
|
||||
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
|
||||
/* Do not use a dependency tree if SETTINGS_NO_RFC7540_PRIORITIES =
|
||||
1. */
|
||||
data_prd.read_callback = fixed_length_data_source_read_callback;
|
||||
|
||||
ud.data_source_length = 128 * 1024;
|
||||
CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
|
||||
|
||||
iv.settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv.value = 1;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1));
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
|
||||
open_recv_stream2(session, 1, NGHTTP2_STREAM_OPENING);
|
||||
CU_ASSERT(0 == nghttp2_submit_response(session, 1, resnv, ARRLEN(resnv),
|
||||
&data_prd));
|
||||
item = nghttp2_session_get_next_ob_item(session);
|
||||
CU_ASSERT(ARRLEN(resnv) == item->frame.headers.nvlen);
|
||||
assert_nv_equal(resnv, item->frame.headers.nva, item->frame.headers.nvlen,
|
||||
mem);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||
CU_ASSERT(1 == nghttp2_pq_size(&session->ob_data));
|
||||
CU_ASSERT(nghttp2_pq_empty(&session->root.obq));
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Priorities are sent as is before client receives
|
||||
SETTINGS_NO_RFC7540_PRIORITIES = 1 from server. */
|
||||
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
|
||||
|
||||
iv.settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv.value = 1;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1));
|
||||
|
||||
pri_spec.stream_id = 5;
|
||||
pri_spec.weight = 111;
|
||||
pri_spec.exclusive = 1;
|
||||
|
||||
CU_ASSERT(1 == nghttp2_submit_request(session, &pri_spec, reqnv,
|
||||
ARRLEN(reqnv), NULL, NULL));
|
||||
|
||||
item = nghttp2_outbound_queue_top(&session->ob_syn);
|
||||
|
||||
CU_ASSERT(NULL != item);
|
||||
CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
|
||||
CU_ASSERT(pri_spec.stream_id == item->frame.headers.pri_spec.stream_id);
|
||||
CU_ASSERT(pri_spec.weight == item->frame.headers.pri_spec.weight);
|
||||
CU_ASSERT(pri_spec.exclusive == item->frame.headers.pri_spec.exclusive);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Priorities are defaulted if client received
|
||||
SETTINGS_NO_RFC7540_PRIORITIES = 1 from server. */
|
||||
CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
|
||||
|
||||
iv.settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
|
||||
iv.value = 1;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1));
|
||||
|
||||
session->remote_settings.no_rfc7540_priorities = 1;
|
||||
|
||||
pri_spec.stream_id = 5;
|
||||
pri_spec.weight = 111;
|
||||
pri_spec.exclusive = 1;
|
||||
|
||||
CU_ASSERT(1 == nghttp2_submit_request(session, &pri_spec, reqnv,
|
||||
ARRLEN(reqnv), NULL, NULL));
|
||||
|
||||
item = nghttp2_outbound_queue_top(&session->ob_syn);
|
||||
|
||||
CU_ASSERT(NULL != item);
|
||||
CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
|
||||
CU_ASSERT(nghttp2_priority_spec_check_default(&item->frame.headers.pri_spec));
|
||||
|
||||
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) {
|
||||
|
|
|
@ -162,6 +162,7 @@ void test_nghttp2_session_removed_closed_stream(void);
|
|||
void test_nghttp2_session_pause_data(void);
|
||||
void test_nghttp2_session_no_closed_streams(void);
|
||||
void test_nghttp2_session_set_stream_user_data(void);
|
||||
void test_nghttp2_session_no_rfc7540_priorities(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